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.
14 changed files with 415 additions and 47 deletions
Showing only changes of commit 3ac54f67bf - Show all commits

View File

@ -191,6 +191,7 @@ set(SRC
engines/gpencil/gpencil_shader_fx.c
engines/select/select_draw_utils.c
engines/select/select_engine.c
engines/select/select_instance.cc
engines/overlay/overlay_antialiasing.cc
engines/overlay/overlay_armature.cc
engines/overlay/overlay_background.cc

View File

@ -12,11 +12,6 @@ namespace blender::draw::overlay {
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. */
const DRWContextState *ctx = DRW_context_state_get();
/* 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)
{
/* WORKAROUND: This is to prevent crashes when using depth picking or selection.
* The selection engine should handle theses cases instead. */
if (!DRW_state_is_fbo()) {
return;
}
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);
int2 render_size = int2(resources.depth_tx.size());
const DRWView *view_legacy = DRW_view_default_get();
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),
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));
resources.color_overlay_tx.wrap(resources.color_overlay_alloc_tx);
resources.color_render_tx.wrap(resources.color_render_alloc_tx);
resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx));
resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx));
resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE);
}
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. */
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.depth_in_front_alloc_tx.release();
resources.color_overlay_alloc_tx.release();
resources.color_render_alloc_tx.release();
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<>::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
/* TODO(fclem): Move elsewhere. */

View File

@ -24,7 +24,7 @@ template<
* 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::Instance>
typename SelectEngineT = select::InstanceDummy>
class Instance {
public:
/* 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<>::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

View File

@ -75,6 +75,8 @@ template<typename SelectEngineT> struct Resources : public SelectEngineT::Select
TextureFromPool line_tx = {"line_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
* engine. */

View File

@ -7,6 +7,10 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/* select_engine.c */
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 GPUTexture *DRW_engine_select_texture_get(void);
/* select_instance.cc */
extern DrawEngineType draw_engine_select_next_type;
#ifdef __cplusplus
}
#endif

View File

@ -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,
};
/** \} */

View File

