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 235 additions and 120 deletions
Showing only changes of commit 84ff44769f - Show all commits

View File

@ -19,12 +19,14 @@
namespace blender::draw::overlay {
class Background {
template<typename SelectEngineT> class Background {
using ResourcesT = Resources<SelectEngineT>;
private:
PassSimple bg_ps_ = {"Background"};
public:
void begin_sync(Resources &res, const State &state)
void begin_sync(ResourcesT &res, const State &state)
{
DRWState pass_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_BACKGROUND;
float4 color_override(0.0f, 0.0f, 0.0f, 0.0f);
@ -92,7 +94,7 @@ class Background {
}
}
void draw(Resources &res, Manager &manager)
void draw(ResourcesT &res, Manager &manager)
{
GPU_framebuffer_bind(res.overlay_color_only_fb);
manager.submit(bg_ps_);

View File

@ -15,14 +15,15 @@
namespace blender::draw::overlay {
class Empties {
template<typename SelectEngineT> class Empties {
using SelectID = typename SelectEngineT::ID;
using ResourcesT = Resources<SelectEngineT>;
using EmptyInstanceBuf = ShapeInstanceBuf<SelectEngineT, ExtraInstanceData>;
private:
PassSimple empty_ps_ = {"Empties"};
PassSimple empty_in_front_ps_ = {"Empties_In_front"};
using EmptyInstanceBuf = StorageVectorBuffer<ExtraInstanceData>;
struct CallBuffers {
EmptyInstanceBuf plain_axes_buf = {"plain_axes_buf"};
EmptyInstanceBuf single_arrow_buf = {"single_arrow_buf"};
@ -49,7 +50,7 @@ class Empties {
}
}
void object_sync(const ObjectRef &ob_ref, const Resources &res, const State &state)
void object_sync(const ObjectRef &ob_ref, ResourcesT &res, const State &state)
{
CallBuffers &call_bufs = call_buffers_[int((ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0)];
@ -57,36 +58,39 @@ class Empties {
ExtraInstanceData data(
float4x4(ob_ref.object->object_to_world), color, ob_ref.object->empty_drawsize);
/* TODO(fclem): Get selection ID from the selection engine. */
const SelectID select_id = res.select_id(ob_ref);
switch (ob_ref.object->empty_drawtype) {
case OB_PLAINAXES:
call_bufs.plain_axes_buf.append(data);
call_bufs.plain_axes_buf.append(data, select_id);
break;
case OB_SINGLE_ARROW:
call_bufs.single_arrow_buf.append(data);
call_bufs.single_arrow_buf.append(data, select_id);
break;
case OB_CUBE:
call_bufs.cube_buf.append(data);
call_bufs.cube_buf.append(data, select_id);
break;
case OB_CIRCLE:
call_bufs.circle_buf.append(data);
call_bufs.circle_buf.append(data, select_id);
break;
case OB_EMPTY_SPHERE:
call_bufs.sphere_buf.append(data);
call_bufs.sphere_buf.append(data, select_id);
break;
case OB_EMPTY_CONE:
call_bufs.cone_buf.append(data);
call_bufs.cone_buf.append(data, select_id);
break;
case OB_ARROWS:
call_bufs.arrows_buf.append(data);
call_bufs.arrows_buf.append(data, select_id);
break;
case OB_EMPTY_IMAGE:
/* This only show the frame. See OVERLAY_image_empty_cache_populate() for the image. */
call_bufs.image_buf.append(data);
call_bufs.image_buf.append(data, select_id);
break;
}
}
void end_sync(Resources &res, ShapeCache &shapes, const State &state)
void end_sync(ResourcesT &res, ShapeCache &shapes, const State &state)
{
auto init_pass = [&](PassSimple &pass, CallBuffers &call_bufs) {
pass.init();
@ -95,49 +99,26 @@ class Empties {
pass.shader_set(OVERLAY_shader_extra(false));
pass.bind_ubo("globalsBlock", &res.globals_buf);
call_bufs.plain_axes_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.plain_axes_buf);
pass.draw(shapes.plain_axes, call_bufs.plain_axes_buf.size());
call_bufs.single_arrow_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.single_arrow_buf);
pass.draw(shapes.single_arrow, call_bufs.single_arrow_buf.size());
call_bufs.cube_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.cube_buf);
pass.draw(shapes.cube, call_bufs.cube_buf.size());
call_bufs.circle_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.circle_buf);
pass.draw(shapes.circle, call_bufs.circle_buf.size());
call_bufs.sphere_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.sphere_buf);
pass.draw(shapes.empty_sphere, call_bufs.sphere_buf.size());
call_bufs.cone_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.cone_buf);
pass.draw(shapes.empty_cone, call_bufs.cone_buf.size());
call_bufs.arrows_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.arrows_buf);
pass.draw(shapes.arrows, call_bufs.arrows_buf.size());
call_bufs.image_buf.push_update();
pass.bind_ssbo("data_buf", &call_bufs.image_buf);
pass.draw(shapes.quad_wire, call_bufs.image_buf.size());
call_bufs.plain_axes_buf.end_sync(pass, shapes.plain_axes);
call_bufs.single_arrow_buf.end_sync(pass, shapes.single_arrow);
call_bufs.cube_buf.end_sync(pass, shapes.cube);
call_bufs.circle_buf.end_sync(pass, shapes.circle);
call_bufs.sphere_buf.end_sync(pass, shapes.empty_sphere);
call_bufs.cone_buf.end_sync(pass, shapes.empty_cone);
call_bufs.arrows_buf.end_sync(pass, shapes.arrows);
call_bufs.image_buf.end_sync(pass, shapes.quad_wire);
};
init_pass(empty_ps_, call_buffers_[0]);
init_pass(empty_in_front_ps_, call_buffers_[1]);
}
void draw(Resources &res, Manager &manager, View &view)
void draw(ResourcesT &res, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_fb);
manager.submit(empty_ps_, view);
}
void draw_in_front(Resources &res, Manager &manager, View &view)
void draw_in_front(ResourcesT &res, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_in_front_fb);
manager.submit(empty_in_front_ps_, view);

View File

@ -30,6 +30,10 @@
#include "overlay_engine.h"
#include "overlay_private.hh"
using namespace blender::draw;
using Instance = blender::draw::overlay::Instance<>;
/* -------------------------------------------------------------------- */
/** \name Engine Callbacks
* \{ */
@ -51,7 +55,7 @@ static void OVERLAY_engine_init(void *vedata)
/* Allocate instance. */
if (data->instance == nullptr) {
data->instance = new blender::draw::overlay::Instance();
data->instance = new Instance();
}
OVERLAY_PrivateData *pd = stl->pd;
@ -737,7 +741,7 @@ static void OVERLAY_engine_free()
static void OVERLAY_instance_free(void *instance_)
{
blender::draw::overlay::Instance *instance = (blender::draw::overlay::Instance *)instance_;
auto *instance = (Instance *)instance_;
if (instance != nullptr) {
delete instance;
}
@ -748,8 +752,6 @@ static void OVERLAY_instance_free(void *instance_)
/** \name Engine Instance
* \{ */
using namespace blender::draw;
static void OVERLAY_next_engine_init(void *vedata)
{
if (!GPU_shader_storage_buffer_objects_support()) {
@ -759,10 +761,10 @@ static void OVERLAY_next_engine_init(void *vedata)
OVERLAY_Data *ved = reinterpret_cast<OVERLAY_Data *>(vedata);
if (ved->instance == nullptr) {
ved->instance = new overlay::Instance();
ved->instance = new Instance();
}
ved->instance->init();
reinterpret_cast<Instance *>(ved->instance)->init();
}
static void OVERLAY_next_cache_init(void *vedata)
@ -770,7 +772,7 @@ static void OVERLAY_next_cache_init(void *vedata)
if (!GPU_shader_storage_buffer_objects_support()) {
return;
}
reinterpret_cast<OVERLAY_Data *>(vedata)->instance->begin_sync();
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)->begin_sync();
}
static void OVERLAY_next_cache_populate(void *vedata, Object *object)
@ -783,7 +785,8 @@ static void OVERLAY_next_cache_populate(void *vedata, Object *object)
ref.dupli_object = DRW_object_get_dupli(object);
ref.dupli_parent = DRW_object_get_dupli_parent(object);
reinterpret_cast<OVERLAY_Data *>(vedata)->instance->object_sync(ref);
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)
->object_sync(ref);
}
static void OVERLAY_next_cache_finish(void *vedata)
@ -791,7 +794,7 @@ static void OVERLAY_next_cache_finish(void *vedata)
if (!GPU_shader_storage_buffer_objects_support()) {
return;
}
reinterpret_cast<OVERLAY_Data *>(vedata)->instance->end_sync();
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)->end_sync();
}
static void OVERLAY_next_draw_scene(void *vedata)
@ -800,7 +803,8 @@ static void OVERLAY_next_draw_scene(void *vedata)
return;
}
reinterpret_cast<OVERLAY_Data *>(vedata)->instance->draw(*DRW_manager_get());
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)
->draw(*DRW_manager_get());
}
/** \} */

