Overlay-Next: Initial implementation #107045

Closed
Clément Foucault wants to merge 28 commits from fclem/blender:overlay-next into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
13 changed files with 189 additions and 18 deletions
Showing only changes of commit 16cc2446f5 - Show all commits

View File

@ -77,7 +77,7 @@ template<typename SelectEngineT> class Background {
bg_ps_.init();
bg_ps_.state_set(pass_state);
bg_ps_.shader_set(OVERLAY_shader_background());
bg_ps_.shader_set(res.shaders.background_fill);
bg_ps_.bind_ubo("globalsBlock", &res.globals_buf);
bg_ps_.bind_texture("colorBuffer", &res.color_render_tx);
bg_ps_.bind_texture("depthBuffer", &res.depth_tx);
@ -87,7 +87,7 @@ template<typename SelectEngineT> class Background {
if (state.clipping_state != 0 && state.rv3d != nullptr && state.rv3d->clipbb != nullptr) {
bg_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | DRW_STATE_CULL_BACK);
bg_ps_.shader_set(OVERLAY_shader_clipbound());
bg_ps_.shader_set(res.shaders.background_clip_bound);
bg_ps_.push_constant("ucolor", res.theme_settings.color_clipping_border);
bg_ps_.push_constant("boundbox", &state.rv3d->clipbb->vec[0][0], 8);
bg_ps_.draw(DRW_cache_cube_get());

View File

@ -95,7 +95,7 @@ template<typename SelectEngineT> class Empties {
pass.init();
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
state.clipping_state);
pass.shader_set(OVERLAY_shader_extra(false));
pass.shader_set(res.shaders.extra_shape);
pass.bind_ubo("globalsBlock", &res.globals_buf);
call_bufs.plain_axes_buf.end_sync(pass, shapes.plain_axes);

View File

@ -737,6 +737,7 @@ static void OVERLAY_draw_scene(void *vedata)
static void OVERLAY_engine_free()
{
OVERLAY_shader_free();
overlay::shader_module_free();
}
static void OVERLAY_instance_free(void *instance_)

View File

@ -176,7 +176,7 @@ template<typename SelectEngineT> class Grid {
grid_ps_.init();
grid_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA);
grid_ps_.shader_set(OVERLAY_shader_grid());
grid_ps_.shader_set(res.shaders.grid);
grid_ps_.bind_ubo("grid_buf", &data_);
grid_ps_.bind_ubo("globalsBlock", &res.globals_buf);
grid_ps_.bind_texture("depth_tx", &res.depth_tx);

View File

@ -71,7 +71,7 @@ template<typename T> void Instance<T>::begin_sync()
View view("OverlayView", view_legacy);
background.begin_sync(resources, state);
prepass.begin_sync(state);
prepass.begin_sync(resources, state);
empties.begin_sync();
metaballs.begin_sync();
grid.begin_sync(resources, state, view);

View File

@ -20,12 +20,6 @@
namespace blender::draw::overlay {
class ShaderCache {
Map<StringRefNull, std::array<GPUShader *, 2>> cache;
int clipping_enabled = 0;
};
template<
/* Selection engine reuse most of the Overlay engine by creating selection IDs for each
* selectable component and using a special shaders for drawing.
@ -34,14 +28,13 @@ template<
typename SelectEngineT = select::EngineEmpty>
class Instance {
public:
ShaderCache shaders;
ShapeCache shapes;
/* WORKAROUND: Legacy. Move to grid pass. */
GPUUniformBuf *grid_ubo = nullptr;
ShapeCache shapes;
/** Global types. */
Resources<SelectEngineT> resources;
Resources<SelectEngineT> resources = {overlay::ShaderModule<SelectEngineT>::module_get()};
State state;
/** Overlay types. */

View File

@ -88,7 +88,7 @@ template<typename SelectEngineT> class Metaballs {
pass.init();
pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL |
state.clipping_state);
pass.shader_set(OVERLAY_shader_armature_sphere(true));
pass.shader_set(res.shaders.armature_sphere_outline);
pass.bind_ubo("globalsBlock", &res.globals_buf);
call_buf.end_sync(pass, shapes.metaball_wire_circle);

View File

@ -24,12 +24,12 @@ template<typename SelectEngineT> class Prepass {
PassMain prepass_in_front_ps_ = {"prepass_in_front"};
public:
void begin_sync(const State &state)
void begin_sync(ResourcesT &res, const State &state)
{
auto init_pass = [&](PassMain &pass) {
pass.init();
pass.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state);
pass.shader_set(OVERLAY_shader_depth_only());
pass.shader_set(res.shaders.depth_mesh);
};
init_pass(prepass_ps_);
init_pass(prepass_in_front_ps_);

View File

@ -16,6 +16,7 @@
#include "draw_handle.hh"
#include "overlay_shader.hh"
#include "overlay_shader_shared.h"
#ifdef __APPLE__
@ -64,6 +65,8 @@ using blender::draw::TextureFromPool;
using blender::draw::TextureRef;
template<typename SelectEngineT> struct Resources : public SelectEngineT::SelectMap {
ShaderModule<SelectEngineT> &shaders;
Framebuffer overlay_fb = {"overlay_fb"};
Framebuffer overlay_in_front_fb = {"overlay_in_front_fb"};
Framebuffer overlay_color_only_fb = {"overlay_color_only_fb"};
@ -83,6 +86,8 @@ template<typename SelectEngineT> struct Resources : public SelectEngineT::Select
TextureRef color_overlay_tx;
TextureRef color_render_tx;
Resources(ShaderModule<SelectEngineT> &shader_module) : shaders(shader_module){};
[[nodiscard]] ThemeColorID object_wire_theme_id(const ObjectRef &ob_ref,
const State &state) const
{

View File

@ -14,6 +14,7 @@
#include "gpu_shader_create_info.hh"
#include "overlay_private.hh"
#include "overlay_shader.hh"
struct OVERLAY_Shaders {
GPUShader *antialiasing;
@ -1231,3 +1232,19 @@ void OVERLAY_shader_free(void)
MEM_SAFE_FREE(*format);
}
}
namespace blender::draw::overlay {
template<>
ShaderModule<select::EngineEmpty> *ShaderModule<select::EngineEmpty>::g_shader_module = nullptr;
template<>
ShaderModule<select::EngineObject> *ShaderModule<select::EngineObject>::g_shader_module = nullptr;
void shader_module_free()
{
ShaderModule<select::EngineEmpty>::module_free();
ShaderModule<select::EngineObject>::module_free();
}
} // namespace blender::draw::overlay

View File

@ -0,0 +1,150 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup overlay
*/
#pragma once
#include <functional>
#include "GPU_shader.h"
#include "gpu_shader_create_info.hh"
#include "../select/select_empty.hh"
#include "../select/select_object.hh"
namespace blender::draw::overlay {
/**
* Shader module. Shared between instances.
*/
template<typename SelectEngineT, bool ClippingEnabled = false> class ShaderModule {
private:
/** Shared shader module across all engine instances. */
static ShaderModule *g_shader_module;
/** TODO: Support clipping. This global state should be set by the overlay::Instance and switch
* to the shader variations that use clipping. */
// bool clipping_enabled = false;
class Shader {
protected:
GPUShader *shader_ = nullptr;
public:
Shader() = default;
Shader(const char *create_info_name)
: shader_(GPU_shader_create_from_info_name(create_info_name)){};
~Shader()
{
DRW_SHADER_FREE_SAFE(shader_);
}
operator GPUShader *()
{
return shader_;
}
};
/**
* Special class for every shader that needs to have clipped and selection variations.
*/
class ShaderGeometry : public Shader {
public:
ShaderGeometry(const char *create_info_name)
{
/* TODO: This is what it should be like with all variations defined with create infos. */
// std::string create_info_name = base_create_info;
// create_info_name += SelectEngineT::shader_suffix;
// create_info_name += ClippingEnabled ? "_clipped" : "";
// this->shader_ = GPU_shader_create_from_info_name(create_info_name.c_str());
/* WORKAROUND: ... but for now, we have to patch the create info used by the old engine. */
gpu::shader::ShaderCreateInfo info =
*reinterpret_cast<const gpu::shader::ShaderCreateInfo *>(
GPU_shader_create_info_get(create_info_name));
info.define(SelectEngineT::shader_define);
this->shader_ = GPU_shader_create_from_info(
reinterpret_cast<const GPUShaderCreateInfo *>(&info));
}
/* WORKAROUND: Create a shader using a patch function to patch the create info. */
ShaderGeometry(const char *create_info_name,
std::function<void(gpu::shader::ShaderCreateInfo &info)> patch)
{
gpu::shader::ShaderCreateInfo info =
*reinterpret_cast<const gpu::shader::ShaderCreateInfo *>(
GPU_shader_create_info_get(create_info_name));
patch(info);
info.define(SelectEngineT::shader_define);
this->shader_ = GPU_shader_create_from_info(
reinterpret_cast<const GPUShaderCreateInfo *>(&info));
}
};
public:
/** ShaderGeometry */
ShaderGeometry armature_sphere_outline = {
"overlay_armature_sphere_outline", [](gpu::shader::ShaderCreateInfo &info) {
using namespace blender::gpu::shader;
info.storage_buf(0, Qualifier::READ, "mat4", "data_buf[]");
info.define("inst_obmat", "data_buf[gl_InstanceID]");
info.vertex_inputs_.pop_last();
}};
ShaderGeometry depth_mesh = {"overlay_depth_only", [](gpu::shader::ShaderCreateInfo &info) {
using namespace blender::gpu::shader;
info.additional_infos_.clear();
info.additional_info(
"draw_view", "draw_modelmat_new", "draw_resource_handle_new");
}};
ShaderGeometry extra_shape = {
"overlay_extra", [](gpu::shader::ShaderCreateInfo &info) {
using namespace blender::gpu::shader;
info.storage_buf(0, Qualifier::READ, "ExtraInstanceData", "data_buf[]");
info.define("color", "data_buf[gl_InstanceID].color_");
info.define("inst_obmat", "data_buf[gl_InstanceID].object_to_world_");
info.vertex_inputs_.pop_last();
info.vertex_inputs_.pop_last();
}};
/** Shader */
Shader grid = {"overlay_grid"};
Shader background_fill = {"overlay_background"};
Shader background_clip_bound = {"overlay_clipbound"};
/** Only to be used by Instance constructor. */
static ShaderModule &module_get()
{
if (g_shader_module == nullptr) {
/* TODO(@fclem) thread-safety. */
g_shader_module = new ShaderModule();
}
return *g_shader_module;
}
static void module_free()
{
if (g_shader_module != nullptr) {
/* TODO(@fclem) thread-safety. */
delete g_shader_module;
g_shader_module = nullptr;
}
}
};
void shader_module_free();
} // namespace blender::draw::overlay

View File

@ -17,6 +17,8 @@ struct EngineEmpty {
/* Add type safety to selection ID. Only the select engine should provide them. */
struct ID {};
static constexpr const char *shader_define = "NO_SELECT";
struct SelectBuf {
void select_clear(){};
void select_append(ID){};

View File

@ -12,6 +12,7 @@
#include "DRW_gpu_wrapper.hh"
#include "draw_manager.hh"
#include "draw_pass.hh"
namespace blender::draw::select {
@ -21,6 +22,8 @@ struct EngineObject {
uint32_t value;
};
static constexpr const char *shader_define = "SELECT_OBJECT";
/**
* Add a dedicated selection id buffer to a pass.
* Use this when not using a #PassMain which can pass the select ID via CustomID.