Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiguel Pozo <pragma37@gmail.com>2022-10-10 14:45:45 +0300
committerMiguel Pozo <pragma37@gmail.com>2022-10-10 14:45:45 +0300
commit8501e93deaaf22a5f25c77967e861153e53dd560 (patch)
treef5bf65f52cb125ac68a1ef1574e4292d47c36f38
parent219d5a9530e5f771956cde7353e8ef8aef82a5ad (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.txt7
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_composite_info.hh2
-rw-r--r--source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh2
-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.cc102
-rw-r--r--source/blender/draw/engines/workbench/workbench_engine.cc813
-rw-r--r--source/blender/draw/engines/workbench/workbench_enums.hh114
-rw-r--r--source/blender/draw/engines/workbench/workbench_materials.cc49
-rw-r--r--source/blender/draw/engines/workbench/workbench_mesh_passes.cc168
-rw-r--r--source/blender/draw/engines/workbench/workbench_private.hh159
-rw-r--r--source/blender/draw/engines/workbench/workbench_shader_cache.cc121
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