View File

@ -20,6 +20,10 @@
#include "overlay_instance.hh"
#include "overlay_private.hh"
using namespace blender::draw;
using Instance = blender::draw::overlay::Instance<>;
BLI_STATIC_ASSERT(SI_GRID_STEPS_LEN == OVERLAY_GRID_STEPS_LEN, "")
void OVERLAY_grid_init(OVERLAY_Data *vedata)
@ -226,10 +230,11 @@ void OVERLAY_grid_cache_init(OVERLAY_Data *ved)
return;
}
if (ved->instance->grid_ubo == nullptr) {
ved->instance->grid_ubo = GPU_uniformbuf_create(sizeof(OVERLAY_GridData));
GPUUniformBuf *&grid_ubo = reinterpret_cast<Instance *>(ved->instance)->grid_ubo;
if (grid_ubo == nullptr) {
grid_ubo = GPU_uniformbuf_create(sizeof(OVERLAY_GridData));
}
GPU_uniformbuf_update(ved->instance->grid_ubo, &pd->grid_data);
GPU_uniformbuf_update(grid_ubo, &pd->grid_data);
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA;
DRW_PASS_CREATE(psl->grid_ps, state);
@ -259,7 +264,7 @@ void OVERLAY_grid_cache_init(OVERLAY_Data *ved)
/* Create 3 quads to render ordered transparency Z axis */
grp = DRW_shgroup_create(sh, psl->grid_ps);
DRW_shgroup_uniform_block(grp, "grid_buf", ved->instance->grid_ubo);
DRW_shgroup_uniform_block(grp, "grid_buf", grid_ubo);
DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo);
DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &dtxl->depth);

