diff --git a/source/blender/compositor/realtime_compositor/intern/shader_operation.cc b/source/blender/compositor/realtime_compositor/intern/shader_operation.cc index fb95c0d4310..2dbea8fd370 100644 --- a/source/blender/compositor/realtime_compositor/intern/shader_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/shader_operation.cc @@ -41,7 +41,8 @@ using namespace nodes::derived_node_tree_types; ShaderOperation::ShaderOperation(Context &context, ShaderCompileUnit &compile_unit) : Operation(context), compile_unit_(compile_unit) { - material_ = GPU_material_from_callbacks(&construct_material, &generate_code, this); + material_ = GPU_material_from_callbacks( + GPU_MAT_COMPOSITOR, &construct_material, &generate_code, this); GPU_material_status_set(material_, GPU_MAT_QUEUED); GPU_material_compile(material_); } diff --git a/source/blender/draw/engines/eevee/eevee_shaders.cc b/source/blender/draw/engines/eevee/eevee_shaders.cc index 0df0a11f335..8c37533116f 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.cc +++ b/source/blender/draw/engines/eevee/eevee_shaders.cc @@ -1384,11 +1384,13 @@ static GPUMaterial *eevee_material_get_ex( if (ma) { bNodeTree *ntree = !is_default ? ma->nodetree : EEVEE_shader_default_surface_nodetree(ma); - mat = DRW_shader_from_material(ma, ntree, options, is_volume, deferred, cbfn, nullptr); + mat = DRW_shader_from_material( + ma, ntree, GPU_MAT_EEVEE_LEGACY, options, is_volume, deferred, cbfn, nullptr); } else { bNodeTree *ntree = !is_default ? wo->nodetree : EEVEE_shader_default_world_nodetree(wo); - mat = DRW_shader_from_world(wo, ntree, options, is_volume, deferred, cbfn, nullptr); + mat = DRW_shader_from_world( + wo, ntree, GPU_MAT_EEVEE_LEGACY, options, is_volume, deferred, cbfn, nullptr); } return mat; } diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc index 9d669dbc8c4..3e1481ed44f 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc @@ -668,8 +668,14 @@ GPUMaterial *ShaderModule::material_shader_get(::Material *blender_mat, uint64_t shader_uuid = shader_uuid_from_material_type( pipeline_type, geometry_type, displacement_type, blender_mat->blend_flag); - return DRW_shader_from_material( - blender_mat, nodetree, shader_uuid, is_volume, deferred_compilation, codegen_callback, this); + return DRW_shader_from_material(blender_mat, + nodetree, + GPU_MAT_EEVEE, + shader_uuid, + is_volume, + deferred_compilation, + codegen_callback, + this); } GPUMaterial *ShaderModule::world_shader_get(::World *blender_world, @@ -683,8 +689,14 @@ GPUMaterial *ShaderModule::world_shader_get(::World *blender_world, uint64_t shader_uuid = shader_uuid_from_material_type(pipeline_type, geometry_type); - return DRW_shader_from_world( - blender_world, nodetree, shader_uuid, is_volume, defer_compilation, codegen_callback, this); + return DRW_shader_from_world(blender_world, + nodetree, + GPU_MAT_EEVEE, + shader_uuid, + is_volume, + defer_compilation, + codegen_callback, + this); } /* Variation to compile a material only with a nodetree. Caller needs to maintain the list of @@ -704,6 +716,7 @@ GPUMaterial *ShaderModule::material_shader_get(const char *name, nodetree, &materials, name, + GPU_MAT_EEVEE, shader_uuid, is_volume, false, diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 15c10544084..06e44ec9018 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -296,6 +296,7 @@ struct GPUShader *DRW_shader_create_fullscreen_with_shaderlib_ex(const char *fra struct GPUMaterial *DRW_shader_from_world(struct World *wo, struct bNodeTree *ntree, + eGPUMaterialEngine engine, const uint64_t shader_id, const bool is_volume_shader, bool deferred, @@ -303,6 +304,7 @@ struct GPUMaterial *DRW_shader_from_world(struct World *wo, void *thunk); struct GPUMaterial *DRW_shader_from_material(struct Material *ma, struct bNodeTree *ntree, + eGPUMaterialEngine engine, const uint64_t shader_id, const bool is_volume_shader, bool deferred, diff --git a/source/blender/draw/intern/draw_manager_shader.cc b/source/blender/draw/intern/draw_manager_shader.cc index b529c139b88..0e2dd7ee7ad 100644 --- a/source/blender/draw/intern/draw_manager_shader.cc +++ b/source/blender/draw/intern/draw_manager_shader.cc @@ -493,6 +493,7 @@ GPUShader *DRW_shader_create_fullscreen_with_shaderlib_ex(const char *frag, GPUMaterial *DRW_shader_from_world(World *wo, bNodeTree *ntree, + eGPUMaterialEngine engine, const uint64_t shader_id, const bool is_volume_shader, bool deferred, @@ -505,6 +506,7 @@ GPUMaterial *DRW_shader_from_world(World *wo, ntree, &wo->gpumaterial, wo->id.name, + engine, shader_id, is_volume_shader, false, @@ -525,6 +527,7 @@ GPUMaterial *DRW_shader_from_world(World *wo, GPUMaterial *DRW_shader_from_material(Material *ma, bNodeTree *ntree, + eGPUMaterialEngine engine, const uint64_t shader_id, const bool is_volume_shader, bool deferred, @@ -537,6 +540,7 @@ GPUMaterial *DRW_shader_from_material(Material *ma, ntree, &ma->gpumaterial, ma->id.name, + engine, shader_id, is_volume_shader, false, diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index e99859a3dcd..a2615cd6927 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -233,19 +233,19 @@ struct GPUUniformBuf *GPU_material_sss_profile_get(GPUMaterial *material, /** * High level functions to create and use GPU materials. */ -GPUMaterial *GPU_material_from_nodetree_find(struct ListBase *gpumaterials, - const void *engine_type, - int options); -/** - * \note Caller must use #GPU_material_from_nodetree_find to re-use existing materials, - * This is enforced since constructing other arguments to this function may be expensive - * so only do this when they are needed. - */ + +typedef enum eGPUMaterialEngine { + GPU_MAT_EEVEE_LEGACY = 0, + GPU_MAT_EEVEE, + GPU_MAT_COMPOSITOR, +} eGPUMaterialEngine; + GPUMaterial *GPU_material_from_nodetree(struct Scene *scene, struct Material *ma, struct bNodeTree *ntree, struct ListBase *gpumaterials, const char *name, + eGPUMaterialEngine engine, uint64_t shader_uuid, bool is_volume_shader, bool is_lookdev, @@ -421,7 +421,8 @@ typedef void (*ConstructGPUMaterialFn)(void *thunk, GPUMaterial *material); /* Construct a GPU material from a set of callbacks. See the callback types for more information. * The given thunk will be passed as the first parameter of each callback. */ -GPUMaterial *GPU_material_from_callbacks(ConstructGPUMaterialFn construct_function_cb, +GPUMaterial *GPU_material_from_callbacks(eGPUMaterialEngine engine, + ConstructGPUMaterialFn construct_function_cb, GPUCodegenCallbackFn generate_code_function_cb, void *thunk); diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index 04cac214b41..2793611d4db 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -97,6 +97,8 @@ struct GPUPass { uint refcount; /** The last time the refcount was greater than 0. */ int gc_timestamp; + /** The engine type this pass is compiled for. */ + eGPUMaterialEngine engine; /** Identity hash generated from all GLSL code. */ uint32_t hash; /** Did we already tried to compile the attached GPUShader. */ @@ -122,12 +124,12 @@ static SpinLock pass_cache_spin; /* Search by hash only. Return first pass with the same hash. * There is hash collision if (pass->next && pass->next->hash == hash) */ -static GPUPass *gpu_pass_cache_lookup(uint32_t hash) +static GPUPass *gpu_pass_cache_lookup(eGPUMaterialEngine engine, uint32_t hash) { BLI_spin_lock(&pass_cache_spin); /* Could be optimized with a Lookup table. */ for (GPUPass *pass = pass_cache; pass; pass = pass->next) { - if (pass->hash == hash) { + if (pass->hash == hash && pass->engine == engine) { BLI_spin_unlock(&pass_cache_spin); return pass; } @@ -157,10 +159,12 @@ static GPUPass *gpu_pass_cache_resolve_collision(GPUPass *pass, GPUShaderCreateInfo *info, uint32_t hash) { + eGPUMaterialEngine engine = pass->engine; BLI_spin_lock(&pass_cache_spin); for (; pass && (pass->hash == hash); pass = pass->next) { if (*reinterpret_cast(info) == - *reinterpret_cast(pass->create_info)) + *reinterpret_cast(pass->create_info) && + pass->engine == engine) { BLI_spin_unlock(&pass_cache_spin); return pass; @@ -732,6 +736,7 @@ void GPUCodegen::generate_graphs() GPUPass *GPU_generate_pass(GPUMaterial *material, GPUNodeGraph *graph, + eGPUMaterialEngine engine, GPUCodegenCallbackFn finalize_source_cb, void *thunk, bool optimize_graph) @@ -763,7 +768,7 @@ GPUPass *GPU_generate_pass(GPUMaterial *material, * NOTE: We only perform cache look-up for non-optimized shader * graphs, as baked constant data among other optimizations will generate too many * shader source permutations, with minimal re-usability. */ - pass_hash = gpu_pass_cache_lookup(codegen.hash_get()); + pass_hash = gpu_pass_cache_lookup(engine, codegen.hash_get()); /* FIXME(fclem): This is broken. Since we only check for the hash and not the full source * there is no way to have a collision currently. Some advocated to only use a bigger hash. */ @@ -813,6 +818,7 @@ GPUPass *GPU_generate_pass(GPUMaterial *material, pass->shader = nullptr; pass->refcount = 1; pass->create_info = codegen.create_info; + pass->engine = engine; pass->hash = codegen.hash_get(); pass->compiled = false; pass->cached = false; diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index 8e009489ef6..c9073fb493d 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -25,6 +25,7 @@ typedef struct GPUPass GPUPass; GPUPass *GPU_generate_pass(GPUMaterial *material, struct GPUNodeGraph *graph, + eGPUMaterialEngine engine, GPUCodegenCallbackFn finalize_source_cb, void *thunk, bool optimize_graph); diff --git a/source/blender/gpu/intern/gpu_material.cc b/source/blender/gpu/intern/gpu_material.cc index 601b6137dfb..ef7bb13823f 100644 --- a/source/blender/gpu/intern/gpu_material.cc +++ b/source/blender/gpu/intern/gpu_material.cc @@ -99,8 +99,9 @@ struct GPUMaterial { eGPUMaterialStatus status; /** Some flags about the nodetree & the needed resources. */ eGPUMaterialFlag flag; - /* Identify shader variations (shadow, probe, world background...). - * Should be unique even across render engines. */ + /** The engine type this material is compiled for. */ + eGPUMaterialEngine engine; + /* Identify shader variations (shadow, probe, world background...) */ uint64_t uuid; /* Number of generated function. */ int generated_function_len; @@ -821,6 +822,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, bNodeTree *ntree, ListBase *gpumaterials, const char *name, + eGPUMaterialEngine engine, uint64_t shader_uuid, bool is_volume_shader, bool is_lookdev, @@ -830,7 +832,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, /* Search if this material is not already compiled. */ LISTBASE_FOREACH (LinkData *, link, gpumaterials) { GPUMaterial *mat = (GPUMaterial *)link->data; - if (mat->uuid == shader_uuid) { + if (mat->uuid == shader_uuid && mat->engine == engine) { return mat; } } @@ -838,6 +840,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, GPUMaterial *mat = static_cast(MEM_callocN(sizeof(GPUMaterial), "GPUMaterial")); mat->ma = ma; mat->scene = scene; + mat->engine = engine; mat->uuid = shader_uuid; mat->flag = GPU_MATFLAG_UPDATED; mat->status = GPU_MAT_CREATED; @@ -860,7 +863,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, { /* Create source code and search pass cache for an already compiled version. */ - mat->pass = GPU_generate_pass(mat, &mat->graph, callback, thunk, false); + mat->pass = GPU_generate_pass(mat, &mat->graph, engine, callback, thunk, false); if (mat->pass == nullptr) { /* We had a cache hit and the shader has already failed to compile. */ @@ -891,7 +894,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, mat->optimize_pass_info.callback = callback; mat->optimize_pass_info.thunk = thunk; #else - mat->optimized_pass = GPU_generate_pass(mat, &mat->graph, callback, thunk, true); + mat->optimized_pass = GPU_generate_pass(mat, &mat->graph, engine, callback, thunk, true); if (mat->optimized_pass == nullptr) { /* Failed to create optimized pass. */ gpu_node_graph_free_nodes(&mat->graph); @@ -1024,8 +1027,12 @@ void GPU_material_optimize(GPUMaterial *mat) * optimal, as these do not benefit from caching, due to baked constants. However, this could * possibly be cause for concern for certain cases. */ if (!mat->optimized_pass) { - mat->optimized_pass = GPU_generate_pass( - mat, &mat->graph, mat->optimize_pass_info.callback, mat->optimize_pass_info.thunk, true); + mat->optimized_pass = GPU_generate_pass(mat, + &mat->graph, + mat->engine, + mat->optimize_pass_info.callback, + mat->optimize_pass_info.thunk, + true); BLI_assert(mat->optimized_pass); } #else @@ -1097,7 +1104,8 @@ void GPU_materials_free(Main *bmain) BKE_material_defaults_free_gpu(); } -GPUMaterial *GPU_material_from_callbacks(ConstructGPUMaterialFn construct_function_cb, +GPUMaterial *GPU_material_from_callbacks(eGPUMaterialEngine engine, + ConstructGPUMaterialFn construct_function_cb, GPUCodegenCallbackFn generate_code_function_cb, void *thunk) { @@ -1110,6 +1118,7 @@ GPUMaterial *GPU_material_from_callbacks(ConstructGPUMaterialFn construct_functi material->optimization_status = GPU_MAT_OPTIMIZATION_SKIP; material->optimized_pass = nullptr; material->default_mat = nullptr; + material->engine = engine; /* Construct the material graph by adding and linking the necessary GPU material nodes. */ construct_function_cb(thunk, material); @@ -1119,7 +1128,7 @@ GPUMaterial *GPU_material_from_callbacks(ConstructGPUMaterialFn construct_functi /* Lookup an existing pass in the cache or generate a new one. */ material->pass = GPU_generate_pass( - material, &material->graph, generate_code_function_cb, thunk, false); + material, &material->graph, material->engine, generate_code_function_cb, thunk, false); material->optimized_pass = nullptr; /* The pass already exists in the pass cache but its shader already failed to compile. */