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.
19 changed files with 193 additions and 18 deletions
Showing only changes of commit ea66898bbe - Show all commits

View File

@ -595,6 +595,7 @@ set(GLSL_SRC
engines/select/shaders/select_id_vert.glsl
engines/select/shaders/select_id_frag.glsl
engines/select/shaders/select_lib.glsl
engines/basic/shaders/basic_conservative_depth_geom.glsl
engines/basic/shaders/basic_depth_vert.glsl

View File

@ -97,6 +97,7 @@ template<typename SelectEngineT> class Empties {
state.clipping_state);
pass.shader_set(res.shaders.extra_shape);
pass.bind_ubo("globalsBlock", &res.globals_buf);
res.select_bind(pass);
call_bufs.plain_axes_buf.end_sync(pass, shapes.plain_axes);
call_bufs.single_arrow_buf.end_sync(pass, shapes.single_arrow);

View File

@ -70,6 +70,8 @@ template<typename T> void Instance<T>::begin_sync()
const DRWView *view_legacy = DRW_view_default_get();
View view("OverlayView", view_legacy);
resources.begin_sync();
background.begin_sync(resources, state);
prepass.begin_sync(resources, state);
empties.begin_sync();
@ -136,6 +138,8 @@ template<typename T> void Instance<T>::object_sync(ObjectRef &ob_ref, Manager &m
template<typename T> void Instance<T>::end_sync()
{
resources.end_sync();
metaballs.end_sync(resources, shapes, state);
empties.end_sync(resources, shapes, state);
}
@ -197,6 +201,8 @@ template<typename T> void Instance<T>::draw(Manager &manager)
resources.line_tx.release();
resources.depth_in_front_alloc_tx.release();
resources.read_result();
}
/* Instantiation. */

View File

@ -90,6 +90,7 @@ template<typename SelectEngineT> class Metaballs {
state.clipping_state);
pass.shader_set(res.shaders.armature_sphere_outline);
pass.bind_ubo("globalsBlock", &res.globals_buf);
res.select_bind(pass);
call_buf.end_sync(pass, shapes.metaball_wire_circle);
};

View File

@ -30,6 +30,7 @@ template<typename SelectEngineT> class Prepass {
pass.init();
pass.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state);
pass.shader_set(res.shaders.depth_mesh);
res.select_bind(pass);
};
init_pass(prepass_ps_);
init_pass(prepass_in_front_ps_);

View File