View File

@ -18,7 +18,9 @@
namespace blender::draw::overlay {
class Grid {
template<typename SelectEngineT> class Grid {
using ResourcesT = Resources<SelectEngineT>;
private:
UniformBuffer<OVERLAY_GridData> data_;
@ -164,7 +166,7 @@ class Grid {
data_.push_update();
}
void begin_sync(Resources &res, const State &state, const View &view)
void begin_sync(ResourcesT &res, const State &state, const View &view)
{
this->update_ubo(state, view);
@ -195,7 +197,7 @@ class Grid {
}
}
void draw(Resources &res, Manager &manager, View &view)
void draw(ResourcesT &res, Manager &manager, View &view)
{
if (!enabled_) {
return;

View File

@ -10,7 +10,7 @@
namespace blender::draw::overlay {
void Instance::init()
template<typename T> void Instance<T>::init()
{
resources.depth_tx.wrap(DRW_viewport_texture_list_get()->depth);
resources.depth_in_front_tx.wrap(DRW_viewport_texture_list_get()->depth_in_front);
@ -65,7 +65,7 @@ void Instance::init()
resources.theme_settings = G_draw.block;
}
void Instance::begin_sync()
template<typename T> void Instance<T>::begin_sync()
{
const DRWView *view_legacy = DRW_view_default_get();
View view("OverlayView", view_legacy);
@ -76,7 +76,7 @@ void Instance::begin_sync()
grid.begin_sync(resources, state, view);
}
void Instance::object_sync(ObjectRef &ob_ref)
template<typename T> void Instance<T>::object_sync(ObjectRef &ob_ref)
{
const bool in_edit_mode = object_is_edit_mode(ob_ref.object);
@ -120,13 +120,13 @@ void Instance::object_sync(ObjectRef &ob_ref)
}
}
void Instance::end_sync()
template<typename T> void Instance<T>::end_sync()
{
metaballs.end_sync(resources, state);
empties.end_sync(resources, shapes, state);
}
void Instance::draw(Manager &manager)
template<typename T> void Instance<T>::draw(Manager &manager)
{
/* WORKAROUND: This is to prevent crashes when using depth picking or selection.
* The selection engine should handle theses cases instead. */
@ -182,4 +182,11 @@ void Instance::draw(Manager &manager)
resources.depth_in_front_alloc_tx.release();
}
/* Instantiation. */
template void Instance<>::init();
template void Instance<>::begin_sync();
template void Instance<>::object_sync(ObjectRef &ob_ref);
template void Instance<>::end_sync();
template void Instance<>::draw(Manager &manager);
} // namespace blender::draw::overlay

View File

@ -14,6 +14,9 @@
#include "overlay_metaball.hh"
#include "overlay_shape.hh"
#include "../select/select_empty.hh"
#include "../select/select_object.hh"
namespace blender::draw::overlay {
class ShaderCache {
@ -22,32 +25,12 @@ class ShaderCache {
int clipping_enabled = 0;
};
class SceneResources {
ShaderCache shaders;
// UniformBuffer<ThemeColorData> theme_colors;
// Texture color_ramp = {"color_ramp"};
void weight_ramp_init()
{
/* Weight Painting color ramp texture */
// bool user_weight_ramp = (U.flag & USER_CUSTOM_RANGE) != 0;
// if (weight_ramp_custom != user_weight_ramp ||
// (user_weight_ramp && memcmp(&weight_ramp_copy, &U.coba_weight, sizeof(ColorBand)) != 0))
// {
// DRW_TEXTURE_FREE_SAFE(G_draw.weight_ramp);
// }
// if (G_draw.weight_ramp == NULL) {
// weight_ramp_custom = user_weight_ramp;
// memcpy(&weight_ramp_copy, &U.coba_weight, sizeof(ColorBand));
// G_draw.weight_ramp = DRW_create_weight_colorramp_texture();
// }
}
};
template<
/* Selection engine reuse most of the Overlay engine by creating selection IDs for each
* selectable component and using a special shaders for drawing.
* Making the select engine templated makes it easier to phase out any overhead of the
* selection for the regular non-selection case.*/
typename SelectEngineT = select::EngineEmpty>
class Instance {
public:
ShaderCache shaders;
@ -57,14 +40,14 @@ class Instance {
GPUUniformBuf *grid_ubo = nullptr;
/** Global types. */
Resources resources;
Resources<SelectEngineT> resources;
State state;
/** Overlay types. */
Background background;
Metaballs metaballs;
Empties empties;
Grid grid;
Background<SelectEngineT> background;
Metaballs<SelectEngineT> metaballs;
Empties<SelectEngineT> empties;
Grid<SelectEngineT> grid;
~Instance()
{
@ -109,4 +92,11 @@ class Instance {
}
};
/* Instantiation. */
extern template void Instance<>::init();
extern template void Instance<>::begin_sync();
extern template void Instance<>::object_sync(ObjectRef &ob_ref);
extern template void Instance<>::end_sync();
extern template void Instance<>::draw(Manager &manager);
} // namespace blender::draw::overlay

View File

@ -19,7 +19,8 @@
namespace blender::draw::overlay {
class Metaballs {
template<typename SelectEngineT> class Metaballs {
using ResourcesT = Resources<SelectEngineT>;
private:
PassSimple metaball_ps_ = {"MetaBalls"};
@ -50,7 +51,7 @@ class Metaballs {
OVERLAY_bone_instance_data_set_color(data, color);
}
void edit_object_sync(const ObjectRef &ob_ref, const Resources &res)
void edit_object_sync(const ObjectRef &ob_ref, const ResourcesT &res)
{
ArmatureSphereBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ?
data_in_front_buf_ :
@ -79,7 +80,7 @@ class Metaballs {
}
}
void object_sync(const ObjectRef &ob_ref, const Resources &res, const State &state)
void object_sync(const ObjectRef &ob_ref, const ResourcesT &res, const State &state)
{
ArmatureSphereBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ?
data_in_front_buf_ :
@ -96,7 +97,7 @@ class Metaballs {
}
}
void end_sync(Resources &res, const State &state)
void end_sync(ResourcesT &res, const State &state)
{
auto init_pass = [&](PassSimple &pass, ArmatureSphereBuf &data_buf) {
data_buf.push_update();
@ -113,13 +114,13 @@ class Metaballs {
init_pass(metaball_in_front_ps_, data_in_front_buf_);
}
void draw(Resources &res, Manager &manager, View &view)
void draw(ResourcesT &res, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_fb);
manager.submit(metaball_ps_, view);
}
void draw_in_front(Resources &res, Manager &manager, View &view)
void draw_in_front(ResourcesT &res, Manager &manager, View &view)
{
GPU_framebuffer_bind(res.overlay_line_in_front_fb);
manager.submit(metaball_in_front_ps_, view);

View File

@ -18,10 +18,6 @@
#include "overlay_shader_shared.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __APPLE__
# define USE_GEOM_SHADER_WORKAROUND 1
#else
@ -35,7 +31,7 @@ extern "C" {
struct ImBuf;
namespace blender::draw::overlay {
class Instance;
template<typename SelectEngineT> class Instance;
struct State {
Depsgraph *depsgraph;
@ -68,7 +64,7 @@ using blender::draw::TextureFromPool;
using blender::draw::TextureRef;
using ArmatureSphereBuf = StorageVectorBuffer<float4x4>;
struct Resources {
template<typename SelectEngineT> struct Resources : public SelectEngineT::SelectMap {
Framebuffer overlay_fb = {"overlay_fb"};
Framebuffer overlay_in_front_fb = {"overlay_in_front_fb"};
Framebuffer overlay_color_only_fb = {"overlay_color_only_fb"};
@ -578,7 +574,7 @@ typedef struct OVERLAY_Data {
OVERLAY_PassList *psl;
OVERLAY_StorageList *stl;
blender::draw::overlay::Instance *instance;
void *instance;
} OVERLAY_Data;
typedef struct OVERLAY_DupliData {
@ -927,7 +923,3 @@ GPUShader *OVERLAY_shader_xray_fade(void);
OVERLAY_InstanceFormats *OVERLAY_shader_instance_formats_get(void);
void OVERLAY_shader_free(void);
#ifdef __cplusplus
}
#endif

View File

@ -192,7 +192,6 @@ struct ThemeColorData {
};
BLI_STATIC_ASSERT_ALIGN(ThemeColorData, 16)
/* TODO Move to overlay engine. */
struct ExtraInstanceData {
float4 color_;
float4x4 object_to_world_;

View File

@ -12,6 +12,41 @@
namespace blender::draw::overlay {
/**
* Buffer containing instances of a certain shape.
*/
template<typename SelectEngineT, typename InstanceDataT>
struct ShapeInstanceBuf : private SelectEngineT::SelectBuf {
using SelectID = typename SelectEngineT::ID;
StorageVectorBuffer<InstanceDataT> data_buf;
ShapeInstanceBuf(const char *name = nullptr) : data_buf(name){};
void clear()
{
this->select_clear();
data_buf.clear();
}
void append(const InstanceDataT &data, SelectID select_id)
{
this->select_append(select_id);
data_buf.append(data);
}
void end_sync(PassSimple &pass, GPUBatch *shape)
{
if (data_buf.size() == 0) {
return;
}
this->select_bind(pass);
data_buf.push_update();
pass.bind_ssbo("data_buf", &data_buf);
pass.draw(shape, data_buf.size());
}
};
/**
* Contains all overlay generic geometry batches.
*/

View File

@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2023 Blender Foundation. */
/** \file
* \ingroup draw_engine
*
* Dummy implementation of the select engine types to avoid any overhead.
*/
#pragma once
#include "draw_manager.hh"
namespace blender::draw::select {
struct EngineEmpty {
/* Add type safety to selection ID. Only the select engine should provide them. */
struct ID {};
struct SelectBuf {
void select_clear(){};
void select_append(ID){};
void select_bind(PassSimple &){};
};
struct SelectMap {
[[nodiscard]] constexpr ID select_id(const ObjectRef &)
{
return {};
}
};
};
} // namespace blender::draw::select

View File

@ -0,0 +1,63 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2023 Blender Foundation. */
/** \file
* \ingroup draw_engine
*
* This is an implementation of the Select engine specialized for selecting object.
* Should plug seamlessly inside the overlay engine logic.
*/
#pragma once
#include "DRW_gpu_wrapper.hh"
#include "draw_manager.hh"
namespace blender::draw::select {
struct EngineObject {
/* Add type safety to selection ID. Only the select engine should provide them. */
struct ID {
uint32_t value;
};
/**
* Add a dedicated selection id buffer to a pass.
* Use this when not using a #PassMain which can pass the select ID via CustomID.
*/
struct SelectBuf {
StorageVectorBuffer<uint32_t> select_buf = {"select_buf"};
void select_clear()
{
select_buf.clear();
}
void select_append(ID select_id)
{
select_buf.append(select_id.value);
}
void select_bind(PassSimple &pass)
{
select_buf.push_update();
pass.bind_ssbo("select_buf", &select_buf);
}
};
/**
* Generate selection IDs from objects and keep record of the mapping between them.
*/
struct SelectMap {
uint next_id = 0;
Map<uint, ObjectRef> map;
[[nodiscard]] const ID select_id(const ObjectRef &)
{
/* TODO Insert Ref into the map. */
return {next_id++};
}
};
};
} // namespace blender::draw::select