From 43dad4d9b1c9ec7cbf533395758f24c1e05dd5a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Foucault?= Date: Sun, 2 Oct 2022 00:14:56 +0200 Subject: WORKBENCH: Rewrite using the new Draw Manager API This adds a new experimental option for testing the new rewrite. This is a full rewrite using C++ and using the new DRW API. This tries to simplify each aspect of the engine: - Materials are put in SSBOs. - Only one shader per pass. The goal is to leverage the new DRW capabilities in term of GPU culling and drawcall batching. --- release/scripts/startup/bl_ui/space_userpref.py | 1 + source/blender/draw/CMakeLists.txt | 1 + .../draw/engines/workbench/workbench_engine.cc | 691 +++++++++++++++++++++ .../draw/engines/workbench/workbench_engine.h | 1 + source/blender/draw/intern/DRW_gpu_wrapper.hh | 10 + source/blender/draw/intern/draw_manager.c | 3 + source/blender/gpu/intern/gpu_texture_private.hh | 2 +- source/blender/makesdna/DNA_userdef_types.h | 3 +- source/blender/makesrna/intern/rna_userdef.c | 7 + 9 files changed, 717 insertions(+), 2 deletions(-) create mode 100644 source/blender/draw/engines/workbench/workbench_engine.cc diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 441babefd60..55b07aeab91 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -2307,6 +2307,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel): ({"property": "use_sculpt_texture_paint"}, "T96225"), ({"property": "use_full_frame_compositor"}, "T88150"), ({"property": "enable_eevee_next"}, "T93220"), + ({"property": "enable_workbench_next"}, ""), ({"property": "use_draw_manager_acquire_lock"}, "T98016"), ), ) diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index a9ccc42644a..f02a1d72da1 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -159,6 +159,7 @@ set(SRC 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_opaque.c engines/workbench/workbench_render.c diff --git a/source/blender/draw/engines/workbench/workbench_engine.cc b/source/blender/draw/engines/workbench/workbench_engine.cc new file mode 100644 index 00000000000..954b6410340 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_engine.cc @@ -0,0 +1,691 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "DRW_render.h" +#include "GPU_capabilities.h" + +#include "draw_manager.hh" +#include "draw_pass.hh" + +namespace blender::workbench { + +using namespace draw; + +#define WB_MATCAP_SLOT 0 +#define WB_TEXTURE_SLOT 1 +#define WB_TILEMAP_SLOT 2 +#define WB_MATERIAL_SLOT 0 + +#define WB_RESOLVE_GROUP_SIZE 8 + +enum class eGeometryType { + MESH = 0, + CURVES, + POINTCLOUD, +}; +static constexpr int geometry_type_len = static_cast(eGeometryType::POINTCLOUD) + 1; + +static inline const char *get_name(eGeometryType type) +{ + switch (type) { + case eGeometryType::MESH: + return "Curves"; + case eGeometryType::CURVES: + return "PointCloud"; + case eGeometryType::POINTCLOUD: + return "Mesh"; + } +} + +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(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(eShadingType::MATCAP) + 1; + +enum class eColorType { + MATERIAL = 0, + TEXTURE, +}; +static constexpr int color_type_len = static_cast(eColorType::TEXTURE) + 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) + { + 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(pipeline_type)][static_cast(geometry_type)] + [static_cast(color_type)][static_cast(shading_type)]; + + if (shader_ptr != nullptr) { + return shader_ptr; + } + std::string info_name = "workbench_next_"; + switch (geometry_type) { + case eGeometryType::MESH: + info_name += "mesh_"; + break; + case eGeometryType::CURVES: + info_name += "curves_"; + break; + case eGeometryType::POINTCLOUD: + info_name += "pointcloud_"; + 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; + } + shader_ptr = GPU_shader_create_from_info_name(info_name.c_str()); + return shader_ptr; + } + + GPUShader *resolve_shader_get(ePipelineType pipeline_type, eShadingType shading_type) + { + GPUShader *&shader_ptr = + resolve_shader_cache_[static_cast(shading_type)][static_cast(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; + Texture depth_tx; + Texture depth_in_front_tx; + + StorageBuffer material_buf = {"material_buf"}; +}; + +class MeshPass : public PassMain { + private: + std::array geometry_passes_; + eColorType color_type_; + + using TextureSubPassKey = std::pair; + Map 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) + { + 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); + + color_type_ = color_type; + texture_subpass_map.clear(); + + for (int geom = 0; geom < geometry_type_len; geom++) { + eGeometryType geom_type = static_cast(geom); + GPUShader *sh = resources.shader_cache->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) + { + 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(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(geometry_type)]; + } +}; + +class OpaquePass { + public: + TextureFromPool gbuffer_normal_tx; + TextureFromPool gbuffer_albedo_tx; + TextureFromPool 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; + 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( + resources.shader_cache->resolve_shader_get(ePipelineType::OPAQUE, shading_type)); + deferred_ps_.bind_texture("depth_tx", depth_tx); + deferred_ps_.bind_texture("stencil_tx", depth_tx.stencil_view()); + deferred_ps_.bind_texture("normal_tx", gbuffer_normal_tx); + deferred_ps_.bind_texture("albedo_tx", gbuffer_albedo_tx); + deferred_ps_.bind_texture("object_id_tx", gbuffer_object_id_tx); + deferred_ps_.dispatch(math::divide_ceil(depth_tx.size(), int3(WB_RESOLVE_GROUP_SIZE))); + } + + void draw_prepass(Manager &manager, View &view, Texture &depth_tx) + { + gbuffer_normal_tx.acquire(int2(depth_tx.size()), GPU_RG16F); + gbuffer_albedo_tx.acquire(int2(depth_tx.size()), GPU_RGBA8); + gbuffer_object_id_tx.acquire(int2(depth_tx.size()), GPU_R16UI); + + opaque_fb.ensure(GPU_ATTACHMENT_TEXTURE(depth_tx), + GPU_ATTACHMENT_TEXTURE(gbuffer_normal_tx), + GPU_ATTACHMENT_TEXTURE(gbuffer_albedo_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_albedo_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) + { + 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(resources.shader_cache->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(); + } +}; + +struct Instance { + SceneResources resources; + + OpaquePass opaque_ps; + OpaquePass opaque_in_front_ps; + + TransparentPass transparent_ps; + TransparentPass transparent_in_front_ps; + + DRWState clip_state; + DRWState cull_state; + + bool use_per_material_batches; + eColorType color_type; + eShadingType shading_type; + + void init(const int2 &output_res, + const rcti *output_rect, + RenderEngine *render_, + Depsgraph *depsgraph_, + Object *camera_object_, + const RenderLayer *render_layer_, + const View3D *v3d_, + const RegionView3D *rv3d_) + { + use_per_material_batches = false; // ELEM(color_type, V3D_COLOR_TEXTURE, V3D_COLOR_MATERIAL); + color_type = eColorType::MATERIAL; + shading_type = eShadingType::STUDIO; + } + + void begin_sync(Manager &manager) + { + 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); + transparent_in_front_ps.sync(cull_state, clip_state, shading_type, color_type, resources); + } + + void object_sync(Manager &manager, ObjectRef &ref) + { + ResourceHandle handle = manager.resource_handle(ref); + + if (use_per_material_batches) { + Span<::Material *> materials = materials_get(ref); + Span batches = geometry_get(ref, materials); + + for (auto i : materials.index_range()) { + PassMain::Sub &pass = pipeline_get(ref, materials[i]); + pass.draw(batches[i], handle); + } + } + else { + GPUBatch *geom = geometry_get(ref); + + PassMain::Sub &pass = pipeline_get(ref); + pass.draw(geom, handle); + } + } + + PassMain::Sub &pipeline_get(ObjectRef &ref, ::Material *material = nullptr) + { + return opaque_ps.gbuffer_ps_.sub_pass_get(geometry_type_from_object(ref.object), ref); + } + + Span geometry_get(ObjectRef &ref, Span<::Material *> materials) + { + return {}; + } + + GPUBatch *geometry_get(ObjectRef &ref) + { + return {}; + } + + Span<::Material *> materials_get(ObjectRef &ref) + { + return {}; + } + + void draw(Manager &manager, View &view) + { + opaque_ps.draw_prepass(manager, view, resources.depth_tx); + // volume_ps.draw_prepass(manager, view, resources.depth_tx); + transparent_ps.draw_prepass(manager, view, resources.depth_tx); + + if (opaque_in_front_ps.is_empty() == false || transparent_in_front_ps.is_empty() == false) { + opaque_in_front_ps.draw_prepass(manager, view, resources.depth_in_front_tx); + transparent_in_front_ps.draw_prepass(manager, view, resources.depth_in_front_tx); + } + + opaque_ps.draw_resolve(manager, view); + transparent_ps.draw_resolve(manager, view); + } + + void draw_viewport(Manager &manager, View &view, GPUTexture *depth_tx, GPUTexture *color_tx) + { + this->draw(manager, view); + + // anti_aliasing_ps.draw(manager, view, depth_tx, color_tx); + } +}; + +} // namespace blender::workbench + +/* -------------------------------------------------------------------- */ +/** \name Interface with legacy C DRW manager + * \{ */ + +using namespace blender; + +struct WORKBENCH_Data { + DrawEngineType *engine_type; + DRWViewportEmptyList *fbl; + DRWViewportEmptyList *txl; + DRWViewportEmptyList *psl; + DRWViewportEmptyList *stl; + workbench::Instance *instance; + + char info[GPU_INFO_SIZE]; +}; + +static void workbench_engine_init(void *vedata) +{ + /* TODO(fclem): Remove once it is minimum required. */ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + + WORKBENCH_Data *ved = reinterpret_cast(vedata); + if (ved->instance == nullptr) { + ved->instance = new workbench::Instance(); + } + + const DRWContextState *ctx_state = DRW_context_state_get(); + Depsgraph *depsgraph = ctx_state->depsgraph; + View3D *v3d = ctx_state->v3d; + RegionView3D *rv3d = ctx_state->rv3d; + + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + int2 size = int2(GPU_texture_width(dtxl->color), GPU_texture_height(dtxl->color)); + + Object *camera = nullptr; + /* Get render borders. */ + rcti rect; + BLI_rcti_init(&rect, 0, size[0], 0, size[1]); + if (v3d) { + if (rv3d && (rv3d->persp == RV3D_CAMOB)) { + camera = v3d->camera; + } + } + + ved->instance->init(size, &rect, nullptr, depsgraph, camera, nullptr, v3d, rv3d); +} + +static void workbench_draw_scene(void *vedata) +{ + WORKBENCH_Data *ved = reinterpret_cast(vedata); + if (!GPU_shader_storage_buffer_objects_support()) { + STRNCPY(ved->info, "Error: No shader storage buffer support"); + return; + } + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + const DRWView *default_view = DRW_view_default_get(); + draw::Manager *manager = DRW_manager_get(); + draw::View view("DefaultView", default_view); + ved->instance->draw_viewport(*manager, view, dtxl->depth, dtxl->color); +} + +static void workbench_cache_init(void *vedata) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + draw::Manager *manager = DRW_manager_get(); + reinterpret_cast(vedata)->instance->begin_sync(*manager); +} + +static void workbench_cache_populate(void *vedata, Object *object) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + draw::Manager *manager = DRW_manager_get(); + + draw::ObjectRef ref; + ref.object = object; + ref.dupli_object = DRW_object_get_dupli(object); + ref.dupli_parent = DRW_object_get_dupli_parent(object); + + reinterpret_cast(vedata)->instance->object_sync(*manager, ref); +} + +static void workbench_cache_finish(void *vedata) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + UNUSED_VARS(vedata); +} + +static void workbench_instance_free(void *instance) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + delete reinterpret_cast(instance); +} + +static void workbench_view_update(void *vedata) +{ + UNUSED_VARS(vedata); +} + +static void workbench_id_update(void *vedata, struct ID *id) +{ + UNUSED_VARS(vedata, id); +} + +static void workbench_render_to_image(void *vedata, + struct RenderEngine *engine, + struct RenderLayer *layer, + const struct rcti *UNUSED(rect)) +{ + UNUSED_VARS(vedata, engine, layer); +} + +void workbench_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer) +{ + RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA); +} + +extern "C" { + +static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data); + +DrawEngineType draw_engine_workbench_next = { + nullptr, + nullptr, + N_("Workbench"), + &workbench_data_size, + &workbench_engine_init, + nullptr, + &workbench_instance_free, + &workbench_cache_init, + &workbench_cache_populate, + &workbench_cache_finish, + &workbench_draw_scene, + &workbench_view_update, + &workbench_id_update, + &workbench_render_to_image, + nullptr, +}; + +RenderEngineType DRW_engine_viewport_workbench_next_type = { + nullptr, + nullptr, + "BLENDER_WORKBENCH", + N_("Workbench Next"), + RE_INTERNAL | RE_USE_STEREO_VIEWPORT | RE_USE_GPU_CONTEXT, + nullptr, + &DRW_render_to_image, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + &workbench_render_update_passes, + &draw_engine_workbench_next, + {nullptr, nullptr, nullptr}, +}; +} + +/** \} */ diff --git a/source/blender/draw/engines/workbench/workbench_engine.h b/source/blender/draw/engines/workbench/workbench_engine.h index 6f6f2143868..1b48acd8054 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.h +++ b/source/blender/draw/engines/workbench/workbench_engine.h @@ -8,3 +8,4 @@ #pragma once extern RenderEngineType DRW_engine_viewport_workbench_type; +extern RenderEngineType DRW_engine_viewport_workbench_next_type; diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh index d53c5fbeaa5..c559ad81a97 100644 --- a/source/blender/draw/intern/DRW_gpu_wrapper.hh +++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh @@ -985,6 +985,16 @@ class Framebuffer : NonCopyable { &fb_, {depth, color1, color2, color3, color4, color5, color6, color7, color8}); } + void bind() + { + GPU_framebuffer_bind(fb_); + } + + void clear_depth(float depth) + { + GPU_framebuffer_clear_depth(fb_, depth); + } + Framebuffer &operator=(Framebuffer &&a) { if (*this != a) { diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index b6ca56d36fc..ea3924f6658 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -3002,6 +3002,9 @@ void DRW_engines_register_experimental(void) if (U.experimental.enable_eevee_next) { RE_engines_register(&DRW_engine_viewport_eevee_next_type); } + if (U.experimental.enable_workbench_next) { + RE_engines_register(&DRW_engine_viewport_workbench_next_type); + } } void DRW_engines_register(void) diff --git a/source/blender/gpu/intern/gpu_texture_private.hh b/source/blender/gpu/intern/gpu_texture_private.hh index 8521b0fd77f..b6db7a1ffe8 100644 --- a/source/blender/gpu/intern/gpu_texture_private.hh +++ b/source/blender/gpu/intern/gpu_texture_private.hh @@ -41,7 +41,7 @@ typedef enum eGPUTextureType { GPU_TEXTURE_CUBE_ARRAY = (GPU_TEXTURE_CUBE | GPU_TEXTURE_ARRAY), } eGPUTextureType; -ENUM_OPERATORS(eGPUTextureType, GPU_TEXTURE_CUBE_ARRAY) +ENUM_OPERATORS(eGPUTextureType, GPU_TEXTURE_BUFFER) #ifdef DEBUG # define DEBUG_NAME_LEN 64 diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 9d8b75450ca..1bd93988714 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -653,7 +653,8 @@ typedef struct UserDef_Experimental { char use_sculpt_texture_paint; char use_draw_manager_acquire_lock; char use_realtime_compositor; - char _pad[7]; + char enable_workbench_next; + char _pad[6]; /** `makesdna` does not allow empty structs. */ } UserDef_Experimental; diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index c9e3822c996..f5f1d29da0e 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -6381,6 +6381,13 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "enable_eevee_next", 1); RNA_def_property_ui_text(prop, "EEVEE Next", "Enable the new EEVEE codebase, requires restart"); + RNA_def_property_boolean_sdna(prop, NULL, "enable_workbench_next", 1); + RNA_def_property_ui_text(prop, + "Workbench Next", + "Enable the new Workbench codebase, requires " + "restart"); + prop = RNA_def_property(srna, "enable_workbench_next", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "use_viewport_debug", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_viewport_debug", 1); RNA_def_property_ui_text(prop, -- cgit v1.2.3