Changeset View
Changeset View
Standalone View
Standalone View
source/blender/gpu/intern/gpu_codegen.cc
| /* SPDX-License-Identifier: GPL-2.0-or-later | /* SPDX-License-Identifier: GPL-2.0-or-later | |||||||||
| * Copyright 2005 Blender Foundation. */ | * Copyright 2005 Blender Foundation. */ | |||||||||
| /** \file | /** \file | |||||||||
| * \ingroup gpu | * \ingroup gpu | |||||||||
| * | * | |||||||||
| * Convert material node-trees to GLSL. | * Convert material node-trees to GLSL. | |||||||||
| */ | */ | |||||||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | |||||||||
| #include "DNA_customdata_types.h" | #include "DNA_customdata_types.h" | |||||||||
| #include "DNA_image_types.h" | #include "DNA_image_types.h" | |||||||||
| #include "DNA_material_types.h" | ||||||||||
| #include "BLI_ghash.h" | #include "BLI_ghash.h" | |||||||||
| #include "BLI_hash_mm2a.h" | #include "BLI_hash_mm2a.h" | |||||||||
| #include "BLI_link_utils.h" | #include "BLI_link_utils.h" | |||||||||
| #include "BLI_threads.h" | #include "BLI_threads.h" | |||||||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | |||||||||
| #include "PIL_time.h" | #include "PIL_time.h" | |||||||||
| #include "BKE_cryptomatte.hh" | ||||||||||
| #include "BKE_material.h" | #include "BKE_material.h" | |||||||||
| #include "GPU_capabilities.h" | #include "GPU_capabilities.h" | |||||||||
| #include "GPU_material.h" | #include "GPU_material.h" | |||||||||
| #include "GPU_shader.h" | #include "GPU_shader.h" | |||||||||
| #include "GPU_uniform_buffer.h" | #include "GPU_uniform_buffer.h" | |||||||||
| #include "GPU_vertex_format.h" | #include "GPU_vertex_format.h" | |||||||||
| ▲ Show 20 Lines • Show All 202 Lines • ▼ Show 20 Lines | public: | |||||||||
| GPUNodeGraph &graph; | GPUNodeGraph &graph; | |||||||||
| GPUCodegenOutput output = {}; | GPUCodegenOutput output = {}; | |||||||||
| GPUCodegenCreateInfo *create_info = nullptr; | GPUCodegenCreateInfo *create_info = nullptr; | |||||||||
| private: | private: | |||||||||
| uint32_t hash_ = 0; | uint32_t hash_ = 0; | |||||||||
| BLI_HashMurmur2A hm2a_; | BLI_HashMurmur2A hm2a_; | |||||||||
| ListBase ubo_inputs_ = {nullptr, nullptr}; | ListBase ubo_inputs_ = {nullptr, nullptr}; | |||||||||
| GPUInput *cryptomatte_input_ = nullptr; | ||||||||||
| public: | public: | |||||||||
| GPUCodegen(GPUMaterial *mat_, GPUNodeGraph *graph_) : mat(*mat_), graph(*graph_) | GPUCodegen(GPUMaterial *mat_, GPUNodeGraph *graph_) : mat(*mat_), graph(*graph_) | |||||||||
| { | { | |||||||||
| BLI_hash_mm2a_init(&hm2a_, GPU_material_uuid_get(&mat)); | BLI_hash_mm2a_init(&hm2a_, GPU_material_uuid_get(&mat)); | |||||||||
| BLI_hash_mm2a_add_int(&hm2a_, GPU_material_flag(&mat)); | BLI_hash_mm2a_add_int(&hm2a_, GPU_material_flag(&mat)); | |||||||||
| create_info = new GPUCodegenCreateInfo("codegen"); | create_info = new GPUCodegenCreateInfo("codegen"); | |||||||||
| output.create_info = reinterpret_cast<GPUShaderCreateInfo *>( | output.create_info = reinterpret_cast<GPUShaderCreateInfo *>( | |||||||||
| static_cast<ShaderCreateInfo *>(create_info)); | static_cast<ShaderCreateInfo *>(create_info)); | |||||||||
| if (GPU_material_flag_get(mat_, GPU_MATFLAG_OBJECT_INFO)) { | if (GPU_material_flag_get(mat_, GPU_MATFLAG_OBJECT_INFO)) { | |||||||||
| create_info->additional_info("draw_object_infos"); | create_info->additional_info("draw_object_infos"); | |||||||||
| } | } | |||||||||
| } | } | |||||||||
| ~GPUCodegen() | ~GPUCodegen() | |||||||||
| { | { | |||||||||
| MEM_SAFE_FREE(output.attr_load); | MEM_SAFE_FREE(output.attr_load); | |||||||||
| MEM_SAFE_FREE(output.surface); | MEM_SAFE_FREE(output.surface); | |||||||||
| MEM_SAFE_FREE(output.volume); | MEM_SAFE_FREE(output.volume); | |||||||||
| MEM_SAFE_FREE(output.thickness); | MEM_SAFE_FREE(output.thickness); | |||||||||
| MEM_SAFE_FREE(output.displacement); | MEM_SAFE_FREE(output.displacement); | |||||||||
| MEM_SAFE_FREE(output.composite); | MEM_SAFE_FREE(output.composite); | |||||||||
| MEM_SAFE_FREE(output.material_functions); | MEM_SAFE_FREE(output.material_functions); | |||||||||
| MEM_SAFE_FREE(cryptomatte_input_); | ||||||||||
| delete create_info; | delete create_info; | |||||||||
| BLI_freelistN(&ubo_inputs_); | BLI_freelistN(&ubo_inputs_); | |||||||||
| }; | }; | |||||||||
| void generate_graphs(); | void generate_graphs(); | |||||||||
| void generate_cryptomatte(); | ||||||||||
| void generate_uniform_buffer(); | void generate_uniform_buffer(); | |||||||||
| void generate_attribs(); | void generate_attribs(); | |||||||||
| void generate_resources(); | void generate_resources(); | |||||||||
| void generate_library(); | void generate_library(); | |||||||||
| uint32_t hash_get() const | uint32_t hash_get() const | |||||||||
| { | { | |||||||||
| return hash_; | return hash_; | |||||||||
| ▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | LISTBASE_FOREACH (GPUMaterialTexture *, tex, &graph.textures) { | |||||||||
| } | } | |||||||||
| } | } | |||||||||
| if (!BLI_listbase_is_empty(&ubo_inputs_)) { | if (!BLI_listbase_is_empty(&ubo_inputs_)) { | |||||||||
| /* NOTE: generate_uniform_buffer() should have sorted the inputs before this. */ | /* NOTE: generate_uniform_buffer() should have sorted the inputs before this. */ | |||||||||
| ss << "struct NodeTree {\n"; | ss << "struct NodeTree {\n"; | |||||||||
| LISTBASE_FOREACH (LinkData *, link, &ubo_inputs_) { | LISTBASE_FOREACH (LinkData *, link, &ubo_inputs_) { | |||||||||
| GPUInput *input = (GPUInput *)(link->data); | GPUInput *input = (GPUInput *)(link->data); | |||||||||
| if (input->source == GPU_SOURCE_CRYPTOMATTE) { | ||||||||||
| ss << input->type << " crypto_hash;\n"; | ||||||||||
fclemUnsubmitted Not Done Inline Actions
fclem: | ||||||||||
| } | ||||||||||
| else { | ||||||||||
| ss << input->type << " u" << input->id << ";\n"; | ss << input->type << " u" << input->id << ";\n"; | |||||||||
| } | } | |||||||||
| } | ||||||||||
| ss << "};\n\n"; | ss << "};\n\n"; | |||||||||
| info.uniform_buf(1, "NodeTree", GPU_UBO_BLOCK_NAME, Frequency::BATCH); | info.uniform_buf(1, "NodeTree", GPU_UBO_BLOCK_NAME, Frequency::BATCH); | |||||||||
| } | } | |||||||||
| if (!BLI_listbase_is_empty(&graph.uniform_attrs.list)) { | if (!BLI_listbase_is_empty(&graph.uniform_attrs.list)) { | |||||||||
| ss << "struct UniformAttrs {\n"; | ss << "struct UniformAttrs {\n"; | |||||||||
| LISTBASE_FOREACH (GPUUniformAttr *, attr, &graph.uniform_attrs.list) { | LISTBASE_FOREACH (GPUUniformAttr *, attr, &graph.uniform_attrs.list) { | |||||||||
| ▲ Show 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | if (node->tag & tree_tag) { | |||||||||
| node_serialize(eval_ss, node); | node_serialize(eval_ss, node); | |||||||||
| } | } | |||||||||
| } | } | |||||||||
| char *eval_c_str = extract_c_str(eval_ss); | char *eval_c_str = extract_c_str(eval_ss); | |||||||||
| BLI_hash_mm2a_add(&hm2a_, (uchar *)eval_c_str, eval_ss.str().size()); | BLI_hash_mm2a_add(&hm2a_, (uchar *)eval_c_str, eval_ss.str().size()); | |||||||||
| return eval_c_str; | return eval_c_str; | |||||||||
| } | } | |||||||||
| void GPUCodegen::generate_cryptomatte() | ||||||||||
| { | ||||||||||
| cryptomatte_input_ = static_cast<GPUInput *>(MEM_callocN(sizeof(GPUInput), __func__)); | ||||||||||
| cryptomatte_input_->type = GPU_FLOAT; | ||||||||||
| cryptomatte_input_->source = GPU_SOURCE_CRYPTOMATTE; | ||||||||||
| float material_hash = 0.0f; | ||||||||||
| Material *material = GPU_material_get_material(&mat); | ||||||||||
| if (material) { | ||||||||||
| blender::bke::cryptomatte::CryptomatteHash hash(material->id.name, | ||||||||||
| BLI_strnlen(material->id.name, MAX_NAME - 2)); | ||||||||||
| material_hash = hash.float_encoded(); | ||||||||||
| } | ||||||||||
| cryptomatte_input_->vec[0] = material_hash; | ||||||||||
| BLI_addtail(&ubo_inputs_, BLI_genericNodeN(cryptomatte_input_)); | ||||||||||
| } | ||||||||||
| void GPUCodegen::generate_uniform_buffer() | void GPUCodegen::generate_uniform_buffer() | |||||||||
| { | { | |||||||||
| /* Extract uniform inputs. */ | /* Extract uniform inputs. */ | |||||||||
| LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) { | LISTBASE_FOREACH (GPUNode *, node, &graph.nodes) { | |||||||||
| LISTBASE_FOREACH (GPUInput *, input, &node->inputs) { | LISTBASE_FOREACH (GPUInput *, input, &node->inputs) { | |||||||||
| if (input->source == GPU_SOURCE_UNIFORM && !input->link) { | if (input->source == GPU_SOURCE_UNIFORM && !input->link) { | |||||||||
| /* We handle the UBO uniforms separately. */ | /* We handle the UBO uniforms separately. */ | |||||||||
| BLI_addtail(&ubo_inputs_, BLI_genericNodeN(input)); | BLI_addtail(&ubo_inputs_, BLI_genericNodeN(input)); | |||||||||
| ▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | GPUPass *GPU_generate_pass(GPUMaterial *material, | |||||||||
| gpu_node_graph_prune_unused(graph); | gpu_node_graph_prune_unused(graph); | |||||||||
| /* Extract attributes before compiling so the generated VBOs are ready to accept the future | /* Extract attributes before compiling so the generated VBOs are ready to accept the future | |||||||||
| * shader. */ | * shader. */ | |||||||||
| gpu_node_graph_finalize_uniform_attrs(graph); | gpu_node_graph_finalize_uniform_attrs(graph); | |||||||||
| GPUCodegen codegen(material, graph); | GPUCodegen codegen(material, graph); | |||||||||
| codegen.generate_graphs(); | codegen.generate_graphs(); | |||||||||
| codegen.generate_cryptomatte(); | ||||||||||
| codegen.generate_uniform_buffer(); | codegen.generate_uniform_buffer(); | |||||||||
| /* Cache lookup: Reuse shaders already compiled. */ | /* Cache lookup: Reuse shaders already compiled. */ | |||||||||
| GPUPass *pass_hash = gpu_pass_cache_lookup(codegen.hash_get()); | GPUPass *pass_hash = gpu_pass_cache_lookup(codegen.hash_get()); | |||||||||
| /* FIXME(fclem): This is broken. Since we only check for the hash and not the full source | /* 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. */ | * there is no way to have a collision currently. Some advocated to only use a bigger hash. */ | |||||||||
| if (pass_hash && (pass_hash->next == nullptr || pass_hash->next->hash != codegen.hash_get())) { | if (pass_hash && (pass_hash->next == nullptr || pass_hash->next->hash != codegen.hash_get())) { | |||||||||
| ▲ Show 20 Lines • Show All 215 Lines • Show Last 20 Lines | ||||||||||