diff options
Diffstat (limited to 'intern')
86 files changed, 4503 insertions, 1451 deletions
diff --git a/intern/CMakeLists.txt b/intern/CMakeLists.txt index bfe230250ae..af3b9296077 100644 --- a/intern/CMakeLists.txt +++ b/intern/CMakeLists.txt @@ -33,6 +33,7 @@ add_subdirectory(opencolorio) add_subdirectory(mikktspace) add_subdirectory(glew-mx) add_subdirectory(eigen) +add_subdirectory(gawain) if(WITH_GAMEENGINE_DECKLINK) add_subdirectory(decklink) diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py index a2d6262fb20..1cb7835d14d 100644 --- a/intern/cycles/blender/addon/__init__.py +++ b/intern/cycles/blender/addon/__init__.py @@ -19,7 +19,7 @@ bl_info = { "name": "Cycles Render Engine", "author": "", - "blender": (2, 76, 0), + "blender": (2, 80, 0), "location": "Info header, render engine menu", "description": "Cycles Render Engine integration", "warning": "", @@ -66,21 +66,21 @@ class CyclesRender(bpy.types.RenderEngine): engine.free(self) # final render - def update(self, data, scene): + def update(self, data, depsgraph, scene): if not self.session: if self.is_preview: cscene = bpy.context.scene.cycles use_osl = cscene.shading_system and cscene.device == 'CPU' - engine.create(self, data, scene, + engine.create(self, data, depsgraph, scene, None, None, None, use_osl) else: - engine.create(self, data, scene) + engine.create(self, data, depsgraph, scene) else: engine.reset(self, data, scene) - def render(self, scene): - engine.render(self) + def render_to_image(self, depsgraph): + engine.render(self, depsgraph) def bake(self, scene, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result): engine.bake(self, obj, pass_type, pass_filter, object_id, pixel_array, num_pixels, depth, result) @@ -88,12 +88,12 @@ class CyclesRender(bpy.types.RenderEngine): # viewport render def view_update(self, context): if not self.session: - engine.create(self, context.blend_data, context.scene, + engine.create(self, context.blend_data, context.depsgraph, context.scene, context.region, context.space_data, context.region_data) engine.update(self, context.blend_data, context.scene) - def view_draw(self, context): - engine.draw(self, context.region, context.space_data, context.region_data) + def render_to_view(self, context): + engine.draw(self, context.depsgraph, context.region, context.space_data, context.region_data) def update_script_node(self, node): if engine.with_osl(): diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index 3018fd5b316..5b2cb9fe39b 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -123,12 +123,13 @@ def exit(): _cycles.exit() -def create(engine, data, scene, region=None, v3d=None, rv3d=None, preview_osl=False): +def create(engine, data, depsgraph, scene, region=None, v3d=None, rv3d=None, preview_osl=False): import bpy import _cycles data = data.as_pointer() userpref = bpy.context.user_preferences.as_pointer() + depsgraph = depsgraph.as_pointer() scene = scene.as_pointer() if region: region = region.as_pointer() @@ -142,7 +143,8 @@ def create(engine, data, scene, region=None, v3d=None, rv3d=None, preview_osl=Fa else: _cycles.debug_flags_reset() - engine.session = _cycles.create(engine.as_pointer(), userpref, data, scene, region, v3d, rv3d, preview_osl) + engine.session = _cycles.create( + engine.as_pointer(), userpref, data, depsgraph, scene, region, v3d, rv3d, preview_osl) def free(engine): @@ -153,7 +155,7 @@ def free(engine): del engine.session -def render(engine): +def render(engine, depsgraph): import _cycles if hasattr(engine, "session"): _cycles.render(engine.session) @@ -178,13 +180,14 @@ def update(engine, data, scene): _cycles.sync(engine.session) -def draw(engine, region, v3d, rv3d): +def draw(engine, depsgraph, region, v3d, rv3d): import _cycles + depsgraph = depsgraph.as_pointer() v3d = v3d.as_pointer() rv3d = rv3d.as_pointer() # draw render image - _cycles.draw(engine.session, v3d, rv3d) + _cycles.draw(engine.session, depsgraph, v3d, rv3d) def available_devices(): diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index c744c1d6932..93b90ec650b 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -195,12 +195,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Pause all viewport preview renders", default=False, ) - cls.preview_active_layer = BoolProperty( - name="Preview Active Layer", - description="Preview active render layer in viewport", - default=False, - ) - cls.aa_samples = IntProperty( name="AA Samples", description="Number of antialiasing samples to render for each pixel", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index b9565aa4c7f..983f817539b 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -17,6 +17,7 @@ # <pep8 compliant> import bpy +from bpy_extras.node_utils import find_node_input, find_output_node from bpy.types import ( Panel, @@ -895,43 +896,22 @@ class CYCLES_OT_use_shading_nodes(Operator): return {'FINISHED'} -def find_node(material, nodetype): - if material and material.node_tree: - ntree = material.node_tree - - active_output_node = None - for node in ntree.nodes: - if getattr(node, "type", None) == nodetype: - if getattr(node, "is_active_output", True): - return node - if not active_output_node: - active_output_node = node - return active_output_node - - return None - - -def find_node_input(node, name): - for input in node.inputs: - if input.name == name: - return input - - return None - - -def panel_node_draw(layout, id_data, output_type, input_name): +def panel_node_draw(layout, id_data, output_types, input_name): if not id_data.use_nodes: layout.operator("cycles.use_shading_nodes", icon='NODETREE') return False ntree = id_data.node_tree - node = find_node(id_data, output_type) - if not node: - layout.label(text="No output node") - else: + node = find_output_node(ntree, output_types) + if node: input = find_node_input(node, input_name) - layout.template_node_view(ntree, node, input) + if input: + layout.template_node_view(ntree, node, input) + else: + layout.label(text="Incompatible output node") + else: + layout.label(text="No output node") return True @@ -1020,7 +1000,7 @@ class CyclesLamp_PT_nodes(CyclesButtonsPanel, Panel): layout = self.layout lamp = context.lamp - if not panel_node_draw(layout, lamp, 'OUTPUT_LAMP', 'Surface'): + if not panel_node_draw(layout, lamp, ('OUTPUT_LAMP',), 'Surface'): layout.prop(lamp, "color") @@ -1075,7 +1055,7 @@ class CyclesWorld_PT_surface(CyclesButtonsPanel, Panel): world = context.world - if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'): + if not panel_node_draw(layout, world, ('OUTPUT_WORLD',), 'Surface'): layout.prop(world, "horizon_color", text="Color") @@ -1093,7 +1073,7 @@ class CyclesWorld_PT_volume(CyclesButtonsPanel, Panel): layout = self.layout world = context.world - panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Volume') + panel_node_draw(layout, world, ('OUTPUT_WORLD',), 'Volume') class CyclesWorld_PT_ambient_occlusion(CyclesButtonsPanel, Panel): @@ -1238,7 +1218,7 @@ class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel): layout = self.layout mat = context.material - if not panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Surface'): + if not panel_node_draw(layout, mat, ('OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'), 'Surface'): layout.prop(mat, "diffuse_color") @@ -1258,7 +1238,7 @@ class CyclesMaterial_PT_volume(CyclesButtonsPanel, Panel): mat = context.material # cmat = mat.cycles - panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Volume') + panel_node_draw(layout, mat, ('OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'), 'Volume') class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel): @@ -1274,7 +1254,7 @@ class CyclesMaterial_PT_displacement(CyclesButtonsPanel, Panel): layout = self.layout mat = context.material - panel_node_draw(layout, mat, 'OUTPUT_MATERIAL', 'Displacement') + panel_node_draw(layout, mat, ('OUTPUT_MATERIAL', 'OUTPUT_EEVEE_MATERIAL'), 'Displacement') class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel): @@ -1663,6 +1643,7 @@ class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel): row.prop(rd, "simplify_subdivision", text="Viewport") row.prop(rd, "simplify_subdivision_render", text="Render") + col = layout.column(align=True) col.label(text="Child Particles") row = col.row(align=True) @@ -1725,11 +1706,8 @@ def draw_pause(self, context): if scene.render.engine == "CYCLES": view = context.space_data - if view.viewport_shade == 'RENDERED': - cscene = scene.cycles - layername = scene.render.layers.active.name - layout.prop(cscene, "preview_pause", icon="PAUSE", text="") - layout.prop(cscene, "preview_active_layer", icon="RENDERLAYERS", text=layername) + cscene = scene.cycles + layout.prop(cscene, "preview_pause", icon="PAUSE", text="") def get_panels(): diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 42b985305ea..63b07936426 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -325,14 +325,14 @@ static bool ObtainCacheParticleVcol(Mesh *mesh, return true; } -static void set_resolution(BL::Object *b_ob, BL::Scene *scene, bool render) +static void set_resolution(BL::Object *b_ob, BL::Scene *scene, BL::SceneLayer *sl, bool render) { BL::Object::modifiers_iterator b_mod; for(b_ob->modifiers.begin(b_mod); b_mod != b_ob->modifiers.end(); ++b_mod) { if((b_mod->type() == b_mod->type_PARTICLE_SYSTEM) && ((b_mod->show_viewport()) || (b_mod->show_render()))) { BL::ParticleSystemModifier psmd((const PointerRNA)b_mod->ptr); BL::ParticleSystem b_psys((const PointerRNA)psmd.particle_system().ptr); - b_psys.set_resolution(*scene, *b_ob, (render)? 2: 1); + b_psys.set_resolution(*scene, *sl, *b_ob, (render)? 2: 1); } } } @@ -912,7 +912,7 @@ void BlenderSync::sync_curves(Mesh *mesh, ParticleCurveData CData; if(!preview) - set_resolution(&b_ob, &b_scene, true); + set_resolution(&b_ob, &b_scene, &b_scene_layer, true); ObtainCacheParticleData(mesh, &b_mesh, &b_ob, &CData, !preview); @@ -1057,7 +1057,7 @@ void BlenderSync::sync_curves(Mesh *mesh, } if(!preview) - set_resolution(&b_ob, &b_scene, false); + set_resolution(&b_ob, &b_scene, &b_scene_layer, false); mesh->compute_bounds(); } diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index b4cca5f00f4..2e3271c735f 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -414,7 +414,7 @@ static void attr_create_uv_map(Scene *scene, int i = 0; for(b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) { - bool active_render = b_mesh.uv_textures[i].active_render(); + bool active_render = b_mesh.uv_layers[i].active_render(); AttributeStandard std = (active_render)? ATTR_STD_UV: ATTR_STD_NONE; ustring name = ustring(l->name().c_str()); @@ -942,6 +942,7 @@ static void sync_mesh_fluid_motion(BL::Object& b_ob, Scene *scene, Mesh *mesh) } Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, + BL::Object& b_ob_instance, bool object_updated, bool hide_tris) { @@ -955,7 +956,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, /* test if we can instance or if the object is modified */ BL::ID b_ob_data = b_ob.data(); - BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob_data; + BL::ID key = (BKE_object_is_modified(b_ob))? b_ob_instance: b_ob_data; BL::Material material_override = render_layer.material_override; /* find shader indices */ @@ -1052,6 +1053,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, + b_scene_layer, true, !preview, need_undeformed, @@ -1183,6 +1185,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, b_mesh = object_to_mesh(b_data, b_ob, b_scene, + b_scene_layer, true, !preview, false, diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index a930c439370..991b834dcfa 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -94,12 +94,13 @@ static uint object_ray_visibility(BL::Object& b_ob) void BlenderSync::sync_light(BL::Object& b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object& b_ob, + BL::Object& b_ob_instance, Transform& tfm, bool *use_portal) { /* test if we need to sync */ Light *light; - ObjectKey key(b_parent, persistent_id, b_ob); + ObjectKey key(b_parent, persistent_id, b_ob_instance); if(!light_map.sync(&light, b_ob, b_parent, key)) { if(light->is_portal) @@ -236,24 +237,41 @@ void BlenderSync::sync_background_light(bool use_portal) /* Object */ -Object *BlenderSync::sync_object(BL::Object& b_parent, - int persistent_id[OBJECT_PERSISTENT_ID_SIZE], - BL::DupliObject& b_dupli_ob, - Transform& tfm, +Object *BlenderSync::sync_object(BL::Depsgraph::duplis_iterator& b_dupli_iter, uint layer_flag, float motion_time, bool hide_tris, BlenderObjectCulling& culling, bool *use_portal) { - BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent); - bool motion = motion_time != 0.0f; - + const bool is_instance = b_dupli_iter->is_instance(); + BL::Object b_ob = b_dupli_iter->object(); + BL::Object b_parent = is_instance ? b_dupli_iter->parent() + : b_dupli_iter->object(); + BL::Object b_ob_instance = is_instance ? b_dupli_iter->instance_object() + : b_ob; + const bool motion = motion_time != 0.0f; + /*const*/ Transform tfm = get_transform(b_ob.matrix_world()); + int *persistent_id = NULL; + BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id_array; + if(is_instance) { + persistent_id_array = b_dupli_iter->persistent_id(); + persistent_id = persistent_id_array.data; + } + /* light is handled separately */ if(object_is_light(b_ob)) { /* don't use lamps for excluded layers used as mask layer */ - if(!motion && !((layer_flag & render_layer.holdout_layer) && (layer_flag & render_layer.exclude_layer))) - sync_light(b_parent, persistent_id, b_ob, tfm, use_portal); + if(!motion && !((layer_flag & render_layer.holdout_layer) && + (layer_flag & render_layer.exclude_layer))) + { + sync_light(b_parent, + persistent_id, + b_ob, + b_ob_instance, + tfm, + use_portal); + } return NULL; } @@ -269,7 +287,7 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, } /* key to lookup object */ - ObjectKey key(b_parent, persistent_id, b_ob); + ObjectKey key(b_parent, persistent_id, b_ob_instance); Object *object; /* motion vector case */ @@ -311,7 +329,7 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, bool use_holdout = (layer_flag & render_layer.holdout_layer) != 0; /* mesh sync */ - object->mesh = sync_mesh(b_ob, object_updated, hide_tris); + object->mesh = sync_mesh(b_ob, b_ob_instance, object_updated, hide_tris); /* special case not tracked by object update flags */ @@ -380,10 +398,10 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, } /* dupli texture coordinates and random_id */ - if(b_dupli_ob) { - object->dupli_generated = 0.5f*get_float3(b_dupli_ob.orco()) - make_float3(0.5f, 0.5f, 0.5f); - object->dupli_uv = get_float2(b_dupli_ob.uv()); - object->random_id = b_dupli_ob.random_id(); + if(is_instance) { + object->dupli_generated = 0.5f*get_float3(b_dupli_iter->orco()) - make_float3(0.5f, 0.5f, 0.5f); + object->dupli_uv = get_float2(b_dupli_iter->uv()); + object->random_id = b_dupli_iter->random_id(); } else { object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f); @@ -469,19 +487,11 @@ static bool object_render_hide(BL::Object& b_ob, } } -static bool object_render_hide_duplis(BL::Object& b_ob) -{ - BL::Object parent = b_ob.parent(); - - return (parent && object_render_hide_original(b_ob.type(), parent.dupli_type())); -} - /* Object Loop */ void BlenderSync::sync_objects(float motion_time) { /* layer data */ - uint scene_layer = render_layer.scene_layer; bool motion = motion_time != 0.0f; if(!motion) { @@ -500,100 +510,34 @@ void BlenderSync::sync_objects(float motion_time) BlenderObjectCulling culling(scene, b_scene); /* object loop */ - BL::Scene::object_bases_iterator b_base; - BL::Scene b_sce = b_scene; - /* modifier result type (not exposed as enum in C++ API) - * 1 : DAG_EVAL_PREVIEW - * 2 : DAG_EVAL_RENDER - */ - int dupli_settings = (render_layer.use_viewport_visibility) ? 1 : 2; - bool cancel = false; bool use_portal = false; - uint layer_override = get_layer(b_engine.layer_override()); - for(; b_sce && !cancel; b_sce = b_sce.background_set()) { - /* Render layer's scene_layer is affected by local view already, - * which is not a desired behavior here. - */ - uint scene_layers = layer_override ? layer_override : get_layer(b_scene.layers()); - for(b_sce.object_bases.begin(b_base); b_base != b_sce.object_bases.end() && !cancel; ++b_base) { - BL::Object b_ob = b_base->object(); - bool hide = (render_layer.use_viewport_visibility)? b_ob.hide(): b_ob.hide_render(); - uint ob_layer = get_layer(b_base->layers(), - b_base->layers_local_view(), - object_is_light(b_ob), - scene_layers); - hide = hide || !(ob_layer & scene_layer); - - if(!hide) { - progress.set_sync_status("Synchronizing object", b_ob.name()); - - /* load per-object culling data */ - culling.init_object(scene, b_ob); - - if(b_ob.is_duplicator() && !object_render_hide_duplis(b_ob)) { - /* dupli objects */ - b_ob.dupli_list_create(b_scene, dupli_settings); - - BL::Object::dupli_list_iterator b_dup; - - for(b_ob.dupli_list.begin(b_dup); b_dup != b_ob.dupli_list.end(); ++b_dup) { - Transform tfm = get_transform(b_dup->matrix()); - BL::Object b_dup_ob = b_dup->object(); - bool dup_hide = (render_layer.use_viewport_visibility)? b_dup_ob.hide(): b_dup_ob.hide_render(); - bool in_dupli_group = (b_dup->type() == BL::DupliObject::type_GROUP); - bool hide_tris; - - if(!(b_dup->hide() || dup_hide || object_render_hide(b_dup_ob, false, in_dupli_group, hide_tris))) { - /* the persistent_id allows us to match dupli objects - * between frames and updates */ - BL::Array<int, OBJECT_PERSISTENT_ID_SIZE> persistent_id = b_dup->persistent_id(); - - /* sync object and mesh or light data */ - Object *object = sync_object(b_ob, - persistent_id.data, - *b_dup, - tfm, - ob_layer, - motion_time, - hide_tris, - culling, - &use_portal); - - /* sync possible particle data, note particle_id - * starts counting at 1, first is dummy particle */ - if(!motion && object) { - sync_dupli_particle(b_ob, *b_dup, object); - } - - } - } - - b_ob.dupli_list_clear(); - } - - /* test if object needs to be hidden */ - bool hide_tris; - - if(!object_render_hide(b_ob, true, true, hide_tris)) { - /* object itself */ - Transform tfm = get_transform(b_ob.matrix_world()); - BL::DupliObject b_empty_dupli_ob(PointerRNA_NULL); - sync_object(b_ob, - NULL, - b_empty_dupli_ob, - tfm, - ob_layer, - motion_time, - hide_tris, - culling, - &use_portal); - } - } - - cancel = progress.get_cancel(); - } + BL::Depsgraph::duplis_iterator b_dupli_iter; + for(b_depsgraph.duplis.begin(b_dupli_iter); + b_dupli_iter != b_depsgraph.duplis.end() && !cancel; + ++b_dupli_iter) + { + BL::Object b_ob = b_dupli_iter->object(); + progress.set_sync_status("Synchronizing object", b_ob.name()); + + /* load per-object culling data */ + culling.init_object(scene, b_ob); + + /* test if object needs to be hidden */ + bool hide_tris; + + if(!object_render_hide(b_ob, true, true, hide_tris)) { + /* object itself */ + sync_object(b_dupli_iter, + ~(0), /* until we get rid of layers */ + motion_time, + hide_tris, + culling, + &use_portal); + } + + cancel = progress.get_cancel(); } progress.set_sync_status(""); diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index 54973fd1b7f..772ce1d555e 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -200,10 +200,10 @@ static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/) static PyObject *create_func(PyObject * /*self*/, PyObject *args) { - PyObject *pyengine, *pyuserpref, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d; + PyObject *pyengine, *pyuserpref, *pydata, *pygraph, *pyscene, *pyregion, *pyv3d, *pyrv3d; int preview_osl; - if(!PyArg_ParseTuple(args, "OOOOOOOi", &pyengine, &pyuserpref, &pydata, &pyscene, + if(!PyArg_ParseTuple(args, "OOOOOOOOi", &pyengine, &pyuserpref, &pydata, &pygraph, &pyscene, &pyregion, &pyv3d, &pyrv3d, &preview_osl)) { return NULL; @@ -222,6 +222,10 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args) RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr); BL::BlendData data(dataptr); + PointerRNA graphptr; + RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pygraph), &graphptr); + BL::Depsgraph graph(graphptr); + PointerRNA sceneptr; RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr); BL::Scene scene(sceneptr); @@ -246,7 +250,7 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args) int width = region.width(); int height = region.height(); - session = new BlenderSession(engine, userpref, data, scene, v3d, rv3d, width, height); + session = new BlenderSession(engine, userpref, data, graph, scene, v3d, rv3d, width, height); } else { /* override some settings for preview */ @@ -258,7 +262,7 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args) } /* offline session or preview render */ - session = new BlenderSession(engine, userpref, data, scene); + session = new BlenderSession(engine, userpref, data, graph, scene); } python_thread_state_save(&session->python_thread_state); @@ -324,9 +328,9 @@ static PyObject *bake_func(PyObject * /*self*/, PyObject *args) static PyObject *draw_func(PyObject * /*self*/, PyObject *args) { - PyObject *pysession, *pyv3d, *pyrv3d; + PyObject *pysession, *pygraph, *pyv3d, *pyrv3d; - if(!PyArg_ParseTuple(args, "OOO", &pysession, &pyv3d, &pyrv3d)) + if(!PyArg_ParseTuple(args, "OOOO", &pysession, &pygraph, &pyv3d, &pyrv3d)) return NULL; BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession); diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 12de3da063f..f4e9da43454 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -52,12 +52,15 @@ int BlenderSession::end_resumable_chunk = 0; BlenderSession::BlenderSession(BL::RenderEngine& b_engine, BL::UserPreferences& b_userpref, BL::BlendData& b_data, + BL::Depsgraph& b_depsgraph, BL::Scene& b_scene) : b_engine(b_engine), b_userpref(b_userpref), b_data(b_data), b_render(b_engine.render()), + b_depsgraph(b_depsgraph), b_scene(b_scene), + b_scene_layer(b_engine.scene_layer()), b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL), python_thread_state(NULL) @@ -76,6 +79,7 @@ BlenderSession::BlenderSession(BL::RenderEngine& b_engine, BlenderSession::BlenderSession(BL::RenderEngine& b_engine, BL::UserPreferences& b_userpref, BL::BlendData& b_data, + BL::Depsgraph& b_depsgraph, BL::Scene& b_scene, BL::SpaceView3D& b_v3d, BL::RegionView3D& b_rv3d, @@ -84,7 +88,9 @@ BlenderSession::BlenderSession(BL::RenderEngine& b_engine, b_userpref(b_userpref), b_data(b_data), b_render(b_scene.render()), + b_depsgraph(b_depsgraph), b_scene(b_scene), + b_scene_layer(b_engine.scene_layer()), b_v3d(b_v3d), b_rv3d(b_rv3d), width(width), @@ -141,7 +147,7 @@ void BlenderSession::create_session() session->set_pause(session_pause); /* create sync */ - sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, is_cpu); + sync = new BlenderSync(b_engine, b_data, b_depsgraph, b_scene, scene, !background, session->progress, is_cpu); BL::Object b_camera_override(b_engine.camera_override()); if(b_v3d) { if(session_pause == false) { @@ -211,7 +217,7 @@ void BlenderSession::reset_session(BL::BlendData& b_data_, BL::Scene& b_scene_) session->stats.mem_peak = session->stats.mem_used; /* sync object should be re-created */ - sync = new BlenderSync(b_engine, b_data, b_scene, scene, !background, session->progress, is_cpu); + sync = new BlenderSync(b_engine, b_data, b_depsgraph, b_scene, scene, !background, session->progress, is_cpu); /* for final render we will do full data sync per render layer, only * do some basic syncing here, no objects or materials for speed */ @@ -1297,7 +1303,7 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, BL::ShaderNodeTexPointDensity b_point_density_node(b_node); int length; int settings = background ? 1 : 0; /* 1 - render settings, 0 - vewport settings. */ - b_point_density_node.calc_point_density(b_scene, settings, &length, &pixels); + b_point_density_node.calc_point_density(b_scene, b_scene_layer, settings, &length, &pixels); } } diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index cbd2303d282..7ae7bde1737 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -36,11 +36,13 @@ public: BlenderSession(BL::RenderEngine& b_engine, BL::UserPreferences& b_userpref, BL::BlendData& b_data, + BL::Depsgraph& b_depsgraph, BL::Scene& b_scene); BlenderSession(BL::RenderEngine& b_engine, BL::UserPreferences& b_userpref, BL::BlendData& b_data, + BL::Depsgraph& b_depsgraph, BL::Scene& b_scene, BL::SpaceView3D& b_v3d, BL::RegionView3D& b_rv3d, @@ -104,7 +106,9 @@ public: BL::UserPreferences b_userpref; BL::BlendData b_data; BL::RenderSettings b_render; + BL::Depsgraph b_depsgraph; BL::Scene b_scene; + BL::SceneLayer b_scene_layer; BL::SpaceView3D b_v3d; BL::RegionView3D b_rv3d; string b_rlay_name; diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index bdbab1006c0..bbf7dc720a8 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -231,17 +231,11 @@ static void get_tex_mapping(TextureMapping *mapping, mapping->max = get_float3(b_mapping.max()); } -static bool is_output_node(BL::Node& b_node) -{ - return (b_node.is_a(&RNA_ShaderNodeOutputMaterial) - || b_node.is_a(&RNA_ShaderNodeOutputWorld) - || b_node.is_a(&RNA_ShaderNodeOutputLamp)); -} - static ShaderNode *add_node(Scene *scene, BL::RenderEngine& b_engine, BL::BlendData& b_data, BL::Scene& b_scene, + BL::SceneLayer b_scene_layer, const bool background, ShaderGraph *graph, BL::ShaderNodeTree& b_ntree, @@ -838,7 +832,7 @@ static ShaderNode *add_node(Scene *scene, /* TODO(sergey): Use more proper update flag. */ if(true) { - b_point_density_node.cache_point_density(b_scene, settings); + b_point_density_node.cache_point_density(b_scene, b_scene_layer, settings); scene->image_manager->tag_reload_image( point_density->filename.string(), point_density->builtin_data, @@ -856,7 +850,7 @@ static ShaderNode *add_node(Scene *scene, BL::Object b_ob(b_point_density_node.object()); if(b_ob) { float3 loc, size; - point_density_texture_space(b_scene, + point_density_texture_space(b_scene, b_scene_layer, b_point_density_node, settings, loc, @@ -949,10 +943,47 @@ static ShaderOutput *node_find_output_by_name(ShaderNode *node, return node->output(name.c_str()); } +static BL::ShaderNode find_output_node(BL::ShaderNodeTree& b_ntree) +{ + BL::ShaderNodeTree::nodes_iterator b_node; + BL::ShaderNode output_node(PointerRNA_NULL); + BL::ShaderNode eevee_output_node(PointerRNA_NULL); + + for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) { + BL::ShaderNodeOutputMaterial b_output_node(*b_node); + + if (b_output_node.is_a(&RNA_ShaderNodeOutputMaterial) || + b_output_node.is_a(&RNA_ShaderNodeOutputWorld) || + b_output_node.is_a(&RNA_ShaderNodeOutputLamp)) { + /* regular Cycles output node */ + if(b_output_node.is_active_output()) { + output_node = b_output_node; + break; + } + else if(!output_node.ptr.data) { + output_node = b_output_node; + } + } + else if (b_output_node.is_a(&RNA_ShaderNodeOutputEeveeMaterial)) { + /* Eevee output used if no Cycles node exists */ + if(b_output_node.is_active_output()) { + eevee_output_node = b_output_node; + } + else if(!eevee_output_node.ptr.data) { + eevee_output_node = b_output_node; + } + + } + } + + return (output_node.ptr.data) ? output_node : eevee_output_node; +} + static void add_nodes(Scene *scene, BL::RenderEngine& b_engine, BL::BlendData& b_data, BL::Scene& b_scene, + BL::SceneLayer& b_scene_layer, const bool background, ShaderGraph *graph, BL::ShaderNodeTree& b_ntree, @@ -968,23 +999,7 @@ static void add_nodes(Scene *scene, BL::Node::outputs_iterator b_output; /* find the node to use for output if there are multiple */ - bool found_active_output = false; - BL::ShaderNode output_node(PointerRNA_NULL); - - for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) { - if(is_output_node(*b_node)) { - BL::ShaderNodeOutputMaterial b_output_node(*b_node); - - if(b_output_node.is_active_output()) { - output_node = b_output_node; - found_active_output = true; - break; - } - else if(!output_node.ptr.data && !found_active_output) { - output_node = b_output_node; - } - } - } + BL::ShaderNode output_node = find_output_node(b_ntree); /* add nodes */ for(b_ntree.nodes.begin(b_node); b_node != b_ntree.nodes.end(); ++b_node) { @@ -1043,6 +1058,7 @@ static void add_nodes(Scene *scene, b_engine, b_data, b_scene, + b_scene_layer, background, graph, b_group_ntree, @@ -1081,10 +1097,8 @@ static void add_nodes(Scene *scene, else { ShaderNode *node = NULL; - if(is_output_node(*b_node)) { - if(b_node->ptr.data == output_node.ptr.data) { - node = graph->output(); - } + if(b_node->ptr.data == output_node.ptr.data) { + node = graph->output(); } else { BL::ShaderNode b_shader_node(*b_node); @@ -1092,6 +1106,7 @@ static void add_nodes(Scene *scene, b_engine, b_data, b_scene, + b_scene_layer, background, graph, b_ntree, @@ -1155,6 +1170,7 @@ static void add_nodes(Scene *scene, BL::RenderEngine& b_engine, BL::BlendData& b_data, BL::Scene& b_scene, + BL::SceneLayer& b_scene_layer, const bool background, ShaderGraph *graph, BL::ShaderNodeTree& b_ntree) @@ -1164,6 +1180,7 @@ static void add_nodes(Scene *scene, b_engine, b_data, b_scene, + b_scene_layer, background, graph, b_ntree, @@ -1177,13 +1194,18 @@ void BlenderSync::sync_materials(bool update_all) { shader_map.set_default(scene->default_surface); - /* material loop */ - BL::BlendData::materials_iterator b_mat; - TaskPool pool; set<Shader*> updated_shaders; - for(b_data.materials.begin(b_mat); b_mat != b_data.materials.end(); ++b_mat) { + /* material loop */ + BL::BlendData::materials_iterator b_mat_orig; + for(b_data.materials.begin(b_mat_orig); + b_mat_orig != b_data.materials.end(); + ++b_mat_orig) + { + /* TODO(sergey): Iterate over evaluated data rather than using mapping. */ + BL::Material b_mat_(b_depsgraph.evaluated_id_get(*b_mat_orig)); + BL::Material *b_mat = &b_mat_; Shader *shader; /* test if we need to sync */ @@ -1197,7 +1219,7 @@ void BlenderSync::sync_materials(bool update_all) if(b_mat->use_nodes() && b_mat->node_tree()) { BL::ShaderNodeTree b_ntree(b_mat->node_tree()); - add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree); + add_nodes(scene, b_engine, b_data, b_scene, b_scene_layer, !preview, graph, b_ntree); } else { DiffuseBsdfNode *diffuse = new DiffuseBsdfNode(); @@ -1268,7 +1290,7 @@ void BlenderSync::sync_world(bool update_all) if(b_world && b_world.use_nodes() && b_world.node_tree()) { BL::ShaderNodeTree b_ntree(b_world.node_tree()); - add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree); + add_nodes(scene, b_engine, b_data, b_scene, b_scene_layer, !preview, graph, b_ntree); /* volume */ PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles"); @@ -1343,9 +1365,14 @@ void BlenderSync::sync_lamps(bool update_all) shader_map.set_default(scene->default_light); /* lamp loop */ - BL::BlendData::lamps_iterator b_lamp; - - for(b_data.lamps.begin(b_lamp); b_lamp != b_data.lamps.end(); ++b_lamp) { + BL::BlendData::lamps_iterator b_lamp_orig; + for(b_data.lamps.begin(b_lamp_orig); + b_lamp_orig != b_data.lamps.end(); + ++b_lamp_orig) + { + /* TODO(sergey): Iterate over evaluated data rather than using mapping. */ + BL::Lamp b_lamp_(b_depsgraph.evaluated_id_get(*b_lamp_orig)); + BL::Lamp *b_lamp = &b_lamp_; Shader *shader; /* test if we need to sync */ @@ -1358,7 +1385,7 @@ void BlenderSync::sync_lamps(bool update_all) BL::ShaderNodeTree b_ntree(b_lamp->node_tree()); - add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree); + add_nodes(scene, b_engine, b_data, b_scene, b_scene_layer, !preview, graph, b_ntree); } else { float strength = 1.0f; diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index e953c685b56..adbabaccdc1 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -44,6 +44,7 @@ CCL_NAMESPACE_BEGIN BlenderSync::BlenderSync(BL::RenderEngine& b_engine, BL::BlendData& b_data, + BL::Depsgraph& b_depsgraph, BL::Scene& b_scene, Scene *scene, bool preview, @@ -51,7 +52,9 @@ BlenderSync::BlenderSync(BL::RenderEngine& b_engine, bool is_cpu) : b_engine(b_engine), b_data(b_data), + b_depsgraph(b_depsgraph), b_scene(b_scene), + b_scene_layer(b_engine.scene_layer()), shader_map(&scene->shaders), object_map(&scene->objects), mesh_map(&scene->meshes), @@ -382,26 +385,9 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D& b_v3d, const char *layer) /* 3d view */ if(b_v3d) { - if(RNA_boolean_get(&cscene, "preview_active_layer")) { - BL::RenderLayers layers(b_scene.render().ptr); - layername = layers.active().name(); - layer = layername.c_str(); - } - else { - render_layer.scene_layer = get_layer(b_v3d.layers(), b_v3d.layers_local_view()); - render_layer.layer = render_layer.scene_layer; - render_layer.exclude_layer = 0; - render_layer.holdout_layer = 0; - render_layer.material_override = PointerRNA_NULL; - render_layer.use_background_shader = true; - render_layer.use_background_ao = true; - render_layer.use_hair = true; - render_layer.use_surfaces = true; - render_layer.use_viewport_visibility = true; - render_layer.samples = 0; - render_layer.bound_samples = false; - return; - } + BL::RenderLayers layers(b_scene.render().ptr); + layername = layers.active().name(); + layer = layername.c_str(); } /* render layer */ @@ -430,7 +416,6 @@ void BlenderSync::sync_render_layers(BL::SpaceView3D& b_v3d, const char *layer) render_layer.use_background_ao = b_rlay->use_ao(); render_layer.use_surfaces = b_rlay->use_solid(); render_layer.use_hair = b_rlay->use_strand(); - render_layer.use_viewport_visibility = false; render_layer.bound_samples = (use_layer_samples == 1); if(use_layer_samples != 2) { @@ -840,17 +825,8 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, params.shadingsystem = SHADINGSYSTEM_OSL; /* color managagement */ -#ifdef GLEW_MX - /* When using GLEW MX we need to check whether we've got an OpenGL - * context for current window. This is because command line rendering - * doesn't have OpenGL context actually. - */ - if(glewGetContext() != NULL) -#endif - { - params.display_buffer_linear = GLEW_ARB_half_float_pixel && - b_engine.support_display_space_shader(b_scene); - } + params.display_buffer_linear = GLEW_ARB_half_float_pixel && + b_engine.support_display_space_shader(b_scene); if(b_engine.is_preview()) { /* For preview rendering we're using same timeout as diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 4ec46424b5a..69fee9551dd 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -43,6 +43,7 @@ class Mesh; class Object; class ParticleSystem; class Scene; +class SceneLayer; class Shader; class ShaderGraph; class ShaderNode; @@ -51,6 +52,7 @@ class BlenderSync { public: BlenderSync(BL::RenderEngine& b_engine, BL::BlendData& b_data, + BL::Depsgraph& b_graph, BL::Scene& b_scene, Scene *scene, bool preview, @@ -115,16 +117,16 @@ private: void sync_curve_settings(); void sync_nodes(Shader *shader, BL::ShaderNodeTree& b_ntree); - Mesh *sync_mesh(BL::Object& b_ob, bool object_updated, bool hide_tris); + Mesh *sync_mesh(BL::Object& b_ob, + BL::Object& b_ob_instance, + bool object_updated, + bool hide_tris); void sync_curves(Mesh *mesh, BL::Mesh& b_mesh, BL::Object& b_ob, bool motion, int time_index = 0); - Object *sync_object(BL::Object& b_parent, - int persistent_id[OBJECT_PERSISTENT_ID_SIZE], - BL::DupliObject& b_dupli_ob, - Transform& tfm, + Object *sync_object(BL::Depsgraph::duplis_iterator& b_dupli_iter, uint layer_flag, float motion_time, bool hide_tris, @@ -133,6 +135,7 @@ private: void sync_light(BL::Object& b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::Object& b_ob, + BL::Object& b_ob_instance, Transform& tfm, bool *use_portal); void sync_background_light(bool use_portal); @@ -161,7 +164,9 @@ private: /* variables */ BL::RenderEngine b_engine; BL::BlendData b_data; + BL::Depsgraph b_depsgraph; BL::Scene b_scene; + BL::SceneLayer b_scene_layer; id_map<void*, Shader> shader_map; id_map<ObjectKey, Object> object_map; @@ -191,7 +196,6 @@ private: use_background_ao(true), use_surfaces(true), use_hair(true), - use_viewport_visibility(false), samples(0), bound_samples(false) {} @@ -205,7 +209,6 @@ private: bool use_background_ao; bool use_surfaces; bool use_hair; - bool use_viewport_visibility; int samples; bool bound_samples; } render_layer; diff --git a/intern/cycles/blender/blender_texture.cpp b/intern/cycles/blender/blender_texture.cpp index b2e27b76189..dd08be3ddc9 100644 --- a/intern/cycles/blender/blender_texture.cpp +++ b/intern/cycles/blender/blender_texture.cpp @@ -34,7 +34,7 @@ void density_texture_space_invert(float3& loc, } /* namespace */ -void point_density_texture_space(BL::Scene& b_scene, +void point_density_texture_space(BL::Scene& b_scene, BL::SceneLayer& b_scene_layer, BL::ShaderNodeTexPointDensity& b_point_density_node, int settings, float3& loc, @@ -48,6 +48,7 @@ void point_density_texture_space(BL::Scene& b_scene, } float3 min, max; b_point_density_node.calc_point_density_minmax(b_scene, + b_scene_layer, settings, &min[0], &max[0]); diff --git a/intern/cycles/blender/blender_texture.h b/intern/cycles/blender/blender_texture.h index 734231a85ec..c343d5dab92 100644 --- a/intern/cycles/blender/blender_texture.h +++ b/intern/cycles/blender/blender_texture.h @@ -22,7 +22,7 @@ CCL_NAMESPACE_BEGIN -void point_density_texture_space(BL::Scene& b_scene, +void point_density_texture_space(BL::Scene& b_scene, BL::SceneLayer& b_scene_layer, BL::ShaderNodeTexPointDensity& b_point_density_node, const int settings, float3& loc, diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 363e19f7a20..314bcaf23c4 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -46,6 +46,7 @@ void python_thread_state_restore(void **python_thread_state); static inline BL::Mesh object_to_mesh(BL::BlendData& data, BL::Object& object, BL::Scene& scene, + BL::SceneLayer scene_layer, bool apply_modifiers, bool render, bool calc_undeformed, @@ -64,7 +65,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, subsurf_mod.show_viewport(false); } - BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed); + BL::Mesh me = data.meshes.new_from_object(scene, scene_layer, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed); if(subdivision_type != Mesh::SUBDIVISION_NONE) { BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index f64436aec7b..5ae83b56fcd 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -23,6 +23,7 @@ #include "util/util_debug.h" #include "util/util_foreach.h" #include "util/util_half.h" +#include "util/util_logging.h" #include "util/util_math.h" #include "util/util_opengl.h" #include "util/util_time.h" @@ -77,8 +78,13 @@ std::ostream& operator <<(std::ostream &os, Device::~Device() { - if(!background && vertex_buffer != 0) { - glDeleteBuffers(1, &vertex_buffer); + if(!background) { + if(vertex_buffer != 0) { + glDeleteBuffers(1, &vertex_buffer); + } + if(fallback_shader_program != 0) { + glDeleteProgram(fallback_shader_program); + } } } @@ -100,125 +106,266 @@ void Device::pixels_free(device_memory& mem) mem_free(mem); } -void Device::draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int dy, int width, int height, bool transparent, - const DeviceDrawParams &draw_params) +/* TODO move shaders to standalone .glsl file. */ +const char *FALLBACK_VERTEX_SHADER = +"#version 330\n" +"uniform vec2 fullscreen;\n" +"in vec2 texCoord;\n" +"in vec2 pos;\n" +"out vec2 texCoord_interp;\n" +"\n" +"vec2 normalize_coordinates()\n" +"{\n" +" return (vec2(2.0) * (pos / fullscreen)) - vec2(1.0);\n" +"}\n" +"\n" +"void main()\n" +"{\n" +" gl_Position = vec4(normalize_coordinates(), 0.0, 1.0);\n" +" texCoord_interp = texCoord;\n" +"}\n\0"; + +const char *FALLBACK_FRAGMENT_SHADER = +"#version 330\n" +"uniform sampler2D image_texture;\n" +"in vec2 texCoord_interp;\n" +"out vec4 fragColor;\n" +"\n" +"void main()\n" +"{\n" +" fragColor = texture(image_texture, texCoord_interp);\n" +"}\n\0"; + +static void shader_print_errors(const char *task, const char *log, const char *code) { - pixels_copy_from(rgba, y, w, h); + LOG(ERROR) << "Shader: " << task << " error:"; + LOG(ERROR) << "===== shader string ===="; - if(transparent) { - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + stringstream stream(code); + string partial; + + int line = 1; + while(getline(stream, partial, '\n')) { + if(line < 10) { + LOG(ERROR) << " " << line << " " << partial; + } + else { + LOG(ERROR) << line << " " << partial; + } + line++; } + LOG(ERROR) << log; +} - glColor3f(1.0f, 1.0f, 1.0f); +static int bind_fallback_shader(void) +{ + GLint status; + GLchar log[5000]; + GLsizei length = 0; + GLuint program = 0; - if(rgba.data_type == TYPE_HALF) { - /* for multi devices, this assumes the inefficient method that we allocate - * all pixels on the device even though we only render to a subset */ - GLhalf *data_pointer = (GLhalf*)rgba.data_pointer; - float vbuffer[16], *basep; - float *vp = NULL; + struct Shader { + const char *source; + GLenum type; + } shaders[2] = { + {FALLBACK_VERTEX_SHADER, GL_VERTEX_SHADER}, + {FALLBACK_FRAGMENT_SHADER, GL_FRAGMENT_SHADER} + }; - data_pointer += 4*y*w; + program = glCreateProgram(); - /* draw half float texture, GLSL shader for display transform assumed to be bound */ - GLuint texid; - glGenTextures(1, &texid); - glBindTexture(GL_TEXTURE_2D, texid); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, w, h, 0, GL_RGBA, GL_HALF_FLOAT, data_pointer); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + for(int i = 0; i < 2; i++) { + GLuint shader = glCreateShader(shaders[i].type); + + string source_str = shaders[i].source; + const char *c_str = source_str.c_str(); - glEnable(GL_TEXTURE_2D); + glShaderSource(shader, 1, &c_str, NULL); + glCompileShader(shader); - if(draw_params.bind_display_space_shader_cb) { - draw_params.bind_display_space_shader_cb(); + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + + if(!status) { + glGetShaderInfoLog(shader, sizeof(log), &length, log); + shader_print_errors("compile", log, c_str); + return 0; } - if(GLEW_VERSION_1_5) { - if(!vertex_buffer) - glGenBuffers(1, &vertex_buffer); + glAttachShader(program, shader); + } + + /* Link output. */ + glBindFragDataLocation(program, 0, "fragColor"); - glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); - /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */ - glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW); + /* Link and error check. */ + glLinkProgram(program); - vp = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + glGetProgramiv(program, GL_LINK_STATUS, &status); + if(!status) { + glGetShaderInfoLog(program, sizeof(log), &length, log); + shader_print_errors("linking", log, FALLBACK_VERTEX_SHADER); + shader_print_errors("linking", log, FALLBACK_FRAGMENT_SHADER); + return 0; + } - basep = NULL; + return program; +} + +bool Device::bind_fallback_display_space_shader(const float width, const float height) +{ + if(fallback_status == FALLBACK_SHADER_STATUS_ERROR) { + return false; + } + + if(fallback_status == FALLBACK_SHADER_STATUS_NONE) { + fallback_shader_program = bind_fallback_shader(); + fallback_status = FALLBACK_SHADER_STATUS_ERROR; + + if (fallback_shader_program == 0) { + return false; } - else { - basep = vbuffer; - vp = vbuffer; + + glUseProgram(fallback_shader_program); + image_texture_location = glGetUniformLocation(fallback_shader_program, "image_texture"); + if(image_texture_location < 0) { + LOG(ERROR) << "Shader doesn't containt the 'image_texture' uniform."; + return false; } - if(vp) { - /* texture coordinate - vertex pair */ - vp[0] = 0.0f; - vp[1] = 0.0f; - vp[2] = dx; - vp[3] = dy; - - vp[4] = 1.0f; - vp[5] = 0.0f; - vp[6] = (float)width + dx; - vp[7] = dy; - - vp[8] = 1.0f; - vp[9] = 1.0f; - vp[10] = (float)width + dx; - vp[11] = (float)height + dy; - - vp[12] = 0.0f; - vp[13] = 1.0f; - vp[14] = dx; - vp[15] = (float)height + dy; - - if(vertex_buffer) - glUnmapBuffer(GL_ARRAY_BUFFER); + fullscreen_location = glGetUniformLocation(fallback_shader_program, "fullscreen"); + if(fullscreen_location < 0) { + LOG(ERROR) << "Shader doesn't containt the 'fullscreen' uniform."; + return false; } - glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), basep); - glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), ((char *)basep) + 2 * sizeof(float)); + fallback_status = FALLBACK_SHADER_STATUS_SUCCESS; + } - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + /* Run this every time. */ + glUseProgram(fallback_shader_program); + glUniform1i(image_texture_location, 0); + glUniform2f(fullscreen_location, width, height); + return true; +} - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +void Device::draw_pixels( + device_memory& rgba, int y, + int w, int h, int width, int height, + int dx, int dy, int dw, int dh, + bool transparent, const DeviceDrawParams &draw_params) +{ + const bool use_fallback_shader = (draw_params.bind_display_space_shader_cb == NULL); + pixels_copy_from(rgba, y, w, h); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + GLuint texid; + glGenTextures(1, &texid); + glBindTexture(GL_TEXTURE_2D, texid); - if(vertex_buffer) { - glBindBuffer(GL_ARRAY_BUFFER, 0); - } + if(rgba.data_type == TYPE_HALF) { + GLhalf *data_pointer = (GLhalf*)rgba.data_pointer; + data_pointer += 4 * y * w; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, w, h, 0, GL_RGBA, GL_HALF_FLOAT, data_pointer); + } + else { + uint8_t *data_pointer = (uint8_t*)rgba.data_pointer; + data_pointer += 4 * y * w; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data_pointer); + } - if(draw_params.unbind_display_space_shader_cb) { - draw_params.unbind_display_space_shader_cb(); - } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glEnable(GL_TEXTURE_2D); + + if(transparent) { + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); - glDeleteTextures(1, &texid); + GLint shader_program; + if(use_fallback_shader) { + if (!bind_fallback_display_space_shader(dw, dh)) { + return; + } + shader_program = fallback_shader_program; } else { - /* fallback for old graphics cards that don't support GLSL, half float, - * and non-power-of-two textures */ - glPixelZoom((float)width/(float)w, (float)height/(float)h); - glRasterPos2f(dx, dy); + draw_params.bind_display_space_shader_cb(); + glGetIntegerv(GL_CURRENT_PROGRAM, &shader_program); + } + + if(!vertex_buffer) { + glGenBuffers(1, &vertex_buffer); + } + + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */ + glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW); + + float *vpointer = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + + if(vpointer) { + /* texture coordinate - vertex pair */ + vpointer[0] = 0.0f; + vpointer[1] = 0.0f; + vpointer[2] = dx; + vpointer[3] = dy; - uint8_t *pixels = (uint8_t*)rgba.data_pointer; + vpointer[4] = 1.0f; + vpointer[5] = 0.0f; + vpointer[6] = (float)width + dx; + vpointer[7] = dy; - pixels += 4*y*w; + vpointer[8] = 1.0f; + vpointer[9] = 1.0f; + vpointer[10] = (float)width + dx; + vpointer[11] = (float)height + dy; - glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + vpointer[12] = 0.0f; + vpointer[13] = 1.0f; + vpointer[14] = dx; + vpointer[15] = (float)height + dy; - glRasterPos2f(0.0f, 0.0f); - glPixelZoom(1.0f, 1.0f); + if(vertex_buffer) { + glUnmapBuffer(GL_ARRAY_BUFFER); + } } - if(transparent) + GLuint vertex_array_object; + GLuint position_attribute, texcoord_attribute; + + glGenVertexArrays(1, &vertex_array_object); + glBindVertexArray(vertex_array_object); + + texcoord_attribute = glGetAttribLocation(shader_program, "texCoord"); + position_attribute = glGetAttribLocation(shader_program, "pos"); + + glEnableVertexAttribArray(texcoord_attribute); + glEnableVertexAttribArray(position_attribute); + + glVertexAttribPointer(texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0); + glVertexAttribPointer(position_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)(sizeof(float) * 2)); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + if(vertex_buffer) { + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + if(use_fallback_shader) { + glUseProgram(0); + } + else { + draw_params.unbind_display_space_shader_cb(); + } + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + glDeleteTextures(1, &texid); + + if(transparent) { glDisable(GL_BLEND); + } } Device *Device::create(DeviceInfo& info, Stats &stats, bool background) diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 26d6d380a10..8736a6927e0 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -236,13 +236,26 @@ struct DeviceDrawParams { class Device { friend class device_sub_ptr; protected: - Device(DeviceInfo& info_, Stats &stats_, bool background) : background(background), vertex_buffer(0), info(info_), stats(stats_) {} + enum { + FALLBACK_SHADER_STATUS_NONE = 0, + FALLBACK_SHADER_STATUS_ERROR, + FALLBACK_SHADER_STATUS_SUCCESS, + }; + + Device(DeviceInfo& info_, Stats &stats_, bool background) : background(background), + vertex_buffer(0), + fallback_status(FALLBACK_SHADER_STATUS_NONE), fallback_shader_program(0), + info(info_), stats(stats_) {} bool background; string error_msg; /* used for real time display */ unsigned int vertex_buffer; + int fallback_status, fallback_shader_program; + int image_texture_location, fullscreen_location; + + bool bind_fallback_display_space_shader(const float width, const float height); virtual device_ptr mem_alloc_sub_ptr(device_memory& /*mem*/, int /*offset*/, int /*size*/, MemoryType /*type*/) { @@ -317,9 +330,10 @@ public: virtual void task_cancel() = 0; /* opengl drawing */ - virtual void draw_pixels(device_memory& mem, int y, int w, int h, - int dx, int dy, int width, int height, bool transparent, - const DeviceDrawParams &draw_params); + virtual void draw_pixels(device_memory& mem, int y, + int w, int h, int width, int height, + int dx, int dy, int dw, int dh, + bool transparent, const DeviceDrawParams &draw_params); #ifdef WITH_NETWORK /* networking */ diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 6769ed0229e..c68eba7bef6 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -1632,10 +1632,14 @@ public: } } - void draw_pixels(device_memory& mem, int y, int w, int h, int dx, int dy, int width, int height, bool transparent, + void draw_pixels( + device_memory& mem, int y, + int w, int h, int width, int height, + int dx, int dy, int dw, int dh, bool transparent, const DeviceDrawParams &draw_params) { if(!background) { + const bool use_fallback_shader = (draw_params.bind_display_space_shader_cb == NULL); PixelMem pmem = pixel_mem_map[mem.device_pointer]; float *vpointer; @@ -1652,10 +1656,12 @@ public: glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pmem.cuPBO); glBindTexture(GL_TEXTURE_2D, pmem.cuTexId); - if(mem.data_type == TYPE_HALF) + if(mem.data_type == TYPE_HALF) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_HALF_FLOAT, (void*)offset); - else + } + else { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, (void*)offset); + } glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); glEnable(GL_TEXTURE_2D); @@ -1665,14 +1671,21 @@ public: glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } - glColor3f(1.0f, 1.0f, 1.0f); - - if(draw_params.bind_display_space_shader_cb) { + GLint shader_program; + if(use_fallback_shader) { + if(!bind_fallback_display_space_shader(dw, dh)) { + return; + } + shader_program = fallback_shader_program; + } + else { draw_params.bind_display_space_shader_cb(); + glGetIntegerv(GL_CURRENT_PROGRAM, &shader_program); } - if(!vertex_buffer) + if(!vertex_buffer) { glGenBuffers(1, &vertex_buffer); + } glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); /* invalidate old contents - avoids stalling if buffer is still waiting in queue to be rendered */ @@ -1705,25 +1718,33 @@ public: glUnmapBuffer(GL_ARRAY_BUFFER); } - glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0); - glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)NULL + 2 * sizeof(float)); + GLuint vertex_array_object; + GLuint position_attribute, texcoord_attribute; - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glGenVertexArrays(1, &vertex_array_object); + glBindVertexArray(vertex_array_object); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + texcoord_attribute = glGetAttribLocation(shader_program, "texCoord"); + position_attribute = glGetAttribLocation(shader_program, "pos"); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + glEnableVertexAttribArray(texcoord_attribute); + glEnableVertexAttribArray(position_attribute); - glBindBuffer(GL_ARRAY_BUFFER, 0); + glVertexAttribPointer(texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0); + glVertexAttribPointer(position_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)(sizeof(float) * 2)); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - if(draw_params.unbind_display_space_shader_cb) { + if(use_fallback_shader) { + glUseProgram(0); + } + else { draw_params.unbind_display_space_shader_cb(); } - if(transparent) + if(transparent) { glDisable(GL_BLEND); + } glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); @@ -1733,7 +1754,7 @@ public: return; } - Device::draw_pixels(mem, y, w, h, dx, dy, width, height, transparent, draw_params); + Device::draw_pixels(mem, y, w, h, width, height, dx, dy, dw, dh, transparent, draw_params); } void thread_run(DeviceTask *task) diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp index bc505b676fc..35ae0303d6e 100644 --- a/intern/cycles/device/device_multi.cpp +++ b/intern/cycles/device/device_multi.cpp @@ -254,8 +254,11 @@ public: mem.device_pointer = tmp; } - void draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int dy, int width, int height, bool transparent, - const DeviceDrawParams &draw_params) + void draw_pixels( + device_memory& rgba, int y, + int w, int h, int width, int height, + int dx, int dy, int dw, int dh, + bool transparent, const DeviceDrawParams &draw_params) { device_ptr tmp = rgba.device_pointer; int i = 0, sub_h = h/devices.size(); @@ -269,7 +272,7 @@ public: /* adjust math for w/width */ rgba.device_pointer = sub.ptr_map[tmp]; - sub.device->draw_pixels(rgba, sy, w, sh, dx, sdy, width, sheight, transparent, draw_params); + sub.device->draw_pixels(rgba, sy, w, sh, width, sheight, dx, sdy, dw, dh, transparent, draw_params); i++; } diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index cf402c3f214..ff6f40c010e 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -428,7 +428,11 @@ void DisplayBuffer::draw(Device *device, const DeviceDrawParams& draw_params) if(draw_width != 0 && draw_height != 0) { device_memory& rgba = rgba_data(); - device->draw_pixels(rgba, 0, draw_width, draw_height, params.full_x, params.full_y, params.width, params.height, transparent, draw_params); + device->draw_pixels( + rgba, 0, + draw_width, draw_height, params.width, params.height, + params.full_x, params.full_y, params.full_width, params.full_height, + transparent, draw_params); } } diff --git a/intern/cycles/util/util_opengl.h b/intern/cycles/util/util_opengl.h index 0b5462e0a09..7a8d5eec1f9 100644 --- a/intern/cycles/util/util_opengl.h +++ b/intern/cycles/util/util_opengl.h @@ -20,12 +20,6 @@ /* OpenGL header includes, used everywhere we use OpenGL, to deal with * platform differences in one central place. */ -#ifdef WITH_GLEW_MX -# include "glew-mx.h" -#else -# include <GL/glew.h> -# define mxCreateContext() glewInit() -# define mxMakeCurrentContext(x) (x) -#endif +#include <GL/glew.h> #endif /* __UTIL_OPENGL_H__ */ diff --git a/intern/cycles/util/util_view.cpp b/intern/cycles/util/util_view.cpp index 10d86167921..7b453d123b8 100644 --- a/intern/cycles/util/util_view.cpp +++ b/intern/cycles/util/util_view.cpp @@ -252,7 +252,7 @@ void view_main_loop(const char *title, int width, int height, glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH); glutCreateWindow(title); - mxMakeCurrentContext(mxCreateContext()); + glewInit(); view_reshape(width, height); diff --git a/intern/elbeem/intern/solver_control.cpp b/intern/elbeem/intern/solver_control.cpp index c3015b82f0a..d7ed1a5a7ef 100644 --- a/intern/elbeem/intern/solver_control.cpp +++ b/intern/elbeem/intern/solver_control.cpp @@ -873,156 +873,4 @@ LbmFsgrSolver::handleCpdata() // warning, may return before } -#if LBM_USE_GUI==1 - -#define USE_GLUTILITIES -#include "../gui/gui_utilities.h" - -void LbmFsgrSolver::cpDebugDisplay(int dispset) -{ - for(int cpssi=0; cpssi<(int)mpControl->mCons.size(); cpssi++) { - ControlParticles *cparts = mpControl->mCons[cpssi]->mCparts; - //ControlParticles *cpmotion = mpControl->mCons[cpssi]->mCpmotion; - // display cp parts - const bool cpCubes = false; - const bool cpDots = true; - const bool cpCpdist = true; - const bool cpHideIna = true; - glShadeModel(GL_FLAT); - glDisable( GL_LIGHTING ); // dont light lines - - // dot influence - if((mpControl->mDebugCpscale>0.) && cpDots) { - glPointSize(mpControl->mDebugCpscale * 8.); - glBegin(GL_POINTS); - for(int i=0; i<cparts->getSize(); i++) { - if((cpHideIna)&&( (cparts->getParticle(i)->influence<=0.) || (cparts->getParticle(i)->size<=0.) )) continue; - ntlVec3Gfx org( vec2G(cparts->getParticle(i)->pos ) ); - //LbmFloat halfsize = 0.5; - LbmFloat scale = cparts->getParticle(i)->densityWeight; - //glColor4f( scale,scale,scale,scale ); - glColor4f( 0.,scale,0.,scale ); - glVertex3f( org[0],org[1],org[2] ); - //errMsg("lbmDebugDisplay","CP "<<i<<" at "<<org); // DEBUG - } - glEnd(); - } - - // cp positions - if((mpControl->mDebugCpscale>0.) && cpDots) { - glPointSize(mpControl->mDebugCpscale * 3.); - glBegin(GL_POINTS); - glColor3f( 0,1,0 ); - } - for(int i=0; i<cparts->getSize(); i++) { - if((cpHideIna)&&( (cparts->getParticle(i)->influence<=0.) || (cparts->getParticle(i)->size<=0.) )) continue; - ntlVec3Gfx org( vec2G(cparts->getParticle(i)->pos ) ); - LbmFloat halfsize = 0.5; - LbmFloat scale = cparts->getRadiusAtt() * cparts->getParticle(i)->densityWeight; - if(cpCubes){ glLineWidth( 1 ); - glColor3f( 1,1,1 ); - ntlVec3Gfx s = org-(halfsize * (scale)); - ntlVec3Gfx e = org+(halfsize * (scale)); - drawCubeWire( s,e ); } - if((mpControl->mDebugCpscale>0.) && cpDots) { - glVertex3f( org[0],org[1],org[2] ); - } - } - if(cpDots) glEnd(); - - if(mpControl->mDebugAvgVelScale>0.) { - const float scale = mpControl->mDebugAvgVelScale; - - glColor3f( 1.0,1.0,1 ); - glBegin(GL_LINES); - for(int i=0; i<cparts->getSize(); i++) { - if((cpHideIna)&&( (cparts->getParticle(i)->influence<=0.) || (cparts->getParticle(i)->size<=0.) )) continue; - ntlVec3Gfx org( vec2G(cparts->getParticle(i)->pos ) ); - - //errMsg("CPAVGVEL","i"<<i<<" pos"<<org<<" av"<<cparts->getParticle(i)->avgVel);// DEBUG - float dx = cparts->getParticle(i)->avgVel[0]; - float dy = cparts->getParticle(i)->avgVel[1]; - float dz = cparts->getParticle(i)->avgVel[2]; - dx *= scale; dy *= scale; dz *= scale; - glVertex3f( org[0],org[1],org[2] ); - glVertex3f( org[0]+dx,org[1]+dy,org[2]+dz ); - } - glEnd(); - } // */ - - if( (LBMDIM==2) && (cpCpdist) ) { - - // debug, for use of e.g. LBMGET_FORCE LbmControlData *mpControl = this; -# define TESTGET_FORCE(lev,i,j,k) mpControl->mCpForces[lev][ ((k*mLevel[lev].lSizey)+j)*mLevel[lev].lSizex+i ] - - glBegin(GL_LINES); - //const int lev=0; - for(int lev=0; lev<=mMaxRefine; lev++) { - FSGR_FORIJK_BOUNDS(lev) { - LbmVec pos = LbmVec( - ((mvGeoEnd[0]-mvGeoStart[0])/(LbmFloat)mLevel[lev].lSizex) * ((LbmFloat)i+0.5) + mvGeoStart[0], - ((mvGeoEnd[1]-mvGeoStart[1])/(LbmFloat)mLevel[lev].lSizey) * ((LbmFloat)j+0.5) + mvGeoStart[1], - ((mvGeoEnd[2]-mvGeoStart[2])/(LbmFloat)mLevel[lev].lSizez) * ((LbmFloat)k+0.5) + mvGeoStart[2] ); - if(LBMDIM==2) pos[2] = ((mvGeoEnd[2]-mvGeoStart[2])*0.5 + mvGeoStart[2]); - - if((mpControl->mDebugMaxdScale>0.) && (TESTGET_FORCE(lev,i,j,k).weightAtt<=0.) ) - if(TESTGET_FORCE(lev,i,j,k).maxDistance>=0.) - if(TESTGET_FORCE(lev,i,j,k).maxDistance<CPF_MAXDINIT ) { - const float scale = mpControl->mDebugMaxdScale*10001.; - float dx = TESTGET_FORCE(lev,i,j,k).forceMaxd[0]; - float dy = TESTGET_FORCE(lev,i,j,k).forceMaxd[1]; - float dz = TESTGET_FORCE(lev,i,j,k).forceMaxd[2]; - dx *= scale; dy *= scale; dz *= scale; - glColor3f( 0,1,0 ); - glVertex3f( pos[0],pos[1],pos[2] ); - glVertex3f( pos[0]+dx,pos[1]+dy,pos[2]+dz ); - } // */ - if((mpControl->mDebugAttScale>0.) && (TESTGET_FORCE(lev,i,j,k).weightAtt>0.)) { - const float scale = mpControl->mDebugAttScale*100011.; - float dx = TESTGET_FORCE(lev,i,j,k).forceAtt[0]; - float dy = TESTGET_FORCE(lev,i,j,k).forceAtt[1]; - float dz = TESTGET_FORCE(lev,i,j,k).forceAtt[2]; - dx *= scale; dy *= scale; dz *= scale; - glColor3f( 1,0,0 ); - glVertex3f( pos[0],pos[1],pos[2] ); - glVertex3f( pos[0]+dx,pos[1]+dy,pos[2]+dz ); - } // */ - // why check maxDistance? - if((mpControl->mDebugVelScale>0.) && (TESTGET_FORCE(lev,i,j,k).maxDistance+TESTGET_FORCE(lev,i,j,k).weightVel>0.)) { - float scale = mpControl->mDebugVelScale*1.; - float wvscale = TESTGET_FORCE(lev,i,j,k).weightVel; - float dx = TESTGET_FORCE(lev,i,j,k).forceVel[0]; - float dy = TESTGET_FORCE(lev,i,j,k).forceVel[1]; - float dz = TESTGET_FORCE(lev,i,j,k).forceVel[2]; - scale *= wvscale; - dx *= scale; dy *= scale; dz *= scale; - glColor3f( 0.2,0.2,1 ); - glVertex3f( pos[0],pos[1],pos[2] ); - glVertex3f( pos[0]+dx,pos[1]+dy,pos[2]+dz ); - } // */ - if((mpControl->mDebugCompavScale>0.) && (TESTGET_FORCE(lev,i,j,k).compAvWeight>0.)) { - const float scale = mpControl->mDebugCompavScale*1.; - float dx = TESTGET_FORCE(lev,i,j,k).compAv[0]; - float dy = TESTGET_FORCE(lev,i,j,k).compAv[1]; - float dz = TESTGET_FORCE(lev,i,j,k).compAv[2]; - dx *= scale; dy *= scale; dz *= scale; - glColor3f( 0.2,0.2,1 ); - glVertex3f( pos[0],pos[1],pos[2] ); - glVertex3f( pos[0]+dx,pos[1]+dy,pos[2]+dz ); - } // */ - } // att,maxd - } - glEnd(); - } - } // cpssi - - //fprintf(stderr,"BLA\n"); - glEnable( GL_LIGHTING ); // dont light lines - glShadeModel(GL_SMOOTH); -} - -#else // LBM_USE_GUI==1 void LbmFsgrSolver::cpDebugDisplay(int dispset) { } -#endif // LBM_USE_GUI==1 - - diff --git a/intern/elbeem/intern/solver_util.cpp b/intern/elbeem/intern/solver_util.cpp index f0c7bce2b4e..4bcc3640d72 100644 --- a/intern/elbeem/intern/solver_util.cpp +++ b/intern/elbeem/intern/solver_util.cpp @@ -1677,223 +1677,6 @@ LbmFloat& LbmFsgrSolver::debRAC(LbmFloat* s,int l) { * GUI&debugging functions *****************************************************************************/ - -#if LBM_USE_GUI==1 -#define USE_GLUTILITIES -#include "../gui/gui_utilities.h" - -//! display a single node -void LbmFsgrSolver::debugDisplayNode(int dispset, CellIdentifierInterface* cell ) { - //debugOut(" DD: "<<cell->getAsString() , 10); - ntlVec3Gfx org = this->getCellOrigin( cell ); - ntlVec3Gfx halfsize = this->getCellSize( cell ); - int set = this->getCellSet( cell ); - //debugOut(" DD: "<<cell->getAsString()<<" "<< (dispset->type) , 10); - - bool showcell = true; - int linewidth = 1; - ntlColor col(0.5); - LbmFloat cscale = 1.0; //dispset->scale; - -#define DRAWDISPCUBE(col,scale) \ - { glLineWidth( linewidth ); \ - glColor3f( (col)[0], (col)[1], (col)[2]); \ - ntlVec3Gfx s = org-(halfsize * (scale)); \ - ntlVec3Gfx e = org+(halfsize * (scale)); \ - drawCubeWire( s,e ); } - - CellFlagType flag = this->getCellFlag(cell, set ); - // always check types - if(flag& CFInvalid ) { if(!guiShowInvalid ) return; } - if(flag& CFUnused ) { if(!guiShowInvalid ) return; } - if(flag& CFEmpty ) { if(!guiShowEmpty ) return; } - if(flag& CFInter ) { if(!guiShowInterface) return; } - if(flag& CFNoDelete ) { if(!guiShowNoDelete ) return; } - if(flag& CFBnd ) { if(!guiShowBnd ) return; } - - // only dismiss one of these types - if(flag& CFGrFromCoarse) { if(!guiShowCoarseInner ) return; } // inner not really interesting - else - if(flag& CFGrFromFine) { if(!guiShowCoarseBorder ) return; } - else - if(flag& CFFluid ) { if(!guiShowFluid ) return; } - - switch(dispset) { - case FLUIDDISPNothing: { - showcell = false; - } break; - case FLUIDDISPCelltypes: { - cscale = 0.5; - - if(flag& CFNoDelete) { // debug, mark nodel cells - ntlColor ccol(0.7,0.0,0.0); - DRAWDISPCUBE(ccol, 0.1); - } - if(flag& CFPersistMask) { // mark persistent flags - ntlColor ccol(0.5); - DRAWDISPCUBE(ccol, 0.125); - } - if(flag& CFNoBndFluid) { // mark persistent flags - ntlColor ccol(0,0,1); - DRAWDISPCUBE(ccol, 0.075); - } - - if(flag& CFInvalid) { - cscale = 0.50; - col = ntlColor(0.0,0,0.0); - } - else if(flag& CFBnd) { - cscale = 0.59; - col = ntlColor(0.4); - } - - else if(flag& CFInter) { - cscale = 0.55; - col = ntlColor(0,1,1); - - } else if(flag& CFGrFromCoarse) { - // draw as - with marker - ntlColor col2(0.0,1.0,0.3); - DRAWDISPCUBE(col2, 0.1); - cscale = 0.5; - showcell=false; // DEBUG - } - else if(flag& CFFluid) { - cscale = 0.5; - if(flag& CFGrToFine) { - ntlColor col2(0.5,0.0,0.5); - DRAWDISPCUBE(col2, 0.1); - col = ntlColor(0,0,1); - } - if(flag& CFGrFromFine) { - ntlColor col2(1.0,1.0,0.0); - DRAWDISPCUBE(col2, 0.1); - col = ntlColor(0,0,1); - } else if(flag& CFGrFromCoarse) { - // draw as fluid with marker - ntlColor col2(0.0,1.0,0.3); - DRAWDISPCUBE(col2, 0.1); - col = ntlColor(0,0,1); - } else { - col = ntlColor(0,0,1); - } - } - else if(flag& CFEmpty) { - showcell=false; - } - - } break; - case FLUIDDISPVelocities: { - // dont use cube display - LbmVec vel = this->getCellVelocity( cell, set ); - glBegin(GL_LINES); - glColor3f( 0.0,0.0,0.0 ); - glVertex3f( org[0], org[1], org[2] ); - org += vec2G(vel * 10.0 * cscale); - glColor3f( 1.0,1.0,1.0 ); - glVertex3f( org[0], org[1], org[2] ); - glEnd(); - showcell = false; - } break; - case FLUIDDISPCellfills: { - cscale = 0.5; - if(flag& CFFluid) { - cscale = 0.75; - col = ntlColor(0,0,0.5); - } - else if(flag& CFInter) { - cscale = 0.75 * this->getCellMass(cell,set); - col = ntlColor(0,1,1); - } - else { - showcell=false; - } - - if( ABS(this->getCellMass(cell,set)) < 10.0 ) { - cscale = 0.75 * this->getCellMass(cell,set); - } else { - showcell = false; - } - if(cscale>0.0) { - col = ntlColor(0,1,1); - } else { - col = ntlColor(1,1,0); - } - // TODO - } break; - case FLUIDDISPDensity: { - LbmFloat rho = this->getCellDensity(cell,set); - cscale = rho*rho * 0.25; - col = ntlColor( MIN(0.5+cscale,1.0) , MIN(0.0+cscale,1.0), MIN(0.0+cscale,1.0) ); - cscale *= 2.0; - } break; - case FLUIDDISPGrid: { - cscale = 0.59; - col = ntlColor(1.0); - } break; - default: { - cscale = 0.5; - col = ntlColor(1.0,0.0,0.0); - } break; - } - - if(!showcell) return; - if(cscale==0.0) return; // dont draw zero values - DRAWDISPCUBE(col, cscale); -} - -//! debug display function -// D has to implement the CellIterator interface -void LbmFsgrSolver::lbmDebugDisplay(int dispset) { - // DEBUG always display testdata -#if LBM_INCLUDE_TESTSOLVERS==1 - if(mUseTestdata){ - cpDebugDisplay(dispset); - mpTest->testDebugDisplay(dispset); - } -#endif // LBM_INCLUDE_TESTSOLVERS==1 - if(dispset<=FLUIDDISPNothing) return; - //if(!dispset->on) return; - glDisable( GL_LIGHTING ); // dont light lines - -#if LBM_INCLUDE_TESTSOLVERS==1 - if((!mUseTestdata)|| (mUseTestdata)&&(mpTest->mFarfMode<=0)) { -#endif // LBM_INCLUDE_TESTSOLVERS==1 - - LbmFsgrSolver::CellIdentifier cid = this->getFirstCell(); - for(; this->noEndCell( cid ); - this->advanceCell( cid ) ) { - this->debugDisplayNode(dispset, cid ); - } - delete cid; - -#if LBM_INCLUDE_TESTSOLVERS==1 - } // 3d check -#endif // LBM_INCLUDE_TESTSOLVERS==1 - - glEnable( GL_LIGHTING ); // dont light lines -} - -//! debug display function -// D has to implement the CellIterator interface -void LbmFsgrSolver::lbmMarkedCellDisplay() { - //fluidDispSettings dispset; - // trick - display marked cells as grid displa -> white, big - int dispset = FLUIDDISPGrid; - glDisable( GL_LIGHTING ); // dont light lines - - LbmFsgrSolver::CellIdentifier cid = this->markedGetFirstCell(); - while(cid) { - this->debugDisplayNode(dispset, cid ); - cid = this->markedAdvanceCell(); - } - delete cid; - - glEnable( GL_LIGHTING ); // dont light lines -} - -#endif // LBM_USE_GUI==1 - //! display a single node void LbmFsgrSolver::debugPrintNodeInfo(CellIdentifierInterface* cell, int forceSet) { //string printInfo, diff --git a/intern/gawain/CMakeLists.txt b/intern/gawain/CMakeLists.txt new file mode 100644 index 00000000000..48392012176 --- /dev/null +++ b/intern/gawain/CMakeLists.txt @@ -0,0 +1,40 @@ + +set(INC + gawain +) + +set(INC_SYS + ${GLEW_INCLUDE_PATH} +) + +set(SRC + src/attrib_binding.c + src/batch.c + src/element.c + src/buffer_id.cpp + src/immediate.c + src/imm_util.c + src/primitive.c + src/shader_interface.c + src/vertex_buffer.c + src/vertex_format.c + + gawain/attrib_binding.h + gawain/attrib_binding_private.h + gawain/batch.h + gawain/buffer_id.h + gawain/common.h + gawain/element.h + gawain/imm_util.h + gawain/immediate.h + gawain/primitive.h + gawain/primitive_private.h + gawain/shader_interface.h + gawain/vertex_buffer.h + gawain/vertex_format.h + gawain/vertex_format_private.h +) + +add_definitions(${GL_DEFINITIONS}) + +blender_add_lib(bf_intern_gawain "${SRC}" "${INC}" "${INC_SYS}") diff --git a/intern/gawain/gawain/attrib_binding.h b/intern/gawain/gawain/attrib_binding.h new file mode 100644 index 00000000000..a254f05dc05 --- /dev/null +++ b/intern/gawain/gawain/attrib_binding.h @@ -0,0 +1,19 @@ + +// Gawain vertex attribute binding +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "common.h" + +typedef struct { + uint64_t loc_bits; // store 4 bits for each of the 16 attribs + uint16_t enabled_bits; // 1 bit for each attrib +} Gwn_AttrBinding; diff --git a/intern/gawain/gawain/attrib_binding_private.h b/intern/gawain/gawain/attrib_binding_private.h new file mode 100644 index 00000000000..53fdecff9ce --- /dev/null +++ b/intern/gawain/gawain/attrib_binding_private.h @@ -0,0 +1,20 @@ + +// Gawain vertex attribute binding +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2017 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "vertex_format.h" +#include "shader_interface.h" + +void AttribBinding_clear(Gwn_AttrBinding*); + +void get_attrib_locations(const Gwn_VertFormat*, Gwn_AttrBinding*, const Gwn_ShaderInterface*); +unsigned read_attrib_location(const Gwn_AttrBinding*, unsigned a_idx); diff --git a/intern/gawain/gawain/batch.h b/intern/gawain/gawain/batch.h new file mode 100644 index 00000000000..6e2f32c1996 --- /dev/null +++ b/intern/gawain/gawain/batch.h @@ -0,0 +1,129 @@ + +// Gawain geometry batch +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "vertex_buffer.h" +#include "element.h" +#include "shader_interface.h" + +typedef enum { + GWN_BATCH_READY_TO_FORMAT, + GWN_BATCH_READY_TO_BUILD, + GWN_BATCH_BUILDING, + GWN_BATCH_READY_TO_DRAW +} Gwn_BatchPhase; + +#define GWN_BATCH_VBO_MAX_LEN 3 + +typedef struct Gwn_Batch { + // geometry + Gwn_VertBuf* verts[GWN_BATCH_VBO_MAX_LEN]; // verts[0] is required, others can be NULL + Gwn_IndexBuf* elem; // NULL if element list not needed + Gwn_PrimType prim_type; + GLenum gl_prim_type; + + // book-keeping + GLuint vao_id; // remembers all geometry state (vertex attrib bindings & element buffer) + Gwn_BatchPhase phase; + bool program_dirty; + bool program_in_use; + + // state + GLuint program; + const Gwn_ShaderInterface* interface; +} Gwn_Batch; + +Gwn_Batch* GWN_batch_create(Gwn_PrimType, Gwn_VertBuf*, Gwn_IndexBuf*); +void GWN_batch_init(Gwn_Batch*, Gwn_PrimType, Gwn_VertBuf*, Gwn_IndexBuf*); + +void GWN_batch_discard(Gwn_Batch*); // verts & elem are not discarded +void GWN_batch_discard_all(Gwn_Batch*); // including verts & elem + +int GWN_batch_vertbuf_add(Gwn_Batch*, Gwn_VertBuf*); + +void GWN_batch_program_set(Gwn_Batch*, GLuint program, const Gwn_ShaderInterface*); +// Entire batch draws with one shader program, but can be redrawn later with another program. +// Vertex shader's inputs must be compatible with the batch's vertex format. + +void GWN_batch_program_use_begin(Gwn_Batch*); // call before Batch_Uniform (temp hack?) +void GWN_batch_program_use_end(Gwn_Batch*); + +void GWN_batch_uniform_1i(Gwn_Batch*, const char* name, int value); +void GWN_batch_uniform_1b(Gwn_Batch*, const char* name, bool value); +void GWN_batch_uniform_1f(Gwn_Batch*, const char* name, float value); +void GWN_batch_uniform_2f(Gwn_Batch*, const char* name, float x, float y); +void GWN_batch_uniform_3f(Gwn_Batch*, const char* name, float x, float y, float z); +void GWN_batch_uniform_4f(Gwn_Batch*, const char* name, float x, float y, float z, float w); +void GWN_batch_uniform_3fv(Gwn_Batch*, const char* name, const float data[3]); +void GWN_batch_uniform_4fv(Gwn_Batch*, const char* name, const float data[4]); + +void GWN_batch_draw(Gwn_Batch*); + + +// clement : temp stuff +void GWN_batch_draw_stupid(Gwn_Batch*); +void GWN_batch_draw_stupid_instanced(Gwn_Batch*, unsigned int instance_vbo, int instance_count, + int attrib_nbr, int attrib_stride, int attrib_loc[16], int attrib_size[16]); +void GWN_batch_draw_stupid_instanced_with_batch(Gwn_Batch*, Gwn_Batch*); + + + + + +#if 0 // future plans + +// Can multiple batches share a Gwn_VertBuf? Use ref count? + + +// We often need a batch with its own data, to be created and discarded together. +// WithOwn variants reduce number of system allocations. + +typedef struct { + Gwn_Batch batch; + Gwn_VertBuf verts; // link batch.verts to this +} BatchWithOwnVertexBuffer; + +typedef struct { + Gwn_Batch batch; + Gwn_IndexBuf elem; // link batch.elem to this +} BatchWithOwnElementList; + +typedef struct { + Gwn_Batch batch; + Gwn_IndexBuf elem; // link batch.elem to this + Gwn_VertBuf verts; // link batch.verts to this +} BatchWithOwnVertexBufferAndElementList; + +Gwn_Batch* create_BatchWithOwnVertexBuffer(Gwn_PrimType, Gwn_VertFormat*, unsigned v_ct, Gwn_IndexBuf*); +Gwn_Batch* create_BatchWithOwnElementList(Gwn_PrimType, Gwn_VertBuf*, unsigned prim_ct); +Gwn_Batch* create_BatchWithOwnVertexBufferAndElementList(Gwn_PrimType, Gwn_VertFormat*, unsigned v_ct, unsigned prim_ct); +// verts: shared, own +// elem: none, shared, own +Gwn_Batch* create_BatchInGeneral(Gwn_PrimType, VertexBufferStuff, ElementListStuff); + +#endif // future plans + + +/* Macros */ + +#define GWN_BATCH_DISCARD_SAFE(batch) do { \ + if (batch != NULL) { \ + GWN_batch_discard(batch); \ + batch = NULL; \ + } \ +} while (0) +#define BATCH_DISCARD_ALL_SAFE(batch) do { \ + if (batch != NULL) { \ + GWN_batch_discard_all(batch); \ + batch = NULL; \ + } \ +} while (0) diff --git a/intern/gawain/gawain/buffer_id.h b/intern/gawain/gawain/buffer_id.h new file mode 100644 index 00000000000..e978eec67d8 --- /dev/null +++ b/intern/gawain/gawain/buffer_id.h @@ -0,0 +1,34 @@ + +// Gawain buffer IDs +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +// Manage GL buffer IDs in a thread-safe way +// Use these instead of glGenBuffers & its friends +// - alloc must be called from main thread +// - free can be called from any thread + +#ifdef __cplusplus +extern "C" { +#endif + +#include "common.h" + +GLuint GWN_buf_id_alloc(void); +void GWN_buf_id_free(GLuint buffer_id); + +GLuint GWN_vao_alloc(void); +void GWN_vao_free(GLuint vao_id); + + +#ifdef __cplusplus +} +#endif diff --git a/intern/gawain/gawain/common.h b/intern/gawain/gawain/common.h new file mode 100644 index 00000000000..e96a3b5c2a2 --- /dev/null +++ b/intern/gawain/gawain/common.h @@ -0,0 +1,34 @@ + +// Gawain common #defines and #includes +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#if defined(NDEBUG) + #define TRUST_NO_ONE 0 +#else + // strict error checking, enabled for debug builds during early development + #define TRUST_NO_ONE 1 +#endif + +#include <GL/glew.h> +#include <stdbool.h> +#include <stdint.h> + +#if TRUST_NO_ONE + #include <assert.h> +#endif + +/* GWN_INLINE */ +#if defined(_MSC_VER) +# define GWN_INLINE static __forceinline +#else +# define GWN_INLINE static inline __attribute__((always_inline)) __attribute__((__unused__)) +#endif
\ No newline at end of file diff --git a/intern/gawain/gawain/element.h b/intern/gawain/gawain/element.h new file mode 100644 index 00000000000..771462be7c5 --- /dev/null +++ b/intern/gawain/gawain/element.h @@ -0,0 +1,75 @@ + +// Gawain element list (AKA index buffer) +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "primitive.h" + +#define GWN_TRACK_INDEX_RANGE 1 + +typedef enum { + GWN_INDEX_U8, // GL has this, Vulkan does not + GWN_INDEX_U16, + GWN_INDEX_U32 +} Gwn_IndexBufType; + +typedef struct { + unsigned index_ct; +#if GWN_TRACK_INDEX_RANGE + Gwn_IndexBufType index_type; + GLenum gl_index_type; + unsigned min_index; + unsigned max_index; + unsigned base_index; +#endif + void* data; // NULL indicates data in VRAM (unmapped) or not yet allocated + GLuint vbo_id; // 0 indicates not yet sent to VRAM +} Gwn_IndexBuf; + +void GWN_indexbuf_use(Gwn_IndexBuf*); +unsigned GWN_indexbuf_size_get(const Gwn_IndexBuf*); + +typedef struct { + unsigned max_allowed_index; + unsigned max_index_ct; + unsigned index_ct; + Gwn_PrimType prim_type; + unsigned* data; +} Gwn_IndexBufBuilder; + +// supported primitives: +// GWN_PRIM_POINTS +// GWN_PRIM_LINES +// GWN_PRIM_TRIS + +void GWN_indexbuf_init(Gwn_IndexBufBuilder*, Gwn_PrimType, unsigned prim_ct, unsigned vertex_ct); +//void GWN_indexbuf_init_custom(Gwn_IndexBufBuilder*, Gwn_PrimType, unsigned index_ct, unsigned vertex_ct); + +void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder*, unsigned v); + +void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder*, unsigned v); +void GWN_indexbuf_add_line_verts(Gwn_IndexBufBuilder*, unsigned v1, unsigned v2); +void GWN_indexbuf_add_tri_verts(Gwn_IndexBufBuilder*, unsigned v1, unsigned v2, unsigned v3); + +Gwn_IndexBuf* GWN_indexbuf_build(Gwn_IndexBufBuilder*); +void GWN_indexbuf_build_in_place(Gwn_IndexBufBuilder*, Gwn_IndexBuf*); + +void GWN_indexbuf_discard(Gwn_IndexBuf*); + + +/* Macros */ + +#define GWN_INDEXBUF_DISCARD_SAFE(elem) do { \ + if (elem != NULL) { \ + GWN_indexbuf_discard(elem); \ + elem = NULL; \ + } \ +} while (0) diff --git a/intern/gawain/gawain/imm_util.h b/intern/gawain/gawain/imm_util.h new file mode 100644 index 00000000000..730bd7c1a3c --- /dev/null +++ b/intern/gawain/gawain/imm_util.h @@ -0,0 +1,18 @@ + +// Gawain immediate mode drawing utilities +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + + +// Draw 2D rectangles (replaces glRect functions) +// caller is reponsible for vertex format & shader +void immRectf(unsigned pos, float x1, float y1, float x2, float y2); +void immRecti(unsigned pos, int x1, int y1, int x2, int y2); diff --git a/intern/gawain/gawain/immediate.h b/intern/gawain/gawain/immediate.h new file mode 100644 index 00000000000..39ba76db931 --- /dev/null +++ b/intern/gawain/gawain/immediate.h @@ -0,0 +1,119 @@ + +// Gawain immediate mode work-alike +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "vertex_format.h" +#include "primitive.h" +#include "shader_interface.h" + +#define IMM_BATCH_COMBO 1 + + +Gwn_VertFormat* immVertexFormat(void); // returns a cleared vertex format, ready for add_attrib + +void immBindProgram(GLuint program, const Gwn_ShaderInterface*); // every immBegin must have a program bound first +void immUnbindProgram(void); // call after your last immEnd, or before binding another program + +void immBegin(Gwn_PrimType, unsigned vertex_ct); // must supply exactly vertex_ct vertices +void immBeginAtMost(Gwn_PrimType, unsigned max_vertex_ct); // can supply fewer vertices +void immEnd(void); // finishes and draws + +#if IMM_BATCH_COMBO +#include "batch.h" +// immBegin a batch, then use standard immFunctions as usual. +// immEnd will finalize the batch instead of drawing. +// Then you can draw it as many times as you like! Partially replaces the need for display lists. +Gwn_Batch* immBeginBatch(Gwn_PrimType, unsigned vertex_ct); +Gwn_Batch* immBeginBatchAtMost(Gwn_PrimType, unsigned vertex_ct); +#endif + + +// provide attribute values that can change per vertex +// first vertex after immBegin must have all its attributes specified +// skipped attributes will continue using the previous value for that attrib_id +void immAttrib1f(unsigned attrib_id, float x); +void immAttrib2f(unsigned attrib_id, float x, float y); +void immAttrib3f(unsigned attrib_id, float x, float y, float z); +void immAttrib4f(unsigned attrib_id, float x, float y, float z, float w); + +void immAttrib2i(unsigned attrib_id, int x, int y); + +void immAttrib1u(unsigned attrib_id, unsigned x); + +void immAttrib2s(unsigned attrib_id, short x, short y); + +void immAttrib2fv(unsigned attrib_id, const float data[2]); +void immAttrib3fv(unsigned attrib_id, const float data[3]); +void immAttrib4fv(unsigned attrib_id, const float data[4]); + +void immAttrib3ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b); +void immAttrib4ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +void immAttrib3ubv(unsigned attrib_id, const unsigned char data[4]); +void immAttrib4ubv(unsigned attrib_id, const unsigned char data[4]); + +// explicitly skip an attribute +// this advanced option kills automatic value copying for this attrib_id +void immSkipAttrib(unsigned attrib_id); + + +// provide one last attribute value & end the current vertex +// this is most often used for 2D or 3D position (similar to glVertex) +void immVertex2f(unsigned attrib_id, float x, float y); +void immVertex3f(unsigned attrib_id, float x, float y, float z); + +void immVertex2i(unsigned attrib_id, int x, int y); + +void immVertex2s(unsigned attrib_id, short x, short y); + +void immVertex2fv(unsigned attrib_id, const float data[2]); +void immVertex3fv(unsigned attrib_id, const float data[3]); + +void immVertex2iv(unsigned attrib_id, const int data[2]); + + +// provide uniform values that don't change for the entire draw call +void immUniform1i(const char* name, int x); +void immUniform4iv(const char* name, const int data[4]); +void immUniform1f(const char* name, float x); +void immUniform2f(const char* name, float x, float y); +void immUniform2fv(const char* name, const float data[2]); +void immUniform3f(const char* name, float x, float y, float z); +void immUniform3fv(const char* name, const float data[3]); +void immUniformArray3fv(const char* name, const float *data, int count); +void immUniform4f(const char* name, float x, float y, float z, float w); +void immUniform4fv(const char* name, const float data[4]); +void immUniformArray4fv(const char* bare_name, const float *data, int count); +void immUniformMatrix4fv(const char* name, const float data[4][4]); + + +// convenience functions for setting "uniform vec4 color" +// the rgb functions have implicit alpha = 1.0 +void immUniformColor4f(float r, float g, float b, float a); +void immUniformColor4fv(const float rgba[4]); +void immUniformColor3f(float r, float g, float b); +void immUniformColor3fv(const float rgb[3]); +void immUniformColor3fvAlpha(const float rgb[3], float a); + +void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b); +void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); +void immUniformColor3ubv(const unsigned char rgb[3]); +void immUniformColor3ubvAlpha(const unsigned char rgb[3], unsigned char a); +void immUniformColor4ubv(const unsigned char rgba[4]); + + +// these are called by the system -- not part of drawing API + +void immInit(void); +void immActivate(void); +void immDeactivate(void); +void immDestroy(void); diff --git a/intern/gawain/gawain/primitive.h b/intern/gawain/gawain/primitive.h new file mode 100644 index 00000000000..c6786dc1993 --- /dev/null +++ b/intern/gawain/gawain/primitive.h @@ -0,0 +1,40 @@ + +// Gawain geometric primitives +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2017 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "common.h" + +typedef enum { + GWN_PRIM_POINTS, + GWN_PRIM_LINES, + GWN_PRIM_TRIS, + GWN_PRIM_LINE_STRIP, + GWN_PRIM_LINE_LOOP, // GL has this, Vulkan does not + GWN_PRIM_TRI_STRIP, + GWN_PRIM_TRI_FAN, + + GWN_PRIM_LINE_STRIP_ADJ, + + GWN_PRIM_NONE +} Gwn_PrimType; + +// what types of primitives does each shader expect? +typedef enum { + GWN_PRIM_CLASS_NONE = 0, + GWN_PRIM_CLASS_POINT = (1 << 0), + GWN_PRIM_CLASS_LINE = (1 << 1), + GWN_PRIM_CLASS_SURFACE = (1 << 2), + GWN_PRIM_CLASS_ANY = GWN_PRIM_CLASS_POINT | GWN_PRIM_CLASS_LINE | GWN_PRIM_CLASS_SURFACE +} Gwn_PrimClass; + +Gwn_PrimClass GWN_primtype_class(Gwn_PrimType); +bool GWN_primtype_belongs_to_class(Gwn_PrimType, Gwn_PrimClass); diff --git a/intern/gawain/gawain/primitive_private.h b/intern/gawain/gawain/primitive_private.h new file mode 100644 index 00000000000..d959cd89852 --- /dev/null +++ b/intern/gawain/gawain/primitive_private.h @@ -0,0 +1,14 @@ + +// Gawain geometric primitives (private interface for use inside Gawain) +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2017 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +GLenum convert_prim_type_to_gl(Gwn_PrimType); diff --git a/intern/gawain/gawain/shader_interface.h b/intern/gawain/gawain/shader_interface.h new file mode 100644 index 00000000000..5304cc9fa51 --- /dev/null +++ b/intern/gawain/gawain/shader_interface.h @@ -0,0 +1,53 @@ + +// Gawain shader interface (C --> GLSL) +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2017 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "common.h" + +typedef enum { + GWN_UNIFORM_NONE, // uninitialized/unknown + + GWN_UNIFORM_MODELVIEW, // mat4 ModelViewMatrix + GWN_UNIFORM_PROJECTION, // mat4 ProjectionMatrix + GWN_UNIFORM_MVP, // mat4 ModelViewProjectionMatrix + + GWN_UNIFORM_MODELVIEW_INV, // mat4 ModelViewInverseMatrix + GWN_UNIFORM_PROJECTION_INV, // mat4 ProjectionInverseMatrix + + GWN_UNIFORM_NORMAL, // mat3 NormalMatrix + + GWN_UNIFORM_COLOR, // vec4 color + + GWN_UNIFORM_CUSTOM // custom uniform, not one of the above built-ins +} Gwn_UniformBuiltin; + +typedef struct { + const char* name; + unsigned name_hash; + GLenum gl_type; + Gwn_UniformBuiltin builtin_type; // only for uniform inputs + GLint size; + GLint location; +} Gwn_ShaderInput; + +typedef struct { + uint16_t uniform_ct; + uint16_t attrib_ct; + Gwn_ShaderInput inputs[0]; // dynamic size, uniforms followed by attribs +} Gwn_ShaderInterface; + +Gwn_ShaderInterface* GWN_shaderinterface_create(GLint program_id); +void GWN_shaderinterface_discard(Gwn_ShaderInterface*); + +const Gwn_ShaderInput* GWN_shaderinterface_uniform(const Gwn_ShaderInterface*, const char* name); +const Gwn_ShaderInput* GWN_shaderinterface_uniform_builtin(const Gwn_ShaderInterface*, Gwn_UniformBuiltin); +const Gwn_ShaderInput* GWN_shaderinterface_attr(const Gwn_ShaderInterface*, const char* name); diff --git a/intern/gawain/gawain/vertex_buffer.h b/intern/gawain/gawain/vertex_buffer.h new file mode 100644 index 00000000000..9aee8e05877 --- /dev/null +++ b/intern/gawain/gawain/vertex_buffer.h @@ -0,0 +1,108 @@ + +// Gawain vertex buffer +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "vertex_format.h" + +// How to create a Gwn_VertBuf: +// 1) verts = GWN_vertbuf_create() or GWN_vertbuf_init(verts) +// 2) GWN_vertformat_attr_add(verts->format, ...) +// 3) GWN_vertbuf_data_alloc(verts, vertex_ct) <-- finalizes/packs vertex format +// 4) GWN_vertbuf_attr_fill(verts, pos, application_pos_buffer) + +// Is Gwn_VertBuf always used as part of a Gwn_Batch? + +typedef struct { + Gwn_VertFormat format; + unsigned vertex_ct; + GLubyte* data; // NULL indicates data in VRAM (unmapped) or not yet allocated + GLuint vbo_id; // 0 indicates not yet sent to VRAM +} Gwn_VertBuf; + +Gwn_VertBuf* GWN_vertbuf_create(void); +Gwn_VertBuf* GWN_vertbuf_create_with_format(const Gwn_VertFormat*); + +void GWN_vertbuf_clear(Gwn_VertBuf* verts); +void GWN_vertbuf_discard(Gwn_VertBuf*); + +void GWN_vertbuf_init(Gwn_VertBuf*); +void GWN_vertbuf_init_with_format(Gwn_VertBuf*, const Gwn_VertFormat*); + +unsigned GWN_vertbuf_size_get(const Gwn_VertBuf*); +void GWN_vertbuf_data_alloc(Gwn_VertBuf*, unsigned v_ct); +void GWN_vertbuf_data_resize(Gwn_VertBuf*, unsigned v_ct); + +// The most important set_attrib variant is the untyped one. Get it right first. +// It takes a void* so the app developer is responsible for matching their app data types +// to the vertex attribute's type and component count. They're in control of both, so this +// should not be a problem. + +void GWN_vertbuf_attr_set(Gwn_VertBuf*, unsigned a_idx, unsigned v_idx, const void* data); +void GWN_vertbuf_attr_fill(Gwn_VertBuf*, unsigned a_idx, const void* data); // tightly packed, non interleaved input data +void GWN_vertbuf_attr_fill_stride(Gwn_VertBuf*, unsigned a_idx, unsigned stride, const void* data); + +// For low level access only +typedef struct { + unsigned size; + unsigned stride; + GLubyte* data; + GLubyte* data_init; +#if TRUST_NO_ONE + // Only for overflow check + GLubyte* _data_end; +#endif +} Gwn_VertBufRaw; + +GWN_INLINE void *GWN_vertbuf_raw_step(Gwn_VertBufRaw *a) + { + GLubyte* data = a->data; + a->data += a->stride; +#if TRUST_NO_ONE + assert(data < a->_data_end); +#endif + return (void *)data; + } + +GWN_INLINE unsigned GWN_vertbuf_raw_used(Gwn_VertBufRaw *a) + { + return ((a->data - a->data_init) / a->stride); + } + +void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf*, unsigned a_idx, Gwn_VertBufRaw *access); + +// TODO: decide whether to keep the functions below +// doesn't immediate mode satisfy these needs? + +// void setAttrib1f(unsigned a_idx, unsigned v_idx, float x); +// void setAttrib2f(unsigned a_idx, unsigned v_idx, float x, float y); +// void setAttrib3f(unsigned a_idx, unsigned v_idx, float x, float y, float z); +// void setAttrib4f(unsigned a_idx, unsigned v_idx, float x, float y, float z, float w); +// +// void setAttrib3ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b); +// void setAttrib4ub(unsigned a_idx, unsigned v_idx, unsigned char r, unsigned char g, unsigned char b, unsigned char a); + +void GWN_vertbuf_use(Gwn_VertBuf*); + + +// Metrics + +unsigned GWN_vertbuf_get_memory_usage(void); + + +// Macros + +#define GWN_VERTBUF_DISCARD_SAFE(verts) do { \ + if (verts != NULL) { \ + GWN_vertbuf_discard(verts); \ + verts = NULL; \ + } \ +} while (0) diff --git a/intern/gawain/gawain/vertex_format.h b/intern/gawain/gawain/vertex_format.h new file mode 100644 index 00000000000..ab61722db60 --- /dev/null +++ b/intern/gawain/gawain/vertex_format.h @@ -0,0 +1,78 @@ + +// Gawain vertex format +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "common.h" + +#define GWN_VERT_ATTR_MAX_LEN 16 +#define MAX_ATTRIB_NAMES 3 +#define GWN_VERT_ATTR_NAME_AVERAGE_LEN 11 +#define GWN_VERT_ATTR_NAMES_BUF_LEN ((GWN_VERT_ATTR_NAME_AVERAGE_LEN + 1) * GWN_VERT_ATTR_MAX_LEN) + +typedef enum { + GWN_COMP_I8, + GWN_COMP_U8, + GWN_COMP_I16, + GWN_COMP_U16, + GWN_COMP_I32, + GWN_COMP_U32, + + GWN_COMP_F32, + + GWN_COMP_I10 +} Gwn_VertCompType; + +typedef enum { + GWN_FETCH_FLOAT, + GWN_FETCH_INT, + GWN_FETCH_INT_TO_FLOAT_UNIT, // 127 (ubyte) -> 0.5 (and so on for other int types) + GWN_FETCH_INT_TO_FLOAT // 127 (any int type) -> 127.0 +} Gwn_VertFetchMode; + +typedef struct { + Gwn_VertCompType comp_type; + unsigned gl_comp_type; + unsigned comp_ct; // 1 to 4 + unsigned sz; // size in bytes, 1 to 16 + unsigned offset; // from beginning of vertex, in bytes + Gwn_VertFetchMode fetch_mode; + const char* name[MAX_ATTRIB_NAMES]; + unsigned name_ct; +} Gwn_VertAttr; + +typedef struct { + unsigned attrib_ct; // 0 to 16 (GWN_VERT_ATTR_MAX_LEN) + unsigned name_ct; // total count of active vertex attrib + unsigned stride; // stride in bytes, 1 to 256 + bool packed; + Gwn_VertAttr attribs[GWN_VERT_ATTR_MAX_LEN]; // TODO: variable-size attribs array + char names[GWN_VERT_ATTR_NAMES_BUF_LEN]; + unsigned name_offset; +} Gwn_VertFormat; + +void GWN_vertformat_clear(Gwn_VertFormat*); +void GWN_vertformat_copy(Gwn_VertFormat* dest, const Gwn_VertFormat* src); + +unsigned GWN_vertformat_attr_add(Gwn_VertFormat*, const char* name, Gwn_VertCompType, unsigned comp_ct, Gwn_VertFetchMode); +void GWN_vertformat_alias_add(Gwn_VertFormat*, const char* alias); + +// format conversion + +typedef struct { + int x : 10; + int y : 10; + int z : 10; + int w : 2; // 0 by default, can manually set to { -2, -1, 0, 1 } +} Gwn_PackedNormal; + +Gwn_PackedNormal GWN_normal_convert_i10_v3(const float data[3]); +Gwn_PackedNormal GWN_normal_convert_i10_s3(const short data[3]); diff --git a/intern/gawain/gawain/vertex_format_private.h b/intern/gawain/gawain/vertex_format_private.h new file mode 100644 index 00000000000..c1a0f734eda --- /dev/null +++ b/intern/gawain/gawain/vertex_format_private.h @@ -0,0 +1,16 @@ + +// Gawain vertex format (private interface for use inside Gawain) +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016-2017 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +void VertexFormat_pack(Gwn_VertFormat*); +unsigned padding(unsigned offset, unsigned alignment); +unsigned vertex_buffer_size(const Gwn_VertFormat*, unsigned vertex_ct); diff --git a/intern/gawain/src/attrib_binding.c b/intern/gawain/src/attrib_binding.c new file mode 100644 index 00000000000..6cdb8a0e542 --- /dev/null +++ b/intern/gawain/src/attrib_binding.c @@ -0,0 +1,70 @@ + +// Gawain vertex attribute binding +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "attrib_binding.h" +#include "attrib_binding_private.h" +#include <stddef.h> + +#if GWN_VERT_ATTR_MAX_LEN != 16 + #error "attrib binding code assumes GWN_VERT_ATTR_MAX_LEN = 16" +#endif + +void AttribBinding_clear(Gwn_AttrBinding* binding) + { + binding->loc_bits = 0; + binding->enabled_bits = 0; + } + +unsigned read_attrib_location(const Gwn_AttrBinding* binding, unsigned a_idx) + { +#if TRUST_NO_ONE + assert(a_idx < GWN_VERT_ATTR_MAX_LEN); + assert(binding->enabled_bits & (1 << a_idx)); +#endif + + return (binding->loc_bits >> (4 * a_idx)) & 0xF; + } + +static void write_attrib_location(Gwn_AttrBinding* binding, unsigned a_idx, unsigned location) + { +#if TRUST_NO_ONE + assert(a_idx < GWN_VERT_ATTR_MAX_LEN); + assert(location < GWN_VERT_ATTR_MAX_LEN); +#endif + + const unsigned shift = 4 * a_idx; + const uint64_t mask = ((uint64_t)0xF) << shift; + // overwrite this attrib's previous location + binding->loc_bits = (binding->loc_bits & ~mask) | (location << shift); + // mark this attrib as enabled + binding->enabled_bits |= 1 << a_idx; + } + +void get_attrib_locations(const Gwn_VertFormat* format, Gwn_AttrBinding* binding, const Gwn_ShaderInterface* shaderface) + { + AttribBinding_clear(binding); + + for (unsigned a_idx = 0; a_idx < format->attrib_ct; ++a_idx) + { + const Gwn_VertAttr* a = format->attribs + a_idx; + for (unsigned n_idx = 0; n_idx < a->name_ct; ++n_idx) + { + const Gwn_ShaderInput* input = GWN_shaderinterface_attr(shaderface, a->name[n_idx]); + +#if TRUST_NO_ONE + assert(input != NULL); + // TODO: make this a recoverable runtime error? indicates mismatch between vertex format and program +#endif + + write_attrib_location(binding, a_idx, input->location); + } + } + } diff --git a/intern/gawain/src/batch.c b/intern/gawain/src/batch.c new file mode 100644 index 00000000000..22a5aab48b4 --- /dev/null +++ b/intern/gawain/src/batch.c @@ -0,0 +1,449 @@ + +// Gawain geometry batch +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "batch.h" +#include "buffer_id.h" +#include "primitive_private.h" +#include <stdlib.h> + +// necessary functions from matrix API +extern void gpuBindMatrices(const Gwn_ShaderInterface* shaderface); +extern bool gpuMatricesDirty(void); // how best to use this here? + +Gwn_Batch* GWN_batch_create(Gwn_PrimType prim_type, Gwn_VertBuf* verts, Gwn_IndexBuf* elem) + { + Gwn_Batch* batch = calloc(1, sizeof(Gwn_Batch)); + + GWN_batch_init(batch, prim_type, verts, elem); + + return batch; + } + +void GWN_batch_init(Gwn_Batch* batch, Gwn_PrimType prim_type, Gwn_VertBuf* verts, Gwn_IndexBuf* elem) + { +#if TRUST_NO_ONE + assert(verts != NULL); +#endif + + batch->verts[0] = verts; + for (int v = 1; v < GWN_BATCH_VBO_MAX_LEN; ++v) + batch->verts[v] = NULL; + batch->elem = elem; + batch->prim_type = prim_type; + batch->gl_prim_type = convert_prim_type_to_gl(prim_type); + batch->phase = GWN_BATCH_READY_TO_DRAW; + } + +void GWN_batch_discard(Gwn_Batch* batch) + { + if (batch->vao_id) + GWN_vao_free(batch->vao_id); + + free(batch); + } + +void GWN_batch_discard_all(Gwn_Batch* batch) + { + for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v) + { + if (batch->verts[v] == NULL) + break; + GWN_vertbuf_discard(batch->verts[v]); + } + + if (batch->elem) + GWN_indexbuf_discard(batch->elem); + + GWN_batch_discard(batch); + } + +int GWN_batch_vertbuf_add(Gwn_Batch* batch, Gwn_VertBuf* verts) + { + for (unsigned v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v) + { + if (batch->verts[v] == NULL) + { +#if TRUST_NO_ONE + // for now all VertexBuffers must have same vertex_ct + assert(verts->vertex_ct == batch->verts[0]->vertex_ct); + // in the near future we will enable instanced attribs which have their own vertex_ct +#endif + batch->verts[v] = verts; + // TODO: mark dirty so we can keep attrib bindings up-to-date + return v; + } + } + + // we only make it this far if there is no room for another Gwn_VertBuf +#if TRUST_NO_ONE + assert(false); +#endif + return -1; + } + +void GWN_batch_program_set(Gwn_Batch* batch, GLuint program, const Gwn_ShaderInterface* shaderface) + { +#if TRUST_NO_ONE + assert(glIsProgram(program)); +#endif + + batch->program = program; + batch->interface = shaderface; + batch->program_dirty = true; + + GWN_batch_program_use_begin(batch); // hack! to make Batch_Uniform* simpler + } + +static void Batch_update_program_bindings(Gwn_Batch* batch) + { + // disable all as a precaution + // why are we not using prev_attrib_enabled_bits?? see immediate.c + for (unsigned a_idx = 0; a_idx < GWN_VERT_ATTR_MAX_LEN; ++a_idx) + glDisableVertexAttribArray(a_idx); + + for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v) + { + Gwn_VertBuf* verts = batch->verts[v]; + if (verts == NULL) + break; + + const Gwn_VertFormat* format = &verts->format; + + const unsigned attrib_ct = format->attrib_ct; + const unsigned stride = format->stride; + + GWN_vertbuf_use(verts); + + for (unsigned a_idx = 0; a_idx < attrib_ct; ++a_idx) + { + const Gwn_VertAttr* a = format->attribs + a_idx; + + const GLvoid* pointer = (const GLubyte*)0 + a->offset; + + for (unsigned n_idx = 0; n_idx < a->name_ct; ++n_idx) + { + const Gwn_ShaderInput* input = GWN_shaderinterface_attr(batch->interface, a->name[n_idx]); + + if (input == NULL) continue; + + glEnableVertexAttribArray(input->location); + + switch (a->fetch_mode) + { + case GWN_FETCH_FLOAT: + case GWN_FETCH_INT_TO_FLOAT: + glVertexAttribPointer(input->location, a->comp_ct, a->gl_comp_type, GL_FALSE, stride, pointer); + break; + case GWN_FETCH_INT_TO_FLOAT_UNIT: + glVertexAttribPointer(input->location, a->comp_ct, a->gl_comp_type, GL_TRUE, stride, pointer); + break; + case GWN_FETCH_INT: + glVertexAttribIPointer(input->location, a->comp_ct, a->gl_comp_type, stride, pointer); + } + } + } + } + + batch->program_dirty = false; + } + +void GWN_batch_program_use_begin(Gwn_Batch* batch) + { + // NOTE: use_program & done_using_program are fragile, depend on staying in sync with + // the GL context's active program. use_program doesn't mark other programs as "not used". + // TODO: make not fragile (somehow) + + if (!batch->program_in_use) + { + glUseProgram(batch->program); + batch->program_in_use = true; + } + } + +void GWN_batch_program_use_end(Gwn_Batch* batch) + { + if (batch->program_in_use) + { + glUseProgram(0); + batch->program_in_use = false; + } + } + +#if TRUST_NO_ONE + #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(batch->interface, name); assert(uniform); +#else + #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(batch->interface, name); +#endif + +void GWN_batch_uniform_1i(Gwn_Batch* batch, const char* name, int value) + { + GET_UNIFORM + glUniform1i(uniform->location, value); + } + +void GWN_batch_uniform_1b(Gwn_Batch* batch, const char* name, bool value) + { + GET_UNIFORM + glUniform1i(uniform->location, value ? GL_TRUE : GL_FALSE); + } + +void GWN_batch_uniform_2f(Gwn_Batch* batch, const char* name, float x, float y) + { + GET_UNIFORM + glUniform2f(uniform->location, x, y); + } + +void GWN_batch_uniform_3f(Gwn_Batch* batch, const char* name, float x, float y, float z) + { + GET_UNIFORM + glUniform3f(uniform->location, x, y, z); + } + +void GWN_batch_uniform_4f(Gwn_Batch* batch, const char* name, float x, float y, float z, float w) + { + GET_UNIFORM + glUniform4f(uniform->location, x, y, z, w); + } + +void GWN_batch_uniform_1f(Gwn_Batch* batch, const char* name, float x) + { + GET_UNIFORM + glUniform1f(uniform->location, x); + } + +void GWN_batch_uniform_3fv(Gwn_Batch* batch, const char* name, const float data[3]) + { + GET_UNIFORM + glUniform3fv(uniform->location, 1, data); + } + +void GWN_batch_uniform_4fv(Gwn_Batch* batch, const char* name, const float data[4]) + { + GET_UNIFORM + glUniform4fv(uniform->location, 1, data); + } + +static void Batch_prime(Gwn_Batch* batch) + { + batch->vao_id = GWN_vao_alloc(); + glBindVertexArray(batch->vao_id); + + for (int v = 0; v < GWN_BATCH_VBO_MAX_LEN; ++v) + { + if (batch->verts[v] == NULL) + break; + GWN_vertbuf_use(batch->verts[v]); + } + + if (batch->elem) + GWN_indexbuf_use(batch->elem); + + // vertex attribs and element list remain bound to this VAO + } + +void GWN_batch_draw(Gwn_Batch* batch) + { +#if TRUST_NO_ONE + assert(batch->phase == GWN_BATCH_READY_TO_DRAW); + assert(glIsProgram(batch->program)); +#endif + + if (batch->vao_id) + glBindVertexArray(batch->vao_id); + else + Batch_prime(batch); + + if (batch->program_dirty) + Batch_update_program_bindings(batch); + + GWN_batch_program_use_begin(batch); + + gpuBindMatrices(batch->interface); + + if (batch->elem) + { + const Gwn_IndexBuf* el = batch->elem; + +#if GWN_TRACK_INDEX_RANGE + if (el->base_index) + glDrawRangeElementsBaseVertex(batch->gl_prim_type, el->min_index, el->max_index, el->index_ct, el->gl_index_type, 0, el->base_index); + else + glDrawRangeElements(batch->gl_prim_type, el->min_index, el->max_index, el->index_ct, el->gl_index_type, 0); +#else + glDrawElements(batch->gl_prim_type, el->index_ct, GL_UNSIGNED_INT, 0); +#endif + } + else + glDrawArrays(batch->gl_prim_type, 0, batch->verts[0]->vertex_ct); + + GWN_batch_program_use_end(batch); + glBindVertexArray(0); + } + + + +// clement : temp stuff +void GWN_batch_draw_stupid(Gwn_Batch* batch) + { + if (batch->vao_id) + glBindVertexArray(batch->vao_id); + else + Batch_prime(batch); + + if (batch->program_dirty) + Batch_update_program_bindings(batch); + + // GWN_batch_program_use_begin(batch); + + //gpuBindMatrices(batch->program); + + if (batch->elem) + { + const Gwn_IndexBuf* el = batch->elem; + +#if GWN_TRACK_INDEX_RANGE + if (el->base_index) + glDrawRangeElementsBaseVertex(batch->gl_prim_type, el->min_index, el->max_index, el->index_ct, el->gl_index_type, 0, el->base_index); + else + glDrawRangeElements(batch->gl_prim_type, el->min_index, el->max_index, el->index_ct, el->gl_index_type, 0); +#else + glDrawElements(batch->gl_prim_type, el->index_ct, GL_UNSIGNED_INT, 0); +#endif + } + else + glDrawArrays(batch->gl_prim_type, 0, batch->verts[0]->vertex_ct); + + // GWN_batch_program_use_end(batch); + glBindVertexArray(0); + } + +// clement : temp stuff +void GWN_batch_draw_stupid_instanced(Gwn_Batch* batch, unsigned int instance_vbo, int instance_count, + int attrib_nbr, int attrib_stride, int attrib_size[16], int attrib_loc[16]) + { + if (batch->vao_id) + glBindVertexArray(batch->vao_id); + else + Batch_prime(batch); + + if (batch->program_dirty) + Batch_update_program_bindings(batch); + + glBindBuffer(GL_ARRAY_BUFFER, instance_vbo); + int ptr_ofs = 0; + for (int i = 0; i < attrib_nbr; ++i) + { + int size = attrib_size[i]; + int loc = attrib_loc[i]; + int atr_ofs = 0; + + while (size > 0) + { + glEnableVertexAttribArray(loc + atr_ofs); + glVertexAttribPointer(loc + atr_ofs, (size > 4) ? 4 : size, GL_FLOAT, GL_FALSE, + sizeof(float) * attrib_stride, (GLvoid*)(sizeof(float) * ptr_ofs)); + glVertexAttribDivisor(loc + atr_ofs, 1); + atr_ofs++; + ptr_ofs += (size > 4) ? 4 : size; + size -= 4; + } + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // GWN_batch_program_use_begin(batch); + + //gpuBindMatrices(batch->program); + + if (batch->elem) + { + const Gwn_IndexBuf* el = batch->elem; +#if GWN_TRACK_INDEX_RANGE + glDrawElementsInstancedBaseVertex(batch->gl_prim_type, el->index_ct, el->gl_index_type, 0, instance_count, el->base_index); +#else + glDrawElementsInstanced(batch->gl_prim_type, el->index_ct, GL_UNSIGNED_INT, 0, instance_count); +#endif + } + else + glDrawArraysInstanced(batch->gl_prim_type, 0, batch->verts[0]->vertex_ct, instance_count); + + // GWN_batch_program_use_end(batch); + glBindVertexArray(0); + } + +void GWN_batch_draw_stupid_instanced_with_batch(Gwn_Batch* batch_instanced, Gwn_Batch* batch_instancing) + { + if (batch_instanced->vao_id) + glBindVertexArray(batch_instanced->vao_id); + else + Batch_prime(batch_instanced); + + if (batch_instanced->program_dirty) + Batch_update_program_bindings(batch_instanced); + + Gwn_VertBuf* verts = batch_instancing->verts[0]; + + const Gwn_VertFormat* format = &verts->format; + + const unsigned attrib_ct = format->attrib_ct; + const unsigned stride = format->stride; + + GWN_vertbuf_use(verts); + + for (unsigned a_idx = 0; a_idx < attrib_ct; ++a_idx) + { + const Gwn_VertAttr* a = format->attribs + a_idx; + + const GLvoid* pointer = (const GLubyte*)0 + a->offset; + + for (unsigned n_idx = 0; n_idx < a->name_ct; ++n_idx) + { + const Gwn_ShaderInput* input = GWN_shaderinterface_attr(batch_instanced->interface, a->name[n_idx]); + + if (input == NULL) continue; + + glEnableVertexAttribArray(input->location); + glVertexAttribDivisor(input->location, 1); + + switch (a->fetch_mode) + { + case GWN_FETCH_FLOAT: + case GWN_FETCH_INT_TO_FLOAT: + glVertexAttribPointer(input->location, a->comp_ct, a->gl_comp_type, GL_FALSE, stride, pointer); + break; + case GWN_FETCH_INT_TO_FLOAT_UNIT: + glVertexAttribPointer(input->location, a->comp_ct, a->gl_comp_type, GL_TRUE, stride, pointer); + break; + case GWN_FETCH_INT: + glVertexAttribIPointer(input->location, a->comp_ct, a->gl_comp_type, stride, pointer); + } + } + } + + // GWN_batch_program_use_begin(batch); + + //gpuBindMatrices(batch->program); + + if (batch_instanced->elem) + { + const Gwn_IndexBuf* el = batch_instanced->elem; + +#if GWN_TRACK_INDEX_RANGE + glDrawElementsInstancedBaseVertex(batch_instanced->gl_prim_type, el->index_ct, el->gl_index_type, 0, verts->vertex_ct, el->base_index); +#else + glDrawElementsInstanced(batch_instanced->gl_prim_type, el->index_ct, GL_UNSIGNED_INT, 0, verts->vertex_ct); +#endif + } + else + glDrawArraysInstanced(batch_instanced->gl_prim_type, 0, batch_instanced->verts[0]->vertex_ct, verts->vertex_ct); + + // GWN_batch_program_use_end(batch); + glBindVertexArray(0); + }
\ No newline at end of file diff --git a/intern/gawain/src/buffer_id.cpp b/intern/gawain/src/buffer_id.cpp new file mode 100644 index 00000000000..59a6b9c89e7 --- /dev/null +++ b/intern/gawain/src/buffer_id.cpp @@ -0,0 +1,115 @@ + +// Gawain buffer IDs +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.#include "buffer_id.h" + +#include "buffer_id.h" +#include <mutex> +#include <vector> + +#define ORPHAN_DEBUG 0 + +#if ORPHAN_DEBUG + #include <cstdio> +#endif + +static std::vector<GLuint> orphaned_buffer_ids; +static std::vector<GLuint> orphaned_vao_ids; + +static std::mutex orphan_mutex; + +extern "C" { +extern int BLI_thread_is_main(void); // Blender-specific function +} + +static bool thread_is_main() + { + // "main" here means the GL context's thread + return BLI_thread_is_main(); + } + +GLuint GWN_buf_id_alloc() + { +#if TRUST_NO_ONE + assert(thread_is_main()); +#endif + + // delete orphaned IDs + orphan_mutex.lock(); + if (!orphaned_buffer_ids.empty()) + { + const auto orphaned_buffer_ct = (unsigned)orphaned_buffer_ids.size(); +#if ORPHAN_DEBUG + printf("deleting %u orphaned VBO%s\n", orphaned_buffer_ct, orphaned_buffer_ct == 1 ? "" : "s"); +#endif + glDeleteBuffers(orphaned_buffer_ct, orphaned_buffer_ids.data()); + orphaned_buffer_ids.clear(); + } + orphan_mutex.unlock(); + + GLuint new_buffer_id = 0; + glGenBuffers(1, &new_buffer_id); + return new_buffer_id; + } + +void GWN_buf_id_free(GLuint buffer_id) + { + if (thread_is_main()) + glDeleteBuffers(1, &buffer_id); + else + { + // add this ID to the orphaned list + orphan_mutex.lock(); +#if ORPHAN_DEBUG + printf("orphaning VBO %u\n", buffer_id); +#endif + orphaned_buffer_ids.emplace_back(buffer_id); + orphan_mutex.unlock(); + } + } + +GLuint GWN_vao_alloc() + { +#if TRUST_NO_ONE + assert(thread_is_main()); +#endif + + // delete orphaned IDs + orphan_mutex.lock(); + if (!orphaned_vao_ids.empty()) + { + const auto orphaned_vao_ct = (unsigned)orphaned_vao_ids.size(); +#if ORPHAN_DEBUG + printf("deleting %u orphaned VAO%s\n", orphaned_vao_ct, orphaned_vao_ct == 1 ? "" : "s"); +#endif + glDeleteVertexArrays(orphaned_vao_ct, orphaned_vao_ids.data()); + orphaned_vao_ids.clear(); + } + orphan_mutex.unlock(); + + GLuint new_vao_id = 0; + glGenVertexArrays(1, &new_vao_id); + return new_vao_id; + } + +void GWN_vao_free(GLuint vao_id) + { + if (thread_is_main()) + glDeleteVertexArrays(1, &vao_id); + else + { + // add this ID to the orphaned list + orphan_mutex.lock(); +#if ORPHAN_DEBUG + printf("orphaning VAO %u\n", vao_id); +#endif + orphaned_vao_ids.emplace_back(vao_id); + orphan_mutex.unlock(); + } + } diff --git a/intern/gawain/src/element.c b/intern/gawain/src/element.c new file mode 100644 index 00000000000..ecf555fbfe8 --- /dev/null +++ b/intern/gawain/src/element.c @@ -0,0 +1,295 @@ + +// Gawain element list (AKA index buffer) +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "element.h" +#include "buffer_id.h" +#include <stdlib.h> + +#define KEEP_SINGLE_COPY 1 + +static GLenum convert_index_type_to_gl(Gwn_IndexBufType type) + { + static const GLenum table[] = { + [GWN_INDEX_U8] = GL_UNSIGNED_BYTE, // GL has this, Vulkan does not + [GWN_INDEX_U16] = GL_UNSIGNED_SHORT, + [GWN_INDEX_U32] = GL_UNSIGNED_INT + }; + return table[type]; + } + +unsigned GWN_indexbuf_size_get(const Gwn_IndexBuf* elem) + { +#if GWN_TRACK_INDEX_RANGE + static const unsigned table[] = { + [GWN_INDEX_U8] = sizeof(GLubyte), // GL has this, Vulkan does not + [GWN_INDEX_U16] = sizeof(GLushort), + [GWN_INDEX_U32] = sizeof(GLuint) + }; + return elem->index_ct * table[elem->index_type]; +#else + return elem->index_ct * sizeof(GLuint); +#endif + } + +static void ElementList_prime(Gwn_IndexBuf* elem) + { + elem->vbo_id = GWN_buf_id_alloc(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id); + // fill with delicious data & send to GPU the first time only + glBufferData(GL_ELEMENT_ARRAY_BUFFER, GWN_indexbuf_size_get(elem), elem->data, GL_STATIC_DRAW); + +#if KEEP_SINGLE_COPY + // now that GL has a copy, discard original + free(elem->data); + elem->data = NULL; +#endif + } + +void GWN_indexbuf_use(Gwn_IndexBuf* elem) + { + if (elem->vbo_id) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id); + else + ElementList_prime(elem); + } + +void GWN_indexbuf_init(Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, unsigned prim_ct, unsigned vertex_ct) + { + unsigned verts_per_prim = 0; + switch (prim_type) + { + case GWN_PRIM_POINTS: + verts_per_prim = 1; + break; + case GWN_PRIM_LINES: + verts_per_prim = 2; + break; + case GWN_PRIM_TRIS: + verts_per_prim = 3; + break; + default: +#if TRUST_NO_ONE + assert(false); +#endif + return; + } + + builder->max_allowed_index = vertex_ct - 1; + builder->max_index_ct = prim_ct * verts_per_prim; + builder->index_ct = 0; // start empty + builder->prim_type = prim_type; + builder->data = calloc(builder->max_index_ct, sizeof(unsigned)); + } + +void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder* builder, unsigned v) + { +#if TRUST_NO_ONE + assert(builder->data != NULL); + assert(builder->index_ct < builder->max_index_ct); + assert(v <= builder->max_allowed_index); +#endif + + builder->data[builder->index_ct++] = v; + } + +void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder* builder, unsigned v) + { +#if TRUST_NO_ONE + assert(builder->prim_type == GWN_PRIM_POINTS); +#endif + + GWN_indexbuf_add_generic_vert(builder, v); + } + +void GWN_indexbuf_add_line_verts(Gwn_IndexBufBuilder* builder, unsigned v1, unsigned v2) + { +#if TRUST_NO_ONE + assert(builder->prim_type == GWN_PRIM_LINES); + assert(v1 != v2); +#endif + + GWN_indexbuf_add_generic_vert(builder, v1); + GWN_indexbuf_add_generic_vert(builder, v2); + } + +void GWN_indexbuf_add_tri_verts(Gwn_IndexBufBuilder* builder, unsigned v1, unsigned v2, unsigned v3) + { +#if TRUST_NO_ONE + assert(builder->prim_type == GWN_PRIM_TRIS); + assert(v1 != v2 && v2 != v3 && v3 != v1); +#endif + + GWN_indexbuf_add_generic_vert(builder, v1); + GWN_indexbuf_add_generic_vert(builder, v2); + GWN_indexbuf_add_generic_vert(builder, v3); + } + +#if GWN_TRACK_INDEX_RANGE +// Everything remains 32 bit while building to keep things simple. +// Find min/max after, then convert to smallest index type possible. + +static unsigned index_range(const unsigned values[], unsigned value_ct, unsigned* min_out, unsigned* max_out) + { + if (value_ct == 0) + { + *min_out = 0; + *max_out = 0; + return 0; + } + unsigned min_value = values[0]; + unsigned max_value = values[0]; + for (unsigned i = 1; i < value_ct; ++i) + { + const unsigned value = values[i]; + if (value < min_value) + min_value = value; + else if (value > max_value) + max_value = value; + } + *min_out = min_value; + *max_out = max_value; + return max_value - min_value; + } + +static void squeeze_indices_byte(const unsigned values[], Gwn_IndexBuf* elem) + { + const unsigned index_ct = elem->index_ct; + GLubyte* data = malloc(index_ct * sizeof(GLubyte)); + + if (elem->max_index > 0xFF) + { + const unsigned base = elem->min_index; + + elem->base_index = base; + elem->min_index = 0; + elem->max_index -= base; + + for (unsigned i = 0; i < index_ct; ++i) + data[i] = (GLubyte)(values[i] - base); + } + else + { + elem->base_index = 0; + + for (unsigned i = 0; i < index_ct; ++i) + data[i] = (GLubyte)(values[i]); + } + + elem->data = data; + } + +static void squeeze_indices_short(const unsigned values[], Gwn_IndexBuf* elem) + { + const unsigned index_ct = elem->index_ct; + GLushort* data = malloc(index_ct * sizeof(GLushort)); + + if (elem->max_index > 0xFFFF) + { + const unsigned base = elem->min_index; + + elem->base_index = base; + elem->min_index = 0; + elem->max_index -= base; + + for (unsigned i = 0; i < index_ct; ++i) + data[i] = (GLushort)(values[i] - base); + } + else + { + elem->base_index = 0; + + for (unsigned i = 0; i < index_ct; ++i) + data[i] = (GLushort)(values[i]); + } + + elem->data = data; + } + +#endif // GWN_TRACK_INDEX_RANGE + +Gwn_IndexBuf* GWN_indexbuf_build(Gwn_IndexBufBuilder* builder) + { + Gwn_IndexBuf* elem = calloc(1, sizeof(Gwn_IndexBuf)); + GWN_indexbuf_build_in_place(builder, elem); + return elem; + } + +void GWN_indexbuf_build_in_place(Gwn_IndexBufBuilder* builder, Gwn_IndexBuf* elem) + { +#if TRUST_NO_ONE + assert(builder->data != NULL); +#endif + + elem->index_ct = builder->index_ct; + +#if GWN_TRACK_INDEX_RANGE + const unsigned range = index_range(builder->data, builder->index_ct, &elem->min_index, &elem->max_index); + + if (range <= 0xFF) + { + elem->index_type = GWN_INDEX_U8; + squeeze_indices_byte(builder->data, elem); + } + else if (range <= 0xFFFF) + { + elem->index_type = GWN_INDEX_U16; + squeeze_indices_short(builder->data, elem); + } + else + { + elem->index_type = GWN_INDEX_U32; + elem->base_index = 0; + + if (builder->index_ct < builder->max_index_ct) + { + builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned)); + // TODO: realloc only if index_ct is much smaller than max_index_ct + } + + elem->data = builder->data; + } + + elem->gl_index_type = convert_index_type_to_gl(elem->index_type); +#else + if (builder->index_ct < builder->max_index_ct) + { + builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned)); + // TODO: realloc only if index_ct is much smaller than max_index_ct + } + + elem->data = builder->data; +#endif + + // elem->data will never be *larger* than builder->data... how about converting + // in place to avoid extra allocation? + + elem->vbo_id = 0; + // TODO: create GL buffer object directly, based on an input flag + + // discard builder (one-time use) + if (builder->data != elem->data) + free(builder->data); + builder->data = NULL; + // other fields are safe to leave + } + +void GWN_indexbuf_discard(Gwn_IndexBuf* elem) + { + if (elem->vbo_id) + GWN_buf_id_free(elem->vbo_id); +#if KEEP_SINGLE_COPY + else +#endif + if (elem->data) + free(elem->data); + + free(elem); + } diff --git a/intern/gawain/src/imm_util.c b/intern/gawain/src/imm_util.c new file mode 100644 index 00000000000..b06778c9045 --- /dev/null +++ b/intern/gawain/src/imm_util.c @@ -0,0 +1,46 @@ + +// Gawain immediate mode drawing utilities +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "imm_util.h" +#include "immediate.h" + + +void immRectf(unsigned pos, float x1, float y1, float x2, float y2) + { + immBegin(GWN_PRIM_TRI_FAN, 4); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x1, y2); + immEnd(); + } + +void immRecti(unsigned pos, int x1, int y1, int x2, int y2) + { + immBegin(GWN_PRIM_TRI_FAN, 4); + immVertex2i(pos, x1, y1); + immVertex2i(pos, x2, y1); + immVertex2i(pos, x2, y2); + immVertex2i(pos, x1, y2); + immEnd(); + } + +#if 0 // more complete version in case we want that +void immRecti_complete(int x1, int y1, int x2, int y2, const float color[4]) + { + Gwn_VertFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(color); + immRecti(pos, x1, y1, x2, y2); + immUnbindProgram(); + } +#endif diff --git a/intern/gawain/src/immediate.c b/intern/gawain/src/immediate.c new file mode 100644 index 00000000000..5eb5ebb8336 --- /dev/null +++ b/intern/gawain/src/immediate.c @@ -0,0 +1,919 @@ + +// Gawain immediate mode work-alike +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "immediate.h" +#include "buffer_id.h" +#include "attrib_binding.h" +#include "attrib_binding_private.h" +#include "vertex_format_private.h" +#include "primitive_private.h" +#include <string.h> + +// necessary functions from matrix API +extern void gpuBindMatrices(const Gwn_ShaderInterface*); +extern bool gpuMatricesDirty(void); + +typedef struct { + // TODO: organize this struct by frequency of change (run-time) + +#if IMM_BATCH_COMBO + Gwn_Batch* batch; +#endif + + // current draw call + GLubyte* buffer_data; + unsigned buffer_offset; + unsigned buffer_bytes_mapped; + unsigned vertex_ct; + bool strict_vertex_ct; + Gwn_PrimType prim_type; + + Gwn_VertFormat vertex_format; + + // current vertex + unsigned vertex_idx; + GLubyte* vertex_data; + uint16_t unassigned_attrib_bits; // which attributes of current vertex have not been given values? + + GLuint vbo_id; + GLuint vao_id; + + GLuint bound_program; + const Gwn_ShaderInterface* shader_interface; + Gwn_AttrBinding attrib_binding; + uint16_t prev_enabled_attrib_bits; // <-- only affects this VAO, so we're ok +} Immediate; + +// size of internal buffer -- make this adjustable? +#define IMM_BUFFER_SIZE (4 * 1024 * 1024) + +static bool initialized = false; +static Immediate imm; + +void immInit(void) + { +#if TRUST_NO_ONE + assert(!initialized); +#endif + + memset(&imm, 0, sizeof(Immediate)); + + imm.vbo_id = GWN_buf_id_alloc(); + glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id); + glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); + + imm.prim_type = GWN_PRIM_NONE; + imm.strict_vertex_ct = true; + + glBindBuffer(GL_ARRAY_BUFFER, 0); + initialized = true; + + immActivate(); + } + +void immActivate(void) + { +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == GWN_PRIM_NONE); // make sure we're not between a Begin/End pair + assert(imm.vao_id == 0); +#endif + + imm.vao_id = GWN_vao_alloc(); + } + +void immDeactivate(void) + { +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == GWN_PRIM_NONE); // make sure we're not between a Begin/End pair + assert(imm.vao_id != 0); +#endif + + GWN_vao_free(imm.vao_id); + imm.vao_id = 0; + imm.prev_enabled_attrib_bits = 0; + } + +void immDestroy(void) + { + immDeactivate(); + GWN_buf_id_free(imm.vbo_id); + initialized = false; + } + +Gwn_VertFormat* immVertexFormat(void) + { + GWN_vertformat_clear(&imm.vertex_format); + return &imm.vertex_format; + } + +void immBindProgram(GLuint program, const Gwn_ShaderInterface* shaderface) + { +#if TRUST_NO_ONE + assert(imm.bound_program == 0); + assert(glIsProgram(program)); +#endif + + imm.bound_program = program; + imm.shader_interface = shaderface; + + if (!imm.vertex_format.packed) + VertexFormat_pack(&imm.vertex_format); + + glUseProgram(program); + get_attrib_locations(&imm.vertex_format, &imm.attrib_binding, shaderface); + gpuBindMatrices(shaderface); + } + +void immUnbindProgram(void) + { +#if TRUST_NO_ONE + assert(imm.bound_program != 0); +#endif + + glUseProgram(0); + imm.bound_program = 0; + } + +#if TRUST_NO_ONE +static bool vertex_count_makes_sense_for_primitive(unsigned vertex_ct, Gwn_PrimType prim_type) + { + // does vertex_ct make sense for this primitive type? + if (vertex_ct == 0) + return false; + + switch (prim_type) + { + case GWN_PRIM_POINTS: + return true; + case GWN_PRIM_LINES: + return vertex_ct % 2 == 0; + case GWN_PRIM_LINE_STRIP: + case GWN_PRIM_LINE_LOOP: + return vertex_ct >= 2; + case GWN_PRIM_LINE_STRIP_ADJ: + return vertex_ct >= 4; + case GWN_PRIM_TRIS: + return vertex_ct % 3 == 0; + case GWN_PRIM_TRI_STRIP: + case GWN_PRIM_TRI_FAN: + return vertex_ct >= 3; + default: + return false; + } + } +#endif + +void immBegin(Gwn_PrimType prim_type, unsigned vertex_ct) + { +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == GWN_PRIM_NONE); // make sure we haven't already begun + assert(vertex_count_makes_sense_for_primitive(vertex_ct, prim_type)); +#endif + + imm.prim_type = prim_type; + imm.vertex_ct = vertex_ct; + imm.vertex_idx = 0; + imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; + + // how many bytes do we need for this draw call? + const unsigned bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_ct); + +#if TRUST_NO_ONE + assert(bytes_needed <= IMM_BUFFER_SIZE); +#endif + + glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id); + + // does the current buffer have enough room? + const unsigned available_bytes = IMM_BUFFER_SIZE - imm.buffer_offset; + // ensure vertex data is aligned + const unsigned pre_padding = padding(imm.buffer_offset, imm.vertex_format.stride); // might waste a little space, but it's safe + if ((bytes_needed + pre_padding) <= available_bytes) + imm.buffer_offset += pre_padding; + else + { + // orphan this buffer & start with a fresh one +#if 1 + // this method works on all platforms, old & new + glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); +#else + // TODO: use other (more recent) methods after thorough testing + if (GLEW_VERSION_4_3 || GLEW_ARB_invalidate_subdata) + glInvalidateBufferData(imm.vbo_id); + else + { + // glitches! +// glMapBufferRange(GL_ARRAY_BUFFER, 0, IMM_BUFFER_SIZE, GL_MAP_INVALIDATE_BUFFER_BIT); + + // works +// glMapBufferRange(GL_ARRAY_BUFFER, 0, IMM_BUFFER_SIZE, +// GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); +// glUnmapBuffer(GL_ARRAY_BUFFER); + + // also works + glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW); + } +#endif + + imm.buffer_offset = 0; + } + +// printf("mapping %u to %u\n", imm.buffer_offset, imm.buffer_offset + bytes_needed - 1); + + imm.buffer_data = glMapBufferRange(GL_ARRAY_BUFFER, imm.buffer_offset, bytes_needed, + GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | (imm.strict_vertex_ct ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT)); + +#if TRUST_NO_ONE + assert(imm.buffer_data != NULL); +#endif + + imm.buffer_bytes_mapped = bytes_needed; + imm.vertex_data = imm.buffer_data; + } + +void immBeginAtMost(Gwn_PrimType prim_type, unsigned vertex_ct) + { +#if TRUST_NO_ONE + assert(vertex_ct > 0); +#endif + + imm.strict_vertex_ct = false; + immBegin(prim_type, vertex_ct); + } + +#if IMM_BATCH_COMBO + +Gwn_Batch* immBeginBatch(Gwn_PrimType prim_type, unsigned vertex_ct) + { +#if TRUST_NO_ONE + assert(initialized); + assert(imm.prim_type == GWN_PRIM_NONE); // make sure we haven't already begun + assert(vertex_count_makes_sense_for_primitive(vertex_ct, prim_type)); +#endif + + imm.prim_type = prim_type; + imm.vertex_ct = vertex_ct; + imm.vertex_idx = 0; + imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; + + Gwn_VertBuf* verts = GWN_vertbuf_create_with_format(&imm.vertex_format); + GWN_vertbuf_data_alloc(verts, vertex_ct); + + imm.buffer_bytes_mapped = GWN_vertbuf_size_get(verts); + imm.vertex_data = verts->data; + + imm.batch = GWN_batch_create(prim_type, verts, NULL); + imm.batch->phase = GWN_BATCH_BUILDING; + + GWN_batch_program_set(imm.batch, imm.bound_program, imm.shader_interface); + + return imm.batch; + } + +Gwn_Batch* immBeginBatchAtMost(Gwn_PrimType prim_type, unsigned vertex_ct) + { + imm.strict_vertex_ct = false; + return immBeginBatch(prim_type, vertex_ct); + } + +#endif // IMM_BATCH_COMBO + +static void immDrawSetup(void) + { + // set up VAO -- can be done during Begin or End really + glBindVertexArray(imm.vao_id); + + // enable/disable vertex attribs as needed + if (imm.attrib_binding.enabled_bits != imm.prev_enabled_attrib_bits) + { + for (unsigned loc = 0; loc < GWN_VERT_ATTR_MAX_LEN; ++loc) + { + bool is_enabled = imm.attrib_binding.enabled_bits & (1 << loc); + bool was_enabled = imm.prev_enabled_attrib_bits & (1 << loc); + + if (is_enabled && !was_enabled) + { +// printf("enabling attrib %u\n", loc); + glEnableVertexAttribArray(loc); + } + else if (was_enabled && !is_enabled) + { +// printf("disabling attrib %u\n", loc); + glDisableVertexAttribArray(loc); + } + } + + imm.prev_enabled_attrib_bits = imm.attrib_binding.enabled_bits; + } + + const unsigned stride = imm.vertex_format.stride; + + for (unsigned a_idx = 0; a_idx < imm.vertex_format.attrib_ct; ++a_idx) + { + const Gwn_VertAttr* a = imm.vertex_format.attribs + a_idx; + + const unsigned offset = imm.buffer_offset + a->offset; + const GLvoid* pointer = (const GLubyte*)0 + offset; + + const unsigned loc = read_attrib_location(&imm.attrib_binding, a_idx); + +// printf("specifying attrib %u '%s' with offset %u, stride %u\n", loc, a->name, offset, stride); + + switch (a->fetch_mode) + { + case GWN_FETCH_FLOAT: + case GWN_FETCH_INT_TO_FLOAT: + glVertexAttribPointer(loc, a->comp_ct, a->gl_comp_type, GL_FALSE, stride, pointer); + break; + case GWN_FETCH_INT_TO_FLOAT_UNIT: + glVertexAttribPointer(loc, a->comp_ct, a->gl_comp_type, GL_TRUE, stride, pointer); + break; + case GWN_FETCH_INT: + glVertexAttribIPointer(loc, a->comp_ct, a->gl_comp_type, stride, pointer); + } + } + + if (gpuMatricesDirty()) + gpuBindMatrices(imm.shader_interface); + } + +void immEnd(void) + { +#if TRUST_NO_ONE + assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + unsigned buffer_bytes_used; + if (imm.strict_vertex_ct) + { +#if TRUST_NO_ONE + assert(imm.vertex_idx == imm.vertex_ct); // with all vertices defined +#endif + buffer_bytes_used = imm.buffer_bytes_mapped; + } + else + { +#if TRUST_NO_ONE + assert(imm.vertex_idx <= imm.vertex_ct); +#endif + // printf("used %u of %u verts,", imm.vertex_idx, imm.vertex_ct); + if (imm.vertex_idx == imm.vertex_ct) + { + buffer_bytes_used = imm.buffer_bytes_mapped; + } + else + { +#if TRUST_NO_ONE + assert(imm.vertex_idx == 0 || vertex_count_makes_sense_for_primitive(imm.vertex_idx, imm.prim_type)); +#endif + imm.vertex_ct = imm.vertex_idx; + buffer_bytes_used = vertex_buffer_size(&imm.vertex_format, imm.vertex_ct); + // unused buffer bytes are available to the next immBegin + // printf(" %u of %u bytes\n", buffer_bytes_used, imm.buffer_bytes_mapped); + } + + // tell OpenGL what range was modified so it doesn't copy the whole mapped range + // printf("flushing %u to %u\n", imm.buffer_offset, imm.buffer_offset + buffer_bytes_used - 1); + glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, buffer_bytes_used); + } + +#if IMM_BATCH_COMBO + if (imm.batch) + { + if (buffer_bytes_used != imm.buffer_bytes_mapped) + { + GWN_vertbuf_data_resize(imm.batch->verts[0], imm.vertex_ct); + // TODO: resize only if vertex count is much smaller + } + + imm.batch->phase = GWN_BATCH_READY_TO_DRAW; + imm.batch = NULL; // don't free, batch belongs to caller + } + else +#endif + { + glUnmapBuffer(GL_ARRAY_BUFFER); + + if (imm.vertex_ct > 0) + { + immDrawSetup(); + glDrawArrays(convert_prim_type_to_gl(imm.prim_type), 0, imm.vertex_ct); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + // prep for next immBegin + imm.buffer_offset += buffer_bytes_used; + } + + // prep for next immBegin + imm.prim_type = GWN_PRIM_NONE; + imm.strict_vertex_ct = true; + } + +static void setAttribValueBit(unsigned attrib_id) + { + uint16_t mask = 1 << attrib_id; + +#if TRUST_NO_ONE + assert(imm.unassigned_attrib_bits & mask); // not already set +#endif + + imm.unassigned_attrib_bits &= ~mask; + } + + +// --- generic attribute functions --- + +void immAttrib1f(unsigned attrib_id, float x) + { + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == GWN_COMP_F32); + assert(attrib->comp_ct == 1); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); + + data[0] = x; + } + +void immAttrib2f(unsigned attrib_id, float x, float y) + { + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == GWN_COMP_F32); + assert(attrib->comp_ct == 2); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); + + data[0] = x; + data[1] = y; + } + +void immAttrib3f(unsigned attrib_id, float x, float y, float z) + { + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == GWN_COMP_F32); + assert(attrib->comp_ct == 3); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); + + data[0] = x; + data[1] = y; + data[2] = z; + } + +void immAttrib4f(unsigned attrib_id, float x, float y, float z, float w) + { + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == GWN_COMP_F32); + assert(attrib->comp_ct == 4); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + float* data = (float*)(imm.vertex_data + attrib->offset); +// printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); + + data[0] = x; + data[1] = y; + data[2] = z; + data[3] = w; + } + +void immAttrib1u(unsigned attrib_id, unsigned x) + { + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == GWN_COMP_U32); + assert(attrib->comp_ct == 1); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + unsigned* data = (unsigned*)(imm.vertex_data + attrib->offset); + + data[0] = x; + } + +void immAttrib2i(unsigned attrib_id, int x, int y) + { + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == GWN_COMP_I32); + assert(attrib->comp_ct == 2); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + int* data = (int*)(imm.vertex_data + attrib->offset); + + data[0] = x; + data[1] = y; + } + +void immAttrib2s(unsigned attrib_id, short x, short y) + { + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == GWN_COMP_I16); + assert(attrib->comp_ct == 2); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + short* data = (short*)(imm.vertex_data + attrib->offset); + + data[0] = x; + data[1] = y; + } + +void immAttrib2fv(unsigned attrib_id, const float data[2]) + { + immAttrib2f(attrib_id, data[0], data[1]); + } + +void immAttrib3fv(unsigned attrib_id, const float data[3]) + { + immAttrib3f(attrib_id, data[0], data[1], data[2]); + } + +void immAttrib4fv(unsigned attrib_id, const float data[4]) + { + immAttrib4f(attrib_id, data[0], data[1], data[2], data[3]); + } + +void immAttrib3ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b) + { + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == GWN_COMP_U8); + assert(attrib->comp_ct == 3); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + GLubyte* data = imm.vertex_data + attrib->offset; +// printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); + + data[0] = r; + data[1] = g; + data[2] = b; + } + +void immAttrib4ub(unsigned attrib_id, unsigned char r, unsigned char g, unsigned char b, unsigned char a) + { + Gwn_VertAttr* attrib = imm.vertex_format.attribs + attrib_id; + +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(attrib->comp_type == GWN_COMP_U8); + assert(attrib->comp_ct == 4); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + + GLubyte* data = imm.vertex_data + attrib->offset; +// printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); + + data[0] = r; + data[1] = g; + data[2] = b; + data[3] = a; + } + +void immAttrib3ubv(unsigned attrib_id, const unsigned char data[3]) + { + immAttrib3ub(attrib_id, data[0], data[1], data[2]); + } + +void immAttrib4ubv(unsigned attrib_id, const unsigned char data[4]) + { + immAttrib4ub(attrib_id, data[0], data[1], data[2], data[3]); + } + +void immSkipAttrib(unsigned attrib_id) + { +#if TRUST_NO_ONE + assert(attrib_id < imm.vertex_format.attrib_ct); + assert(imm.vertex_idx < imm.vertex_ct); + assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair +#endif + + setAttribValueBit(attrib_id); + } + +static void immEndVertex(void) // and move on to the next vertex + { +#if TRUST_NO_ONE + assert(imm.prim_type != GWN_PRIM_NONE); // make sure we're between a Begin/End pair + assert(imm.vertex_idx < imm.vertex_ct); +#endif + + // have all attribs been assigned values? + // if not, copy value from previous vertex + if (imm.unassigned_attrib_bits) + { +#if TRUST_NO_ONE + assert(imm.vertex_idx > 0); // first vertex must have all attribs specified +#endif + + for (unsigned a_idx = 0; a_idx < imm.vertex_format.attrib_ct; ++a_idx) + { + if ((imm.unassigned_attrib_bits >> a_idx) & 1) + { + const Gwn_VertAttr* a = imm.vertex_format.attribs + a_idx; + +// printf("copying %s from vertex %u to %u\n", a->name, imm.vertex_idx - 1, imm.vertex_idx); + + GLubyte* data = imm.vertex_data + a->offset; + memcpy(data, data - imm.vertex_format.stride, a->sz); + // TODO: consolidate copy of adjacent attributes + } + } + } + + imm.vertex_idx++; + imm.vertex_data += imm.vertex_format.stride; + imm.unassigned_attrib_bits = imm.attrib_binding.enabled_bits; + } + +void immVertex2f(unsigned attrib_id, float x, float y) + { + immAttrib2f(attrib_id, x, y); + immEndVertex(); + } + +void immVertex3f(unsigned attrib_id, float x, float y, float z) + { + immAttrib3f(attrib_id, x, y, z); + immEndVertex(); + } + +void immVertex2i(unsigned attrib_id, int x, int y) + { + immAttrib2i(attrib_id, x, y); + immEndVertex(); + } + +void immVertex2s(unsigned attrib_id, short x, short y) + { + immAttrib2s(attrib_id, x, y); + immEndVertex(); + } + +void immVertex2fv(unsigned attrib_id, const float data[2]) + { + immAttrib2f(attrib_id, data[0], data[1]); + immEndVertex(); + } + +void immVertex3fv(unsigned attrib_id, const float data[3]) + { + immAttrib3f(attrib_id, data[0], data[1], data[2]); + immEndVertex(); + } + +void immVertex2iv(unsigned attrib_id, const int data[2]) + { + immAttrib2i(attrib_id, data[0], data[1]); + immEndVertex(); + } + + +// --- generic uniform functions --- + +#if 0 + #if TRUST_NO_ONE + #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(imm.shader_interface, name); assert(uniform); + #else + #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(imm.shader_interface, name); + #endif +#else + // NOTE: It is possible to have uniform fully optimized out from the shader. + // In this case we can't assert failure or allow NULL-pointer dereference. + // TODO(sergey): How can we detect existing-but-optimized-out uniform but still + // catch typos in uniform names passed to immUniform*() functions? + #define GET_UNIFORM const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform(imm.shader_interface, name); if (uniform == NULL) return; +#endif + +void immUniform1f(const char* name, float x) + { + GET_UNIFORM + glUniform1f(uniform->location, x); + } + +void immUniform2f(const char* name, float x, float y) + { + GET_UNIFORM + glUniform2f(uniform->location, x, y); + } + +void immUniform2fv(const char* name, const float data[2]) + { + GET_UNIFORM + glUniform2fv(uniform->location, 1, data); + } + +void immUniform3f(const char* name, float x, float y, float z) + { + GET_UNIFORM + glUniform3f(uniform->location, x, y, z); + } + +void immUniform3fv(const char* name, const float data[3]) + { + GET_UNIFORM + glUniform3fv(uniform->location, 1, data); + } + +// can increase this limit or move to another file +#define MAX_UNIFORM_NAME_LEN 60 + +void immUniformArray3fv(const char* bare_name, const float *data, int count) + { + // look up "name[0]" when given "name" + const size_t len = strlen(bare_name); +#if TRUST_NO_ONE + assert(len <= MAX_UNIFORM_NAME_LEN); +#endif + char name[MAX_UNIFORM_NAME_LEN]; + strcpy(name, bare_name); + name[len + 0] = '['; + name[len + 1] = '0'; + name[len + 2] = ']'; + name[len + 3] = '\0'; + + GET_UNIFORM + glUniform3fv(uniform->location, count, data); + } + +void immUniform4f(const char* name, float x, float y, float z, float w) + { + GET_UNIFORM + glUniform4f(uniform->location, x, y, z, w); + } + +void immUniform4fv(const char* name, const float data[4]) + { + GET_UNIFORM + glUniform4fv(uniform->location, 1, data); + } + +void immUniformArray4fv(const char* bare_name, const float *data, int count) + { + // look up "name[0]" when given "name" + const size_t len = strlen(bare_name); +#if TRUST_NO_ONE + assert(len <= MAX_UNIFORM_NAME_LEN); +#endif + char name[MAX_UNIFORM_NAME_LEN]; + strcpy(name, bare_name); + name[len + 0] = '['; + name[len + 1] = '0'; + name[len + 2] = ']'; + name[len + 3] = '\0'; + + GET_UNIFORM + glUniform4fv(uniform->location, count, data); + } + +void immUniformMatrix4fv(const char* name, const float data[4][4]) + { + GET_UNIFORM + glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (float *)data); + } + +void immUniform1i(const char* name, int x) + { + GET_UNIFORM + glUniform1i(uniform->location, x); + } + +void immUniform4iv(const char* name, const int data[4]) + { + GET_UNIFORM + glUniform4iv(uniform->location, 1, data); + } + +// --- convenience functions for setting "uniform vec4 color" --- + +void immUniformColor4f(float r, float g, float b, float a) + { + const Gwn_ShaderInput* uniform = GWN_shaderinterface_uniform_builtin(imm.shader_interface, GWN_UNIFORM_COLOR); + +#if TRUST_NO_ONE + assert(uniform != NULL); +#endif + + glUniform4f(uniform->location, r, g, b, a); + } + +void immUniformColor4fv(const float rgba[4]) + { + immUniformColor4f(rgba[0], rgba[1], rgba[2], rgba[3]); + } + +void immUniformColor3f(float r, float g, float b) + { + immUniformColor4f(r, g, b, 1.0f); + } + +void immUniformColor3fv(const float rgb[3]) + { + immUniformColor4f(rgb[0], rgb[1], rgb[2], 1.0f); + } + +void immUniformColor3fvAlpha(const float rgb[3], float a) + { + immUniformColor4f(rgb[0], rgb[1], rgb[2], a); + } + +// TODO: v-- treat as sRGB? --v + +void immUniformColor3ub(unsigned char r, unsigned char g, unsigned char b) + { + const float scale = 1.0f / 255.0f; + immUniformColor4f(scale * r, scale * g, scale * b, 1.0f); + } + +void immUniformColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) + { + const float scale = 1.0f / 255.0f; + immUniformColor4f(scale * r, scale * g, scale * b, scale * a); + } + +void immUniformColor3ubv(const unsigned char rgb[3]) + { + immUniformColor3ub(rgb[0], rgb[1], rgb[2]); + } + +void immUniformColor3ubvAlpha(const unsigned char rgb[3], unsigned char alpha) + { + immUniformColor4ub(rgb[0], rgb[1], rgb[2], alpha); + } + +void immUniformColor4ubv(const unsigned char rgba[4]) + { + immUniformColor4ub(rgba[0], rgba[1], rgba[2], rgba[3]); + } diff --git a/intern/gawain/src/primitive.c b/intern/gawain/src/primitive.c new file mode 100644 index 00000000000..b9d92a6bdf8 --- /dev/null +++ b/intern/gawain/src/primitive.c @@ -0,0 +1,63 @@ + +// Gawain geometric primitives +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2017 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "primitive.h" +#include "primitive_private.h" + +Gwn_PrimClass GWN_primtype_class(Gwn_PrimType prim_type) + { + static const Gwn_PrimClass classes[] = + { + [GWN_PRIM_POINTS] = GWN_PRIM_CLASS_POINT, + [GWN_PRIM_LINES] = GWN_PRIM_CLASS_LINE, + [GWN_PRIM_LINE_STRIP] = GWN_PRIM_CLASS_LINE, + [GWN_PRIM_LINE_LOOP] = GWN_PRIM_CLASS_LINE, + [GWN_PRIM_TRIS] = GWN_PRIM_CLASS_SURFACE, + [GWN_PRIM_TRI_STRIP] = GWN_PRIM_CLASS_SURFACE, + [GWN_PRIM_TRI_FAN] = GWN_PRIM_CLASS_SURFACE, + + [GWN_PRIM_LINE_STRIP_ADJ] = GWN_PRIM_CLASS_LINE, + + [GWN_PRIM_NONE] = GWN_PRIM_CLASS_NONE + }; + + return classes[prim_type]; + } + +bool GWN_primtype_belongs_to_class(Gwn_PrimType prim_type, Gwn_PrimClass prim_class) + { + if (prim_class == GWN_PRIM_CLASS_NONE && prim_type == GWN_PRIM_NONE) + return true; + + return prim_class & GWN_primtype_class(prim_type); + } + +GLenum convert_prim_type_to_gl(Gwn_PrimType prim_type) + { +#if TRUST_NO_ONE + assert(prim_type != GWN_PRIM_NONE); +#endif + + static const GLenum table[] = + { + [GWN_PRIM_POINTS] = GL_POINTS, + [GWN_PRIM_LINES] = GL_LINES, + [GWN_PRIM_LINE_STRIP] = GL_LINE_STRIP, + [GWN_PRIM_LINE_LOOP] = GL_LINE_LOOP, + [GWN_PRIM_TRIS] = GWN_PRIM_CLASS_SURFACE, + [GWN_PRIM_TRI_STRIP] = GL_TRIANGLE_STRIP, + [GWN_PRIM_TRI_FAN] = GL_TRIANGLE_FAN, + + [GWN_PRIM_LINE_STRIP_ADJ] = GL_LINE_STRIP_ADJACENCY, + }; + + return table[prim_type]; + } diff --git a/intern/gawain/src/shader_interface.c b/intern/gawain/src/shader_interface.c new file mode 100644 index 00000000000..dff2c06f531 --- /dev/null +++ b/intern/gawain/src/shader_interface.c @@ -0,0 +1,311 @@ + +// Gawain shader interface (C --> GLSL) +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2017 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "shader_interface.h" +#include <stdlib.h> +#include <stddef.h> +#include <string.h> + +#define SUPPORT_LEGACY_GLSL 1 +#define DEBUG_SHADER_INTERFACE 0 + +#if DEBUG_SHADER_INTERFACE + #include <stdio.h> +#endif + +static const char* BuiltinUniform_name(Gwn_UniformBuiltin u) + { + static const char* names[] = + { + [GWN_UNIFORM_NONE] = NULL, + + [GWN_UNIFORM_MODELVIEW] = "ModelViewMatrix", + [GWN_UNIFORM_PROJECTION] = "ProjectionMatrix", + [GWN_UNIFORM_MVP] = "ModelViewProjectionMatrix", + + [GWN_UNIFORM_MODELVIEW_INV] = "ModelViewInverseMatrix", + [GWN_UNIFORM_PROJECTION_INV] = "ProjectionInverseMatrix", + + [GWN_UNIFORM_NORMAL] = "NormalMatrix", + + [GWN_UNIFORM_COLOR] = "color", + + [GWN_UNIFORM_CUSTOM] = NULL + }; + + return names[u]; + } + +static bool match(const char* a, const char* b) + { + return strcmp(a, b) == 0; + } + +static unsigned hash_string(const char *str) + { + unsigned i = 0, c; + + while ((c = *str++)) + { + i = i * 37 + c; + } + + return i; + } + +static void set_input_name(Gwn_ShaderInput* input, const char* name) + { + input->name = name; + input->name_hash = hash_string(name); + } + +// keep these in sync with Gwn_UniformBuiltin order +#define FIRST_MAT4_UNIFORM GWN_UNIFORM_MODELVIEW +#define LAST_MAT4_UNIFORM GWN_UNIFORM_PROJECTION_INV + +static bool setup_builtin_uniform(Gwn_ShaderInput* input, const char* name) + { + // TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types + + // detect built-in uniforms (gl_type and name must match) + // if a match is found, use BuiltinUniform_name so name buffer space can be reclaimed + switch (input->gl_type) + { + case GL_FLOAT_MAT4: + for (Gwn_UniformBuiltin u = FIRST_MAT4_UNIFORM; u <= LAST_MAT4_UNIFORM; ++u) + { + const char* builtin_name = BuiltinUniform_name(u); + if (match(name, builtin_name)) + { + set_input_name(input, builtin_name); + input->builtin_type = u; + return true; + } + } + break; + case GL_FLOAT_MAT3: + { + const char* builtin_name = BuiltinUniform_name(GWN_UNIFORM_NORMAL); + if (match(name, builtin_name)) + { + set_input_name(input, builtin_name); + input->builtin_type = GWN_UNIFORM_NORMAL; + return true; + } + } + break; + case GL_FLOAT_VEC4: + { + const char* builtin_name = BuiltinUniform_name(GWN_UNIFORM_COLOR); + if (match(name, builtin_name)) + { + set_input_name(input, builtin_name); + input->builtin_type = GWN_UNIFORM_COLOR; + return true; + } + } + break; + default: + ; + } + + input->builtin_type = GWN_UNIFORM_CUSTOM; + return false; + } + +Gwn_ShaderInterface* GWN_shaderinterface_create(GLint program) + { +#if DEBUG_SHADER_INTERFACE + printf("%s {\n", __func__); // enter function +#endif + + GLint uniform_ct, attrib_ct; + glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniform_ct); + glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attrib_ct); + const GLint input_ct = uniform_ct + attrib_ct; + + GLint max_uniform_name_len, max_attrib_name_len; + glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len); + glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attrib_name_len); + const uint32_t name_buffer_len = uniform_ct * max_uniform_name_len + attrib_ct * max_attrib_name_len; + + // allocate enough space for input counts, details for each input, and a buffer for name strings + Gwn_ShaderInterface* shaderface = calloc(1, offsetof(Gwn_ShaderInterface, inputs) + input_ct * sizeof(Gwn_ShaderInput) + name_buffer_len); + shaderface->uniform_ct = uniform_ct; + shaderface->attrib_ct = attrib_ct; + + char* name_buffer = (char*)shaderface + offsetof(Gwn_ShaderInterface, inputs) + input_ct * sizeof(Gwn_ShaderInput); + uint32_t name_buffer_offset = 0; + + for (uint32_t i = 0; i < uniform_ct; ++i) + { + Gwn_ShaderInput* input = shaderface->inputs + i; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; + char* name = name_buffer + name_buffer_offset; + GLsizei name_len = 0; + + glGetActiveUniform(program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name); + + input->location = glGetUniformLocation(program, name); + +#if SUPPORT_LEGACY_GLSL + if (input->location != -1) + { +#elif TRUST_NO_ONE + assert(input->location != -1); +#endif + + if (setup_builtin_uniform(input, name)) + ; // reclaim space from name buffer (don't advance offset) + else + { + set_input_name(input, name); + name_buffer_offset += name_len + 1; // include NULL terminator + } +#if SUPPORT_LEGACY_GLSL + } +#endif + +#if DEBUG_SHADER_INTERFACE + printf("uniform[%u] '%s' at location %d\n", i, name, input->location); +#endif + } + + for (uint32_t i = 0; i < attrib_ct; ++i) + { + Gwn_ShaderInput* input = shaderface->inputs + uniform_ct + i; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; + char* name = name_buffer + name_buffer_offset; + GLsizei name_len = 0; + + glGetActiveAttrib(program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name); + + // TODO: reject DOUBLE gl_types + + input->location = glGetAttribLocation(program, name); + +#if SUPPORT_LEGACY_GLSL + if (input->location != -1) + { +#elif TRUST_NO_ONE + assert(input->location != -1); +#endif + + set_input_name(input, name); + name_buffer_offset += name_len + 1; // include NULL terminator +#if SUPPORT_LEGACY_GLSL + } +#endif + +#if DEBUG_SHADER_INTERFACE + printf("attrib[%u] '%s' at location %d\n", i, name, input->location); +#endif + } + + const uint32_t name_buffer_used = name_buffer_offset; + +#if DEBUG_SHADER_INTERFACE + printf("using %u of %u bytes from name buffer\n", name_buffer_used, name_buffer_len); + printf("}\n"); // exit function +#endif + + if (name_buffer_used < name_buffer_len) + { + // realloc shaderface to shrink name buffer + const size_t shaderface_alloc = + offsetof(Gwn_ShaderInterface, inputs) + (input_ct * sizeof(Gwn_ShaderInput)) + name_buffer_used; + const char* shaderface_orig_start = (const char*)shaderface; + const char* shaderface_orig_end = &shaderface_orig_start[shaderface_alloc]; + shaderface = realloc(shaderface, shaderface_alloc); + const ptrdiff_t delta = (char*)shaderface - shaderface_orig_start; + + if (delta) + { + // each input->name will need adjustment (except static built-in names) + for (uint32_t i = 0; i < input_ct; ++i) + { + Gwn_ShaderInput* input = shaderface->inputs + i; + + if (input->name >= shaderface_orig_start && input->name < shaderface_orig_end) + input->name += delta; + } + } + } + + return shaderface; + } + +void GWN_shaderinterface_discard(Gwn_ShaderInterface* shaderface) + { + // allocated as one chunk, so discard is simple + free(shaderface); + } + +const Gwn_ShaderInput* GWN_shaderinterface_uniform(const Gwn_ShaderInterface* shaderface, const char* name) + { + const unsigned name_hash = hash_string(name); + for (uint32_t i = 0; i < shaderface->uniform_ct; ++i) + { + const Gwn_ShaderInput* uniform = shaderface->inputs + i; + +#if SUPPORT_LEGACY_GLSL + if (uniform->name == NULL) continue; +#endif + + if (uniform->name_hash != name_hash) continue; + + if (match(uniform->name, name)) + return uniform; + + // TODO: warn if we find a matching builtin, since these can be looked up much quicker --v + } + + return NULL; // not found + } + +const Gwn_ShaderInput* GWN_shaderinterface_uniform_builtin(const Gwn_ShaderInterface* shaderface, Gwn_UniformBuiltin builtin) + { +#if TRUST_NO_ONE + assert(builtin != GWN_UNIFORM_NONE); + assert(builtin != GWN_UNIFORM_CUSTOM); +#endif + + // look up by enum, not name + for (uint32_t i = 0; i < shaderface->uniform_ct; ++i) + { + const Gwn_ShaderInput* uniform = shaderface->inputs + i; + + if (uniform->builtin_type == builtin) + return uniform; + } + return NULL; // not found + } + +const Gwn_ShaderInput* GWN_shaderinterface_attr(const Gwn_ShaderInterface* shaderface, const char* name) + { + // attribs are stored after uniforms + const uint32_t input_ct = shaderface->uniform_ct + shaderface->attrib_ct; + const unsigned name_hash = hash_string(name); + for (uint32_t i = shaderface->uniform_ct; i < input_ct; ++i) + { + const Gwn_ShaderInput* attrib = shaderface->inputs + i; + +#if SUPPORT_LEGACY_GLSL + if (attrib->name == NULL) continue; +#endif + + if (attrib->name_hash != name_hash) continue; + + if (match(attrib->name, name)) + return attrib; + } + return NULL; // not found + } diff --git a/intern/gawain/src/vertex_buffer.c b/intern/gawain/src/vertex_buffer.c new file mode 100644 index 00000000000..364e16a1a68 --- /dev/null +++ b/intern/gawain/src/vertex_buffer.c @@ -0,0 +1,222 @@ + +// Gawain vertex buffer +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "vertex_buffer.h" +#include "buffer_id.h" +#include "vertex_format_private.h" +#include <stdlib.h> +#include <string.h> + +#define KEEP_SINGLE_COPY 1 + +static unsigned vbo_memory_usage; + +Gwn_VertBuf* GWN_vertbuf_create(void) + { + Gwn_VertBuf* verts = malloc(sizeof(Gwn_VertBuf)); + GWN_vertbuf_init(verts); + return verts; + } + +Gwn_VertBuf* GWN_vertbuf_create_with_format(const Gwn_VertFormat* format) + { + Gwn_VertBuf* verts = GWN_vertbuf_create(); + GWN_vertformat_copy(&verts->format, format); + if (!format->packed) + VertexFormat_pack(&verts->format); + return verts; + + // this function might seem redundant, but there is potential for memory savings here... + // TODO: implement those memory savings + } + +void GWN_vertbuf_init(Gwn_VertBuf* verts) + { + memset(verts, 0, sizeof(Gwn_VertBuf)); + } + +void GWN_vertbuf_init_with_format(Gwn_VertBuf* verts, const Gwn_VertFormat* format) + { + GWN_vertbuf_init(verts); + GWN_vertformat_copy(&verts->format, format); + if (!format->packed) + VertexFormat_pack(&verts->format); + } + +/** + * Like #GWN_vertbuf_discard but doesn't free. + */ +void GWN_vertbuf_clear(Gwn_VertBuf* verts) + { + if (verts->vbo_id) { + GWN_buf_id_free(verts->vbo_id); + vbo_memory_usage -= GWN_vertbuf_size_get(verts); + } +#if KEEP_SINGLE_COPY + else +#endif + if (verts->data) + { + free(verts->data); + verts->data = NULL; + } + } + +void GWN_vertbuf_discard(Gwn_VertBuf* verts) + { + if (verts->vbo_id) { + GWN_buf_id_free(verts->vbo_id); + vbo_memory_usage -= GWN_vertbuf_size_get(verts); + } +#if KEEP_SINGLE_COPY + else +#endif + if (verts->data) + free(verts->data); + + + free(verts); + } + +unsigned GWN_vertbuf_size_get(const Gwn_VertBuf* verts) + { + return vertex_buffer_size(&verts->format, verts->vertex_ct); + } + +void GWN_vertbuf_data_alloc(Gwn_VertBuf* verts, unsigned v_ct) + { + Gwn_VertFormat* format = &verts->format; + if (!format->packed) + VertexFormat_pack(format); + + verts->vertex_ct = v_ct; + + // Data initially lives in main memory. Will be transferred to VRAM when we "prime" it. + verts->data = malloc(GWN_vertbuf_size_get(verts)); + } + +void GWN_vertbuf_data_resize(Gwn_VertBuf* verts, unsigned v_ct) + { +#if TRUST_NO_ONE + assert(verts->vertex_ct != v_ct); // allow this? + assert(verts->data != NULL); // has already been allocated + assert(verts->vbo_id == 0); // has not been sent to VRAM +#endif + + verts->vertex_ct = v_ct; + verts->data = realloc(verts->data, GWN_vertbuf_size_get(verts)); + // TODO: skip realloc if v_ct < existing vertex count + // extra space will be reclaimed, and never sent to VRAM (see VertexBuffer_prime) + } + +void GWN_vertbuf_attr_set(Gwn_VertBuf* verts, unsigned a_idx, unsigned v_idx, const void* data) + { + const Gwn_VertFormat* format = &verts->format; + const Gwn_VertAttr* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attrib_ct); + assert(v_idx < verts->vertex_ct); + assert(verts->data != NULL); // data must be in main mem +#endif + + memcpy((GLubyte*)verts->data + a->offset + v_idx * format->stride, data, a->sz); + } + +void GWN_vertbuf_attr_fill(Gwn_VertBuf* verts, unsigned a_idx, const void* data) + { + const Gwn_VertFormat* format = &verts->format; + const Gwn_VertAttr* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attrib_ct); +#endif + + const unsigned stride = a->sz; // tightly packed input data + + GWN_vertbuf_attr_fill_stride(verts, a_idx, stride, data); + } + +void GWN_vertbuf_attr_fill_stride(Gwn_VertBuf* verts, unsigned a_idx, unsigned stride, const void* data) + { + const Gwn_VertFormat* format = &verts->format; + const Gwn_VertAttr* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attrib_ct); + assert(verts->data != NULL); // data must be in main mem +#endif + + const unsigned vertex_ct = verts->vertex_ct; + + if (format->attrib_ct == 1 && stride == format->stride) + { + // we can copy it all at once + memcpy(verts->data, data, vertex_ct * a->sz); + } + else + { + // we must copy it per vertex + for (unsigned v = 0; v < vertex_ct; ++v) + memcpy((GLubyte*)verts->data + a->offset + v * format->stride, (const GLubyte*)data + v * stride, a->sz); + } + } + +void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf* verts, unsigned a_idx, Gwn_VertBufRaw *access) + { + const Gwn_VertFormat* format = &verts->format; + const Gwn_VertAttr* a = format->attribs + a_idx; + +#if TRUST_NO_ONE + assert(a_idx < format->attrib_ct); + assert(verts->data != NULL); // data must be in main mem +#endif + + access->size = a->sz; + access->stride = format->stride; + access->data = (GLubyte*)verts->data + a->offset; + access->data_init = access->data; +#if TRUST_NO_ONE + access->_data_end = access->data_init + (size_t)(verts->vertex_ct * format->stride); +#endif + } + + +static void VertexBuffer_prime(Gwn_VertBuf* verts) + { + const unsigned buffer_sz = GWN_vertbuf_size_get(verts); + + verts->vbo_id = GWN_buf_id_alloc(); + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + // fill with delicious data & send to GPU the first time only + glBufferData(GL_ARRAY_BUFFER, buffer_sz, verts->data, GL_STATIC_DRAW); + + vbo_memory_usage += buffer_sz; + +#if KEEP_SINGLE_COPY + // now that GL has a copy, discard original + free(verts->data); + verts->data = NULL; +#endif + } + +void GWN_vertbuf_use(Gwn_VertBuf* verts) + { + if (verts->vbo_id) + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + else + VertexBuffer_prime(verts); + } + +unsigned GWN_vertbuf_get_memory_usage(void) + { + return vbo_memory_usage; + } diff --git a/intern/gawain/src/vertex_format.c b/intern/gawain/src/vertex_format.c new file mode 100644 index 00000000000..34704db3359 --- /dev/null +++ b/intern/gawain/src/vertex_format.c @@ -0,0 +1,296 @@ + +// Gawain vertex format +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2016 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "vertex_format.h" +#include "vertex_format_private.h" +#include <stddef.h> +#include <string.h> + +#define PACK_DEBUG 0 + +#if PACK_DEBUG + #include <stdio.h> +#endif + +void GWN_vertformat_clear(Gwn_VertFormat* format) + { +#if TRUST_NO_ONE + memset(format, 0, sizeof(Gwn_VertFormat)); +#else + format->attrib_ct = 0; + format->packed = false; + format->name_offset = 0; + format->name_ct = 0; + + for (unsigned i = 0; i < GWN_VERT_ATTR_MAX_LEN; i++) + { + format->attribs[i].name_ct = 0; + } +#endif + } + +void GWN_vertformat_copy(Gwn_VertFormat* dest, const Gwn_VertFormat* src) + { + // copy regular struct fields + memcpy(dest, src, sizeof(Gwn_VertFormat)); + + for (unsigned i = 0; i < dest->attrib_ct; i++) + { + dest->attribs[i].name_ct = dest->attribs[i].name_ct; + for (unsigned j = 0; j < dest->attribs[i].name_ct; j++) + { + dest->attribs[i].name[j] = (char *)dest + (src->attribs[i].name[j] - ((char *)src)); + } + } + } + +static GLenum convert_comp_type_to_gl(Gwn_VertCompType type) + { + static const GLenum table[] = { + [GWN_COMP_I8] = GL_BYTE, + [GWN_COMP_U8] = GL_UNSIGNED_BYTE, + [GWN_COMP_I16] = GL_SHORT, + [GWN_COMP_U16] = GL_UNSIGNED_SHORT, + [GWN_COMP_I32] = GL_INT, + [GWN_COMP_U32] = GL_UNSIGNED_INT, + + [GWN_COMP_F32] = GL_FLOAT, + + [GWN_COMP_I10] = GL_INT_2_10_10_10_REV + }; + return table[type]; + } + +static unsigned comp_sz(Gwn_VertCompType type) + { +#if TRUST_NO_ONE + assert(type <= GWN_COMP_F32); // other types have irregular sizes (not bytes) +#endif + + const GLubyte sizes[] = {1,1,2,2,4,4,4}; + return sizes[type]; + } + +static unsigned attrib_sz(const Gwn_VertAttr *a) + { + if (a->comp_type == GWN_COMP_I10) + return 4; // always packed as 10_10_10_2 + + return a->comp_ct * comp_sz(a->comp_type); + } + +static unsigned attrib_align(const Gwn_VertAttr *a) + { + if (a->comp_type == GWN_COMP_I10) + return 4; // always packed as 10_10_10_2 + + unsigned c = comp_sz(a->comp_type); + if (a->comp_ct == 3 && c <= 2) + return 4 * c; // AMD HW can't fetch these well, so pad it out (other vendors too?) + else + return c; // most fetches are ok if components are naturally aligned + } + +unsigned vertex_buffer_size(const Gwn_VertFormat* format, unsigned vertex_ct) + { +#if TRUST_NO_ONE + assert(format->packed && format->stride > 0); +#endif + + return format->stride * vertex_ct; + } + +static const char* copy_attrib_name(Gwn_VertFormat* format, const char* name) + { + // strncpy does 110% of what we need; let's do exactly 100% + char* name_copy = format->names + format->name_offset; + unsigned available = GWN_VERT_ATTR_NAMES_BUF_LEN - format->name_offset; + bool terminated = false; + + for (unsigned i = 0; i < available; ++i) + { + const char c = name[i]; + name_copy[i] = c; + if (c == '\0') + { + terminated = true; + format->name_offset += (i + 1); + break; + } + } + +#if TRUST_NO_ONE + assert(terminated); + assert(format->name_offset <= GWN_VERT_ATTR_NAMES_BUF_LEN); +#else + (void)terminated; +#endif + + return name_copy; + } + +unsigned GWN_vertformat_attr_add(Gwn_VertFormat* format, const char* name, Gwn_VertCompType comp_type, unsigned comp_ct, Gwn_VertFetchMode fetch_mode) + { +#if TRUST_NO_ONE + assert(format->name_ct < GWN_VERT_ATTR_MAX_LEN); // there's room for more + assert(format->attrib_ct < GWN_VERT_ATTR_MAX_LEN); // there's room for more + assert(!format->packed); // packed means frozen/locked + assert(comp_ct >= 1 && comp_ct <= 4); + switch (comp_type) + { + case GWN_COMP_F32: + // float type can only kept as float + assert(fetch_mode == GWN_FETCH_FLOAT); + break; + case GWN_COMP_I10: + // 10_10_10 format intended for normals (xyz) or colors (rgb) + // extra component packed.w can be manually set to { -2, -1, 0, 1 } + assert(comp_ct == 3 || comp_ct == 4); + assert(fetch_mode == GWN_FETCH_INT_TO_FLOAT_UNIT); // not strictly required, may relax later + break; + default: + // integer types can be kept as int or converted/normalized to float + assert(fetch_mode != GWN_FETCH_FLOAT); + } +#endif + format->name_ct++; // multiname support + + const unsigned attrib_id = format->attrib_ct++; + Gwn_VertAttr* attrib = format->attribs + attrib_id; + + attrib->name[attrib->name_ct++] = copy_attrib_name(format, name); + attrib->comp_type = comp_type; + attrib->gl_comp_type = convert_comp_type_to_gl(comp_type); + attrib->comp_ct = (comp_type == GWN_COMP_I10) ? 4 : comp_ct; // system needs 10_10_10_2 to be 4 or BGRA + attrib->sz = attrib_sz(attrib); + attrib->offset = 0; // offsets & stride are calculated later (during pack) + attrib->fetch_mode = fetch_mode; + + return attrib_id; + } + +void GWN_vertformat_alias_add(Gwn_VertFormat* format, const char* alias) + { + Gwn_VertAttr* attrib = format->attribs + (format->attrib_ct - 1); +#if TRUST_NO_ONE + assert(format->name_ct < GWN_VERT_ATTR_MAX_LEN); // there's room for more + assert(attrib->name_ct < MAX_ATTRIB_NAMES); +#endif + format->name_ct++; // multiname support + attrib->name[attrib->name_ct++] = copy_attrib_name(format, alias); + } + +unsigned padding(unsigned offset, unsigned alignment) + { + const unsigned mod = offset % alignment; + return (mod == 0) ? 0 : (alignment - mod); + } + +#if PACK_DEBUG +static void show_pack(unsigned a_idx, unsigned sz, unsigned pad) + { + const char c = 'A' + a_idx; + for (unsigned i = 0; i < pad; ++i) + putchar('-'); + for (unsigned i = 0; i < sz; ++i) + putchar(c); + } +#endif + +void VertexFormat_pack(Gwn_VertFormat* format) + { + // for now, attributes are packed in the order they were added, + // making sure each attrib is naturally aligned (add padding where necessary) + + // later we can implement more efficient packing w/ reordering + // (keep attrib ID order, adjust their offsets to reorder in buffer) + + // TODO: + // realloc just enough to hold the final combo string. And just enough to + // hold used attribs, not all 16. + + Gwn_VertAttr* a0 = format->attribs + 0; + a0->offset = 0; + unsigned offset = a0->sz; + +#if PACK_DEBUG + show_pack(0, a0->sz, 0); +#endif + + for (unsigned a_idx = 1; a_idx < format->attrib_ct; ++a_idx) + { + Gwn_VertAttr* a = format->attribs + a_idx; + unsigned mid_padding = padding(offset, attrib_align(a)); + offset += mid_padding; + a->offset = offset; + offset += a->sz; + +#if PACK_DEBUG + show_pack(a_idx, a->sz, mid_padding); +#endif + } + + unsigned end_padding = padding(offset, attrib_align(a0)); + +#if PACK_DEBUG + show_pack(0, 0, end_padding); + putchar('\n'); +#endif + + format->stride = offset + end_padding; + format->packed = true; + } + + +// OpenGL ES packs in a different order as desktop GL but component conversion is the same. +// Of the code here, only struct Gwn_PackedNormal needs to change. + +#define SIGNED_INT_10_MAX 511 +#define SIGNED_INT_10_MIN -512 + +static int clampi(int x, int min_allowed, int max_allowed) + { +#if TRUST_NO_ONE + assert(min_allowed <= max_allowed); +#endif + + if (x < min_allowed) + return min_allowed; + else if (x > max_allowed) + return max_allowed; + else + return x; + } + +static int quantize(float x) + { + int qx = x * 511.0f; + return clampi(qx, SIGNED_INT_10_MIN, SIGNED_INT_10_MAX); + } + +static int convert_i16(short x) + { + // 16-bit signed --> 10-bit signed + return x >> 6; + // TODO: round? + } + +Gwn_PackedNormal GWN_normal_convert_i10_v3(const float data[3]) + { + Gwn_PackedNormal n = { .x = quantize(data[0]), .y = quantize(data[1]), .z = quantize(data[2]) }; + return n; + } + +Gwn_PackedNormal GWN_normal_convert_i10_s3(const short data[3]) + { + Gwn_PackedNormal n = { .x = convert_i16(data[0]), .y = convert_i16(data[1]), .z = convert_i16(data[2]) }; + return n; + } diff --git a/intern/ghost/intern/GHOST_Context.cpp b/intern/ghost/intern/GHOST_Context.cpp index 72db17c4f56..823a476d244 100644 --- a/intern/ghost/intern/GHOST_Context.cpp +++ b/intern/ghost/intern/GHOST_Context.cpp @@ -143,11 +143,7 @@ bool win32_chk(bool result, const char *file, int line, const char *text) void GHOST_Context::initContextGLEW() { - mxDestroyContext(m_mxContext); // no-op if m_mxContext is NULL - - mxMakeCurrentContext(mxCreateContext()); - - m_mxContext = mxGetCurrentContext(); + GLEW_CHK(glewInit()); } diff --git a/intern/ghost/intern/GHOST_Context.h b/intern/ghost/intern/GHOST_Context.h index 18d36c40e9c..8776fa4764f 100644 --- a/intern/ghost/intern/GHOST_Context.h +++ b/intern/ghost/intern/GHOST_Context.h @@ -50,15 +50,13 @@ public: */ GHOST_Context(bool stereoVisual, GHOST_TUns16 numOfAASamples) : m_stereoVisual(stereoVisual), - m_numOfAASamples(numOfAASamples), - m_mxContext(NULL) + m_numOfAASamples(numOfAASamples) {} /** * Destructor. */ virtual ~GHOST_Context() { - mxDestroyContext(m_mxContext); } /** @@ -128,19 +126,12 @@ public: protected: void initContextGLEW(); - inline void activateGLEW() const { - mxMakeCurrentContext(m_mxContext); - } - bool m_stereoVisual; GHOST_TUns16 m_numOfAASamples; static void initClearGL(); -private: - MXContext *m_mxContext; - #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("GHOST:GHOST_Context") #endif diff --git a/intern/ghost/intern/GHOST_ContextCGL.h b/intern/ghost/intern/GHOST_ContextCGL.h index dd49b81b561..6dcc4da0f0a 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.h +++ b/intern/ghost/intern/GHOST_ContextCGL.h @@ -34,10 +34,6 @@ #include "GHOST_Context.h" -//#define cglewGetContext() cglewContext -//#include <GL/cglew.h> -//extern "C" CGLEWContext *cglewContext; - #ifndef GHOST_OPENGL_CGL_CONTEXT_FLAGS #define GHOST_OPENGL_CGL_CONTEXT_FLAGS 0 #endif @@ -120,21 +116,14 @@ public: */ GHOST_TSuccess updateDrawingContext(); -//protected: -// inline void activateCGLEW() const { -// cglewContext = m_cglewContext; -// } - private: - //void initContextCGLEW() - /** The openGL view */ NSOpenGLView *m_openGLView; /** The OpenGL drawing context */ NSOpenGLContext *m_openGLContext; - //static CGLEWContext *s_cglewContext; + bool m_coreProfile; const bool m_debug; diff --git a/intern/ghost/intern/GHOST_ContextCGL.mm b/intern/ghost/intern/GHOST_ContextCGL.mm index 03c45f9945b..03af3cc497e 100644 --- a/intern/ghost/intern/GHOST_ContextCGL.mm +++ b/intern/ghost/intern/GHOST_ContextCGL.mm @@ -63,6 +63,23 @@ GHOST_ContextCGL::GHOST_ContextCGL( m_debug(contextFlags) { assert(openGLView != nil); + + // for now be very strict about OpenGL version requested + switch (contextMajorVersion) { + case 2: + assert(contextMinorVersion == 1); + assert(contextProfileMask == 0); + m_coreProfile = false; + break; + case 3: + // Apple didn't implement 3.0 or 3.1 + assert(contextMinorVersion == 2); + assert(contextProfileMask == GL_CONTEXT_CORE_PROFILE_BIT); + m_coreProfile = true; + break; + default: + assert(false); + } } @@ -142,9 +159,6 @@ GHOST_TSuccess GHOST_ContextCGL::activateDrawingContext() if (m_openGLContext != nil) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [m_openGLContext makeCurrentContext]; - - activateGLEW(); - [pool drain]; return GHOST_kSuccess; } @@ -170,6 +184,7 @@ GHOST_TSuccess GHOST_ContextCGL::updateDrawingContext() static void makeAttribList( std::vector<NSOpenGLPixelFormatAttribute>& attribs, + bool coreProfile, bool stereoVisual, int numOfAASamples, bool needAlpha, @@ -178,6 +193,9 @@ static void makeAttribList( { attribs.clear(); + attribs.push_back(NSOpenGLPFAOpenGLProfile); + attribs.push_back(coreProfile ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy); + // Pixel Format Attributes for the windowed NSOpenGLContext attribs.push_back(NSOpenGLPFADoubleBuffer); @@ -190,15 +208,11 @@ static void makeAttribList( attribs.push_back(NSOpenGLPFANoRecovery); } - /* Removed to allow 10.4 builds, and 2 GPUs rendering is not used anyway */ - //attribs.push_back(NSOpenGLPFAAllowOfflineRenderers); + attribs.push_back(NSOpenGLPFAAllowOfflineRenderers); // for automatic GPU switching attribs.push_back(NSOpenGLPFADepthSize); attribs.push_back((NSOpenGLPixelFormatAttribute) 32); - attribs.push_back(NSOpenGLPFAAccumSize); - attribs.push_back((NSOpenGLPixelFormatAttribute) 32); - if (stereoVisual) attribs.push_back(NSOpenGLPFAStereo); @@ -263,7 +277,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext() NSOpenGLPixelFormat *pixelFormat; // TODO: keep pixel format for subsequent windows/contexts instead of recreating each time - makeAttribList(attribs, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL); + makeAttribList(attribs, m_coreProfile, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL); pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]]; @@ -274,7 +288,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext() // (Now that I think about it, does WGL really require the code that it has for finding a lesser match?) attribs.clear(); - makeAttribList(attribs, m_stereoVisual, 0, needAlpha, needStencil, softwareGL); + makeAttribList(attribs, m_coreProfile, m_stereoVisual, 0, needAlpha, needStencil, softwareGL); pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]]; } @@ -316,7 +330,7 @@ GHOST_TSuccess GHOST_ContextCGL::initializeDrawingContext() [m_openGLContext release]; // create software GL context - makeAttribList(attribs, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL); + makeAttribList(attribs, m_coreProfile, m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, softwareGL); pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]]; m_openGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:s_sharedOpenGLContext]; [pixelFormat release]; diff --git a/intern/ghost/intern/GHOST_ContextEGL.cpp b/intern/ghost/intern/GHOST_ContextEGL.cpp index 520aa0fffb2..a591d9b7583 100644 --- a/intern/ghost/intern/GHOST_ContextEGL.cpp +++ b/intern/ghost/intern/GHOST_ContextEGL.cpp @@ -42,11 +42,6 @@ #include <cstring> -#ifdef WITH_GLEW_MX -EGLEWContext *eglewContext = NULL; -#endif - - #define CASE_CODE_RETURN_STR(code) case code: return #code; static const char *get_egl_error_enum_string(EGLenum error) @@ -168,13 +163,8 @@ static bool egl_chk(bool result, const char *file = NULL, int line = 0, const ch static inline bool bindAPI(EGLenum api) { -#ifdef WITH_GLEW_MX - if (eglewContext != NULL) -#endif - { - if (EGLEW_VERSION_1_2) { - return (EGL_CHK(eglBindAPI(api)) == EGL_TRUE); - } + if (EGLEW_VERSION_1_2) { + return (EGL_CHK(eglBindAPI(api)) == EGL_TRUE); } return false; @@ -238,9 +228,6 @@ GHOST_ContextEGL::GHOST_ContextEGL( m_surface(EGL_NO_SURFACE), m_display(EGL_NO_DISPLAY), m_swap_interval(1), -#ifdef WITH_GLEW_MX - m_eglewContext(NULL), -#endif m_sharedContext(choose_api(api, s_gl_sharedContext, s_gles_sharedContext, s_vg_sharedContext)), m_sharedCount (choose_api(api, s_gl_sharedCount, s_gles_sharedCount, s_vg_sharedCount)) { @@ -252,7 +239,6 @@ GHOST_ContextEGL::GHOST_ContextEGL( GHOST_ContextEGL::~GHOST_ContextEGL() { if (m_display != EGL_NO_DISPLAY) { - activateEGLEW(); bindAPI(m_api); @@ -276,10 +262,6 @@ GHOST_ContextEGL::~GHOST_ContextEGL() EGL_CHK(::eglDestroySurface(m_display, m_surface)); EGL_CHK(::eglTerminate(m_display)); - -#ifdef WITH_GLEW_MX - delete m_eglewContext; -#endif } } @@ -321,9 +303,6 @@ GHOST_TSuccess GHOST_ContextEGL::getSwapInterval(int &intervalOut) GHOST_TSuccess GHOST_ContextEGL::activateDrawingContext() { if (m_display) { - activateEGLEW(); - activateGLEW(); - bindAPI(m_api); return EGL_CHK(::eglMakeCurrent(m_display, m_surface, m_surface, m_context)) ? GHOST_kSuccess : GHOST_kFailure; @@ -336,14 +315,6 @@ GHOST_TSuccess GHOST_ContextEGL::activateDrawingContext() void GHOST_ContextEGL::initContextEGLEW() { -#ifdef WITH_GLEW_MX - eglewContext = new EGLEWContext; - memset(eglewContext, 0, sizeof(EGLEWContext)); - - delete m_eglewContext; - m_eglewContext = eglewContext; -#endif - if (GLEW_CHK(eglewInit(m_display)) != GLEW_OK) fprintf(stderr, "Warning! EGLEW failed to initialize properly.\n"); } diff --git a/intern/ghost/intern/GHOST_ContextEGL.h b/intern/ghost/intern/GHOST_ContextEGL.h index 70c26c940fc..6dfb177f26d 100644 --- a/intern/ghost/intern/GHOST_ContextEGL.h +++ b/intern/ghost/intern/GHOST_ContextEGL.h @@ -34,17 +34,8 @@ #include "GHOST_Context.h" -#ifdef WITH_GLEW_MX -# define eglewGetContext() eglewContext -#endif - #include <GL/eglew.h> -#ifdef WITH_GLEW_MX -extern "C" EGLEWContext *eglewContext; -#endif - - #ifndef GHOST_OPENGL_EGL_CONTEXT_FLAGS #define GHOST_OPENGL_EGL_CONTEXT_FLAGS 0 #endif @@ -116,13 +107,6 @@ public: */ GHOST_TSuccess getSwapInterval(int &intervalOut); -protected: - inline void activateEGLEW() const { -#ifdef WITH_GLEW_MX - eglewContext = m_eglewContext; -#endif - } - private: void initContextEGLEW(); @@ -143,10 +127,6 @@ private: EGLint m_swap_interval; -#ifdef WITH_GLEW_MX - EGLEWContext *m_eglewContext; -#endif - EGLContext &m_sharedContext; EGLint &m_sharedCount; diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp index 9ac61db4041..0a9dc900aed 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.cpp +++ b/intern/ghost/intern/GHOST_ContextGLX.cpp @@ -48,10 +48,6 @@ static GLuint _glewStrLen(const GLubyte *s); static GLboolean _glewSearchExtension(const char *name, const GLubyte *start, const GLubyte *end); #endif -#ifdef WITH_GLEW_MX -GLXEWContext *glxewContext = NULL; -#endif - GLXContext GHOST_ContextGLX::s_sharedContext = None; int GHOST_ContextGLX::s_sharedCount = 0; @@ -79,10 +75,6 @@ GHOST_ContextGLX::GHOST_ContextGLX( m_contextFlags(contextFlags), m_contextResetNotificationStrategy(contextResetNotificationStrategy), m_context(None) -#ifdef WITH_GLEW_MX - , - m_glxewContext(NULL) -#endif { assert(m_window != 0); assert(m_display != NULL); @@ -92,8 +84,6 @@ GHOST_ContextGLX::GHOST_ContextGLX( GHOST_ContextGLX::~GHOST_ContextGLX() { if (m_display != NULL) { - activateGLXEW(); - if (m_context != None) { if (m_window != 0 && m_context == ::glXGetCurrentContext()) ::glXMakeCurrent(m_display, None, NULL); @@ -109,11 +99,6 @@ GHOST_ContextGLX::~GHOST_ContextGLX() ::glXDestroyContext(m_display, m_context); } } - -#ifdef WITH_GLEW_MX - if (m_glxewContext) - delete m_glxewContext; -#endif } } @@ -129,9 +114,6 @@ GHOST_TSuccess GHOST_ContextGLX::swapBuffers() GHOST_TSuccess GHOST_ContextGLX::activateDrawingContext() { if (m_display) { - activateGLXEW(); - activateGLEW(); - return ::glXMakeCurrent(m_display, m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure; } else { @@ -141,15 +123,6 @@ GHOST_TSuccess GHOST_ContextGLX::activateDrawingContext() void GHOST_ContextGLX::initContextGLXEW() { -#ifdef WITH_GLEW_MX - glxewContext = new GLXEWContext; - memset(glxewContext, 0, sizeof(GLXEWContext)); - - if (m_glxewContext) - delete m_glxewContext; - m_glxewContext = glxewContext; -#endif - initContextGLEW(); } @@ -255,9 +228,6 @@ const bool GLXEW_ARB_create_context_robustness = if (m_contextMajorVersion != 0) { attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB; attribs[i++] = m_contextMajorVersion; - } - - if (m_contextMinorVersion != 0) { attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB; attribs[i++] = m_contextMinorVersion; } @@ -300,8 +270,8 @@ const bool GLXEW_ARB_create_context_robustness = } } else { - /* Create legacy context */ - m_context = glXCreateContext(m_display, m_visualInfo, s_sharedContext, True); + /* Don't create legacy context */ + fprintf(stderr, "Warning! GLX_ARB_create_context not available.\n"); } GHOST_TSuccess success; @@ -328,8 +298,14 @@ const bool GLXEW_ARB_create_context_robustness = version = glGetString(GL_VERSION); - if (!version || version[0] < '2' || ((version[0] == '2') && (version[2] < '1'))) { - fprintf(stderr, "Error! Blender requires OpenGL 2.1 to run. Try updating your drivers.\n"); +#if 0 // enable this when Blender switches to 3.3 core profile + if (!version || version[0] < '3' || ((version[0] == '3') && (version[2] < '3'))) { + fprintf(stderr, "Error! Blender requires OpenGL 3.3 to run. Try updating your drivers.\n"); +#else + // with Mesa, the closest thing to 3.3 compatibility profile is 3.0 + if (!version || version[0] < '3') { + fprintf(stderr, "Error! Blender requires OpenGL 3.0 (soon 3.3) to run. Try updating your drivers.\n"); +#endif fflush(stderr); /* ugly, but we get crashes unless a whole bunch of systems are patched. */ exit(0); diff --git a/intern/ghost/intern/GHOST_ContextGLX.h b/intern/ghost/intern/GHOST_ContextGLX.h index f0f010d1942..6547a0bd00a 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.h +++ b/intern/ghost/intern/GHOST_ContextGLX.h @@ -34,16 +34,8 @@ #include "GHOST_Context.h" -#ifdef WITH_GLEW_MX -# define glxewGetContext() glxewContext -#endif - #include <GL/glxew.h> -#ifdef WITH_GLEW_MX -extern "C" GLXEWContext *glxewContext; -#endif - #ifndef GHOST_OPENGL_GLX_CONTEXT_FLAGS /* leave as convenience define for the future */ @@ -117,13 +109,6 @@ public: */ GHOST_TSuccess getSwapInterval(int &intervalOut); -protected: - inline void activateGLXEW() const { -#ifdef WITH_GLEW_MX - glxewContext = m_glxewContext; -#endif - } - private: void initContextGLXEW(); @@ -140,10 +125,6 @@ private: GLXContext m_context; -#ifdef WITH_GLEW_MX - GLXEWContext *m_glxewContext; -#endif - /** The first created OpenGL context (for sharing display lists) */ static GLXContext s_sharedContext; static int s_sharedCount; diff --git a/intern/ghost/intern/GHOST_ContextSDL.cpp b/intern/ghost/intern/GHOST_ContextSDL.cpp index 39627fac899..7a02e9743c3 100644 --- a/intern/ghost/intern/GHOST_ContextSDL.cpp +++ b/intern/ghost/intern/GHOST_ContextSDL.cpp @@ -97,8 +97,6 @@ GHOST_TSuccess GHOST_ContextSDL::swapBuffers() GHOST_TSuccess GHOST_ContextSDL::activateDrawingContext() { if (m_context) { - activateGLEW(); - return SDL_GL_MakeCurrent(m_window, m_context) ? GHOST_kSuccess : GHOST_kFailure; } else { diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp index 64ee692797b..d2dd38878f7 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.cpp +++ b/intern/ghost/intern/GHOST_ContextWGL.cpp @@ -40,10 +40,6 @@ #include <vector> -#ifdef WITH_GLEW_MX -WGLEWContext *wglewContext = NULL; -#endif - HGLRC GHOST_ContextWGL::s_sharedHGLRC = NULL; int GHOST_ContextWGL::s_sharedCount = 0; @@ -82,10 +78,6 @@ GHOST_ContextWGL::GHOST_ContextWGL( m_alphaBackground(alphaBackground), m_contextResetNotificationStrategy(contextResetNotificationStrategy), m_hGLRC(NULL) -#ifdef WITH_GLEW_MX - , - m_wglewContext(NULL) -#endif #ifndef NDEBUG , m_dummyVendor(NULL), @@ -116,10 +108,6 @@ GHOST_ContextWGL::~GHOST_ContextWGL() } } -#ifdef WITH_GLEW_MX - delete m_wglewContext; -#endif - #ifndef NDEBUG free((void*)m_dummyRenderer); free((void*)m_dummyVendor); @@ -158,7 +146,6 @@ GHOST_TSuccess GHOST_ContextWGL::getSwapInterval(int &intervalOut) GHOST_TSuccess GHOST_ContextWGL::activateDrawingContext() { if (WIN32_CHK(::wglMakeCurrent(m_hDC, m_hGLRC))) { - activateGLEW(); return GHOST_kSuccess; } else { @@ -338,15 +325,6 @@ void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD) int iPixelFormat; - -#ifdef WITH_GLEW_MX - wglewContext = new WGLEWContext; - memset(wglewContext, 0, sizeof(WGLEWContext)); - - delete m_wglewContext; - m_wglewContext = wglewContext; -#endif - SetLastError(NO_ERROR); prevHDC = ::wglGetCurrentDC(); @@ -385,13 +363,8 @@ void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD) if (!WIN32_CHK(::wglMakeCurrent(dummyHDC, dummyHGLRC))) goto finalize; -#ifdef WITH_GLEW_MX - if (GLEW_CHK(wglewInit()) != GLEW_OK) - fprintf(stderr, "Warning! WGLEW failed to initialize properly.\n"); -#else if (GLEW_CHK(glewInit()) != GLEW_OK) fprintf(stderr, "Warning! Dummy GLEW/WGLEW failed to initialize properly.\n"); -#endif // the following are not technially WGLEW, but they also require a context to work @@ -828,8 +801,6 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext() return GHOST_kFailure; } - activateWGLEW(); - if (WGLEW_ARB_create_context) { int profileBitCore = m_contextProfileMask & WGL_CONTEXT_CORE_PROFILE_BIT_ARB; int profileBitCompat = m_contextProfileMask & WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; @@ -907,21 +878,6 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext() else m_hGLRC = s_sharedHGLRC; } - else { - if (m_contextProfileMask != 0) - fprintf(stderr, "Warning! Legacy WGL is unable to select between OpenGL profiles."); - - if (m_contextMajorVersion != 0 || m_contextMinorVersion != 0) - fprintf(stderr, "Warning! Legacy WGL is unable to select between OpenGL versions."); - - if (m_contextFlags != 0) - fprintf(stderr, "Warning! Legacy WGL is unable to set context flags."); - - if (!s_singleContextMode || s_sharedHGLRC == NULL) - m_hGLRC = ::wglCreateContext(m_hDC); - else - m_hGLRC = s_sharedHGLRC; - } if (!WIN32_CHK(m_hGLRC != NULL)) { ::wglMakeCurrent(prevHDC, prevHGLRC); @@ -958,29 +914,6 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext() reportContextString("Version", m_dummyVersion, version); #endif - if ((strcmp(vendor, "Microsoft Corporation") == 0 || - strcmp(renderer, "GDI Generic") == 0) && version[0] == '1' && version[2] == '1') - { - MessageBox(m_hWnd, "Your system does not use 3D hardware acceleration.\n" - "Blender requires a graphics driver with OpenGL 2.1 support.\n\n" - "This may be caused by:\n" - "* A missing or faulty graphics driver installation.\n" - " Blender needs a graphics card driver to work correctly.\n" - "* Accessing Blender through a remote connection.\n" - "* Using Blender through a virtual machine.\n\n" - "The program will now close.", - "Blender - Can't detect 3D hardware accelerated Driver!", - MB_OK | MB_ICONERROR); - exit(0); - } - else if (version[0] < '2' || (version[0] == '2' && version[2] < '1')) { - MessageBox(m_hWnd, "Blender requires a graphics driver with OpenGL 2.1 support.\n\n" - "The program will now close.", - "Blender - Unsupported Graphics Driver!", - MB_OK | MB_ICONERROR); - exit(0); - } - return GHOST_kSuccess; } @@ -994,3 +927,97 @@ GHOST_TSuccess GHOST_ContextWGL::releaseNativeHandles() return success; } + +/** + * For any given HDC you may call SetPixelFormat once + * + * So we better try to get the correct OpenGL version in a new window altogether, in case it fails. + * (see https://msdn.microsoft.com/en-us/library/windows/desktop/dd369049(v=vs.85).aspx) + */ +static bool TryOpenGLVersion( + HWND hwnd, + bool wantStereoVisual, + bool wantAlphaBackground, + GHOST_TUns16 wantNumOfAASamples, + int contextProfileMask, + bool debugContext, + int major, int minor) +{ + HWND dummyHWND = clone_window(hwnd, NULL); + if (dummyHWND == NULL) { + return false; + } + + HDC dummyHDC = GetDC(dummyHWND); + if (dummyHDC == NULL) { + return false; + } + + GHOST_ContextWGL * context = new GHOST_ContextWGL( + wantStereoVisual, + wantAlphaBackground, + wantNumOfAASamples, + dummyHWND, + dummyHDC, + contextProfileMask, + major, minor, + (debugContext ? WGL_CONTEXT_DEBUG_BIT_ARB : 0), + GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); + + bool result = context->initializeDrawingContext(); + delete context; + + ReleaseDC(dummyHWND, dummyHDC); + DestroyWindow(dummyHWND); + + return result; +} + +GHOST_TSuccess GHOST_ContextWGL::getMaximumSupportedOpenGLVersion( + HWND hwnd, + bool wantStereoVisual, + bool wantAlphaBackground, + GHOST_TUns16 wantNumOfAASamples, + int contextProfileMask, + bool debugContext, + GHOST_TUns8 *r_major_version, + GHOST_TUns8 *r_minor_version) +{ + /* - AMD and Intel give us exactly this version + * - NVIDIA gives at least this version <-- desired behavior + * So we ask for 4.5, 4.4 ... 3.3 in descending order to get the best version on the user's system. */ + for (int minor = 5; minor >= 0; --minor) { + if (TryOpenGLVersion( + hwnd, + wantStereoVisual, + wantAlphaBackground, + wantNumOfAASamples, + contextProfileMask, + debugContext, + 4, minor)) + { + *r_major_version = 4; + *r_minor_version = minor; + return GHOST_kSuccess; + } + } + + /* Fallback to OpenGL 3.3 */ + if (TryOpenGLVersion( + hwnd, + wantStereoVisual, + wantAlphaBackground, + wantNumOfAASamples, + contextProfileMask, + debugContext, + 3, 3)) + { + *r_major_version = 3; + *r_minor_version = 3; + return GHOST_kSuccess; + } + + *r_major_version = 0; + *r_minor_version = 0; + return GHOST_kFailure; +} diff --git a/intern/ghost/intern/GHOST_ContextWGL.h b/intern/ghost/intern/GHOST_ContextWGL.h index 580b4dcb82f..0d9986a0802 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.h +++ b/intern/ghost/intern/GHOST_ContextWGL.h @@ -36,24 +36,8 @@ #include "GHOST_Context.h" -#ifdef WITH_GLEW_MX -#define wglewGetContext() wglewContext -#endif - #include <GL/wglew.h> -#ifdef WITH_GLEW_MX -extern "C" WGLEWContext *wglewContext; -#endif - -#ifndef GHOST_OPENGL_WGL_CONTEXT_FLAGS -# ifdef WITH_GPU_DEBUG -# define GHOST_OPENGL_WGL_CONTEXT_FLAGS WGL_CONTEXT_DEBUG_BIT_ARB -# else -# define GHOST_OPENGL_WGL_CONTEXT_FLAGS 0 -# endif -#endif - #ifndef GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY #define GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY 0 #endif @@ -121,12 +105,19 @@ public: */ GHOST_TSuccess getSwapInterval(int &intervalOut); -protected: - inline void activateWGLEW() const { -#ifdef WITH_GLEW_MX - wglewContext = m_wglewContext; -#endif - } + /** + * Gets the maximum supported OpenGL context for the user hardware + * \return Whether major_version and minor_version resulted in a valid context. + */ + static GHOST_TSuccess getMaximumSupportedOpenGLVersion( + HWND hwnd, + bool wantStereoVisual, + bool wantAlphaBackground, + GHOST_TUns16 wantNumOfAASamples, + int contextProfileMask, + bool debugContext, + GHOST_TUns8 *r_major_version, + GHOST_TUns8 *r_minor_version); private: int choose_pixel_format( @@ -171,10 +162,6 @@ private: const int m_contextResetNotificationStrategy; HGLRC m_hGLRC; - -#ifdef WITH_GLEW_MX - WGLEWContext *m_wglewContext; -#endif #ifndef NDEBUG const char *m_dummyVendor; diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 73c89f9d68d..a018bbe15c6 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -1086,82 +1086,23 @@ GHOST_TSuccess GHOST_WindowCocoa::setOrder(GHOST_TWindowOrder order) GHOST_Context *GHOST_WindowCocoa::newDrawingContext(GHOST_TDrawingContextType type) { if (type == GHOST_kDrawingContextTypeOpenGL) { -#if !defined(WITH_GL_EGL) -#if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextCGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_openGLView, - GL_CONTEXT_CORE_PROFILE_BIT, - 3, 2, - GHOST_OPENGL_CGL_CONTEXT_FLAGS, - GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY); -#elif defined(WITH_GL_PROFILE_ES20) GHOST_Context *context = new GHOST_ContextCGL( m_wantStereoVisual, m_wantNumOfAASamples, m_window, m_openGLView, - CGL_CONTEXT_ES2_PROFILE_BIT_EXT, - 2, 0, - GHOST_OPENGL_CGL_CONTEXT_FLAGS, - GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY); -#elif defined(WITH_GL_PROFILE_COMPAT) - GHOST_Context *context = new GHOST_ContextCGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_openGLView, - 0, // profile bit - 0, 0, - m_debug_context, - GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY); -#else -# error -#endif - -#else #if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_openGLView, - EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, + GL_CONTEXT_CORE_PROFILE_BIT, 3, 2, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#elif defined(WITH_GL_PROFILE_ES20) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_openGLView, - 0, // profile bit - 2, 0, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_ES_API); -#elif defined(WITH_GL_PROFILE_COMPAT) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_openGLView, - 0, // profile bit - 0, 0, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); #else -# error + 0, // no profile bit + 2, 1, #endif + GHOST_OPENGL_CGL_CONTEXT_FLAGS, + GHOST_OPENGL_CGL_RESET_NOTIFICATION_STRATEGY); -#endif if (context->initializeDrawingContext()) return context; else diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 7ac54e5c915..fc4979291ec 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -611,101 +611,72 @@ GHOST_TSuccess GHOST_WindowWin32::invalidate() GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType type) { if (type == GHOST_kDrawingContextTypeOpenGL) { -#if !defined(WITH_GL_EGL) + GHOST_Context *context; #if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextWGL( - m_wantStereoVisual, - m_wantAlphaBackground, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, - WGL_CONTEXT_CORE_PROFILE_BIT_ARB, - 3, 2, - GHOST_OPENGL_WGL_CONTEXT_FLAGS, - GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); -#elif defined(WITH_GL_PROFILE_ES20) - GHOST_Context *context = new GHOST_ContextWGL( - m_wantStereoVisual, - m_wantAlphaBackground, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, - WGL_CONTEXT_ES2_PROFILE_BIT_EXT, - 2, 0, - GHOST_OPENGL_WGL_CONTEXT_FLAGS, - GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); + GHOST_TUns8 major, minor; + + if (GHOST_ContextWGL::getMaximumSupportedOpenGLVersion( + m_hWnd, + m_wantStereoVisual, + m_wantAlphaBackground, + m_wantNumOfAASamples, + WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + m_debug_context, + &major, &minor)) + { + context = new GHOST_ContextWGL( + m_wantStereoVisual, + m_wantAlphaBackground, + m_wantNumOfAASamples, + m_hWnd, + m_hDC, + WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + major, minor, + (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0), + GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); + + if (context->initializeDrawingContext()) { + return context; + } + else { + delete context; + } + } + else { + MessageBox( + m_hWnd, + "Blender requires a graphics driver with at least OpenGL 3.3 support.\n\n" + "The program will now close.", + "Blender - Unsupported Graphics Driver!", + MB_OK | MB_ICONERROR); + exit(0); + return NULL; + } + #elif defined(WITH_GL_PROFILE_COMPAT) - GHOST_Context *context = new GHOST_ContextWGL( + // ask for 2.1 context, driver gives any GL version >= 2.1 (hopefully the latest compatibility profile) + // 2.1 ignores the profile bit & is incompatible with core profile + context = new GHOST_ContextWGL( m_wantStereoVisual, m_wantAlphaBackground, m_wantNumOfAASamples, m_hWnd, m_hDC, -#if 1 - 0, // profile bit - 2, 1, // GL version requested -#else - // switch to this for Blender 2.8 development - WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, - 3, 2, -#endif + 0, // no profile bit + 2, 1, (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0), GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY); #else -# error -#endif - -#else - -#if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, - EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, - 3, 2, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#elif defined(WITH_GL_PROFILE_ES20) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, - 0, // profile bit - 2, 0, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_ES_API); -#elif defined(WITH_GL_PROFILE_COMPAT) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_hWnd, - m_hDC, -#if 1 - 0, // profile bit - 2, 1, // GL version requested -#else - // switch to this for Blender 2.8 development - EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT, - 3, 2, -#endif - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#else -# error +# error // must specify either core or compat at build time #endif -#endif - if (context->initializeDrawingContext()) + if (context->initializeDrawingContext()) { return context; - else + } + else { delete context; + } } return NULL; diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 2019f58251f..450fe568814 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -1318,92 +1318,74 @@ GHOST_WindowX11:: GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type) { if (type == GHOST_kDrawingContextTypeOpenGL) { -#if !defined(WITH_GL_EGL) + + // During development: + // try 4.x compatibility profile + // try 3.3 compatibility profile + // fall back to 3.0 if needed + // + // Final Blender 2.8: + // try 4.x core profile + // try 3.3 core profile + // no fallbacks #if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextGLX( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_display, - m_visualInfo, - (GLXFBConfig)m_fbconfig, - GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - 3, 2, - GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), - GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); -#elif defined(WITH_GL_PROFILE_ES20) - GHOST_Context *context = new GHOST_ContextGLX( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_display, - m_visualInfo, - (GLXFBConfig)m_fbconfig, - GLX_CONTEXT_ES2_PROFILE_BIT_EXT, - 2, 0, - GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), - GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); + { + const char *version_major = (char*)glewGetString(GLEW_VERSION_MAJOR); + if (version_major != NULL && version_major[0] == '1') { + fprintf(stderr, "Error: GLEW version 2.0 and above is required.\n"); + abort(); + } + } +#endif + + const int profile_mask = +#if defined(WITH_GL_PROFILE_CORE) + GLX_CONTEXT_CORE_PROFILE_BIT_ARB; #elif defined(WITH_GL_PROFILE_COMPAT) - GHOST_Context *context = new GHOST_ContextGLX( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_display, - m_visualInfo, - (GLXFBConfig)m_fbconfig, - 0, // profile bit - 0, 0, - GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), - GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); + GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; #else -# error +# error // must specify either core or compat at build time #endif -#else + GHOST_Context *context; + + for (int minor = 5; minor >= 0; --minor) { + context = new GHOST_ContextGLX( + m_wantStereoVisual, + m_wantNumOfAASamples, + m_window, + m_display, + m_visualInfo, + (GLXFBConfig)m_fbconfig, + profile_mask, + 4, minor, + GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), + GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); + + if (context->initializeDrawingContext()) + return context; + else + delete context; + } -#if defined(WITH_GL_PROFILE_CORE) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_display, - EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT, - 3, 2, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#elif defined(WITH_GL_PROFILE_ES20) - GHOST_Context *context = new GHOST_ContextEGL( + context = new GHOST_ContextGLX( m_wantStereoVisual, m_wantNumOfAASamples, m_window, m_display, - 0, // profile bit - 2, 0, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_ES_API); -#elif defined(WITH_GL_PROFILE_COMPAT) - GHOST_Context *context = new GHOST_ContextEGL( - m_wantStereoVisual, - m_wantNumOfAASamples, - m_window, - m_display, - 0, // profile bit - 0, 0, - GHOST_OPENGL_EGL_CONTEXT_FLAGS, - GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY, - EGL_OPENGL_API); -#else -# error -#endif + m_visualInfo, + (GLXFBConfig)m_fbconfig, + profile_mask, + 3, 3, + GHOST_OPENGL_GLX_CONTEXT_FLAGS | (m_is_debug_context ? GLX_CONTEXT_DEBUG_BIT_ARB : 0), + GHOST_OPENGL_GLX_RESET_NOTIFICATION_STRATEGY); -#endif if (context->initializeDrawingContext()) return context; else delete context; + } return NULL; diff --git a/intern/ghost/test/CMakeLists.txt b/intern/ghost/test/CMakeLists.txt index fb9ef621ecf..ef6e8915871 100644 --- a/intern/ghost/test/CMakeLists.txt +++ b/intern/ghost/test/CMakeLists.txt @@ -203,7 +203,6 @@ target_link_libraries(gears_c glewmx_lib string_lib ${OPENGL_gl_LIBRARY} - ${OPENGL_glu_LIBRARY} ${PLATFORM_LINKLIBS} ) @@ -217,7 +216,6 @@ target_link_libraries(gears_cpp glewmx_lib string_lib ${OPENGL_gl_LIBRARY} - ${OPENGL_glu_LIBRARY} ${PLATFORM_LINKLIBS} ) @@ -248,7 +246,6 @@ target_link_libraries(multitest_c guardedalloc_lib wcwidth_lib ${OPENGL_gl_LIBRARY} - ${OPENGL_glu_LIBRARY} ${FREETYPE_LIBRARY} ${ZLIB_LIBRARIES} ${PLATFORM_LINKLIBS} diff --git a/intern/glew-mx/glew-mx.h b/intern/glew-mx/glew-mx.h index ed17ea4a0e6..86f48a1068d 100644 --- a/intern/glew-mx/glew-mx.h +++ b/intern/glew-mx/glew-mx.h @@ -49,12 +49,6 @@ #ifndef __GLEW_MX_H__ #define __GLEW_MX_H__ -#ifdef WITH_GLEW_MX -/* glew itself expects this */ -# define GLEW_MX 1 -# define glewGetContext() (&(_mx_context->glew_context)) -#endif - #include <GL/glew.h> @@ -62,39 +56,16 @@ extern "C" { #endif -/* MXContext is used instead of GLEWContext directly so that - extending what data is held by a context is easier. - */ -typedef struct MXContext { -#ifdef WITH_GLEW_MX - GLEWContext glew_context; -#endif - - int reserved; /* structs need at least one member */ - -} MXContext; - -#ifdef WITH_GLEW_MX -extern MXContext *_mx_context; -#endif - - #include "intern/symbol-binding.h" /* If compiling only for OpenGL 3.2 Core Profile then we should make sure * no legacy API entries or symbolic constants are used. */ -#if defined(WITH_GL_PROFILE_CORE) && !defined(WITH_GL_PROFILE_COMPAT) && !defined(WITH_GL_PROFILE_ES20) +#if (!defined(WITH_LEGACY_OPENGL)) || defined(WITH_GL_PROFILE_CORE) && !defined(WITH_GL_PROFILE_COMPAT) && !defined(WITH_GL_PROFILE_ES20) # include "intern/gl-deprecated.h" #endif - -MXContext *mxCreateContext (void); -MXContext *mxGetCurrentContext (void); -void mxMakeCurrentContext(MXContext *ctx); -void mxDestroyContext (MXContext *ctx); - GLenum glew_chk(GLenum error, const char *file, int line, const char *text); #ifndef NDEBUG diff --git a/intern/glew-mx/intern/gl-deprecated.h b/intern/glew-mx/intern/gl-deprecated.h index 1a23642fbfc..669fb83a644 100644 --- a/intern/glew-mx/intern/gl-deprecated.h +++ b/intern/glew-mx/intern/gl-deprecated.h @@ -841,6 +841,7 @@ #undef GL_SOURCE2_RGB #define GL_SOURCE2_RGB DO_NOT_USE_GL_SOURCE2_RGB +#if 0 /* Those are deprecated but still valid */ // Old Token Names 3.0 #undef GL_CLIP_PLANE0 #define GL_CLIP_PLANE0 USE_GL_CLIP_DISTANCE0 @@ -864,9 +865,6 @@ // Old Token Names 3.2 #undef GL_VERTEX_PROGRAM_POINT_SIZE #define GL_VERTEX_PROGRAM_POINT_SIZE USE_GL_PROGRAM_POINT_SIZE - -// Old Token Names 4.1 -#undef GL_CURRENT_PROGRAM -#define GL_CURRENT_PROGRAM DO_NOT_USE_GL_CURRENT_PROGRAM +#endif #endif /* __GL_DEPRECATED_H__ */ diff --git a/intern/glew-mx/intern/glew-mx.c b/intern/glew-mx/intern/glew-mx.c index 6fbb1a7a2e2..9db2d233085 100644 --- a/intern/glew-mx/intern/glew-mx.c +++ b/intern/glew-mx/intern/glew-mx.c @@ -84,61 +84,3 @@ GLenum glew_chk(GLenum error, const char *file, int line, const char *text) return error; } - - -#ifdef WITH_GLEW_MX -MXContext *_mx_context = NULL; -#endif - - -MXContext *mxCreateContext(void) -{ -#ifdef WITH_GLEW_MX - MXContext* new_ctx = calloc(1, sizeof(MXContext)); - - if (new_ctx != NULL) { - MXContext* cur_ctx = _mx_context; - _mx_context = new_ctx; - GLEW_CHK(glewInit()); - _mx_context = cur_ctx; - } - - return new_ctx; -#else - GLEW_CHK(glewInit()); - return NULL; -#endif -} - - -MXContext *mxGetCurrentContext(void) -{ -#ifdef WITH_GLEW_MX - return _mx_context; -#else - return NULL; -#endif -} - - -void mxMakeCurrentContext(MXContext *ctx) -{ -#ifdef WITH_GLEW_MX - _mx_context = ctx; -#else - (void)ctx; -#endif -} - - -void mxDestroyContext(MXContext *ctx) -{ -#ifdef WITH_GLEW_MX - if (_mx_context == ctx) - _mx_context = NULL; - - free(ctx); -#else - (void)ctx; -#endif -} diff --git a/intern/itasc/FixedObject.hpp b/intern/itasc/FixedObject.hpp index ad26e7cb2d6..02c1804073c 100644 --- a/intern/itasc/FixedObject.hpp +++ b/intern/itasc/FixedObject.hpp @@ -21,7 +21,7 @@ public: int addFrame(const std::string& name, const Frame& frame); - virtual void updateCoordinates(const Timestamp& timestamp) {}; + virtual void updateCoordinates(struct EvaluationContext *eval_ctx, const Timestamp& timestamp) {}; virtual int addEndEffector(const std::string& name); virtual bool finalize(); virtual const Frame& getPose(const unsigned int frameIndex); diff --git a/intern/itasc/MovingFrame.cpp b/intern/itasc/MovingFrame.cpp index 90ebe091eb5..b1815ddd0de 100644 --- a/intern/itasc/MovingFrame.cpp +++ b/intern/itasc/MovingFrame.cpp @@ -90,7 +90,7 @@ bool MovingFrame::setCallback(MovingFrameCallback _function, void* _param) return true; } -void MovingFrame::updateCoordinates(const Timestamp& timestamp) +void MovingFrame::updateCoordinates(struct EvaluationContext *eval_ctx, const Timestamp& timestamp) { // don't compute the velocity during substepping, it is assumed constant. if (!timestamp.substep) { @@ -98,7 +98,7 @@ void MovingFrame::updateCoordinates(const Timestamp& timestamp) if (!timestamp.reiterate) { cacheAvail = popInternalFrame(timestamp.cacheTimestamp); if (m_function) - (*m_function)(timestamp, m_internalPose, m_nextPose, m_param); + (*m_function)(eval_ctx, timestamp, m_internalPose, m_nextPose, m_param); } // only compute velocity if we have a previous pose if (cacheAvail && timestamp.interpolate) { diff --git a/intern/itasc/MovingFrame.hpp b/intern/itasc/MovingFrame.hpp index d2a956d7312..89519832840 100644 --- a/intern/itasc/MovingFrame.hpp +++ b/intern/itasc/MovingFrame.hpp @@ -11,10 +11,11 @@ #include "UncontrolledObject.hpp" #include <vector> +struct EvaluationContext; namespace iTaSC{ -typedef bool (*MovingFrameCallback)(const Timestamp& timestamp, const Frame& _current, Frame& _next, void *param); +typedef bool (*MovingFrameCallback)(struct EvaluationContext *eval_ctx, const Timestamp& timestamp, const Frame& _current, Frame& _next, void *param); class MovingFrame: public UncontrolledObject { public: @@ -24,7 +25,7 @@ public: bool setFrame(const Frame& frame); bool setCallback(MovingFrameCallback _function, void* _param); - virtual void updateCoordinates(const Timestamp& timestamp); + virtual void updateCoordinates(struct EvaluationContext *eval_ctx, const Timestamp& timestamp); virtual void updateKinematics(const Timestamp& timestamp); virtual void pushCache(const Timestamp& timestamp); virtual void initCache(Cache *_cache); diff --git a/intern/itasc/Scene.cpp b/intern/itasc/Scene.cpp index 5768a994970..fd8b006d19c 100644 --- a/intern/itasc/Scene.cpp +++ b/intern/itasc/Scene.cpp @@ -257,7 +257,7 @@ bool Scene::getConstraintPose(ConstraintSet* constraint, void *_param, KDL::Fram return true; } -bool Scene::update(double timestamp, double timestep, unsigned int numsubstep, bool reiterate, bool cache, bool interpolate) +bool Scene::update(struct EvaluationContext *eval_ctx, double timestamp, double timestep, unsigned int numsubstep, bool reiterate, bool cache, bool interpolate) { // we must have valid timestep and timestamp if (timestamp < KDL::epsilon || timestep < 0.0) @@ -316,7 +316,7 @@ bool Scene::update(double timestamp, double timestep, unsigned int numsubstep, b } } if (os->object->getType()==Object::UnControlled && ((UncontrolledObject*)os->object)->getNrOfCoordinates() != 0) { - ((UncontrolledObject*)(os->object))->updateCoordinates(ts); + ((UncontrolledObject*)(os->object))->updateCoordinates(eval_ctx, ts); if (!ts.substep) { // velocity of uncontrolled object remains constant during substepping project(m_xdot,os->coordinaterange) = ((UncontrolledObject*)(os->object))->getXudot(); diff --git a/intern/itasc/Scene.hpp b/intern/itasc/Scene.hpp index 5ed031b543e..0039be07584 100644 --- a/intern/itasc/Scene.hpp +++ b/intern/itasc/Scene.hpp @@ -39,7 +39,7 @@ public: bool addSolver(Solver* _solver); bool addCache(Cache* _cache); bool initialize(); - bool update(double timestamp, double timestep, unsigned int numsubstep=1, bool reiterate=false, bool cache=true, bool interpolate=true); + bool update(struct EvaluationContext *eval_ctx, double timestamp, double timestep, unsigned int numsubstep=1, bool reiterate=false, bool cache=true, bool interpolate=true); bool setParam(SceneParam paramId, double value); EIGEN_MAKE_ALIGNED_OPERATOR_NEW diff --git a/intern/itasc/UncontrolledObject.hpp b/intern/itasc/UncontrolledObject.hpp index 81445538fa6..889bc742c6d 100644 --- a/intern/itasc/UncontrolledObject.hpp +++ b/intern/itasc/UncontrolledObject.hpp @@ -11,6 +11,9 @@ #include "eigen_types.hpp" #include "Object.hpp" + +struct EvaluationContext; + namespace iTaSC{ class UncontrolledObject: public Object { @@ -26,7 +29,7 @@ public: virtual void initialize(unsigned int _nu, unsigned int _nf); virtual const e_matrix& getJu(unsigned int frameIndex) const; virtual const e_vector& getXudot() const {return m_xudot;} - virtual void updateCoordinates(const Timestamp& timestamp)=0; + virtual void updateCoordinates(struct EvaluationContext *eval_ctx, const Timestamp& timestamp)=0; virtual const unsigned int getNrOfCoordinates(){return m_nu;}; virtual const unsigned int getNrOfFrames(){return m_nf;}; diff --git a/intern/itasc/WorldObject.hpp b/intern/itasc/WorldObject.hpp index 99756dcd684..b992445ab10 100644 --- a/intern/itasc/WorldObject.hpp +++ b/intern/itasc/WorldObject.hpp @@ -16,7 +16,7 @@ public: WorldObject(); virtual ~WorldObject(); - virtual void updateCoordinates(const Timestamp& timestamp) {}; + virtual void updateCoordinates(struct EvaluationContext *eval_ctx, const Timestamp& timestamp) {}; virtual void updateKinematics(const Timestamp& timestamp) {}; virtual void pushCache(const Timestamp& timestamp) {}; virtual void initCache(Cache *_cache) {}; diff --git a/intern/opencolorio/CMakeLists.txt b/intern/opencolorio/CMakeLists.txt index 75e228933aa..2611477252a 100644 --- a/intern/opencolorio/CMakeLists.txt +++ b/intern/opencolorio/CMakeLists.txt @@ -27,6 +27,7 @@ set(INC . ../glew-mx ../guardedalloc + ../gawain ../../source/blender/blenlib ) @@ -66,6 +67,7 @@ if(WITH_OPENCOLORIO) endif() data_to_c_simple(gpu_shader_display_transform.glsl SRC) + data_to_c_simple(gpu_shader_display_transform_vertex.glsl SRC) endif() diff --git a/intern/opencolorio/gpu_shader_display_transform.glsl b/intern/opencolorio/gpu_shader_display_transform.glsl index 853bf575582..372d41dfecb 100644 --- a/intern/opencolorio/gpu_shader_display_transform.glsl +++ b/intern/opencolorio/gpu_shader_display_transform.glsl @@ -10,6 +10,10 @@ uniform float image_texture_width; uniform float image_texture_height; #endif +in vec2 texCoord_interp; +out vec4 fragColor; +#define texture2D texture + #ifdef USE_CURVE_MAPPING /* Curve mapping parameters * @@ -143,7 +147,7 @@ vec4 apply_dither(vec2 st, vec4 col) void main() { - vec4 col = texture2D(image_texture, gl_TexCoord[0].st); + vec4 col = texture2D(image_texture, texCoord_interp.st); #ifdef USE_CURVE_MAPPING col = curvemapping_evaluate_premulRGBF(col); #endif @@ -165,8 +169,8 @@ void main() vec4 result = OCIODisplay(col, lut3d_texture); #ifdef USE_DITHER - result = apply_dither(gl_TexCoord[0].st, result); + result = apply_dither(texCoord_interp.st, result); #endif - gl_FragColor = result; + fragColor = result; } diff --git a/intern/opencolorio/gpu_shader_display_transform_vertex.glsl b/intern/opencolorio/gpu_shader_display_transform_vertex.glsl new file mode 100644 index 00000000000..054f7f3ec91 --- /dev/null +++ b/intern/opencolorio/gpu_shader_display_transform_vertex.glsl @@ -0,0 +1,12 @@ + +uniform mat4 ModelViewProjectionMatrix; + +in vec2 texCoord; +in vec2 pos; +out vec2 texCoord_interp; + +void main() +{ + gl_Position = ModelViewProjectionMatrix * vec4(pos.xy, 0.0f, 1.0f); + texCoord_interp = texCoord; +} diff --git a/intern/opencolorio/ocio_impl_glsl.cc b/intern/opencolorio/ocio_impl_glsl.cc index bf91ea143da..b89221c36da 100644 --- a/intern/opencolorio/ocio_impl_glsl.cc +++ b/intern/opencolorio/ocio_impl_glsl.cc @@ -48,6 +48,9 @@ # pragma warning(pop) #endif +extern "C" { +#include "gawain/immediate.h" +} using namespace OCIO_NAMESPACE; @@ -58,6 +61,7 @@ using namespace OCIO_NAMESPACE; static const int LUT3D_EDGE_SIZE = 64; extern "C" char datatoc_gpu_shader_display_transform_glsl[]; +extern "C" char datatoc_gpu_shader_display_transform_vertex_glsl[]; /* **** OpenGL drawing routines using GLSL for color space transform ***** */ @@ -89,7 +93,9 @@ typedef struct OCIO_GLSLDrawState { /* GLSL stuff */ GLuint ocio_shader; + GLuint vert_shader; GLuint program; + Gwn_ShaderInterface *shader_interface; /* Previous OpenGL state. */ GLint last_texture, last_texture_unit; @@ -116,14 +122,15 @@ static GLuint compileShaderText(GLenum shaderType, const char *text) return shader; } -static GLuint linkShaders(GLuint ocio_shader) +static GLuint linkShaders(GLuint ocio_shader, GLuint vert_shader) { - if (!ocio_shader) + if (!ocio_shader || !vert_shader) return 0; GLuint program = glCreateProgram(); glAttachShader(program, ocio_shader); + glAttachShader(program, vert_shader); glLinkProgram(program); @@ -339,6 +346,25 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc glDeleteShader(state->ocio_shader); } + if (state->vert_shader) { + glDeleteShader(state->vert_shader); + } + + /* Vertex shader */ + std::ostringstream osv; + + if (supportGLSL13()) { + osv << "#version 130\n"; + } + else { + osv << "#version 120\n"; + } + + osv << datatoc_gpu_shader_display_transform_vertex_glsl; + + state->vert_shader = compileShaderText(GL_VERTEX_SHADER, osv.str().c_str()); + + /* Fragment shader */ std::ostringstream os; if (supportGLSL13()) { @@ -366,8 +392,12 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc state->ocio_shader = compileShaderText(GL_FRAGMENT_SHADER, os.str().c_str()); - if (state->ocio_shader) { - state->program = linkShaders(state->ocio_shader); + if (state->ocio_shader && state->vert_shader) { + state->program = linkShaders(state->ocio_shader, state->vert_shader); + } + + if (state->program) { + state->shader_interface = GWN_shaderinterface_create(state->program); } state->curve_mapping_used = use_curve_mapping; @@ -386,10 +416,21 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc glActiveTexture(GL_TEXTURE0); - glUseProgram(state->program); - - glUniform1i(glGetUniformLocation(state->program, "image_texture"), 0); - glUniform1i(glGetUniformLocation(state->program, "lut3d_texture"), 1); + /* IMM needs vertex format even if we don't draw with it. + * + * NOTE: The only reason why it's here is because of Cycles viewport. + * All other areas are managing their own vertex formats. + * Doing it here is probably harmless, but kind of stupid. + * + * TODO(sergey): Look into some nicer solution. + */ + Gwn_VertFormat *format = immVertexFormat(); + GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindProgram(state->program, state->shader_interface); + + immUniform1i("image_texture", 0); + immUniform1i("lut3d_texture", 1); if (state->texture_size_used) { /* we use textureSize() if possible for best performance, if not @@ -399,30 +440,30 @@ bool OCIOImpl::setupGLSLDraw(OCIO_GLSLDrawState **state_r, OCIO_ConstProcessorRc glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); - glUniform1f(glGetUniformLocation(state->program, "image_texture_width"), (float)width); - glUniform1f(glGetUniformLocation(state->program, "image_texture_height"), (float)height); + immUniform1f("image_texture_width", (float)width); + immUniform1f("image_texture_height", (float)height); } if (use_dither) { - glUniform1f(glGetUniformLocation(state->program, "dither"), dither); + immUniform1f("dither", dither); } if (use_curve_mapping) { - glUniform1i(glGetUniformLocation(state->program, "curve_mapping_texture"), 2); - glUniform1i(glGetUniformLocation(state->program, "curve_mapping_lut_size"), curve_mapping_settings->lut_size); - glUniform4iv(glGetUniformLocation(state->program, "use_curve_mapping_extend_extrapolate"), 1, curve_mapping_settings->use_extend_extrapolate); - glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_mintable"), 1, curve_mapping_settings->mintable); - glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_range"), 1, curve_mapping_settings->range); - glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_ext_in_x"), 1, curve_mapping_settings->ext_in_x); - glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_ext_in_y"), 1, curve_mapping_settings->ext_in_y); - glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_ext_out_x"), 1, curve_mapping_settings->ext_out_x); - glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_ext_out_y"), 1, curve_mapping_settings->ext_out_y); - glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_first_x"), 1, curve_mapping_settings->first_x); - glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_first_y"), 1, curve_mapping_settings->first_y); - glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_last_x"), 1, curve_mapping_settings->last_x); - glUniform4fv(glGetUniformLocation(state->program, "curve_mapping_last_y"), 1, curve_mapping_settings->last_y); - glUniform3fv(glGetUniformLocation(state->program, "curve_mapping_black"), 1, curve_mapping_settings->black); - glUniform3fv(glGetUniformLocation(state->program, "curve_mapping_bwmul"), 1, curve_mapping_settings->bwmul); + immUniform1i("curve_mapping_texture", 2); + immUniform1i("curve_mapping_lut_size", curve_mapping_settings->lut_size); + immUniform4iv("use_curve_mapping_extend_extrapolate", curve_mapping_settings->use_extend_extrapolate); + immUniform4fv("curve_mapping_mintable", curve_mapping_settings->mintable); + immUniform4fv("curve_mapping_range", curve_mapping_settings->range); + immUniform4fv("curve_mapping_ext_in_x", curve_mapping_settings->ext_in_x); + immUniform4fv("curve_mapping_ext_in_y", curve_mapping_settings->ext_in_y); + immUniform4fv("curve_mapping_ext_out_x", curve_mapping_settings->ext_out_x); + immUniform4fv("curve_mapping_ext_out_y", curve_mapping_settings->ext_out_y); + immUniform4fv("curve_mapping_first_x", curve_mapping_settings->first_x); + immUniform4fv("curve_mapping_first_y", curve_mapping_settings->first_y); + immUniform4fv("curve_mapping_last_x", curve_mapping_settings->last_x); + immUniform4fv("curve_mapping_last_y", curve_mapping_settings->last_y); + immUniform3fv("curve_mapping_black", curve_mapping_settings->black); + immUniform3fv("curve_mapping_bwmul", curve_mapping_settings->bwmul); } return true; @@ -439,7 +480,7 @@ void OCIOImpl::finishGLSLDraw(OCIO_GLSLDrawState *state) { glActiveTexture(state->last_texture_unit); glBindTexture(GL_TEXTURE_2D, state->last_texture); - glUseProgram(0); + immUnbindProgram(); } void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state) @@ -455,6 +496,9 @@ void OCIOImpl::freeGLState(struct OCIO_GLSLDrawState *state) if (state->program) glDeleteProgram(state->program); + if (state->shader_interface) + GWN_shaderinterface_discard(state->shader_interface); + if (state->ocio_shader) glDeleteShader(state->ocio_shader); diff --git a/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl b/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl index 3a83d44a8be..b16a5cca733 100644 --- a/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl +++ b/intern/opensubdiv/gpu_shader_opensubdiv_geometry.glsl @@ -29,22 +29,11 @@ struct VertexData { vec2 uv; }; -#if __VERSION__ >= 150 layout(lines_adjacency) in; - #ifdef WIREFRAME +#ifdef WIREFRAME layout(line_strip, max_vertices = 8) out; - #else -layout(triangle_strip, max_vertices = 4) out; - #endif #else - #extension GL_EXT_geometry_shader4: require - /* application provides input/output layout info */ -#endif - -#if __VERSION__ < 140 - #extension GL_ARB_uniform_buffer_object: require - #extension GL_ARB_texture_buffer_object: enable - #extension GL_EXT_texture_buffer_object: enable +layout(triangle_strip, max_vertices = 4) out; #endif uniform mat4 modelViewMatrix; diff --git a/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl b/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl index 6d3c06f59c9..6fcf5ad20cd 100644 --- a/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl +++ b/intern/opensubdiv/gpu_shader_opensubdiv_vertex.glsl @@ -43,11 +43,4 @@ void main() { outpt.v.position = modelViewMatrix * position; outpt.v.normal = normalize(normalMatrix * normal); - -#if __VERSION__ < 140 - /* Some compilers expects gl_Position to be written. - * It's not needed once we explicitly switch to GLSL 1.40 or above. - */ - gl_Position = outpt.v.position; -#endif } diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc index 0a55a432cc6..bb865bc0e0f 100644 --- a/intern/opensubdiv/opensubdiv_capi.cc +++ b/intern/opensubdiv/opensubdiv_capi.cc @@ -412,19 +412,6 @@ const struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_getGLMeshTopologyRefine return gl_mesh->topology_refiner; } -int openSubdiv_supportGPUDisplay(void) -{ - // TODO: simplify extension check once Blender adopts GL 3.2 - return openSubdiv_gpu_legacy_support() && - (GLEW_VERSION_3_2 || - (GLEW_VERSION_3_1 && GLEW_EXT_geometry_shader4) || - (GLEW_VERSION_3_0 && - GLEW_EXT_geometry_shader4 && - GLEW_ARB_uniform_buffer_object && - (GLEW_ARB_texture_buffer_object || GLEW_EXT_texture_buffer_object))); - /* also ARB_explicit_attrib_location? */ -} - int openSubdiv_getVersionHex(void) { #if defined(OPENSUBDIV_VERSION_NUMBER) diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h index 281bd3f010d..2c3fcee7dbb 100644 --- a/intern/opensubdiv/opensubdiv_capi.h +++ b/intern/opensubdiv/opensubdiv_capi.h @@ -146,11 +146,9 @@ void openSubdiv_osdGLAllocFVar(struct OpenSubdiv_TopologyRefinerDescr *topology_ void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh); /* ** Utility functions ** */ -int openSubdiv_supportGPUDisplay(void); int openSubdiv_getAvailableEvaluators(void); -void openSubdiv_init(bool gpu_legacy_support); +void openSubdiv_init(void); void openSubdiv_cleanup(void); -bool openSubdiv_gpu_legacy_support(void); int openSubdiv_getVersionHex(void); diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc index c36eaae1c6e..811cd18745e 100644 --- a/intern/opensubdiv/opensubdiv_gpu_capi.cc +++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc @@ -275,24 +275,6 @@ GLuint linkProgram(const char *version, const char *define) glBindAttribLocation(program, 0, "position"); glBindAttribLocation(program, 1, "normal"); - - if (!GLEW_VERSION_3_2) { - /* provide input/output layout info */ - glProgramParameteriEXT(program, - GL_GEOMETRY_INPUT_TYPE_EXT, - GL_LINES_ADJACENCY_EXT); - - bool wireframe = strstr(define, "WIREFRAME") != NULL; - - glProgramParameteriEXT(program, - GL_GEOMETRY_OUTPUT_TYPE_EXT, - wireframe ? GL_LINE_STRIP : GL_TRIANGLE_STRIP); - - glProgramParameteriEXT(program, - GL_GEOMETRY_VERTICES_OUT_EXT, - 8); - } - glLinkProgram(program); glDeleteShader(vertexShader); @@ -314,17 +296,26 @@ GLuint linkProgram(const char *version, const char *define) glGetUniformBlockIndex(program, "Lighting"), 0); - glProgramUniform1i(program, - glGetUniformLocation(program, "texture_buffer"), - 0); /* GL_TEXTURE0 */ + if (GLEW_VERSION_4_1) { + glProgramUniform1i(program, + glGetUniformLocation(program, "texture_buffer"), + 0); /* GL_TEXTURE0 */ - glProgramUniform1i(program, - glGetUniformLocation(program, "FVarDataOffsetBuffer"), - 30); /* GL_TEXTURE30 */ + glProgramUniform1i(program, + glGetUniformLocation(program, "FVarDataOffsetBuffer"), + 30); /* GL_TEXTURE30 */ - glProgramUniform1i(program, - glGetUniformLocation(program, "FVarDataBuffer"), - 31); /* GL_TEXTURE31 */ + glProgramUniform1i(program, + glGetUniformLocation(program, "FVarDataBuffer"), + 31); /* GL_TEXTURE31 */ + } + else { + glUseProgram(program); + glUniform1i(glGetUniformLocation(program, "texture_buffer"), 0); /* GL_TEXTURE0 */ + glUniform1i(glGetUniformLocation(program, "FVarDataOffsetBuffer"), 30); /* GL_TEXTURE30 */ + glUniform1i(glGetUniformLocation(program, "FVarDataBuffer"), 31); /* GL_TEXTURE31 */ + glUseProgram(0); + } return program; } @@ -353,10 +344,8 @@ void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program) glBindBufferBase(GL_UNIFORM_BUFFER, 0, g_lighting_ub); /* Color */ - GLboolean use_lighting; - glGetBooleanv(GL_LIGHTING, &use_lighting); - - if (use_lighting) { + { + /* TODO: stop using glGetMaterial */ float color[4]; glGetMaterialfv(GL_FRONT, GL_DIFFUSE, color); glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color); @@ -367,11 +356,6 @@ void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program) glGetMaterialfv(GL_FRONT, GL_SHININESS, color); glUniform1f(glGetUniformLocation(program, "shininess"), color[0]); } - else { - float color[4]; - glGetFloatv(GL_CURRENT_COLOR, color); - glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color); - } /* Face-vertex data */ if (gl_mesh->fvar_data != NULL) { @@ -409,11 +393,10 @@ bool openSubdiv_osdGLDisplayInit(void) { static bool need_init = true; static bool init_success = false; - if (need_init) { - if (!openSubdiv_supportGPUDisplay()) { - return false; - } + if (need_init) { + /* TODO: update OSD drawing to OpenGL 3.3 core, then remove following line */ + return false; const char *version = ""; if (GLEW_VERSION_3_2) { @@ -538,6 +521,7 @@ void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl, g_lighting_data.num_enabled++; } + /* TODO: stop using glGetLight */ glGetLightfv(GL_LIGHT0 + i, GL_POSITION, g_lighting_data.lights[i].position); @@ -635,31 +619,24 @@ static GLuint prepare_patchDraw(OpenSubdiv_GLMesh *gl_mesh, GLboolean use_texture_2d, use_lighting; glGetIntegerv(GL_SHADE_MODEL, &model); glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d); - glGetBooleanv(GL_LIGHTING, &use_lighting); + if (model == GL_FLAT) { if (use_texture_2d) { - program = use_lighting - ? g_flat_fill_texture2d_program - : g_flat_fill_texture2d_shadeless_program; + program = g_flat_fill_texture2d_program; } else { - program = use_lighting - ? g_flat_fill_solid_program - : g_flat_fill_solid_shadeless_program; + program = g_flat_fill_solid_program; } } else { if (use_texture_2d) { - program = use_lighting - ? g_smooth_fill_texture2d_program - : g_smooth_fill_texture2d_shadeless_program; + program = g_smooth_fill_texture2d_program; } else { - program = use_lighting - ? g_smooth_fill_solid_program - : g_smooth_fill_solid_shadeless_program; + program = g_smooth_fill_solid_program; } } + } else { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); diff --git a/intern/opensubdiv/opensubdiv_utils_capi.cc b/intern/opensubdiv/opensubdiv_utils_capi.cc index ae5592367dd..72e3751e6b3 100644 --- a/intern/opensubdiv/opensubdiv_utils_capi.cc +++ b/intern/opensubdiv/opensubdiv_utils_capi.cc @@ -41,14 +41,8 @@ # include "opensubdiv_device_context_cuda.h" #endif /* OPENSUBDIV_HAS_CUDA */ -static bool gpu_legacy_support_global = false; - int openSubdiv_getAvailableEvaluators(void) { - if (!openSubdiv_supportGPUDisplay()) { - return 0; - } - int flags = OPENSUBDIV_EVALUATOR_CPU; #ifdef OPENSUBDIV_HAS_OPENMP @@ -82,19 +76,13 @@ int openSubdiv_getAvailableEvaluators(void) return flags; } -void openSubdiv_init(bool gpu_legacy_support) +void openSubdiv_init(void) { /* Ensure all OpenGL strings are cached. */ (void)openSubdiv_getAvailableEvaluators(); - gpu_legacy_support_global = gpu_legacy_support; } void openSubdiv_cleanup(void) { openSubdiv_osdGLDisplayDeinit(); } - -bool openSubdiv_gpu_legacy_support(void) -{ - return gpu_legacy_support_global; -} |