@ -6,8 +6,6 @@
#pragma once
#include <functional>
#include "GPU_shader.h"
#include "gpu_shader_create_info.hh"
@ -51,7 +49,7 @@ template<typename SelectEngineT, bool ClippingEnabled = false> class ShaderModul
};
/**
* Special class for every shader that needs to have clipped and selection variations.
* Special class for any shader that needs to have clipped and selection variations.
*/
class ShaderGeometry : public Shader {
public:
@ -83,7 +81,7 @@ template<typename SelectEngineT, bool ClippingEnabled = false> class ShaderModul
GPU_shader_create_info_get(create_info_name));
patch(info);
info.define(SelectEngineT::shader_define);
SelectEngineT::SelectShader::patch(info);
this->shader_ = GPU_shader_create_from_info(
reinterpret_cast<const GPUShaderCreateInfo *>(&info));
@ -125,6 +123,8 @@ template<typename SelectEngineT, bool ClippingEnabled = false> class ShaderModul
Shader background_fill = {"overlay_background"};
Shader background_clip_bound = {"overlay_clipbound"};
/** Module */
/** Only to be used by Instance constructor. */
static ShaderModule &module_get()
{

View File

@ -1,6 +1,10 @@
#pragma BLENDER_REQUIRE(select_lib.glsl)
void main()
{
/* No color output, only depth (line below is implicit). */
// gl_FragDepth = gl_FragCoord.z;
/* This is optimized to noop in the non select case. */
select_id_output(select_id);
}

View File

@ -1,11 +1,14 @@
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(select_lib.glsl)
void main()
{
GPU_INTEL_VERTEX_SHADER_WORKAROUND
select_id_set(in_select_buf[resource_id]);
vec3 world_pos = point_object_to_world(pos);
gl_Position = point_world_to_ndc(world_pos);

View File

@ -1,8 +1,11 @@
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(select_lib.glsl)
void main()
{
fragColor = finalColor;
lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos);
select_id_output(select_id);
}

View File

@ -1,6 +1,7 @@
#pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(select_lib.glsl)
#define lamp_area_size inst_data.xy
#define lamp_clip_sta inst_data.z
@ -41,6 +42,8 @@
void main()
{
select_id_set(in_select_buf[gl_InstanceID]);
/* Extract data packed inside the unused mat4 members. */
vec4 inst_data = vec4(inst_obmat[0][3], inst_obmat[1][3], inst_obmat[2][3], inst_obmat[3][3]);
float inst_color_data = color.a;

View File

@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup draw_engine
*/
#pragma once
#define SELECT_ID_IN 5
#define SELECT_ID_OUT 6

View File

@ -11,13 +11,17 @@
#include "draw_manager.hh"
#include "gpu_shader_create_info.hh"
namespace blender::draw::select {
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 SelectShader {
static void patch(gpu::shader::ShaderCreateInfo &){};
};
struct SelectBuf {
void select_clear(){};
@ -30,6 +34,16 @@ struct EngineEmpty {
{
return {};
}
void begin_sync(){};
void select_bind(PassSimple &){};
void select_bind(PassMain &){};
void end_sync(){};
void read_result(){};
};
};

View File

@ -148,7 +148,7 @@ static void select_cache_init(void *vedata)
}
else {
pd->shgrp_face_unif = DRW_shgroup_create(sh->select_id_uniform, psl->select_id_face_pass);
DRW_shgroup_uniform_int_copy(pd->shgrp_face_unif, "id", 0);
DRW_shgroup_uniform_int_copy(pd->shgrp_face_unif, "select_id", 0);
}
if (e_data.context.select_mode & SCE_SELECT_EDGE) {

View File

@ -11,18 +11,39 @@
#pragma once
#include "DRW_gpu_wrapper.hh"
#include "draw_manager.hh"
#include "draw_pass.hh"
#include "gpu_shader_create_info.hh"
#include "select_defines.h"
namespace blender::draw::select {
struct EngineObject {
/* Add type safety to selection ID. Only the select engine should provide them. */
struct ID {
uint32_t value;
friend constexpr bool operator==(ID a, ID b)
{
return a.value == b.value;
}
uint64_t hash() const
{
return BLI_ghashutil_uinthash(value);
}
};
static constexpr const char *shader_define = "SELECT_OBJECT";
struct SelectShader {
static void patch(gpu::shader::ShaderCreateInfo &info)
{
info.define("SELECT_UNORDERED");
info.additional_info("select_id_patch");
};
};
/**
* Add a dedicated selection id buffer to a pass.
@ -44,23 +65,85 @@ struct EngineObject {
void select_bind(PassSimple &pass)
{
select_buf.push_update();
pass.bind_ssbo("select_buf", &select_buf);
pass.bind_ssbo(SELECT_ID_IN, &select_buf);
}
};
/**
* Generate selection IDs from objects and keep record of the mapping between them.
* The id's are contiguous so that we can create a destination buffer.
*/
struct SelectMap {
uint next_id = 0;
Map<uint, ObjectRef> map;
/** Mapping between internal IDs and `object->runtime.select_id`. */
Vector<uint> select_id_map;
#ifdef DEBUG
/** Debug map containing a copy of the object name. */
Vector<std::string> map_names;
#endif
/** Stores the result of the whole selection drawing. Content depends on selection mode. */
StorageArrayBuffer<uint> select_output_buf = {"select_output_buf"};
/** Dummy buffer. Might be better to remove, but simplify the shader create info patching. */
StorageArrayBuffer<uint, 4, true> dummy_select_buf = {"dummy_select_buf"};
/* TODO(fclem): The sub_object_id id should eventually become some enum or take a sub-object
* reference directly. */
[[nodiscard]] const ID select_id(const ObjectRef &, uint sub_object_id = 0)
* reference directly. This would isolate the selection logic to this class. */
[[nodiscard]] const ID select_id(const ObjectRef &ob_ref, uint sub_object_id = 0)
{
/* TODO Insert Ref into the map. */
return {sub_object_id | next_id++};
uint object_id = ob_ref.object->runtime.select_id;
uint id = select_id_map.append_and_get_index(object_id | sub_object_id);
#ifdef DEBUG
map_names.append(ob_ref.object->id.name);
#endif
return {id};
}
void begin_sync()
{
select_id_map.clear();
/* Index 0 is the invalid selection ID. */
select_id_map.append(uint(-1));
#ifdef DEBUG
map_names.clear();
map_names.append("Invalid Index");
#endif
}
void select_bind(PassSimple &pass)
{
pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf);
}
void select_bind(PassMain &pass)
{
/* 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_OUT, &select_output_buf);
}
void end_sync()
{
select_output_buf.resize(ceil_to_multiple_u(select_id_map.size(), 4));
select_output_buf.push_update();
select_output_buf.clear_to_zero();
}
void read_result()
{
/* TODO right barrier. */
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) {
std::cout << map_names[i * 32 + bit] << std::endl;
}
word >>= 1;
}
}
#endif
}
};
};

