Overlay-Next: Initial implementation #107045
|
@ -191,6 +191,7 @@ set(SRC
|
||||||
engines/gpencil/gpencil_shader_fx.c
|
engines/gpencil/gpencil_shader_fx.c
|
||||||
engines/select/select_draw_utils.c
|
engines/select/select_draw_utils.c
|
||||||
engines/select/select_engine.c
|
engines/select/select_engine.c
|
||||||
|
engines/select/select_instance.cc
|
||||||
engines/overlay/overlay_antialiasing.cc
|
engines/overlay/overlay_antialiasing.cc
|
||||||
engines/overlay/overlay_armature.cc
|
engines/overlay/overlay_armature.cc
|
||||||
engines/overlay/overlay_background.cc
|
engines/overlay/overlay_background.cc
|
||||||
|
|
|
@ -12,11 +12,6 @@ namespace blender::draw::overlay {
|
||||||
|
|
||||||
template<typename T> void Instance<T>::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);
|
|
||||||
resources.color_overlay_tx.wrap(DRW_viewport_texture_list_get()->color_overlay);
|
|
||||||
resources.color_render_tx.wrap(DRW_viewport_texture_list_get()->color);
|
|
||||||
|
|
||||||
/* TODO(fclem): Remove DRW global usage. */
|
/* TODO(fclem): Remove DRW global usage. */
|
||||||
const DRWContextState *ctx = DRW_context_state_get();
|
const DRWContextState *ctx = DRW_context_state_get();
|
||||||
/* Was needed by `object_wire_theme_id()` when doing the port. Not sure if needed nowadays. */
|
/* Was needed by `object_wire_theme_id()` when doing the port. Not sure if needed nowadays. */
|
||||||
|
@ -146,26 +141,41 @@ template<typename T> void Instance<T>::end_sync()
|
||||||
|
|
||||||
template<typename T> void Instance<T>::draw(Manager &manager)
|
template<typename T> void Instance<T>::draw(Manager &manager)
|
||||||
{
|
{
|
||||||
/* WORKAROUND: This is to prevent crashes when using depth picking or selection.
|
resources.depth_tx.wrap(DRW_viewport_texture_list_get()->depth);
|
||||||
* The selection engine should handle theses cases instead. */
|
resources.depth_in_front_tx.wrap(DRW_viewport_texture_list_get()->depth_in_front);
|
||||||
if (!DRW_state_is_fbo()) {
|
resources.color_overlay_tx.wrap(DRW_viewport_texture_list_get()->color_overlay);
|
||||||
return;
|
resources.color_render_tx.wrap(DRW_viewport_texture_list_get()->color);
|
||||||
}
|
|
||||||
|
|
||||||
int2 render_size = int2(resources.depth_tx.size());
|
int2 render_size = int2(resources.depth_tx.size());
|
||||||
|
|
||||||
const DRWView *view_legacy = DRW_view_default_get();
|
const DRWView *view_legacy = DRW_view_default_get();
|
||||||
View view("OverlayView", view_legacy);
|
View view("OverlayView", view_legacy);
|
||||||
|
|
||||||
resources.line_tx.acquire(render_size, GPU_RGBA8);
|
/* TODO: Better semantical switch? */
|
||||||
|
if (!resources.color_overlay_tx.is_valid()) {
|
||||||
|
/* Likely to be the selection case. Allocate dummy texture and bind only depth buffer. */
|
||||||
|
resources.line_tx.acquire(int2(1, 1), GPU_RGBA8);
|
||||||
|
resources.color_overlay_alloc_tx.acquire(int2(1, 1), GPU_SRGB8_A8);
|
||||||
|
resources.color_render_alloc_tx.acquire(int2(1, 1), GPU_SRGB8_A8);
|
||||||
|
|
||||||
resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx),
|
resources.color_overlay_tx.wrap(resources.color_overlay_alloc_tx);
|
||||||
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx));
|
resources.color_render_tx.wrap(resources.color_render_alloc_tx);
|
||||||
resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx),
|
|
||||||
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx),
|
resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx));
|
||||||
GPU_ATTACHMENT_TEXTURE(resources.line_tx));
|
resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx));
|
||||||
resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE,
|
resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE);
|
||||||
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx));
|
}
|
||||||
|
else {
|
||||||
|
resources.line_tx.acquire(render_size, GPU_RGBA8);
|
||||||
|
|
||||||
|
resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx),
|
||||||
|
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx));
|
||||||
|
resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx),
|
||||||
|
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx),
|
||||||
|
GPU_ATTACHMENT_TEXTURE(resources.line_tx));
|
||||||
|
resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE,
|
||||||
|
GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx));
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO(fclem): Remove mandatory allocation. */
|
/* TODO(fclem): Remove mandatory allocation. */
|
||||||
if (!resources.depth_in_front_tx.is_valid()) {
|
if (!resources.depth_in_front_tx.is_valid()) {
|
||||||
|
@ -201,6 +211,8 @@ template<typename T> void Instance<T>::draw(Manager &manager)
|
||||||
|
|
||||||
resources.line_tx.release();
|
resources.line_tx.release();
|
||||||
resources.depth_in_front_alloc_tx.release();
|
resources.depth_in_front_alloc_tx.release();
|
||||||
|
resources.color_overlay_alloc_tx.release();
|
||||||
|
resources.color_render_alloc_tx.release();
|
||||||
|
|
||||||
resources.read_result();
|
resources.read_result();
|
||||||
}
|
}
|
||||||
|
@ -212,6 +224,12 @@ template void Instance<>::object_sync(ObjectRef &ob_ref, Manager &manager);
|
||||||
template void Instance<>::end_sync();
|
template void Instance<>::end_sync();
|
||||||
template void Instance<>::draw(Manager &manager);
|
template void Instance<>::draw(Manager &manager);
|
||||||
|
|
||||||
|
template void Instance<select::Instance>::init();
|
||||||
|
template void Instance<select::Instance>::begin_sync();
|
||||||
|
template void Instance<select::Instance>::object_sync(ObjectRef &ob_ref, Manager &manager);
|
||||||
|
template void Instance<select::Instance>::end_sync();
|
||||||
|
template void Instance<select::Instance>::draw(Manager &manager);
|
||||||
|
|
||||||
} // namespace blender::draw::overlay
|
} // namespace blender::draw::overlay
|
||||||
|
|
||||||
/* TODO(fclem): Move elsewhere. */
|
/* TODO(fclem): Move elsewhere. */
|
||||||
|
|
|
@ -24,7 +24,7 @@ template<
|
||||||
* selectable component and using a special shaders for drawing.
|
* selectable component and using a special shaders for drawing.
|
||||||
* Making the select engine templated makes it easier to phase out any overhead of the
|
* Making the select engine templated makes it easier to phase out any overhead of the
|
||||||
* selection for the regular non-selection case.*/
|
* selection for the regular non-selection case.*/
|
||||||
typename SelectEngineT = select::Instance>
|
typename SelectEngineT = select::InstanceDummy>
|
||||||
class Instance {
|
class Instance {
|
||||||
public:
|
public:
|
||||||
/* WORKAROUND: Legacy. Move to grid pass. */
|
/* WORKAROUND: Legacy. Move to grid pass. */
|
||||||
|
@ -93,4 +93,10 @@ extern template void Instance<>::object_sync(ObjectRef &ob_ref, Manager &manager
|
||||||
extern template void Instance<>::end_sync();
|
extern template void Instance<>::end_sync();
|
||||||
extern template void Instance<>::draw(Manager &manager);
|
extern template void Instance<>::draw(Manager &manager);
|
||||||
|
|
||||||
|
extern template void Instance<select::Instance>::init();
|
||||||
|
extern template void Instance<select::Instance>::begin_sync();
|
||||||
|
extern template void Instance<select::Instance>::object_sync(ObjectRef &ob_ref, Manager &manager);
|
||||||
|
extern template void Instance<select::Instance>::end_sync();
|
||||||
|
extern template void Instance<select::Instance>::draw(Manager &manager);
|
||||||
|
|
||||||
} // namespace blender::draw::overlay
|
} // namespace blender::draw::overlay
|
||||||
|
|
|
@ -75,6 +75,8 @@ template<typename SelectEngineT> struct Resources : public SelectEngineT::Select
|
||||||
|
|
||||||
TextureFromPool line_tx = {"line_tx"};
|
TextureFromPool line_tx = {"line_tx"};
|
||||||
TextureFromPool depth_in_front_alloc_tx = {"overlay_depth_in_front_tx"};
|
TextureFromPool depth_in_front_alloc_tx = {"overlay_depth_in_front_tx"};
|
||||||
|
TextureFromPool color_overlay_alloc_tx = {"overlay_color_overlay_alloc_tx"};
|
||||||
|
TextureFromPool color_render_alloc_tx = {"overlay_color_render_alloc_tx"};
|
||||||
|
|
||||||
/** TODO(fclem): Copy of G_data.block that should become theme colors only and managed by the
|
/** TODO(fclem): Copy of G_data.block that should become theme colors only and managed by the
|
||||||
* engine. */
|
* engine. */
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* select_engine.c */
|
/* select_engine.c */
|
||||||
|
|
||||||
extern DrawEngineType draw_engine_select_type;
|
extern DrawEngineType draw_engine_select_type;
|
||||||
|
@ -22,3 +26,11 @@ struct SELECTID_Context *DRW_select_engine_context_get(void);
|
||||||
|
|
||||||
struct GPUFrameBuffer *DRW_engine_select_framebuffer_get(void);
|
struct GPUFrameBuffer *DRW_engine_select_framebuffer_get(void);
|
||||||
struct GPUTexture *DRW_engine_select_texture_get(void);
|
struct GPUTexture *DRW_engine_select_texture_get(void);
|
||||||
|
|
||||||
|
/* select_instance.cc */
|
||||||
|
|
||||||
|
extern DrawEngineType draw_engine_select_next_type;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* \ingroup select
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DRW_render.h"
|
||||||
|
|
||||||
|
#include "GPU_capabilities.h"
|
||||||
|
|
||||||
|
#include "select_engine.h"
|
||||||
|
|
||||||
|
#include "../overlay/overlay_instance.hh"
|
||||||
|
#include "select_instance.hh"
|
||||||
|
|
||||||
|
using namespace blender::draw;
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Select-Next Engine
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
using Instance = overlay::Instance<select::Instance>;
|
||||||
|
|
||||||
|
typedef struct SELECT_NextData {
|
||||||
|
void *engine_type;
|
||||||
|
DRWViewportEmptyList *fbl;
|
||||||
|
DRWViewportEmptyList *txl;
|
||||||
|
DRWViewportEmptyList *psl;
|
||||||
|
DRWViewportEmptyList *stl;
|
||||||
|
|
||||||
|
Instance *instance;
|
||||||
|
} SELECT_NextData;
|
||||||
|
|
||||||
|
static void SELECT_next_engine_init(void *vedata)
|
||||||
|
{
|
||||||
|
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OVERLAY_Data *ved = reinterpret_cast<OVERLAY_Data *>(vedata);
|
||||||
|
|
||||||
|
if (ved->instance == nullptr) {
|
||||||
|
ved->instance = new Instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
reinterpret_cast<Instance *>(ved->instance)->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SELECT_next_cache_init(void *vedata)
|
||||||
|
{
|
||||||
|
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)->begin_sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SELECT_next_cache_populate(void *vedata, Object *object)
|
||||||
|
{
|
||||||
|
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ObjectRef ref;
|
||||||
|
ref.object = object;
|
||||||
|
ref.dupli_object = DRW_object_get_dupli(object);
|
||||||
|
ref.dupli_parent = DRW_object_get_dupli_parent(object);
|
||||||
|
|
||||||
|
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)
|
||||||
|
->object_sync(ref, *DRW_manager_get());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SELECT_next_cache_finish(void *vedata)
|
||||||
|
{
|
||||||
|
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)->end_sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SELECT_next_draw_scene(void *vedata)
|
||||||
|
{
|
||||||
|
if (!GPU_shader_storage_buffer_objects_support()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reinterpret_cast<Instance *>(reinterpret_cast<OVERLAY_Data *>(vedata)->instance)
|
||||||
|
->draw(*DRW_manager_get());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SELECT_next_instance_free(void *instance_)
|
||||||
|
{
|
||||||
|
auto *instance = (Instance *)instance_;
|
||||||
|
if (instance != nullptr) {
|
||||||
|
delete instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const DrawEngineDataSize SELECT_next_data_size = DRW_VIEWPORT_DATA_SIZE(SELECT_NextData);
|
||||||
|
|
||||||
|
DrawEngineType draw_engine_select_next_type = {
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
N_("Select-Next"),
|
||||||
|
&SELECT_next_data_size,
|
||||||
|
&SELECT_next_engine_init,
|
||||||
|
NULL,
|
||||||
|
&SELECT_next_instance_free,
|
||||||
|
&SELECT_next_cache_init,
|
||||||
|
&SELECT_next_cache_populate,
|
||||||
|
&SELECT_next_cache_finish,
|
||||||
|
&SELECT_next_draw_scene,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** \} */
|
|
@ -10,6 +10,10 @@
|
||||||
|
|
||||||
#include "DRW_gpu_wrapper.hh"
|
#include "DRW_gpu_wrapper.hh"
|
||||||
|
|
||||||
|
#include "GPU_select.h"
|
||||||
|
|
||||||
|
#include "../intern/gpu_select_private.h"
|
||||||
|
|
||||||
#include "draw_manager.hh"
|
#include "draw_manager.hh"
|
||||||
#include "draw_pass.hh"
|
#include "draw_pass.hh"
|
||||||
|
|
||||||
|
@ -133,6 +137,8 @@ struct Instance {
|
||||||
StorageArrayBuffer<uint, 4, true> dummy_select_buf = {"dummy_select_buf"};
|
StorageArrayBuffer<uint, 4, true> dummy_select_buf = {"dummy_select_buf"};
|
||||||
/** Uniform buffer to bind to all passes to pass information about the selection state. */
|
/** Uniform buffer to bind to all passes to pass information about the selection state. */
|
||||||
UniformBuffer<SelectInfoData> info_buf;
|
UniformBuffer<SelectInfoData> info_buf;
|
||||||
|
/** Will remove the depth test state from any pass drawing objects with select id. */
|
||||||
|
bool disable_depth_test;
|
||||||
|
|
||||||
/* TODO(fclem): The sub_object_id id should eventually become some enum or take a sub-object
|
/* TODO(fclem): The sub_object_id id should eventually become some enum or take a sub-object
|
||||||
* reference directly. This would isolate the selection logic to this class. */
|
* reference directly. This would isolate the selection logic to this class. */
|
||||||
|
@ -154,23 +160,52 @@ struct Instance {
|
||||||
|
|
||||||
void begin_sync()
|
void begin_sync()
|
||||||
{
|
{
|
||||||
|
switch (gpu_select_next_get_mode()) {
|
||||||
|
case GPU_SELECT_ALL:
|
||||||
|
info_buf.mode = SelectType::SELECT_ALL;
|
||||||
|
disable_depth_test = true;
|
||||||
|
break;
|
||||||
|
/* Not sure if these 2 NEAREST are mapped to the right algorithm. */
|
||||||
|
case GPU_SELECT_NEAREST_FIRST_PASS:
|
||||||
|
case GPU_SELECT_NEAREST_SECOND_PASS:
|
||||||
|
case GPU_SELECT_PICK_ALL:
|
||||||
|
info_buf.mode = SelectType::SELECT_PICK_ALL;
|
||||||
|
info_buf.cursor = int2(gpu_select_next_get_pick_area_center());
|
||||||
|
disable_depth_test = true;
|
||||||
|
break;
|
||||||
|
case GPU_SELECT_PICK_NEAREST:
|
||||||
|
info_buf.mode = SelectType::SELECT_PICK_NEAREST;
|
||||||
|
info_buf.cursor = int2(gpu_select_next_get_pick_area_center());
|
||||||
|
disable_depth_test = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
info_buf.push_update();
|
||||||
|
|
||||||
select_id_map.clear();
|
select_id_map.clear();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
map_names.clear();
|
map_names.clear();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/** IMPORTANT: Changes the draw state. Need to be called after the pass own state. */
|
/** IMPORTANT: Changes the draw state. Need to be called after the pass own state_set. */
|
||||||
void select_bind(PassSimple &pass)
|
void select_bind(PassSimple &pass)
|
||||||
{
|
{
|
||||||
|
if (disable_depth_test) {
|
||||||
|
/* TODO: clipping state. */
|
||||||
|
pass.state_set(DRW_STATE_WRITE_COLOR);
|
||||||
|
}
|
||||||
pass.bind_ubo(SELECT_DATA, &info_buf);
|
pass.bind_ubo(SELECT_DATA, &info_buf);
|
||||||
pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf);
|
pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** IMPORTANT: Changes the draw state. Need to be called after the pass own state. */
|
/** IMPORTANT: Changes the draw state. Need to be called after the pass own state_set. */
|
||||||
void select_bind(PassMain &pass)
|
void select_bind(PassMain &pass)
|
||||||
{
|
{
|
||||||
pass.use_custom_ids = true;
|
pass.use_custom_ids = true;
|
||||||
|
if (disable_depth_test) {
|
||||||
|
/* TODO: clipping state. */
|
||||||
|
pass.state_set(DRW_STATE_WRITE_COLOR);
|
||||||
|
}
|
||||||
pass.bind_ubo(SELECT_DATA, &info_buf);
|
pass.bind_ubo(SELECT_DATA, &info_buf);
|
||||||
/* IMPORTANT: This binds a dummy buffer `in_select_buf` but it is not supposed to be used. */
|
/* IMPORTANT: This binds a dummy buffer `in_select_buf` but it is not supposed to be used. */
|
||||||
pass.bind_ssbo(SELECT_ID_IN, &dummy_select_buf);
|
pass.bind_ssbo(SELECT_ID_IN, &dummy_select_buf);
|
||||||
|
@ -179,11 +214,6 @@ struct Instance {
|
||||||
|
|
||||||
void end_sync()
|
void end_sync()
|
||||||
{
|
{
|
||||||
info_buf.mode = SelectType::SELECT_ALL;
|
|
||||||
/* TODO: Should be select rect center. */
|
|
||||||
info_buf.cursor = int2(512, 512);
|
|
||||||
info_buf.push_update();
|
|
||||||
|
|
||||||
select_output_buf.resize(ceil_to_multiple_u(select_id_map.size(), 4));
|
select_output_buf.resize(ceil_to_multiple_u(select_id_map.size(), 4));
|
||||||
select_output_buf.push_update();
|
select_output_buf.push_update();
|
||||||
select_output_buf.clear_to_zero();
|
select_output_buf.clear_to_zero();
|
||||||
|
@ -195,18 +225,31 @@ struct Instance {
|
||||||
GPU_finish();
|
GPU_finish();
|
||||||
select_output_buf.read();
|
select_output_buf.read();
|
||||||
|
|
||||||
#ifdef DEBUG
|
Vector<GPUSelectResult> result;
|
||||||
for (auto i : IndexRange(select_output_buf.size())) {
|
|
||||||
uint32_t word = select_output_buf[i];
|
/* Convert raw data from GPU to #GPUSelectResult. */
|
||||||
for (auto bit : IndexRange(32)) {
|
switch (info_buf.mode) {
|
||||||
if ((word & 1) != 0) {
|
case SelectType::SELECT_ALL:
|
||||||
uint index = i * 32 + bit;
|
for (auto i : IndexRange(select_id_map.size())) {
|
||||||
std::cout << index << map_names[index] << std::endl;
|
if (((select_output_buf[i / 32] >> (i % 32)) & 1) != 0) {
|
||||||
|
result.append({select_id_map[i], 0xFFFFu});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
word >>= 1;
|
break;
|
||||||
}
|
|
||||||
|
case SelectType::SELECT_PICK_ALL:
|
||||||
|
case SelectType::SELECT_PICK_NEAREST:
|
||||||
|
for (auto i : IndexRange(select_id_map.size())) {
|
||||||
|
if (select_output_buf[i] != 0) {
|
||||||
|
/* NOTE: For `SELECT_PICK_NEAREST`, `select_output_buf` also contains the screen
|
||||||
|
* distance to cursor in the lowest bits. */
|
||||||
|
result.append({select_id_map[i], select_output_buf[i]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
gpu_select_next_set_result(result.data(), result.size());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -2457,7 +2457,10 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
|
||||||
DST.options.is_material_select = do_material_sub_selection;
|
DST.options.is_material_select = do_material_sub_selection;
|
||||||
drw_task_graph_init();
|
drw_task_graph_init();
|
||||||
/* Get list of enabled engines */
|
/* Get list of enabled engines */
|
||||||
if (use_obedit) {
|
if (U.experimental.enable_overlay_next) {
|
||||||
|
use_drw_engine(&draw_engine_select_next_type);
|
||||||
|
}
|
||||||
|
else if (use_obedit) {
|
||||||
drw_engines_enable_overlays();
|
drw_engines_enable_overlays();
|
||||||
}
|
}
|
||||||
else if (!draw_surface) {
|
else if (!draw_surface) {
|
||||||
|
@ -2566,6 +2569,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
|
||||||
draw_select_framebuffer_depth_only_setup(viewport_size);
|
draw_select_framebuffer_depth_only_setup(viewport_size);
|
||||||
GPU_framebuffer_bind(g_select_buffer.framebuffer_depth_only);
|
GPU_framebuffer_bind(g_select_buffer.framebuffer_depth_only);
|
||||||
GPU_framebuffer_clear_depth(g_select_buffer.framebuffer_depth_only, 1.0f);
|
GPU_framebuffer_clear_depth(g_select_buffer.framebuffer_depth_only, 1.0f);
|
||||||
|
/* WORKAROUND: Needed for Select-Next for keeping the same codeflow as Overlay-Next. */
|
||||||
|
BLI_assert(DRW_viewport_texture_list_get()->depth == NULL);
|
||||||
|
DRW_viewport_texture_list_get()->depth = g_select_buffer.texture_depth;
|
||||||
|
|
||||||
/* Start Drawing */
|
/* Start Drawing */
|
||||||
DRW_state_reset();
|
DRW_state_reset();
|
||||||
|
@ -2578,11 +2584,15 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
|
||||||
if (!select_pass_fn(DRW_SELECT_PASS_PRE, select_pass_user_data)) {
|
if (!select_pass_fn(DRW_SELECT_PASS_PRE, select_pass_user_data)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
DRW_state_lock(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_TEST_ENABLED);
|
if (!U.experimental.enable_overlay_next) {
|
||||||
|
DRW_state_lock(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_TEST_ENABLED);
|
||||||
|
}
|
||||||
|
|
||||||
drw_engines_draw_scene();
|
drw_engines_draw_scene();
|
||||||
|
|
||||||
DRW_state_lock(0);
|
if (!U.experimental.enable_overlay_next) {
|
||||||
|
DRW_state_lock(0);
|
||||||
|
}
|
||||||
|
|
||||||
if (!select_pass_fn(DRW_SELECT_PASS_POST, select_pass_user_data)) {
|
if (!select_pass_fn(DRW_SELECT_PASS_POST, select_pass_user_data)) {
|
||||||
break;
|
break;
|
||||||
|
@ -2591,6 +2601,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
|
||||||
|
|
||||||
DRW_smoke_exit(DST.vmempool);
|
DRW_smoke_exit(DST.vmempool);
|
||||||
|
|
||||||
|
/* WORKAROUND: Do not leave ownership to the viewport list. */
|
||||||
|
DRW_viewport_texture_list_get()->depth = NULL;
|
||||||
|
|
||||||
DRW_state_reset();
|
DRW_state_reset();
|
||||||
drw_engines_disable();
|
drw_engines_disable();
|
||||||
|
|
||||||
|
@ -3012,6 +3025,7 @@ void DRW_engines_register(void)
|
||||||
|
|
||||||
DRW_engine_register(&draw_engine_overlay_type);
|
DRW_engine_register(&draw_engine_overlay_type);
|
||||||
DRW_engine_register(&draw_engine_overlay_next_type);
|
DRW_engine_register(&draw_engine_overlay_next_type);
|
||||||
|
DRW_engine_register(&draw_engine_select_next_type);
|
||||||
DRW_engine_register(&draw_engine_select_type);
|
DRW_engine_register(&draw_engine_select_type);
|
||||||
DRW_engine_register(&draw_engine_basic_type);
|
DRW_engine_register(&draw_engine_basic_type);
|
||||||
DRW_engine_register(&draw_engine_compositor_type);
|
DRW_engine_register(&draw_engine_compositor_type);
|
||||||
|
|
|
@ -485,7 +485,7 @@ static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data)
|
||||||
bool continue_pass = false;
|
bool continue_pass = false;
|
||||||
struct DrawSelectLoopUserData *data = user_data;
|
struct DrawSelectLoopUserData *data = user_data;
|
||||||
if (stage == DRW_SELECT_PASS_PRE) {
|
if (stage == DRW_SELECT_PASS_PRE) {
|
||||||
GPU_select_begin(
|
GPU_select_begin_next(
|
||||||
data->buffer, data->buffer_len, data->rect, data->gpu_select_mode, data->hits);
|
data->buffer, data->buffer_len, data->rect, data->gpu_select_mode, data->hits);
|
||||||
/* always run POST after PRE. */
|
/* always run POST after PRE. */
|
||||||
continue_pass = true;
|
continue_pass = true;
|
||||||
|
@ -596,7 +596,7 @@ int view3d_opengl_select_ex(ViewContext *vc,
|
||||||
/* Re-use cache (rect must be smaller than the cached)
|
/* Re-use cache (rect must be smaller than the cached)
|
||||||
* other context is assumed to be unchanged */
|
* other context is assumed to be unchanged */
|
||||||
if (GPU_select_is_cached()) {
|
if (GPU_select_is_cached()) {
|
||||||
GPU_select_begin(buffer, buffer_len, &rect, gpu_select_mode, 0);
|
GPU_select_begin_next(buffer, buffer_len, &rect, gpu_select_mode, 0);
|
||||||
GPU_select_cache_load_id();
|
GPU_select_cache_load_id();
|
||||||
hits = GPU_select_end();
|
hits = GPU_select_end();
|
||||||
goto finally;
|
goto finally;
|
||||||
|
|
|
@ -68,6 +68,7 @@ set(SRC
|
||||||
intern/gpu_platform.cc
|
intern/gpu_platform.cc
|
||||||
intern/gpu_query.cc
|
intern/gpu_query.cc
|
||||||
intern/gpu_select.c
|
intern/gpu_select.c
|
||||||
|
intern/gpu_select_next.cc
|
||||||
intern/gpu_select_pick.c
|
intern/gpu_select_pick.c
|
||||||
intern/gpu_select_sample_query.cc
|
intern/gpu_select_sample_query.cc
|
||||||
intern/gpu_shader.cc
|
intern/gpu_shader.cc
|
||||||
|
|
|
@ -50,6 +50,15 @@ void GPU_select_begin(GPUSelectResult *buffer,
|
||||||
const struct rcti *input,
|
const struct rcti *input,
|
||||||
eGPUSelectMode mode,
|
eGPUSelectMode mode,
|
||||||
int oldhits);
|
int oldhits);
|
||||||
|
/**
|
||||||
|
* Initialize and provide buffer for results.
|
||||||
|
* Uses the new Select-Next engine if enabled.
|
||||||
|
*/
|
||||||
|
void GPU_select_begin_next(GPUSelectResult *buffer,
|
||||||
|
const uint buffer_len,
|
||||||
|
const struct rcti *input,
|
||||||
|
eGPUSelectMode mode,
|
||||||
|
int oldhits);
|
||||||
/**
|
/**
|
||||||
* Loads a new selection id and ends previous query, if any.
|
* Loads a new selection id and ends previous query, if any.
|
||||||
* In second pass of selection it also returns
|
* In second pass of selection it also returns
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "DNA_userdef_types.h"
|
||||||
|
|
||||||
#include "GPU_select.h"
|
#include "GPU_select.h"
|
||||||
|
|
||||||
#include "BLI_rect.h"
|
#include "BLI_rect.h"
|
||||||
|
@ -30,6 +32,8 @@ typedef enum eGPUSelectAlgo {
|
||||||
/** Read depth buffer for every drawing pass and extract depths, `gpu_select_pick.c`
|
/** Read depth buffer for every drawing pass and extract depths, `gpu_select_pick.c`
|
||||||
* Only sets 4th component (ID) correctly. */
|
* Only sets 4th component (ID) correctly. */
|
||||||
ALGO_GL_PICK = 2,
|
ALGO_GL_PICK = 2,
|
||||||
|
/** Use Select-Next draw engine. */
|
||||||
|
ALGO_SELECT_NEXT = 3,
|
||||||
} eGPUSelectAlgo;
|
} eGPUSelectAlgo;
|
||||||
|
|
||||||
typedef struct GPUSelectState {
|
typedef struct GPUSelectState {
|
||||||
|
@ -60,11 +64,12 @@ static GPUSelectState g_select_state = {0};
|
||||||
/** \name Public API
|
/** \name Public API
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
void GPU_select_begin(GPUSelectResult *buffer,
|
static void gpu_select_begin_ex(GPUSelectResult *buffer,
|
||||||
const uint buffer_len,
|
const uint buffer_len,
|
||||||
const rcti *input,
|
const rcti *input,
|
||||||
eGPUSelectMode mode,
|
eGPUSelectMode mode,
|
||||||
int oldhits)
|
int oldhits,
|
||||||
|
bool use_select_next)
|
||||||
{
|
{
|
||||||
if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
|
if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
|
||||||
/* In the case hits was '-1',
|
/* In the case hits was '-1',
|
||||||
|
@ -76,7 +81,10 @@ void GPU_select_begin(GPUSelectResult *buffer,
|
||||||
g_select_state.select_is_active = true;
|
g_select_state.select_is_active = true;
|
||||||
g_select_state.mode = mode;
|
g_select_state.mode = mode;
|
||||||
|
|
||||||
if (ELEM(g_select_state.mode, GPU_SELECT_PICK_ALL, GPU_SELECT_PICK_NEAREST)) {
|
if (use_select_next) {
|
||||||
|
g_select_state.algorithm = ALGO_SELECT_NEXT;
|
||||||
|
}
|
||||||
|
else if (ELEM(g_select_state.mode, GPU_SELECT_PICK_ALL, GPU_SELECT_PICK_NEAREST)) {
|
||||||
g_select_state.algorithm = ALGO_GL_PICK;
|
g_select_state.algorithm = ALGO_GL_PICK;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -89,6 +97,7 @@ void GPU_select_begin(GPUSelectResult *buffer,
|
||||||
g_select_state.use_cache_needs_init = false;
|
g_select_state.use_cache_needs_init = false;
|
||||||
|
|
||||||
switch (g_select_state.algorithm) {
|
switch (g_select_state.algorithm) {
|
||||||
|
case ALGO_SELECT_NEXT:
|
||||||
case ALGO_GL_QUERY: {
|
case ALGO_GL_QUERY: {
|
||||||
g_select_state.use_cache = false;
|
g_select_state.use_cache = false;
|
||||||
break;
|
break;
|
||||||
|
@ -102,6 +111,10 @@ void GPU_select_begin(GPUSelectResult *buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (g_select_state.algorithm) {
|
switch (g_select_state.algorithm) {
|
||||||
|
case ALGO_SELECT_NEXT: {
|
||||||
|
gpu_select_next_begin(buffer, buffer_len, input, mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ALGO_GL_QUERY: {
|
case ALGO_GL_QUERY: {
|
||||||
gpu_select_query_begin(buffer, buffer_len, input, mode, oldhits);
|
gpu_select_query_begin(buffer, buffer_len, input, mode, oldhits);
|
||||||
break;
|
break;
|
||||||
|
@ -114,6 +127,25 @@ void GPU_select_begin(GPUSelectResult *buffer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPU_select_begin_next(GPUSelectResult *buffer,
|
||||||
|
const uint buffer_len,
|
||||||
|
const rcti *input,
|
||||||
|
eGPUSelectMode mode,
|
||||||
|
int oldhits)
|
||||||
|
{
|
||||||
|
gpu_select_begin_ex(
|
||||||
|
buffer, buffer_len, input, mode, oldhits, U.experimental.enable_overlay_next);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPU_select_begin(GPUSelectResult *buffer,
|
||||||
|
const uint buffer_len,
|
||||||
|
const rcti *input,
|
||||||
|
eGPUSelectMode mode,
|
||||||
|
int oldhits)
|
||||||
|
{
|
||||||
|
gpu_select_begin_ex(buffer, buffer_len, input, mode, oldhits, false);
|
||||||
|
}
|
||||||
|
|
||||||
bool GPU_select_load_id(uint id)
|
bool GPU_select_load_id(uint id)
|
||||||
{
|
{
|
||||||
/* if no selection mode active, ignore */
|
/* if no selection mode active, ignore */
|
||||||
|
@ -122,6 +154,11 @@ bool GPU_select_load_id(uint id)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (g_select_state.algorithm) {
|
switch (g_select_state.algorithm) {
|
||||||
|
case ALGO_SELECT_NEXT:
|
||||||
|
/* This shouldn't use this pipeline. */
|
||||||
|
BLI_assert_unreachable();
|
||||||
|
return 0;
|
||||||
|
|
||||||
case ALGO_GL_QUERY: {
|
case ALGO_GL_QUERY: {
|
||||||
return gpu_select_query_load_id(id);
|
return gpu_select_query_load_id(id);
|
||||||
}
|
}
|
||||||
|
@ -137,6 +174,10 @@ uint GPU_select_end(void)
|
||||||
uint hits = 0;
|
uint hits = 0;
|
||||||
|
|
||||||
switch (g_select_state.algorithm) {
|
switch (g_select_state.algorithm) {
|
||||||
|
case ALGO_SELECT_NEXT: {
|
||||||
|
hits = gpu_select_next_end();
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ALGO_GL_QUERY: {
|
case ALGO_GL_QUERY: {
|
||||||
hits = gpu_select_query_end();
|
hits = gpu_select_query_end();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
* Copyright 2017 Blender Foundation. All rights reserved. */
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* \ingroup gpu
|
||||||
|
*
|
||||||
|
* Glue to make the new Select-Next engine work with the old GPU select API.
|
||||||
|
*/
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
|
#include "BLI_rect.h"
|
||||||
|
#include "BLI_span.hh"
|
||||||
|
|
||||||
|
#include "GPU_select.h"
|
||||||
|
|
||||||
|
#include "gpu_select_private.h"
|
||||||
|
|
||||||
|
struct GPUSelectNextState {
|
||||||
|
/** Result buffer set on initialization. */
|
||||||
|
GPUSelectResult *buffer;
|
||||||
|
uint buffer_len;
|
||||||
|
/** Area of the viewport to render / select from. */
|
||||||
|
rcti rect;
|
||||||
|
/** Number of hits. Set to -1 if it overflows buffer_len. */
|
||||||
|
uint hits;
|
||||||
|
/** Mode of operation. */
|
||||||
|
eGPUSelectMode mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
static GPUSelectNextState g_state = {};
|
||||||
|
|
||||||
|
void gpu_select_next_begin(GPUSelectResult *buffer,
|
||||||
|
uint buffer_len,
|
||||||
|
const rcti *input,
|
||||||
|
eGPUSelectMode mode)
|
||||||
|
|
||||||
|
{
|
||||||
|
g_state.buffer = buffer;
|
||||||
|
g_state.rect = *input;
|
||||||
|
g_state.buffer_len = buffer_len;
|
||||||
|
g_state.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gpu_select_next_get_pick_area_center()
|
||||||
|
{
|
||||||
|
BLI_assert(BLI_rcti_size_x(&g_state.rect) == BLI_rcti_size_y(&g_state.rect));
|
||||||
|
return BLI_rcti_size_x(&g_state.rect) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
eGPUSelectMode gpu_select_next_get_mode()
|
||||||
|
{
|
||||||
|
return g_state.mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gpu_select_next_set_result(GPUSelectResult *hit_buf, uint hit_len)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (hit_len > g_state.buffer_len) {
|
||||||
|
g_state.hits = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
blender::MutableSpan<GPUSelectResult> result(g_state.buffer, g_state.buffer_len);
|
||||||
|
blender::Span<GPUSelectResult> hits(hit_buf, hit_len);
|
||||||
|
|
||||||
|
/* TODO(fclem): There might be some conversion to do to align to the other APIs output. */
|
||||||
|
switch (g_state.mode) {
|
||||||
|
case eGPUSelectMode::GPU_SELECT_ALL:
|
||||||
|
result.take_front(hit_len).copy_from(hits);
|
||||||
|
break;
|
||||||
|
case eGPUSelectMode::GPU_SELECT_NEAREST_FIRST_PASS:
|
||||||
|
result.take_front(hit_len).copy_from(hits);
|
||||||
|
break;
|
||||||
|
case eGPUSelectMode::GPU_SELECT_NEAREST_SECOND_PASS:
|
||||||
|
result.take_front(hit_len).copy_from(hits);
|
||||||
|
break;
|
||||||
|
case eGPUSelectMode::GPU_SELECT_PICK_ALL:
|
||||||
|
result.take_front(hit_len).copy_from(hits);
|
||||||
|
break;
|
||||||
|
case eGPUSelectMode::GPU_SELECT_PICK_NEAREST:
|
||||||
|
result.take_front(hit_len).copy_from(hits);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_state.hits = hit_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint gpu_select_next_end()
|
||||||
|
{
|
||||||
|
return g_state.hits;
|
||||||
|
}
|
|
@ -37,6 +37,19 @@ void gpu_select_query_begin(
|
||||||
bool gpu_select_query_load_id(uint id);
|
bool gpu_select_query_load_id(uint id);
|
||||||
uint gpu_select_query_end(void);
|
uint gpu_select_query_end(void);
|
||||||
|
|
||||||
|
/* gpu_select_next */
|
||||||
|
|
||||||
|
void gpu_select_next_begin(GPUSelectResult *buffer,
|
||||||
|
uint buffer_len,
|
||||||
|
const rcti *input,
|
||||||
|
eGPUSelectMode mode);
|
||||||
|
uint gpu_select_next_end(void);
|
||||||
|
|
||||||
|
/* Return a single offset since picking uses squared viewport. */
|
||||||
|
int gpu_select_next_get_pick_area_center(void);
|
||||||
|
eGPUSelectMode gpu_select_next_get_mode(void);
|
||||||
|
void gpu_select_next_set_result(GPUSelectResult *buffer, uint buffer_len);
|
||||||
|
|
||||||
#define SELECT_ID_NONE ((uint)0xffffffff)
|
#define SELECT_ID_NONE ((uint)0xffffffff)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
Loading…
Reference in New Issue