diff options
author | Miguel Pozo <pragma37@gmail.com> | 2022-10-10 14:45:45 +0300 |
---|---|---|
committer | Miguel Pozo <pragma37@gmail.com> | 2022-10-10 14:45:45 +0300 |
commit | 8501e93deaaf22a5f25c77967e861153e53dd560 (patch) | |
tree | f5bf65f52cb125ac68a1ef1574e4292d47c36f38 | |
parent | 219d5a9530e5f771956cde7353e8ef8aef82a5ad (diff) |
Refactor
Split workbench_engine.cc into multiple files.
Move all the SceneResources loading logic directly into Instance.
-rw-r--r-- | source/blender/draw/CMakeLists.txt | 7 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh | 2 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh | 2 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_defines.hh (renamed from source/blender/draw/engines/workbench/workbench_defines.h) | 2 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_effect_antialiasing.cc | 102 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_engine.cc | 813 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_enums.hh | 114 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_materials.cc | 49 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_mesh_passes.cc | 168 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_private.hh | 159 | ||||
-rw-r--r-- | source/blender/draw/engines/workbench/workbench_shader_cache.cc | 121 |
11 files changed, 814 insertions, 725 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 95ebbd054c0..d84f0df816b 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -155,15 +155,19 @@ set(SRC engines/eevee_next/eevee_world.cc engines/workbench/workbench_data.c engines/workbench/workbench_effect_antialiasing.c + engines/workbench/workbench_effect_antialiasing.cc engines/workbench/workbench_effect_cavity.c engines/workbench/workbench_effect_dof.c engines/workbench/workbench_effect_outline.c engines/workbench/workbench_engine.c engines/workbench/workbench_engine.cc engines/workbench/workbench_materials.c + engines/workbench/workbench_materials.cc + engines/workbench/workbench_mesh_passes.cc engines/workbench/workbench_opaque.c engines/workbench/workbench_render.c engines/workbench/workbench_shader.cc + engines/workbench/workbench_shader_cache.cc engines/workbench/workbench_shadow.c engines/workbench/workbench_transparent.c engines/workbench/workbench_volume.c @@ -678,6 +682,7 @@ set(GLSL_SRC ) set(GLSL_C) + foreach(GLSL_FILE ${GLSL_SRC}) data_to_c_simple(${GLSL_FILE} GLSL_C) endforeach() @@ -689,6 +694,7 @@ list(APPEND LIB ) set(GLSL_SOURCE_CONTENT "") + foreach(GLSL_FILE ${GLSL_SRC}) get_filename_component(GLSL_FILE_NAME ${GLSL_FILE} NAME) string(REPLACE "." "_" GLSL_FILE_NAME_UNDERSCORES ${GLSL_FILE_NAME}) @@ -733,7 +739,6 @@ if(WITH_GTESTS) endif() endif() - blender_add_lib(bf_draw "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") # Needed so we can use dna_type_offsets.h for defaults initialization. diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh index 2cd795d3f7e..f2e996a1f0f 100644 --- a/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh +++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "gpu_shader_create_info.hh" -#include "workbench_defines.h" +#include "workbench_defines.hh" /* -------------------------------------------------------------------- */ /** \name Base Composite diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh index ab4a2a2ac33..f4db7bc522f 100644 --- a/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh +++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "gpu_shader_create_info.hh" -#include "workbench_defines.h" +#include "workbench_defines.hh" /* -------------------------------------------------------------------- */ /** \name Object Type diff --git a/source/blender/draw/engines/workbench/workbench_defines.h b/source/blender/draw/engines/workbench/workbench_defines.hh index 33fe189c9ff..2b85c19b0a3 100644 --- a/source/blender/draw/engines/workbench/workbench_defines.h +++ b/source/blender/draw/engines/workbench/workbench_defines.hh @@ -5,3 +5,5 @@ #define WB_TILEMAP_SLOT 2 #define WB_MATERIAL_SLOT 0 #define WB_WORLD_SLOT 4 + +#define WB_RESOLVE_GROUP_SIZE 8 diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.cc b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.cc new file mode 100644 index 00000000000..a437717f7f6 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.cc @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "workbench_private.hh" + +#include "smaa_textures.h" + +namespace blender::workbench { + +AntiAliasingPass::AntiAliasingPass() +{ + smaa_edge_detect_sh = GPU_shader_create_from_info_name("workbench_smaa_stage_0"); + smaa_aa_weight_sh = GPU_shader_create_from_info_name("workbench_smaa_stage_1"); + smaa_resolve_sh = GPU_shader_create_from_info_name("workbench_smaa_stage_2"); + + smaa_search_tx.ensure_2d(GPU_R8, {SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT}); + GPU_texture_update(smaa_search_tx, GPU_DATA_UBYTE, searchTexBytes); + GPU_texture_filter_mode(smaa_search_tx, true); + + smaa_area_tx.ensure_2d(GPU_RG8, {AREATEX_WIDTH, AREATEX_HEIGHT}); + GPU_texture_update(smaa_area_tx, GPU_DATA_UBYTE, areaTexBytes); + GPU_texture_filter_mode(smaa_area_tx, true); +} + +AntiAliasingPass::~AntiAliasingPass() +{ + if (smaa_edge_detect_sh) { + GPU_shader_free(smaa_edge_detect_sh); + } + if (smaa_aa_weight_sh) { + GPU_shader_free(smaa_aa_weight_sh); + } + if (smaa_resolve_sh) { + GPU_shader_free(smaa_resolve_sh); + } +} + +void AntiAliasingPass::sync(SceneResources &resources) +{ + { + smaa_edge_detect_ps_.init(); + smaa_edge_detect_ps_.state_set(DRW_STATE_WRITE_COLOR); + smaa_edge_detect_ps_.shader_set(smaa_edge_detect_sh); + smaa_edge_detect_ps_.bind_texture("colorTex", &resources.color_tx); + smaa_edge_detect_ps_.push_constant("viewportMetrics", &smaa_viewport_metrics, 1); + smaa_edge_detect_ps_.clear_color(float4(0.0f)); + smaa_edge_detect_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); + } + { + smaa_aa_weight_ps_.init(); + smaa_aa_weight_ps_.state_set(DRW_STATE_WRITE_COLOR); + smaa_aa_weight_ps_.shader_set(smaa_aa_weight_sh); + smaa_aa_weight_ps_.bind_texture("edgesTex", &smaa_edge_tx); + smaa_aa_weight_ps_.bind_texture("areaTex", smaa_area_tx); + smaa_aa_weight_ps_.bind_texture("searchTex", smaa_search_tx); + smaa_aa_weight_ps_.push_constant("viewportMetrics", &smaa_viewport_metrics, 1); + smaa_aa_weight_ps_.clear_color(float4(0.0f)); + smaa_aa_weight_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); + } + { + smaa_resolve_ps_.init(); + smaa_resolve_ps_.state_set(DRW_STATE_WRITE_COLOR); + smaa_resolve_ps_.shader_set(smaa_resolve_sh); + smaa_resolve_ps_.bind_texture("blendTex", &smaa_weight_tx); + smaa_resolve_ps_.bind_texture("colorTex", &resources.color_tx); + smaa_resolve_ps_.push_constant("viewportMetrics", &smaa_viewport_metrics, 1); + smaa_resolve_ps_.push_constant("mixFactor", &smaa_mix_factor, 1); + smaa_resolve_ps_.push_constant("taaAccumulatedWeight", &taa_weight_accum, 1); + smaa_resolve_ps_.clear_color(float4(0.0f)); + smaa_resolve_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); + } +} + +void AntiAliasingPass::draw(Manager &manager, + View &view, + GPUTexture *depth_tx, + GPUTexture *color_tx) +{ + int2 size = {GPU_texture_width(depth_tx), GPU_texture_height(depth_tx)}; + + taa_weight_accum = 1.0f; /* TODO */ + + smaa_viewport_metrics = float4(1.0f / size.x, 1.0f / size.y, size.x, size.y); + smaa_mix_factor = 1.0f; /* TODO */ + + smaa_edge_tx.acquire(size, GPU_RG8); + smaa_edge_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(smaa_edge_tx)); + smaa_edge_fb.bind(); + manager.submit(smaa_edge_detect_ps_, view); + + smaa_weight_tx.acquire(size, GPU_RGBA8); + smaa_weight_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(smaa_weight_tx)); + smaa_weight_fb.bind(); + manager.submit(smaa_aa_weight_ps_, view); + smaa_edge_tx.release(); + + smaa_resolve_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(color_tx)); + smaa_resolve_fb.bind(); + manager.submit(smaa_resolve_ps_, view); + smaa_weight_tx.release(); +} + +} // namespace blender::workbench diff --git a/source/blender/draw/engines/workbench/workbench_engine.cc b/source/blender/draw/engines/workbench/workbench_engine.cc index 509c82ea572..2f11ed48723 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.cc +++ b/source/blender/draw/engines/workbench/workbench_engine.cc @@ -2,625 +2,14 @@ #include "BKE_studiolight.h" #include "DEG_depsgraph_query.h" -#include "DRW_render.h" #include "GPU_capabilities.h" -#include "smaa_textures.h" - -#include "draw_manager.hh" -#include "draw_pass.hh" - -#include "workbench_defines.h" -#include "workbench_shader_shared.h" +#include "workbench_private.hh" namespace blender::workbench { using namespace draw; -#define WB_RESOLVE_GROUP_SIZE 8 - -enum class eGeometryType { - MESH = 0, - CURVES, - POINTCLOUD, -}; -static constexpr int geometry_type_len = static_cast<int>(eGeometryType::POINTCLOUD) + 1; - -static inline const char *get_name(eGeometryType type) -{ - switch (type) { - case eGeometryType::MESH: - return "Mesh"; - case eGeometryType::CURVES: - return "Curves"; - case eGeometryType::POINTCLOUD: - return "PointCloud"; - default: - BLI_assert_unreachable(); - return ""; - } -} - -static inline eGeometryType geometry_type_from_object(Object *ob) -{ - switch (ob->type) { - case OB_CURVES: - return eGeometryType::CURVES; - case OB_POINTCLOUD: - return eGeometryType::POINTCLOUD; - default: - return eGeometryType::MESH; - } -} - -enum class ePipelineType { - OPAQUE = 0, - TRANSPARENT, - SHADOW, -}; -static constexpr int pipeline_type_len = static_cast<int>(ePipelineType::SHADOW) + 1; - -enum class eShadingType { - FLAT = 0, /* V3D_LIGHTING_STUDIO */ - STUDIO, /* V3D_LIGHTING_MATCAP */ - MATCAP, /* V3D_LIGHTING_FLAT */ -}; -static constexpr int shading_type_len = static_cast<int>(eShadingType::MATCAP) + 1; - -enum class eColorType { - MATERIAL = 0, - TEXTURE, -}; -static constexpr int color_type_len = static_cast<int>(eColorType::TEXTURE) + 1; - -enum class eMaterialSubType { - NONE = 0, - MATERIAL, - RANDOM, - SINGLE, - OBJECT, - ATTRIBUTE, -}; -static constexpr int material_subtype_len = static_cast<int>(eMaterialSubType::ATTRIBUTE) + 1; - -struct Material { - float3 base_color; - /* Packed data into a int. Decoded in the shader. */ - uint packed_data; - - Material() = default; - - Material(float3 color) - { - base_color = color; - packed_data = Material::pack_data(0.0f, 0.4f, 1.0f); - } - Material(::Object &ob, bool random = false) - { - if (random) { - uint hash = BLI_ghashutil_strhash_p_murmur(ob.id.name); - if (ob.id.lib) { - hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob.id.lib->filepath); - } - float3 hsv = float3(BLI_hash_int_01(hash), 0.5f, 0.8f); - hsv_to_rgb_v(hsv, base_color); - } - else { - base_color = ob.color; - } - packed_data = Material::pack_data(0.0f, 0.4f, ob.color[3]); - } - Material(::Material &mat) - { - base_color = &mat.r; - packed_data = Material::pack_data(mat.metallic, mat.roughness, mat.a); - } - - static uint32_t pack_data(float metallic, float roughness, float alpha) - { - /* Remap to Disney roughness. */ - roughness = sqrtf(roughness); - uint32_t packed_roughness = unit_float_to_uchar_clamp(roughness); - uint32_t packed_metallic = unit_float_to_uchar_clamp(metallic); - uint32_t packed_alpha = unit_float_to_uchar_clamp(alpha); - return (packed_alpha << 16u) | (packed_roughness << 8u) | packed_metallic; - } -}; - -class ShaderCache { - private: - /* TODO(fclem): We might want to change to a Map since most shader will never be compiled. */ - GPUShader *prepass_shader_cache_[shading_type_len][color_type_len][geometry_type_len] - [pipeline_type_len] = {{{{nullptr}}}}; - GPUShader *resolve_shader_cache_[shading_type_len][pipeline_type_len] = {{nullptr}}; - - public: - ~ShaderCache() - { - for (auto i : IndexRange(shading_type_len)) { - for (auto j : IndexRange(color_type_len)) { - for (auto k : IndexRange(geometry_type_len)) { - for (auto l : IndexRange(pipeline_type_len)) { - DRW_SHADER_FREE_SAFE(prepass_shader_cache_[i][j][k][l]); - } - } - } - } - for (auto i : IndexRange(shading_type_len)) { - for (auto j : IndexRange(pipeline_type_len)) { - DRW_SHADER_FREE_SAFE(resolve_shader_cache_[i][j]); - } - } - } - - GPUShader *prepass_shader_get(ePipelineType pipeline_type, - eGeometryType geometry_type, - eColorType color_type, - eShadingType shading_type) - { - GPUShader *&shader_ptr = - prepass_shader_cache_[static_cast<int>(pipeline_type)][static_cast<int>(geometry_type)] - [static_cast<int>(color_type)][static_cast<int>(shading_type)]; - - if (shader_ptr != nullptr) { - return shader_ptr; - } - std::string info_name = "workbench_next_prepass_"; - switch (geometry_type) { - case eGeometryType::MESH: - info_name += "mesh_"; - break; - case eGeometryType::CURVES: - info_name += "curves_"; - break; - case eGeometryType::POINTCLOUD: - info_name += "ptcloud_"; - break; - } - switch (pipeline_type) { - case ePipelineType::OPAQUE: - info_name += "opaque_"; - break; - case ePipelineType::TRANSPARENT: - info_name += "transparent_"; - break; - case ePipelineType::SHADOW: - info_name += "shadow_"; - break; - } - switch (shading_type) { - case eShadingType::FLAT: - info_name += "flat_"; - break; - case eShadingType::STUDIO: - info_name += "studio_"; - break; - case eShadingType::MATCAP: - info_name += "matcap_"; - break; - } - switch (color_type) { - case eColorType::MATERIAL: - info_name += "material"; - break; - case eColorType::TEXTURE: - info_name += "texture"; - break; - } - /* TODO Clipping */ - info_name += "_no_clip"; - shader_ptr = GPU_shader_create_from_info_name(info_name.c_str()); - prepass_shader_cache_[static_cast<int>(pipeline_type)][static_cast<int>( - geometry_type)][static_cast<int>(color_type)][static_cast<int>(shading_type)] = shader_ptr; - return shader_ptr; - } - - GPUShader *resolve_shader_get(ePipelineType pipeline_type, eShadingType shading_type) - { - GPUShader *&shader_ptr = - resolve_shader_cache_[static_cast<int>(shading_type)][static_cast<int>(pipeline_type)]; - - if (shader_ptr != nullptr) { - return shader_ptr; - } - std::string info_name = "workbench_next_resolve_"; - switch (pipeline_type) { - case ePipelineType::OPAQUE: - info_name += "opaque_"; - break; - case ePipelineType::TRANSPARENT: - info_name += "transparent_"; - break; - case ePipelineType::SHADOW: - BLI_assert_unreachable(); - break; - } - switch (shading_type) { - case eShadingType::FLAT: - info_name += "flat"; - break; - case eShadingType::STUDIO: - info_name += "studio"; - break; - case eShadingType::MATCAP: - info_name += "matcap"; - break; - } - shader_ptr = GPU_shader_create_from_info_name(info_name.c_str()); - return shader_ptr; - } -}; - -struct SceneResources { - ShaderCache shader_cache; - - Texture matcap_tx = "matcap_tx"; - - TextureFromPool color_tx = "wb_color_tx"; - Texture depth_tx = "wb_depth_tx"; - Texture depth_in_front_tx = "wb_depth_in_front_tx"; - - StorageVectorBuffer<workbench::Material> material_buf = {"material_buf"}; - UniformBuffer<WorldData> world_buf; - - void init(int2 output_res, float4 background_color) - { - world_buf.background_color = background_color; - matcap_tx.ensure_2d_array(GPU_RGBA16F, int2(1), 1); - depth_tx.ensure_2d(GPU_DEPTH24_STENCIL8, output_res); - } - - void world_sync(StudioLight *studio_light) - { - float4x4 rot_matrix = float4x4::identity(); - - // if (USE_WORLD_ORIENTATION(wpd)) { - /* TODO */ - // } - - if (U.edit_studio_light) { - studio_light = BKE_studiolight_studio_edit_get(); - } - - /* Studio Lights. */ - for (int i = 0; i < 4; i++) { - LightData &light = world_buf.lights[i]; - - SolidLight *sl = (studio_light) ? &studio_light->light[i] : nullptr; - if (sl && sl->flag) { - float3 direction = rot_matrix * float3(sl->vec); - light.direction = float4(UNPACK3(direction), 0.0f); - /* We should pre-divide the power by PI but that makes the lights really dim. */ - light.specular_color = float4(UNPACK3(sl->spec), 0.0f); - light.diffuse_color_wrap = float4(UNPACK3(sl->col), sl->smooth); - } - else { - light.direction = float4(1.0f, 0.0f, 0.0f, 0.0f); - light.specular_color = float4(0.0f); - light.diffuse_color_wrap = float4(0.0f); - } - } - - if (studio_light != nullptr) { - world_buf.ambient_color = float4(UNPACK3(studio_light->light_ambient), 0.0f); - } - else { - world_buf.ambient_color = float4(1.0f, 1.0f, 1.0f, 0.0f); - } - - /* TODO */ - world_buf.use_specular = true; - - world_buf.push_update(); - } -}; - -class MeshPass : public PassMain { - private: - std::array<PassMain::Sub *, geometry_type_len> geometry_passes_; - eColorType color_type_; - - using TextureSubPassKey = std::pair<GPUTexture *, eGeometryType>; - Map<TextureSubPassKey, PassMain::Sub *> texture_subpass_map; - - public: - MeshPass(const char *name) : PassMain(name){}; - - /* Move to draw::Pass */ - bool is_empty() const - { - return false; /* TODO */ - } - - void init(ePipelineType pipeline, - eColorType color_type, - eShadingType shading, - SceneResources &resources, - DRWState state) - { - ShaderCache &shaders = resources.shader_cache; - - this->PassMain::init(); - this->state_set(state); - this->bind_texture(WB_MATCAP_SLOT, resources.matcap_tx); - this->bind_ssbo(WB_MATERIAL_SLOT, &resources.material_buf); - this->bind_ubo(WB_WORLD_SLOT, resources.world_buf); - - color_type_ = color_type; - texture_subpass_map.clear(); - - for (int geom = 0; geom < geometry_type_len; geom++) { - eGeometryType geom_type = static_cast<eGeometryType>(geom); - GPUShader *sh = shaders.prepass_shader_get(pipeline, geom_type, color_type, shading); - PassMain::Sub *pass = &this->sub(get_name(geom_type)); - pass->shader_set(sh); - geometry_passes_[geom] = pass; - } - } - - PassMain::Sub &sub_pass_get(eGeometryType geometry_type, - ObjectRef & /*ref*/, - ::Material * /*material*/) - { - if (color_type_ == eColorType::TEXTURE) { - /* TODO(fclem): Always query a layered texture so we can use only a single shader. */ - GPUTexture *texture = nullptr; // ref.object->texture_get(); - GPUTexture *tilemap = nullptr; // ref.object->texture_get(); - - auto add_cb = [&] { - PassMain::Sub *sub_pass = geometry_passes_[static_cast<int>(geometry_type)]; - sub_pass = &sub_pass->sub("Blender Texture Name" /* texture.name */); - sub_pass->bind_texture(WB_TEXTURE_SLOT, texture); - sub_pass->bind_texture(WB_TILEMAP_SLOT, tilemap); - return sub_pass; - }; - - return *texture_subpass_map.lookup_or_add_cb(TextureSubPassKey(texture, geometry_type), - add_cb); - } - return *geometry_passes_[static_cast<int>(geometry_type)]; - } -}; - -class OpaquePass { - public: - TextureFromPool gbuffer_normal_tx = {"gbuffer_normal_tx"}; - TextureFromPool gbuffer_material_tx = {"gbuffer_material_tx"}; - TextureFromPool gbuffer_object_id_tx = {"gbuffer_object_id_tx"}; - Framebuffer opaque_fb; - - MeshPass gbuffer_ps_ = {"Opaque.Gbuffer"}; - PassSimple deferred_ps_ = {"Opaque.Deferred"}; - - void sync(DRWState cull_state, - DRWState clip_state, - eShadingType shading_type, - eColorType color_type, - SceneResources &resources) - { - Texture &depth_tx = resources.depth_tx; - Texture &depth_in_front_tx = resources.depth_in_front_tx; - TextureFromPool &color_tx = resources.color_tx; - ShaderCache &shaders = resources.shader_cache; - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - cull_state | clip_state; - - gbuffer_ps_.init(ePipelineType::OPAQUE, color_type, shading_type, resources, state); - - deferred_ps_.init(); - deferred_ps_.shader_set(shaders.resolve_shader_get(ePipelineType::OPAQUE, shading_type)); - deferred_ps_.bind_ubo(WB_WORLD_SLOT, resources.world_buf); - deferred_ps_.bind_texture(WB_MATCAP_SLOT, resources.matcap_tx); - deferred_ps_.bind_texture("normal_tx", &gbuffer_normal_tx); - deferred_ps_.bind_texture("material_tx", &gbuffer_material_tx); - deferred_ps_.bind_texture("depth_tx", &depth_tx); - deferred_ps_.bind_image("out_color_img", &color_tx); - deferred_ps_.dispatch(math::divide_ceil(int2(depth_tx.size()), int2(WB_RESOLVE_GROUP_SIZE))); - deferred_ps_.barrier(GPU_BARRIER_TEXTURE_FETCH); - } - - void draw_prepass(Manager &manager, View &view, Texture &depth_tx) - { - gbuffer_material_tx.acquire(int2(depth_tx.size()), GPU_RGBA16F); - gbuffer_normal_tx.acquire(int2(depth_tx.size()), GPU_RG16F); - gbuffer_object_id_tx.acquire(int2(depth_tx.size()), GPU_R16UI); - - opaque_fb.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx), - GPU_ATTACHMENT_TEXTURE(gbuffer_material_tx), - GPU_ATTACHMENT_TEXTURE(gbuffer_normal_tx), - GPU_ATTACHMENT_TEXTURE(gbuffer_object_id_tx)); - opaque_fb.bind(); - opaque_fb.clear_depth(1.0f); - - manager.submit(gbuffer_ps_, view); - } - - void draw_resolve(Manager &manager, View &view) - { - manager.submit(deferred_ps_, view); - - gbuffer_normal_tx.release(); - gbuffer_material_tx.release(); - gbuffer_object_id_tx.release(); - } - - bool is_empty() const - { - return gbuffer_ps_.is_empty(); - } -}; - -class TransparentPass { - public: - TextureFromPool accumulation_tx; - TextureFromPool reveal_tx; - Framebuffer transparent_fb; - - MeshPass accumulation_ps_ = {"Transparent.Accumulation"}; - PassSimple resolve_ps_ = {"Transparent.Resolve"}; - - void sync(DRWState cull_state, - DRWState clip_state, - eShadingType shading_type, - eColorType color_type, - SceneResources &resources) - { - ShaderCache &shaders = resources.shader_cache; - Texture &depth_tx = resources.depth_tx; - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | - cull_state | clip_state; - - accumulation_ps_.init(ePipelineType::TRANSPARENT, color_type, shading_type, resources, state); - - resolve_ps_.init(); - resolve_ps_.shader_set( - shaders.resolve_shader_get(ePipelineType::TRANSPARENT, eShadingType::FLAT)); - resolve_ps_.bind_texture("accumulation_tx", accumulation_tx); - resolve_ps_.bind_texture("reveal_tx", reveal_tx); - resolve_ps_.dispatch(math::divide_ceil(depth_tx.size(), int3(WB_RESOLVE_GROUP_SIZE))); - } - - void draw_prepass(Manager &manager, View &view, Texture &depth_tx) - { - accumulation_tx.acquire(int2(depth_tx.size()), GPU_RGBA16F); - reveal_tx.acquire(int2(depth_tx.size()), GPU_R8); - - transparent_fb.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx), - GPU_ATTACHMENT_TEXTURE(accumulation_tx), - GPU_ATTACHMENT_TEXTURE(reveal_tx)); - transparent_fb.bind(); - - manager.submit(accumulation_ps_, view); - } - - void draw_resolve(Manager &manager, View &view) - { - manager.submit(resolve_ps_, view); - - accumulation_tx.release(); - reveal_tx.release(); - } - - bool is_empty() const - { - return accumulation_ps_.is_empty(); - } -}; - -class AntiAliasingPass { - public: - Texture smaa_search_tx = {"smaa_search_tx"}; - Texture smaa_area_tx = {"smaa_area_tx"}; - TextureFromPool smaa_edge_tx = {"smaa_edge_tx"}; - TextureFromPool smaa_weight_tx = {"smaa_weight_tx"}; - - Framebuffer smaa_edge_fb = {"smaa_edge_fb"}; - Framebuffer smaa_weight_fb = {"smaa_weight_fb"}; - Framebuffer smaa_resolve_fb = {"smaa_resolve_fb"}; - - float4 smaa_viewport_metrics = {0.0f, 0.0f, 0.0f, 0.0f}; - float smaa_mix_factor = 0.0f; - float taa_weight_accum = 1.0f; - - GPUShader *smaa_edge_detect_sh = nullptr; - GPUShader *smaa_aa_weight_sh = nullptr; - GPUShader *smaa_resolve_sh = nullptr; - - PassSimple smaa_edge_detect_ps_ = {"SMAA.EdgeDetect"}; - PassSimple smaa_aa_weight_ps_ = {"SMAA.BlendWeights"}; - PassSimple smaa_resolve_ps_ = {"SMAA.Resolve"}; - - AntiAliasingPass() - { - smaa_edge_detect_sh = GPU_shader_create_from_info_name("workbench_smaa_stage_0"); - smaa_aa_weight_sh = GPU_shader_create_from_info_name("workbench_smaa_stage_1"); - smaa_resolve_sh = GPU_shader_create_from_info_name("workbench_smaa_stage_2"); - - smaa_search_tx.ensure_2d(GPU_R8, {SEARCHTEX_WIDTH, SEARCHTEX_HEIGHT}); - GPU_texture_update(smaa_search_tx, GPU_DATA_UBYTE, searchTexBytes); - GPU_texture_filter_mode(smaa_search_tx, true); - - smaa_area_tx.ensure_2d(GPU_RG8, {AREATEX_WIDTH, AREATEX_HEIGHT}); - GPU_texture_update(smaa_area_tx, GPU_DATA_UBYTE, areaTexBytes); - GPU_texture_filter_mode(smaa_area_tx, true); - } - - ~AntiAliasingPass() - { - if (smaa_edge_detect_sh) { - GPU_shader_free(smaa_edge_detect_sh); - } - if (smaa_aa_weight_sh) { - GPU_shader_free(smaa_aa_weight_sh); - } - if (smaa_resolve_sh) { - GPU_shader_free(smaa_resolve_sh); - } - } - - void sync(SceneResources &resources) - { - { - smaa_edge_detect_ps_.init(); - smaa_edge_detect_ps_.state_set(DRW_STATE_WRITE_COLOR); - smaa_edge_detect_ps_.shader_set(smaa_edge_detect_sh); - smaa_edge_detect_ps_.bind_texture("colorTex", &resources.color_tx); - smaa_edge_detect_ps_.push_constant("viewportMetrics", &smaa_viewport_metrics, 1); - smaa_edge_detect_ps_.clear_color(float4(0.0f)); - smaa_edge_detect_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); - } - { - smaa_aa_weight_ps_.init(); - smaa_aa_weight_ps_.state_set(DRW_STATE_WRITE_COLOR); - smaa_aa_weight_ps_.shader_set(smaa_aa_weight_sh); - smaa_aa_weight_ps_.bind_texture("edgesTex", &smaa_edge_tx); - smaa_aa_weight_ps_.bind_texture("areaTex", smaa_area_tx); - smaa_aa_weight_ps_.bind_texture("searchTex", smaa_search_tx); - smaa_aa_weight_ps_.push_constant("viewportMetrics", &smaa_viewport_metrics, 1); - smaa_aa_weight_ps_.clear_color(float4(0.0f)); - smaa_aa_weight_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); - } - { - smaa_resolve_ps_.init(); - smaa_resolve_ps_.state_set(DRW_STATE_WRITE_COLOR); - smaa_resolve_ps_.shader_set(smaa_resolve_sh); - smaa_resolve_ps_.bind_texture("blendTex", &smaa_weight_tx); - smaa_resolve_ps_.bind_texture("colorTex", &resources.color_tx); - smaa_resolve_ps_.push_constant("viewportMetrics", &smaa_viewport_metrics, 1); - smaa_resolve_ps_.push_constant("mixFactor", &smaa_mix_factor, 1); - smaa_resolve_ps_.push_constant("taaAccumulatedWeight", &taa_weight_accum, 1); - smaa_resolve_ps_.clear_color(float4(0.0f)); - smaa_resolve_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); - } - } - - void draw(Manager &manager, View &view, GPUTexture *depth_tx, GPUTexture *color_tx) - { - int2 size = {GPU_texture_width(depth_tx), GPU_texture_height(depth_tx)}; - - taa_weight_accum = 1.0f; /* TODO */ - - smaa_viewport_metrics = float4(1.0f / size.x, 1.0f / size.y, size.x, size.y); - smaa_mix_factor = 1.0f; /* TODO */ - - smaa_edge_tx.acquire(size, GPU_RG8); - smaa_edge_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(smaa_edge_tx)); - smaa_edge_fb.bind(); - manager.submit(smaa_edge_detect_ps_, view); - - smaa_weight_tx.acquire(size, GPU_RGBA8); - smaa_weight_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(smaa_weight_tx)); - smaa_weight_fb.bind(); - manager.submit(smaa_aa_weight_ps_, view); - smaa_edge_tx.release(); - - smaa_resolve_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(color_tx)); - smaa_resolve_fb.bind(); - manager.submit(smaa_resolve_ps_, view); - smaa_weight_tx.release(); - } -}; - class Instance { public: SceneResources resources; @@ -639,12 +28,12 @@ class Instance { bool use_per_material_batches = false; eColorType color_type = eColorType::MATERIAL; eMaterialSubType material_subtype = eMaterialSubType::MATERIAL; + eShadingType shading_type = eShadingType::STUDIO; + /** Used when material_subtype == eMaterialSubType::SINGLE */ Material material_override = Material(float3(1.0f)); - - eShadingType shading_type = eShadingType::STUDIO; - /** Chosen studiolight or matcap. */ - StudioLight *studio_light; + /* When r == -1.0 the shader uses the vertex color */ + Material material_attribute_color = Material(float3(-1.0f)); void init(const int2 &output_res, const Depsgraph *depsgraph, @@ -653,101 +42,87 @@ class Instance { const RegionView3D *rv3d) { Scene *scene = DEG_get_evaluated_scene(depsgraph); - View3DShading &shading = scene->display.shading; - cull_state = DRW_STATE_NO_DRAW; - if (shading.flag & V3D_SHADING_BACKFACE_CULLING) { - cull_state |= DRW_STATE_CULL_BACK; - } + /* TODO(pragma37): + * Check why Workbench Next exposes OB_MATERIAL, and Workbench exposes OB_RENDER */ + bool is_render_mode = !v3d || ELEM(v3d->shading.type, OB_RENDER, OB_MATERIAL); + const View3DShading &shading = is_render_mode ? scene->display.shading : v3d->shading; + + cull_state = shading.flag & V3D_SHADING_BACKFACE_CULLING ? DRW_STATE_CULL_BACK : + DRW_STATE_NO_DRAW; + + material_override = Material(shading.single_color); use_per_material_batches = ELEM( shading.color_type, V3D_SHADING_TEXTURE_COLOR, V3D_SHADING_MATERIAL_COLOR); - color_type = shading.color_type == V3D_SHADING_TEXTURE_COLOR ? eColorType::TEXTURE : - eColorType::MATERIAL; - - if (color_type == eColorType::MATERIAL) { - switch (shading.color_type) { - case V3D_SHADING_MATERIAL_COLOR: - material_subtype = eMaterialSubType::MATERIAL; - break; - case V3D_SHADING_RANDOM_COLOR: - material_subtype = eMaterialSubType::RANDOM; - break; - case V3D_SHADING_SINGLE_COLOR: - material_subtype = eMaterialSubType::SINGLE; - break; - case V3D_SHADING_TEXTURE_COLOR: - BLI_assert_msg(false, "V3D_SHADING_TEXTURE_COLOR is not an eMaterialSubType"); - break; - case V3D_SHADING_OBJECT_COLOR: - material_subtype = eMaterialSubType::OBJECT; - break; - case V3D_SHADING_VERTEX_COLOR: - material_subtype = eMaterialSubType::ATTRIBUTE; - break; - default: - BLI_assert_msg(false, "Unhandled V3D_SHADING type"); - } - } - else { - material_subtype = eMaterialSubType::NONE; - } + color_type = color_type_from_v3d_shading(shading.color_type); + material_subtype = material_subtype_from_v3d_shading(shading.color_type); + shading_type = shading_type_from_v3d_lighting(shading.light); - if (material_subtype == eMaterialSubType::SINGLE) { - material_override = Material(shading.single_color); - } - else if (material_subtype == eMaterialSubType::ATTRIBUTE) { - /* TODO(pragma37): Don't use override, check per object if it has color attribute */ - /* When r == -1.0 the shader uses the vertex color */ - material_override = Material(float3(-1.0f, 1.0f, 1.0f)); - } + UniformBuffer<WorldData> &world_buf = resources.world_buf; - switch (shading.light) { - case V3D_LIGHTING_FLAT: - shading_type = eShadingType::FLAT; - break; - case V3D_LIGHTING_MATCAP: - shading_type = eShadingType::MATCAP; - break; - case V3D_LIGHTING_STUDIO: - shading_type = eShadingType::STUDIO; - break; + float4x4 rot_matrix = float4x4::identity(); + if (shading.flag & V3D_SHADING_WORLD_ORIENTATION) { + /* TODO(pragma37) */ } - float4 background_color = float4(0.0f); + StudioLight *studio_light = nullptr; + if (U.edit_studio_light) { + studio_light = BKE_studiolight_studio_edit_get(); + } + else { + if (shading_type == eShadingType::MATCAP) { + studio_light = BKE_studiolight_find(shading.matcap, STUDIOLIGHT_TYPE_MATCAP); + } + /* If matcaps are missing, use this as fallback. */ + if (studio_light == nullptr) { + studio_light = BKE_studiolight_find(shading.studio_light, STUDIOLIGHT_TYPE_STUDIO); + } + } - /*TODO(pragma37): Replace when Workbench next is complete*/ - // bool is_workbench_render = BKE_scene_uses_blender_workbench(scene); - bool is_workbench_render = std::string(scene->r.engine) == - std::string("BLENDER_WORKBENCH_NEXT"); + for (int i = 0; i < 4; i++) { + LightData &light = world_buf.lights[i]; - /* TODO(pragma37): - * Check why Workbench Next exposes OB_MATERIAL, and Workbench exposes OB_RENDER */ - if (!v3d || (ELEM(v3d->shading.type, OB_RENDER, OB_MATERIAL) && is_workbench_render)) { - if (scene->r.alphamode != R_ALPHAPREMUL) { - World *w = scene->world; - background_color = w ? float4(w->horr, w->horg, w->horb, 1.0f) : - float4(0.0f, 0.0f, 0.0f, 1.0f); + SolidLight *sl = (studio_light) ? &studio_light->light[i] : nullptr; + if (sl && sl->flag) { + float3 direction = rot_matrix * float3(sl->vec); + light.direction = float4(direction, 0.0f); + /* We should pre-divide the power by PI but that makes the lights really dim. */ + light.specular_color = float4(float3(sl->spec), 0.0f); + light.diffuse_color_wrap = float4(float3(sl->col), sl->smooth); + } + else { + light.direction = float4(1.0f, 0.0f, 0.0f, 0.0f); + light.specular_color = float4(0.0f); + light.diffuse_color_wrap = float4(0.0f); } } - resources.init(output_res, background_color); + world_buf.ambient_color = float4(1.0f, 1.0f, 1.0f, 0.0f); + world_buf.use_specular = false; - studio_light = nullptr; - if (shading_type == eShadingType::MATCAP) { - studio_light = BKE_studiolight_find(shading.matcap, STUDIOLIGHT_TYPE_MATCAP); + if (studio_light != nullptr) { + world_buf.ambient_color = float4(float3(studio_light->light_ambient), 0.0f); + world_buf.use_specular = shading.flag & V3D_SHADING_SPECULAR_HIGHLIGHT && + studio_light->flag & STUDIOLIGHT_SPECULAR_HIGHLIGHT_PASS; } - /* If matcaps are missing, use this as fallback. */ - if (studio_light == nullptr) { - studio_light = BKE_studiolight_find(shading.studio_light, STUDIOLIGHT_TYPE_STUDIO); + + world_buf.background_color = float4(0.0f); + + if (is_render_mode && scene->r.alphamode != R_ALPHAPREMUL) { + if (World *w = scene->world) { + world_buf.background_color = float4(w->horr, w->horg, w->horb, 1.0f); + } } + + resources.matcap_tx.ensure_2d_array(GPU_RGBA16F, int2(1), 1); + resources.depth_tx.ensure_2d(GPU_DEPTH24_STENCIL8, output_res); } void begin_sync() { - resources.world_sync(studio_light); - + resources.world_buf.push_update(); opaque_ps.sync(cull_state, clip_state, shading_type, color_type, resources); // opaque_in_front_ps.sync(cull_state, clip_state, shading_type, color_type, resources); // transparent_ps.sync(cull_state, clip_state, shading_type, color_type, resources); @@ -755,6 +130,11 @@ class Instance { anti_aliasing_ps.sync(resources); } + void end_sync() + { + resources.material_buf.push_update(); + } + void object_sync(Manager &manager, ObjectRef &ob_ref) { if (ob_ref.object->type != OB_MESH) { @@ -763,20 +143,21 @@ class Instance { } if (use_per_material_batches) { - Vector<::Material *> materials = materials_get(ob_ref); - Span<GPUBatch *> batches = geometry_get(ob_ref, materials.size()); - - if (batches.size() == materials.size()) { - for (auto i : materials.index_range()) { + const int material_count = DRW_cache_object_material_count_get(ob_ref.object); + Span<GPUBatch *> batches = geometry_get(ob_ref, material_count); + /* TODO(pragma37): Could this ever be false??? */ + if (batches.size() == material_count) { + for (auto i : IndexRange(material_count)) { /* TODO(fclem): This create a cull-able instance for each sub-object. This is done for * simplicity to reduce complexity. But this increase the overhead per object. Instead, * we should use an indirection buffer to the material buffer. */ + ::Material *mat = BKE_object_material_get_eval(ob_ref.object, i + 1); + if (mat == nullptr) { + mat = BKE_material_default_empty(); + } ResourceHandle handle = manager.resource_handle(ob_ref); - - Material &mat = resources.material_buf.get_or_resize(handle.resource_index()); - mat = Material(*materials[i]); - - pipeline_get(ob_ref, materials[i]).draw(batches[i], handle); + resources.material_buf.get_or_resize(handle.resource_index()) = Material(*mat); + pipeline_get(ob_ref, mat).draw(batches[i], handle); } } } @@ -791,9 +172,12 @@ class Instance { else if (material_subtype == eMaterialSubType::RANDOM) { mat = Material(*ob_ref.object, true); } - else { /* SINGLE OR ATTRIBUTE */ + else if (material_subtype == eMaterialSubType::SINGLE) { mat = material_override; } + else if (material_subtype == eMaterialSubType::ATTRIBUTE) { + mat = material_attribute_color; + } GPUBatch *batch = geometry_get(ob_ref); if (batch) { @@ -808,25 +192,15 @@ class Instance { geometry_type_from_object(ob_ref.object), ob_ref, material); } - Vector<::Material *> materials_get(ObjectRef &ob_ref) - { - const int material_count = DRW_cache_object_material_count_get(ob_ref.object); - Vector<::Material *> materials(material_count); - for (auto i : IndexRange(material_count)) { - ::Material *mat = BKE_object_material_get_eval(ob_ref.object, i + 1); - if (mat == nullptr) { - mat = BKE_material_default_empty(); - } - materials[i] = mat; - } - return materials; - } - Span<GPUBatch *> geometry_get(ObjectRef &ob_ref, int material_count) { - Vector<GPUMaterial *> gpu_materials(material_count, nullptr, {}); + /* This is never used, but it's required by DRW_cache_object_surface_material_get */ + static Vector<GPUMaterial *> dummy_gpu_materials(1, nullptr, {}); + if (material_count > dummy_gpu_materials.size()) { + dummy_gpu_materials.resize(material_count, nullptr); + } return {DRW_cache_object_surface_material_get( - ob_ref.object, gpu_materials.begin(), material_count), + ob_ref.object, dummy_gpu_materials.begin(), material_count), material_count}; } @@ -839,11 +213,6 @@ class Instance { return DRW_cache_object_surface_get(ob_ref.object); } - void end_sync() - { - resources.material_buf.push_update(); - } - void draw(Manager &manager, View &view, GPUTexture *depth_tx, GPUTexture *color_tx) { resources.color_tx.acquire(int2(resources.depth_tx.size()), GPU_RGBA16F); diff --git a/source/blender/draw/engines/workbench/workbench_enums.hh b/source/blender/draw/engines/workbench/workbench_enums.hh new file mode 100644 index 00000000000..d5628a458cd --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_enums.hh @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_assert.h" +#include "DNA_object_types.h" +#include "DNA_view3d_enums.h" + +namespace blender::workbench { + +enum class eGeometryType { + MESH = 0, + CURVES, + POINTCLOUD, +}; +static constexpr int geometry_type_len = static_cast<int>(eGeometryType::POINTCLOUD) + 1; + +static inline const char *get_name(eGeometryType type) +{ + switch (type) { + case eGeometryType::MESH: + return "Mesh"; + case eGeometryType::CURVES: + return "Curves"; + case eGeometryType::POINTCLOUD: + return "PointCloud"; + default: + BLI_assert_unreachable(); + return ""; + } +} + +static inline eGeometryType geometry_type_from_object(Object *ob) +{ + switch (ob->type) { + case OB_CURVES: + return eGeometryType::CURVES; + case OB_POINTCLOUD: + return eGeometryType::POINTCLOUD; + default: + return eGeometryType::MESH; + } +} + +enum class ePipelineType { + OPAQUE = 0, + TRANSPARENT, + SHADOW, +}; +static constexpr int pipeline_type_len = static_cast<int>(ePipelineType::SHADOW) + 1; + +enum class eShadingType { + FLAT = 0, + STUDIO, + MATCAP, +}; +static constexpr int shading_type_len = static_cast<int>(eShadingType::MATCAP) + 1; + +static inline eShadingType shading_type_from_v3d_lighting(char lighting) +{ + switch (lighting) { + case V3D_LIGHTING_FLAT: + return eShadingType::FLAT; + case V3D_LIGHTING_MATCAP: + return eShadingType::MATCAP; + case V3D_LIGHTING_STUDIO: + return eShadingType::STUDIO; + default: + BLI_assert_unreachable(); + return static_cast<eShadingType>(-1); + } +} + +enum class eColorType { + MATERIAL = 0, + TEXTURE, +}; +static constexpr int color_type_len = static_cast<int>(eColorType::TEXTURE) + 1; + +static inline eColorType color_type_from_v3d_shading(char shading) +{ + return shading == V3D_SHADING_TEXTURE_COLOR ? eColorType::TEXTURE : eColorType::MATERIAL; +} + +enum class eMaterialSubType { + NONE = 0, + MATERIAL, + RANDOM, + SINGLE, + OBJECT, + ATTRIBUTE, +}; +static constexpr int material_subtype_len = static_cast<int>(eMaterialSubType::ATTRIBUTE) + 1; + +static inline eMaterialSubType material_subtype_from_v3d_shading(char shading) +{ + switch (shading) { + case V3D_SHADING_MATERIAL_COLOR: + return eMaterialSubType::MATERIAL; + case V3D_SHADING_RANDOM_COLOR: + return eMaterialSubType::RANDOM; + case V3D_SHADING_SINGLE_COLOR: + return eMaterialSubType::SINGLE; + case V3D_SHADING_TEXTURE_COLOR: + return eMaterialSubType::NONE; + case V3D_SHADING_OBJECT_COLOR: + return eMaterialSubType::OBJECT; + case V3D_SHADING_VERTEX_COLOR: + return eMaterialSubType::ATTRIBUTE; + default: + BLI_assert_unreachable(); + return static_cast<eMaterialSubType>(-1); + } +} + +} // namespace blender::workbench diff --git a/source/blender/draw/engines/workbench/workbench_materials.cc b/source/blender/draw/engines/workbench/workbench_materials.cc new file mode 100644 index 00000000000..e235ca0247c --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_materials.cc @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "workbench_private.hh" + +#include "BLI_hash.h" + +namespace blender::workbench { + +Material::Material() = default; + +Material::Material(float3 color) +{ + base_color = color; + packed_data = Material::pack_data(0.0f, 0.4f, 1.0f); +} + +Material::Material(::Object &ob, bool random) +{ + if (random) { + uint hash = BLI_ghashutil_strhash_p_murmur(ob.id.name); + if (ob.id.lib) { + hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob.id.lib->filepath); + } + float3 hsv = float3(BLI_hash_int_01(hash), 0.5f, 0.8f); + hsv_to_rgb_v(hsv, base_color); + } + else { + base_color = ob.color; + } + packed_data = Material::pack_data(0.0f, 0.4f, ob.color[3]); +} + +Material::Material(::Material &mat) +{ + base_color = &mat.r; + packed_data = Material::pack_data(mat.metallic, mat.roughness, mat.a); +} + +uint32_t Material::pack_data(float metallic, float roughness, float alpha) +{ + /* Remap to Disney roughness. */ + roughness = sqrtf(roughness); + uint32_t packed_roughness = unit_float_to_uchar_clamp(roughness); + uint32_t packed_metallic = unit_float_to_uchar_clamp(metallic); + uint32_t packed_alpha = unit_float_to_uchar_clamp(alpha); + return (packed_alpha << 16u) | (packed_roughness << 8u) | packed_metallic; +} + +} // namespace blender::workbench diff --git a/source/blender/draw/engines/workbench/workbench_mesh_passes.cc b/source/blender/draw/engines/workbench/workbench_mesh_passes.cc new file mode 100644 index 00000000000..b5ea221ac9f --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_mesh_passes.cc @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "workbench_private.hh" + +namespace blender::workbench { + +MeshPass::MeshPass(const char *name) : PassMain(name){}; + +/* Move to draw::Pass */ +bool MeshPass::is_empty() const +{ + return false; /* TODO */ +} + +void MeshPass::init(ePipelineType pipeline, + eColorType color_type, + eShadingType shading, + SceneResources &resources, + DRWState state) +{ + ShaderCache &shaders = resources.shader_cache; + + this->PassMain::init(); + this->state_set(state); + this->bind_texture(WB_MATCAP_SLOT, resources.matcap_tx); + this->bind_ssbo(WB_MATERIAL_SLOT, &resources.material_buf); + this->bind_ubo(WB_WORLD_SLOT, resources.world_buf); + + color_type_ = color_type; + texture_subpass_map.clear(); + + for (int geom = 0; geom < geometry_type_len; geom++) { + eGeometryType geom_type = static_cast<eGeometryType>(geom); + GPUShader *sh = shaders.prepass_shader_get(pipeline, geom_type, color_type, shading); + PassMain::Sub *pass = &this->sub(get_name(geom_type)); + pass->shader_set(sh); + geometry_passes_[geom] = pass; + } +} + +PassMain::Sub &MeshPass::sub_pass_get(eGeometryType geometry_type, + ObjectRef & /*ref*/, + ::Material * /*material*/) +{ + if (color_type_ == eColorType::TEXTURE) { + /* TODO(fclem): Always query a layered texture so we can use only a single shader. */ + GPUTexture *texture = nullptr; // ref.object->texture_get(); + GPUTexture *tilemap = nullptr; // ref.object->texture_get(); + + auto add_cb = [&] { + PassMain::Sub *sub_pass = geometry_passes_[static_cast<int>(geometry_type)]; + sub_pass = &sub_pass->sub("Blender Texture Name" /* texture.name */); + sub_pass->bind_texture(WB_TEXTURE_SLOT, texture); + sub_pass->bind_texture(WB_TILEMAP_SLOT, tilemap); + return sub_pass; + }; + + return *texture_subpass_map.lookup_or_add_cb(TextureSubPassKey(texture, geometry_type), + add_cb); + } + return *geometry_passes_[static_cast<int>(geometry_type)]; +} + +void OpaquePass::sync(DRWState cull_state, + DRWState clip_state, + eShadingType shading_type, + eColorType color_type, + SceneResources &resources) +{ + Texture &depth_tx = resources.depth_tx; + Texture &depth_in_front_tx = resources.depth_in_front_tx; + TextureFromPool &color_tx = resources.color_tx; + ShaderCache &shaders = resources.shader_cache; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | + cull_state | clip_state; + + gbuffer_ps_.init(ePipelineType::OPAQUE, color_type, shading_type, resources, state); + + deferred_ps_.init(); + deferred_ps_.shader_set(shaders.resolve_shader_get(ePipelineType::OPAQUE, shading_type)); + deferred_ps_.bind_ubo(WB_WORLD_SLOT, resources.world_buf); + deferred_ps_.bind_texture(WB_MATCAP_SLOT, resources.matcap_tx); + deferred_ps_.bind_texture("normal_tx", &gbuffer_normal_tx); + deferred_ps_.bind_texture("material_tx", &gbuffer_material_tx); + deferred_ps_.bind_texture("depth_tx", &depth_tx); + deferred_ps_.bind_image("out_color_img", &color_tx); + deferred_ps_.dispatch(math::divide_ceil(int2(depth_tx.size()), int2(WB_RESOLVE_GROUP_SIZE))); + deferred_ps_.barrier(GPU_BARRIER_TEXTURE_FETCH); +} + +void OpaquePass::draw_prepass(Manager &manager, View &view, Texture &depth_tx) +{ + gbuffer_material_tx.acquire(int2(depth_tx.size()), GPU_RGBA16F); + gbuffer_normal_tx.acquire(int2(depth_tx.size()), GPU_RG16F); + gbuffer_object_id_tx.acquire(int2(depth_tx.size()), GPU_R16UI); + + opaque_fb.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx), + GPU_ATTACHMENT_TEXTURE(gbuffer_material_tx), + GPU_ATTACHMENT_TEXTURE(gbuffer_normal_tx), + GPU_ATTACHMENT_TEXTURE(gbuffer_object_id_tx)); + opaque_fb.bind(); + opaque_fb.clear_depth(1.0f); + + manager.submit(gbuffer_ps_, view); +} + +void OpaquePass::draw_resolve(Manager &manager, View &view) +{ + manager.submit(deferred_ps_, view); + + gbuffer_normal_tx.release(); + gbuffer_material_tx.release(); + gbuffer_object_id_tx.release(); +} + +bool OpaquePass::is_empty() const +{ + return gbuffer_ps_.is_empty(); +} + +void TransparentPass::sync(DRWState cull_state, + DRWState clip_state, + eShadingType shading_type, + eColorType color_type, + SceneResources &resources) +{ + ShaderCache &shaders = resources.shader_cache; + Texture &depth_tx = resources.depth_tx; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | + cull_state | clip_state; + + accumulation_ps_.init(ePipelineType::TRANSPARENT, color_type, shading_type, resources, state); + + resolve_ps_.init(); + resolve_ps_.shader_set( + shaders.resolve_shader_get(ePipelineType::TRANSPARENT, eShadingType::FLAT)); + resolve_ps_.bind_texture("accumulation_tx", accumulation_tx); + resolve_ps_.bind_texture("reveal_tx", reveal_tx); + resolve_ps_.dispatch(math::divide_ceil(depth_tx.size(), int3(WB_RESOLVE_GROUP_SIZE))); +} + +void TransparentPass::draw_prepass(Manager &manager, View &view, Texture &depth_tx) +{ + accumulation_tx.acquire(int2(depth_tx.size()), GPU_RGBA16F); + reveal_tx.acquire(int2(depth_tx.size()), GPU_R8); + + transparent_fb.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx), + GPU_ATTACHMENT_TEXTURE(accumulation_tx), + GPU_ATTACHMENT_TEXTURE(reveal_tx)); + transparent_fb.bind(); + + manager.submit(accumulation_ps_, view); +} + +void TransparentPass::draw_resolve(Manager &manager, View &view) +{ + manager.submit(resolve_ps_, view); + + accumulation_tx.release(); + reveal_tx.release(); +} + +bool TransparentPass::is_empty() const +{ + return accumulation_ps_.is_empty(); +} + +} // namespace blender::workbench diff --git a/source/blender/draw/engines/workbench/workbench_private.hh b/source/blender/draw/engines/workbench/workbench_private.hh new file mode 100644 index 00000000000..d320eac5dc4 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_private.hh @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "DRW_render.h" +#include "draw_manager.hh" +#include "draw_pass.hh" + +#include "workbench_defines.hh" +#include "workbench_enums.hh" +#include "workbench_shader_shared.h" + +namespace blender::workbench { + +using namespace draw; + +struct Material { + float3 base_color; + /* Packed data into a int. Decoded in the shader. */ + uint packed_data; + + Material(); + Material(float3 color); + Material(::Object &ob, bool random = false); + Material(::Material &mat); + + static uint32_t pack_data(float metallic, float roughness, float alpha); +}; + +class ShaderCache { + private: + /* TODO(fclem): We might want to change to a Map since most shader will never be compiled. */ + GPUShader *prepass_shader_cache_[shading_type_len][color_type_len][geometry_type_len] + [pipeline_type_len] = {{{{nullptr}}}}; + GPUShader *resolve_shader_cache_[shading_type_len][pipeline_type_len] = {{nullptr}}; + + public: + ~ShaderCache(); + + GPUShader *prepass_shader_get(ePipelineType pipeline_type, + eGeometryType geometry_type, + eColorType color_type, + eShadingType shading_type); + + GPUShader *resolve_shader_get(ePipelineType pipeline_type, eShadingType shading_type); +}; + +struct SceneResources { + ShaderCache shader_cache; + + Texture matcap_tx = "matcap_tx"; + + TextureFromPool color_tx = "wb_color_tx"; + Texture depth_tx = "wb_depth_tx"; + Texture depth_in_front_tx = "wb_depth_in_front_tx"; + + StorageVectorBuffer<Material> material_buf = {"material_buf"}; + UniformBuffer<WorldData> world_buf; +}; + +class MeshPass : public PassMain { + private: + std::array<PassMain::Sub *, geometry_type_len> geometry_passes_; + eColorType color_type_; + + using TextureSubPassKey = std::pair<GPUTexture *, eGeometryType>; + Map<TextureSubPassKey, PassMain::Sub *> texture_subpass_map; + + public: + MeshPass(const char *name); + + /* Move to draw::Pass */ + bool is_empty() const; + + void init(ePipelineType pipeline, + eColorType color_type, + eShadingType shading, + SceneResources &resources, + DRWState state); + + PassMain::Sub &sub_pass_get(eGeometryType geometry_type, ObjectRef &ref, ::Material *material); +}; + +class OpaquePass { + public: + TextureFromPool gbuffer_normal_tx = {"gbuffer_normal_tx"}; + TextureFromPool gbuffer_material_tx = {"gbuffer_material_tx"}; + TextureFromPool gbuffer_object_id_tx = {"gbuffer_object_id_tx"}; + Framebuffer opaque_fb; + + MeshPass gbuffer_ps_ = {"Opaque.Gbuffer"}; + PassSimple deferred_ps_ = {"Opaque.Deferred"}; + + void sync(DRWState cull_state, + DRWState clip_state, + eShadingType shading_type, + eColorType color_type, + SceneResources &resources); + + void draw_prepass(Manager &manager, View &view, Texture &depth_tx); + + void draw_resolve(Manager &manager, View &view); + + bool is_empty() const; +}; + +class TransparentPass { + public: + TextureFromPool accumulation_tx; + TextureFromPool reveal_tx; + Framebuffer transparent_fb; + + MeshPass accumulation_ps_ = {"Transparent.Accumulation"}; + PassSimple resolve_ps_ = {"Transparent.Resolve"}; + + void sync(DRWState cull_state, + DRWState clip_state, + eShadingType shading_type, + eColorType color_type, + SceneResources &resources); + + void draw_prepass(Manager &manager, View &view, Texture &depth_tx); + + void draw_resolve(Manager &manager, View &view); + + bool is_empty() const; +}; + +class AntiAliasingPass { + public: + Texture smaa_search_tx = {"smaa_search_tx"}; + Texture smaa_area_tx = {"smaa_area_tx"}; + TextureFromPool smaa_edge_tx = {"smaa_edge_tx"}; + TextureFromPool smaa_weight_tx = {"smaa_weight_tx"}; + + Framebuffer smaa_edge_fb = {"smaa_edge_fb"}; + Framebuffer smaa_weight_fb = {"smaa_weight_fb"}; + Framebuffer smaa_resolve_fb = {"smaa_resolve_fb"}; + + float4 smaa_viewport_metrics = {0.0f, 0.0f, 0.0f, 0.0f}; + float smaa_mix_factor = 0.0f; + float taa_weight_accum = 1.0f; + + GPUShader *smaa_edge_detect_sh = nullptr; + GPUShader *smaa_aa_weight_sh = nullptr; + GPUShader *smaa_resolve_sh = nullptr; + + PassSimple smaa_edge_detect_ps_ = {"SMAA.EdgeDetect"}; + PassSimple smaa_aa_weight_ps_ = {"SMAA.BlendWeights"}; + PassSimple smaa_resolve_ps_ = {"SMAA.Resolve"}; + + AntiAliasingPass(); + + ~AntiAliasingPass(); + + void sync(SceneResources &resources); + + void draw(Manager &manager, View &view, GPUTexture *depth_tx, GPUTexture *color_tx); +}; + +} // namespace blender::workbench diff --git a/source/blender/draw/engines/workbench/workbench_shader_cache.cc b/source/blender/draw/engines/workbench/workbench_shader_cache.cc new file mode 100644 index 00000000000..9b8d932ba49 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_shader_cache.cc @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "workbench_private.hh" + +namespace blender::workbench { + +ShaderCache::~ShaderCache() +{ + for (auto i : IndexRange(shading_type_len)) { + for (auto j : IndexRange(color_type_len)) { + for (auto k : IndexRange(geometry_type_len)) { + for (auto l : IndexRange(pipeline_type_len)) { + DRW_SHADER_FREE_SAFE(prepass_shader_cache_[i][j][k][l]); + } + } + } + } + for (auto i : IndexRange(shading_type_len)) { + for (auto j : IndexRange(pipeline_type_len)) { + DRW_SHADER_FREE_SAFE(resolve_shader_cache_[i][j]); + } + } +} + +GPUShader *ShaderCache::prepass_shader_get(ePipelineType pipeline_type, + eGeometryType geometry_type, + eColorType color_type, + eShadingType shading_type) +{ + GPUShader *&shader_ptr = prepass_shader_cache_[static_cast<int>(pipeline_type)][static_cast<int>( + geometry_type)][static_cast<int>(color_type)][static_cast<int>(shading_type)]; + + if (shader_ptr != nullptr) { + return shader_ptr; + } + std::string info_name = "workbench_next_prepass_"; + switch (geometry_type) { + case eGeometryType::MESH: + info_name += "mesh_"; + break; + case eGeometryType::CURVES: + info_name += "curves_"; + break; + case eGeometryType::POINTCLOUD: + info_name += "ptcloud_"; + break; + } + switch (pipeline_type) { + case ePipelineType::OPAQUE: + info_name += "opaque_"; + break; + case ePipelineType::TRANSPARENT: + info_name += "transparent_"; + break; + case ePipelineType::SHADOW: + info_name += "shadow_"; + break; + } + switch (shading_type) { + case eShadingType::FLAT: + info_name += "flat_"; + break; + case eShadingType::STUDIO: + info_name += "studio_"; + break; + case eShadingType::MATCAP: + info_name += "matcap_"; + break; + } + switch (color_type) { + case eColorType::MATERIAL: + info_name += "material"; + break; + case eColorType::TEXTURE: + info_name += "texture"; + break; + } + /* TODO Clipping */ + info_name += "_no_clip"; + shader_ptr = GPU_shader_create_from_info_name(info_name.c_str()); + prepass_shader_cache_[static_cast<int>(pipeline_type)][static_cast<int>(geometry_type)] + [static_cast<int>(color_type)][static_cast<int>(shading_type)] = shader_ptr; + return shader_ptr; +} + +GPUShader *ShaderCache::resolve_shader_get(ePipelineType pipeline_type, eShadingType shading_type) +{ + GPUShader *&shader_ptr = + resolve_shader_cache_[static_cast<int>(shading_type)][static_cast<int>(pipeline_type)]; + + if (shader_ptr != nullptr) { + return shader_ptr; + } + std::string info_name = "workbench_next_resolve_"; + switch (pipeline_type) { + case ePipelineType::OPAQUE: + info_name += "opaque_"; + break; + case ePipelineType::TRANSPARENT: + info_name += "transparent_"; + break; + case ePipelineType::SHADOW: + BLI_assert_unreachable(); + break; + } + switch (shading_type) { + case eShadingType::FLAT: + info_name += "flat"; + break; + case eShadingType::STUDIO: + info_name += "studio"; + break; + case eShadingType::MATCAP: + info_name += "matcap"; + break; + } + shader_ptr = GPU_shader_create_from_info_name(info_name.c_str()); + return shader_ptr; +} + +} // namespace blender::workbench |