View File

@ -1,12 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_create_info.hh"
#include "select_defines.h"
/* -------------------------------------------------------------------- */
/** \name Select ID for Edit Mesh Selection
* \{ */
GPU_SHADER_INTERFACE_INFO(select_id_iface, "").flat(Type::INT, "id");
GPU_SHADER_INTERFACE_INFO(select_id_iface, "").flat(Type::INT, "select_id");
GPU_SHADER_CREATE_INFO(select_id_flat)
.push_constant(Type::FLOAT, "sizeVertex")
@ -23,7 +24,7 @@ GPU_SHADER_CREATE_INFO(select_id_flat)
GPU_SHADER_CREATE_INFO(select_id_uniform)
.define("UNIFORM_ID")
.push_constant(Type::FLOAT, "sizeVertex")
.push_constant(Type::INT, "id")
.push_constant(Type::INT, "select_id")
.vertex_in(0, Type::VEC3, "pos")
.fragment_out(0, Type::UINT, "fragColor")
.vertex_source("select_id_vert.glsl")
@ -40,4 +41,13 @@ GPU_SHADER_CREATE_INFO(select_id_uniform_clipped)
.additional_info("select_id_uniform")
.additional_info("drw_clipped")
.do_static_compilation(true);
/* Used to patch overlay shaders. */
GPU_SHADER_CREATE_INFO(select_id_patch)
.vertex_out(select_id_iface)
/* Select IDs for instanced draw-calls not using #PassMain. */
.storage_buf(SELECT_ID_IN, Qualifier::READ, "int", "in_select_buf[]")
/* Stores the result of the whole selection drawing. Content depends on selection mode. */
.storage_buf(SELECT_ID_OUT, Qualifier::READ_WRITE, "uint", "out_select_buf[]");
/** \} */

View File

@ -1,4 +1,4 @@
void main()
{
fragColor = floatBitsToUint(intBitsToFloat(id));
fragColor = floatBitsToUint(intBitsToFloat(select_id));
}

View File

@ -4,7 +4,7 @@
void main()
{
#ifndef UNIFORM_ID
id = offset + index;
select_id = offset + index;
#endif
vec3 world_pos = point_object_to_world(pos);

View File

@ -0,0 +1,34 @@
#if !(defined(SELECT_UNORDERED) || defined(SELECT_DEPTH_PICKING))
/* Avoid requesting the select_id when not in selection mode. */
# define select_id_set(select_id)
# define select_id_output(select_id)
#elif defined(GPU_VERTEX_SHADER)
void select_id_set(int id)
{
/* Declared in the create info. */
select_id = id;
}
#elif defined(GPU_FRAGMENT_SHADER)
void select_id_output(int id)
{
# if defined(SELECT_UNORDERED)
/* Used by rectangle selection.
* Set the bit of the select id in the bitmap. */
atomicOr(out_select_buf[id / 32u], 1u << (uint(id) % 32u));
# elif defined(SELECT_DEPTH_PICKING)
/* Used by mouse-clicking selection.
* Stores the nearest depth for this select id. */
atomicMin(out_select_buf[id], floatBitsToUint(gl_FragCoord.z));
# else
# error
# endif
}
#endif

View File

@ -29,6 +29,7 @@ set(INC
# For *_info.hh includes.
../compositor/realtime_compositor
../draw/engines/eevee_next
../draw/engines/select
../draw/engines/workbench
../draw/intern