@ -10,6 +10,10 @@
#include "DRW_gpu_wrapper.hh"
#include "GPU_select.h"
#include "../intern/gpu_select_private.h"
#include "draw_manager.hh"
#include "draw_pass.hh"
@ -133,6 +137,8 @@ struct Instance {
StorageArrayBuffer<uint, 4, true> dummy_select_buf = {"dummy_select_buf"};
/** Uniform buffer to bind to all passes to pass information about the selection state. */
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
* reference directly. This would isolate the selection logic to this class. */
@ -154,23 +160,52 @@ struct Instance {
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();
#ifdef DEBUG
map_names.clear();
#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)
{
if (disable_depth_test) {
/* TODO: clipping state. */
pass.state_set(DRW_STATE_WRITE_COLOR);
}
pass.bind_ubo(SELECT_DATA, &info_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)
{
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);
/* 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);
@ -179,11 +214,6 @@ struct Instance {
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.push_update();
select_output_buf.clear_to_zero();
@ -195,18 +225,31 @@ struct Instance {
GPU_finish();
select_output_buf.read();
#ifdef DEBUG
for (auto i : IndexRange(select_output_buf.size())) {
uint32_t word = select_output_buf[i];
for (auto bit : IndexRange(32)) {
if ((word & 1) != 0) {
uint index = i * 32 + bit;
std::cout << index << map_names[index] << std::endl;
Vector<GPUSelectResult> result;
/* Convert raw data from GPU to #GPUSelectResult. */
switch (info_buf.mode) {
case SelectType::SELECT_ALL:
for (auto i : IndexRange(select_id_map.size())) {
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());
}
};
};

View File

@ -2457,7 +2457,10 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
DST.options.is_material_select = do_material_sub_selection;
drw_task_graph_init();
/* 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();
}
else if (!draw_surface) {
@ -2566,6 +2569,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
draw_select_framebuffer_depth_only_setup(viewport_size);
GPU_framebuffer_bind(g_select_buffer.framebuffer_depth_only);
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 */
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)) {
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_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)) {
break;
@ -2591,6 +2601,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
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_engines_disable();
@ -3012,6 +3025,7 @@ void DRW_engines_register(void)
DRW_engine_register(&draw_engine_overlay_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_basic_type);
DRW_engine_register(&draw_engine_compositor_type);

View File

@ -485,7 +485,7 @@ static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data)
bool continue_pass = false;
struct DrawSelectLoopUserData *data = user_data;
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);
/* always run POST after PRE. */
continue_pass = true;
@ -596,7 +596,7 @@ int view3d_opengl_select_ex(ViewContext *vc,
/* Re-use cache (rect must be smaller than the cached)
* other context is assumed to be unchanged */
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();
hits = GPU_select_end();
goto finally;

View File

@ -68,6 +68,7 @@ set(SRC
intern/gpu_platform.cc
intern/gpu_query.cc
intern/gpu_select.c
intern/gpu_select_next.cc
intern/gpu_select_pick.c
intern/gpu_select_sample_query.cc
intern/gpu_shader.cc

View File

@ -50,6 +50,15 @@ void GPU_select_begin(GPUSelectResult *buffer,
const struct rcti *input,
eGPUSelectMode mode,
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.
* In second pass of selection it also returns

View File

@ -10,6 +10,8 @@
#include <stdlib.h>
#include <string.h>
#include "DNA_userdef_types.h"
#include "GPU_select.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`
* Only sets 4th component (ID) correctly. */
ALGO_GL_PICK = 2,
/** Use Select-Next draw engine. */
ALGO_SELECT_NEXT = 3,
} eGPUSelectAlgo;
typedef struct GPUSelectState {
@ -60,11 +64,12 @@ static GPUSelectState g_select_state = {0};
/** \name Public API
* \{ */
void GPU_select_begin(GPUSelectResult *buffer,
const uint buffer_len,
const rcti *input,
eGPUSelectMode mode,
int oldhits)
static void gpu_select_begin_ex(GPUSelectResult *buffer,
const uint buffer_len,
const rcti *input,
eGPUSelectMode mode,
int oldhits,
bool use_select_next)
{
if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
/* 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.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;
}
else {
@ -89,6 +97,7 @@ void GPU_select_begin(GPUSelectResult *buffer,
g_select_state.use_cache_needs_init = false;
switch (g_select_state.algorithm) {
case ALGO_SELECT_NEXT:
case ALGO_GL_QUERY: {
g_select_state.use_cache = false;
break;
@ -102,6 +111,10 @@ void GPU_select_begin(GPUSelectResult *buffer,
}
switch (g_select_state.algorithm) {
case ALGO_SELECT_NEXT: {
gpu_select_next_begin(buffer, buffer_len, input, mode);
break;
}
case ALGO_GL_QUERY: {
gpu_select_query_begin(buffer, buffer_len, input, mode, oldhits);
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)
{
/* if no selection mode active, ignore */
@ -122,6 +154,11 @@ bool GPU_select_load_id(uint id)
}
switch (g_select_state.algorithm) {
case ALGO_SELECT_NEXT:
/* This shouldn't use this pipeline. */
BLI_assert_unreachable();
return 0;
case ALGO_GL_QUERY: {
return gpu_select_query_load_id(id);
}
@ -137,6 +174,10 @@ uint GPU_select_end(void)
uint hits = 0;
switch (g_select_state.algorithm) {
case ALGO_SELECT_NEXT: {
hits = gpu_select_next_end();
break;
}
case ALGO_GL_QUERY: {
hits = gpu_select_query_end();
break;

View File

@ -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;
}

View File

@ -37,6 +37,19 @@ void gpu_select_query_begin(
bool gpu_select_query_load_id(uint id);
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)
#ifdef __cplusplus