WIP: Draw: Sub Handles #105175

Closed
Miguel Pozo wants to merge 5 commits from pragma37/blender:pull-thin-handles-2 into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
12 changed files with 100 additions and 43 deletions

View File

@ -31,12 +31,12 @@ void main()
frustum = isect_data_setup(pyramid); frustum = isect_data_setup(pyramid);
} }
uint resource_id = resource_ids_buf[gl_GlobalInvocationID.x]; uint _resource_id = resource_ids_buf[gl_GlobalInvocationID.x];
IsectBox box = isect_data_setup(bounds_buf[resource_id].bounding_corners[0].xyz, IsectBox box = isect_data_setup(bounds_buf[_resource_id].bounding_corners[0].xyz,
bounds_buf[resource_id].bounding_corners[1].xyz, bounds_buf[_resource_id].bounding_corners[1].xyz,
bounds_buf[resource_id].bounding_corners[2].xyz, bounds_buf[_resource_id].bounding_corners[2].xyz,
bounds_buf[resource_id].bounding_corners[3].xyz); bounds_buf[_resource_id].bounding_corners[3].xyz);
int clipped = 0; int clipped = 0;
/* NDC space post projection [-1..1] (unclamped). */ /* NDC space post projection [-1..1] (unclamped). */

View File

@ -126,13 +126,15 @@ GPU_SHADER_CREATE_INFO(workbench_next_prepass)
GPU_SHADER_CREATE_INFO(workbench_color_material) GPU_SHADER_CREATE_INFO(workbench_color_material)
.define("WORKBENCH_COLOR_MATERIAL") .define("WORKBENCH_COLOR_MATERIAL")
.storage_buf(WB_MATERIAL_SLOT, Qualifier::READ, "vec4", "materials_data[]"); .storage_buf(WB_MATERIAL_SLOT, Qualifier::READ, "vec4", "materials_data[]")
.storage_buf(WB_MATERIAL_START_SLOT, Qualifier::READ, "uint", "material_start_indices[]");
GPU_SHADER_CREATE_INFO(workbench_color_texture) GPU_SHADER_CREATE_INFO(workbench_color_texture)
.define("WORKBENCH_COLOR_TEXTURE") .define("WORKBENCH_COLOR_TEXTURE")
.define("WORKBENCH_TEXTURE_IMAGE_ARRAY") .define("WORKBENCH_TEXTURE_IMAGE_ARRAY")
.define("WORKBENCH_COLOR_MATERIAL") .define("WORKBENCH_COLOR_MATERIAL")
.storage_buf(WB_MATERIAL_SLOT, Qualifier::READ, "vec4", "materials_data[]") .storage_buf(WB_MATERIAL_SLOT, Qualifier::READ, "vec4", "materials_data[]")
.storage_buf(WB_MATERIAL_START_SLOT, Qualifier::READ, "uint", "material_start_indices[]")
.sampler(1, ImageType::FLOAT_2D, "imageTexture", Frequency::BATCH) .sampler(1, ImageType::FLOAT_2D, "imageTexture", Frequency::BATCH)
.sampler(2, ImageType::FLOAT_2D_ARRAY, "imageTileArray", Frequency::BATCH) .sampler(2, ImageType::FLOAT_2D_ARRAY, "imageTileArray", Frequency::BATCH)
.sampler(3, ImageType::FLOAT_1D_ARRAY, "imageTileData", Frequency::BATCH) .sampler(3, ImageType::FLOAT_1D_ARRAY, "imageTileData", Frequency::BATCH)

View File

@ -17,7 +17,8 @@ void workbench_material_data_get(int handle,
#else #else
# ifdef WORKBENCH_COLOR_MATERIAL # ifdef WORKBENCH_COLOR_MATERIAL
vec4 data = materials_data[handle]; uint index = material_start_indices[resource_id] + sub_resource_id;
vec4 data = materials_data[index];
# else # else
vec4 data = vec4(0.0); vec4 data = vec4(0.0);
# endif # endif

View File

@ -1,10 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */ /* SPDX-License-Identifier: GPL-2.0-or-later */
/* TEXTURE SLOTS */
#define WB_MATCAP_SLOT 0 #define WB_MATCAP_SLOT 0
#define WB_TEXTURE_SLOT 1 #define WB_TEXTURE_SLOT 1
#define WB_TILE_ARRAY_SLOT 2 #define WB_TILE_ARRAY_SLOT 2
#define WB_TILE_DATA_SLOT 3 #define WB_TILE_DATA_SLOT 3
#define WB_MATERIAL_SLOT 0 /* UBO SLOTS */
#define WB_WORLD_SLOT 4 #define WB_WORLD_SLOT 4
/* SSBO SLOTS */
#define WB_MATERIAL_SLOT 0
#define WB_MATERIAL_START_SLOT 1
#define WB_RESOLVE_GROUP_SIZE 8 #define WB_RESOLVE_GROUP_SIZE 8

View File

@ -38,6 +38,8 @@ class Instance {
DofPass dof_ps; DofPass dof_ps;
AntiAliasingPass anti_aliasing_ps; AntiAliasingPass anti_aliasing_ps;
uint material_count = 0;
/* An array of nullptr GPUMaterial pointers so we can call DRW_cache_object_surface_material_get. /* An array of nullptr GPUMaterial pointers so we can call DRW_cache_object_surface_material_get.
* They never get actually used. */ * They never get actually used. */
Vector<GPUMaterial *> dummy_gpu_materials = {1, nullptr, {}}; Vector<GPUMaterial *> dummy_gpu_materials = {1, nullptr, {}};
@ -68,6 +70,7 @@ class Instance {
resolution, resolution,
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT |
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW); GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW);
material_count = 0;
opaque_ps.sync(scene_state, resources); opaque_ps.sync(scene_state, resources);
transparent_ps.sync(scene_state, resources); transparent_ps.sync(scene_state, resources);
@ -82,6 +85,7 @@ class Instance {
void end_sync() void end_sync()
{ {
resources.material_buf.push_update(); resources.material_buf.push_update();
resources.per_obj_material_start_buf.push_update();
} }
void object_sync(Manager &manager, ObjectRef &ob_ref) void object_sync(Manager &manager, ObjectRef &ob_ref)
@ -177,6 +181,7 @@ class Instance {
void mesh_sync(Manager &manager, ObjectRef &ob_ref, const ObjectState &object_state) void mesh_sync(Manager &manager, ObjectRef &ob_ref, const ObjectState &object_state)
{ {
ResourceHandle handle = manager.resource_handle(ob_ref); ResourceHandle handle = manager.resource_handle(ob_ref);
resources.per_obj_material_start_buf.get_or_resize(handle.resource_index()) = material_count;
bool has_transparent_material = false; bool has_transparent_material = false;
if (object_state.sculpt_pbvh) { if (object_state.sculpt_pbvh) {
@ -186,7 +191,7 @@ class Instance {
} }
else { else {
if (object_state.use_per_material_batches) { if (object_state.use_per_material_batches) {
const int material_count = DRW_cache_object_material_count_get(ob_ref.object); const int slot_count = DRW_cache_object_material_count_get(ob_ref.object);
struct GPUBatch **batches; struct GPUBatch **batches;
if (object_state.color_type == V3D_SHADING_TEXTURE_COLOR) { if (object_state.color_type == V3D_SHADING_TEXTURE_COLOR) {
@ -194,20 +199,16 @@ class Instance {
} }
else { else {
batches = DRW_cache_object_surface_material_get( batches = DRW_cache_object_surface_material_get(
ob_ref.object, get_dummy_gpu_materials(material_count), material_count); ob_ref.object, get_dummy_gpu_materials(slot_count), slot_count);
} }
if (batches) { if (batches) {
for (auto i : IndexRange(material_count)) { for (auto i : IndexRange(slot_count)) {
if (batches[i] == nullptr) { if (batches[i] == nullptr) {
continue; continue;
} }
/* TODO(fclem): This create a cull-able instance for each sub-object. This is done
* for simplicity to reduce complexity. But this increase the overhead per object.
* Instead, we should use an indirection buffer to the material buffer. */
ResourceHandle _handle = i == 0 ? handle : manager.resource_handle(ob_ref);
Material &mat = resources.material_buf.get_or_resize(_handle.resource_index()); Material &mat = resources.material_buf.get_or_resize(material_count++);
if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, i + 1)) { if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, i + 1)) {
mat = Material(*_mat); mat = Material(*_mat);
@ -225,7 +226,10 @@ class Instance {
get_material_image(ob_ref.object, i + 1, image, iuser, sampler_state); get_material_image(ob_ref.object, i + 1, image, iuser, sampler_state);
} }
draw_mesh(ob_ref, mat, batches[i], _handle, image, sampler_state, iuser); if (i != 0) {
handle = manager.resource_sub_handle(handle);
}
draw_mesh(ob_ref, mat, batches[i], handle, image, sampler_state, iuser);
} }
} }
} }
@ -247,7 +251,7 @@ class Instance {
} }
if (batch) { if (batch) {
Material &mat = resources.material_buf.get_or_resize(handle.resource_index()); Material &mat = resources.material_buf.get_or_resize(material_count++);
if (object_state.color_type == V3D_SHADING_OBJECT_COLOR) { if (object_state.color_type == V3D_SHADING_OBJECT_COLOR) {
mat = Material(*ob_ref.object); mat = Material(*ob_ref.object);

View File

@ -22,8 +22,9 @@ void MeshPass::init_pass(SceneResources &resources, DRWState state, int clip_pla
PassMain::init(); PassMain::init();
state_set(state, clip_planes); state_set(state, clip_planes);
bind_texture(WB_MATCAP_SLOT, resources.matcap_tx); bind_texture(WB_MATCAP_SLOT, resources.matcap_tx);
bind_ssbo(WB_MATERIAL_SLOT, &resources.material_buf);
bind_ubo(WB_WORLD_SLOT, resources.world_buf); bind_ubo(WB_WORLD_SLOT, resources.world_buf);
bind_ssbo(WB_MATERIAL_SLOT, &resources.material_buf);
bind_ssbo(WB_MATERIAL_START_SLOT, &resources.per_obj_material_start_buf);
if (clip_planes > 0) { if (clip_planes > 0) {
bind_ubo(DRW_CLIPPING_UBO_SLOT, resources.clip_planes_buf); bind_ubo(DRW_CLIPPING_UBO_SLOT, resources.clip_planes_buf);
} }

View File

@ -148,6 +148,7 @@ struct SceneResources {
TextureFromPool depth_in_front_tx = "wb_depth_in_front_tx"; TextureFromPool depth_in_front_tx = "wb_depth_in_front_tx";
StorageVectorBuffer<Material> material_buf = {"material_buf"}; StorageVectorBuffer<Material> material_buf = {"material_buf"};
StorageVectorBuffer<uint> per_obj_material_start_buf = {"per_obj_material_start_buf"};
UniformBuffer<WorldData> world_buf = {}; UniformBuffer<WorldData> world_buf = {};
UniformArrayBuffer<float4, 6> clip_planes_buf; UniformArrayBuffer<float4, 6> clip_planes_buf;

View File

@ -26,24 +26,28 @@ struct DupliObject;
namespace blender::draw { namespace blender::draw {
struct ResourceHandle { struct ResourceHandle {
uint raw; union {
uint raw;
struct {
uint index : 26;
uint sub_index : 5;
uint inverted_handedness : 1;
};
};
ResourceHandle() = default; ResourceHandle() = default;
ResourceHandle(uint raw_) : raw(raw_){}; ResourceHandle(uint raw_) : raw(raw_){};
ResourceHandle(uint index, bool inverted_handedness) ResourceHandle(uint index, bool inverted_handedness)
{ : index(index), sub_index(0), inverted_handedness(inverted_handedness){};
raw = index;
SET_FLAG_FROM_TEST(raw, inverted_handedness, 0x80000000u);
}
bool has_inverted_handedness() const bool has_inverted_handedness() const
{ {
return (raw & 0x80000000u) != 0; return inverted_handedness != 0;
} }
uint resource_index() const uint resource_index() const
{ {
return (raw & 0x7FFFFFFFu); return index;
} }
}; };

View File

@ -55,6 +55,7 @@ void Manager::begin_sync()
#endif #endif
resource_len_ = 0; resource_len_ = 0;
attribute_len_ = 0; attribute_len_ = 0;
sub_handle_indices_.clear();
/* TODO(fclem): Resize buffers if too big, but with an hysteresis threshold. */ /* TODO(fclem): Resize buffers if too big, but with an hysteresis threshold. */
object_active = DST.draw_ctx.obact; object_active = DST.draw_ctx.obact;

View File

@ -109,6 +109,9 @@ class Manager {
/** Number of object attribute recorded. */ /** Number of object attribute recorded. */
uint attribute_len_ = 0; uint attribute_len_ = 0;
Vector<uint8_t> sub_handle_indices_;
int max_sub_handles_ = 32;
Object *object_active = nullptr; Object *object_active = nullptr;
public: public:
@ -134,6 +137,12 @@ class Manager {
const float3 &bounds_center, const float3 &bounds_center,
const float3 &bounds_half_extent); const float3 &bounds_half_extent);
/**
* Returns a copy of the resource handle with a unique sub-index.
* Or a new full copy handle when running out of sub-indices.
*/
ResourceHandle resource_sub_handle(const ResourceHandle handle);
/** /**
* Populate additional per resource data on demand. * Populate additional per resource data on demand.
*/ */
@ -196,6 +205,7 @@ inline ResourceHandle Manager::resource_handle(const ObjectRef ref)
matrix_buf.current().get_or_resize(resource_len_).sync(*ref.object); matrix_buf.current().get_or_resize(resource_len_).sync(*ref.object);
bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object); bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object);
infos_buf.current().get_or_resize(resource_len_).sync(ref, is_active_object); infos_buf.current().get_or_resize(resource_len_).sync(ref, is_active_object);
sub_handle_indices_.append(0);
return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0); return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0);
} }
@ -204,6 +214,7 @@ inline ResourceHandle Manager::resource_handle(const float4x4 &model_matrix)
matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix); matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);
bounds_buf.current().get_or_resize(resource_len_).sync(); bounds_buf.current().get_or_resize(resource_len_).sync();
infos_buf.current().get_or_resize(resource_len_).sync(); infos_buf.current().get_or_resize(resource_len_).sync();
sub_handle_indices_.append(0);
return ResourceHandle(resource_len_++, false); return ResourceHandle(resource_len_++, false);
} }
@ -214,9 +225,34 @@ inline ResourceHandle Manager::resource_handle(const float4x4 &model_matrix,
matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix); matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);
bounds_buf.current().get_or_resize(resource_len_).sync(bounds_center, bounds_half_extent); bounds_buf.current().get_or_resize(resource_len_).sync(bounds_center, bounds_half_extent);
infos_buf.current().get_or_resize(resource_len_).sync(); infos_buf.current().get_or_resize(resource_len_).sync();
sub_handle_indices_.append(0);
return ResourceHandle(resource_len_++, false); return ResourceHandle(resource_len_++, false);
} }
inline ResourceHandle Manager::resource_sub_handle(const ResourceHandle handle)
{
const uint i = handle.resource_index();
/* Always call resource_sub_handle_with a new handle or its last created sub-handle.
* This avoids reaching a point where a handle has been already saturated and each call to this
* function creates a new copy.*/
BLI_assert(handle.sub_index == sub_handle_indices_[i]);
if (++sub_handle_indices_[i] < max_sub_handles_) {
ResourceHandle sub_handle = handle;
sub_handle.sub_index = sub_handle_indices_[i];
return sub_handle;
}
else {
/* Can't add more sub handles, make a full copy instead. */
matrix_buf.current().get_or_resize(resource_len_) = matrix_buf.current()[i];
bounds_buf.current().get_or_resize(resource_len_) = bounds_buf.current()[i];
infos_buf.current().get_or_resize(resource_len_) = infos_buf.current()[i];
sub_handle_indices_.append(0);
return ResourceHandle(resource_len_++, handle.has_inverted_handedness());
}
}
inline void Manager::extract_object_attributes(ResourceHandle handle, inline void Manager::extract_object_attributes(ResourceHandle handle,
const ObjectRef &ref, const ObjectRef &ref,
Span<GPUMaterial *> materials) Span<GPUMaterial *> materials)

View File

@ -88,22 +88,22 @@ uniform int drw_resourceChunk;
/* This is in the case we want to do a special instance drawcall for one object but still want to /* This is in the case we want to do a special instance drawcall for one object but still want to
* have the right resourceId and all the correct ubo datas. */ * have the right resourceId and all the correct ubo datas. */
uniform int drw_ResourceID; uniform int drw_ResourceID;
# define resource_id drw_ResourceID # define _resource_id_ drw_ResourceID
# else # else
# define resource_id (gpu_BaseInstance + instanceId) # define _resource_id_ (gpu_BaseInstance + instanceId)
# endif # endif
/* Use this to declare and pass the value if /* Use this to declare and pass the value if
* the fragment shader uses the resource_id. */ * the fragment shader uses the resource_id. */
# if defined(EEVEE_GENERATED_INTERFACE) # if defined(EEVEE_GENERATED_INTERFACE)
# define RESOURCE_ID_VARYING # define RESOURCE_ID_VARYING
# define PASS_RESOURCE_ID resourceIDFrag = resource_id; # define PASS_RESOURCE_ID resourceIDFrag = _resource_id_;
# elif defined(USE_GEOMETRY_SHADER) # elif defined(USE_GEOMETRY_SHADER)
# define RESOURCE_ID_VARYING flat out int resourceIDGeom; # define RESOURCE_ID_VARYING flat out int resourceIDGeom;
# define PASS_RESOURCE_ID resourceIDGeom = resource_id; # define PASS_RESOURCE_ID resourceIDGeom = _resource_id_;
# else # else
# define RESOURCE_ID_VARYING flat out int resourceIDFrag; # define RESOURCE_ID_VARYING flat out int resourceIDFrag;
# define PASS_RESOURCE_ID resourceIDFrag = resource_id; # define PASS_RESOURCE_ID resourceIDFrag = _resource_id_;
# endif # endif
# endif /* USE_GPU_SHADER_CREATE_INFO */ # endif /* USE_GPU_SHADER_CREATE_INFO */
@ -114,23 +114,23 @@ uniform int drw_ResourceID;
#ifdef USE_GPU_SHADER_CREATE_INFO #ifdef USE_GPU_SHADER_CREATE_INFO
/* TODO(fclem): Rename PASS_RESOURCE_ID to DRW_RESOURCE_ID_VARYING_SET */ /* TODO(fclem): Rename PASS_RESOURCE_ID to DRW_RESOURCE_ID_VARYING_SET */
# if defined(UNIFORM_RESOURCE_ID) # if defined(UNIFORM_RESOURCE_ID)
# define resource_id drw_ResourceID # define _resource_id_ drw_ResourceID
# define PASS_RESOURCE_ID # define PASS_RESOURCE_ID
# elif defined(GPU_VERTEX_SHADER) # elif defined(GPU_VERTEX_SHADER)
# if defined(UNIFORM_RESOURCE_ID_NEW) # if defined(UNIFORM_RESOURCE_ID_NEW)
# define resource_id (drw_ResourceID >> DRW_VIEW_SHIFT) # define _resource_id_ (drw_ResourceID >> DRW_VIEW_SHIFT)
# else # else
# define resource_id gpu_InstanceIndex # define _resource_id_ gpu_InstanceIndex
# endif # endif
# define PASS_RESOURCE_ID drw_ResourceID_iface.resource_index = resource_id; # define PASS_RESOURCE_ID drw_ResourceID_iface.resource_index = _resource_id_;
# elif defined(GPU_GEOMETRY_SHADER) # elif defined(GPU_GEOMETRY_SHADER)
# define resource_id drw_ResourceID_iface_in[0].resource_index # define _resource_id_ drw_ResourceID_iface_in[0].resource_index
# define PASS_RESOURCE_ID drw_ResourceID_iface_out.resource_index = resource_id; # define PASS_RESOURCE_ID drw_ResourceID_iface_out.resource_index = _resource_id_;
# elif defined(GPU_FRAGMENT_SHADER) # elif defined(GPU_FRAGMENT_SHADER)
# define resource_id drw_ResourceID_iface.resource_index # define _resource_id_ drw_ResourceID_iface.resource_index
# endif # endif
/* TODO(fclem): Remove. */ /* TODO(fclem): Remove. */
@ -149,18 +149,21 @@ uniform int drw_ResourceID;
# define RESOURCE_ID_VARYING # define RESOURCE_ID_VARYING
# endif # endif
# define resource_id resourceIDGeom # define _resource_id_ resourceIDGeom
# define PASS_RESOURCE_ID resourceIDFrag = resource_id[0]; # define PASS_RESOURCE_ID resourceIDFrag = _resource_id_[0];
# endif # endif
# if defined(GPU_FRAGMENT_SHADER) # if defined(GPU_FRAGMENT_SHADER)
# if !defined(EEVEE_GENERATED_INTERFACE) # if !defined(EEVEE_GENERATED_INTERFACE)
flat in int resourceIDFrag; flat in int resourceIDFrag;
# endif # endif
# define resource_id resourceIDFrag # define _resource_id_ resourceIDFrag
# endif # endif
#endif #endif
#define resource_id int(_resource_id_ & 0x03FFFFFFu)
#define sub_resource_id int((_resource_id_ >> 26) & 0x1Fu)
/* Breaking this across multiple lines causes issues for some older GLSL compilers. */ /* Breaking this across multiple lines causes issues for some older GLSL compilers. */
/* clang-format off */ /* clang-format off */
#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && (!defined(OS_MAC) || defined(GPU_METAL)) && !defined(INSTANCED_ATTR) && !defined(DRW_LEGACY_MODEL_MATRIX) #if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && (!defined(OS_MAC) || defined(GPU_METAL)) && !defined(INSTANCED_ATTR) && !defined(DRW_LEGACY_MODEL_MATRIX)

View File

@ -53,7 +53,7 @@ void main()
DrawPrototype proto = prototype_buf[proto_id]; DrawPrototype proto = prototype_buf[proto_id];
uint group_id = proto.group_id; uint group_id = proto.group_id;
bool is_inverted = (proto.resource_handle & 0x80000000u) != 0; bool is_inverted = (proto.resource_handle & 0x80000000u) != 0;
uint resource_index = (proto.resource_handle & 0x7FFFFFFFu); uint resource_index = (proto.resource_handle & 0x03FFFFFFu);
/* Visibility test result. */ /* Visibility test result. */
uint visible_instance_len = 0; uint visible_instance_len = 0;
@ -117,7 +117,7 @@ void main()
} }
else { else {
for (uint i = dst_index; i < dst_index + visible_instance_len; i++) { for (uint i = dst_index; i < dst_index + visible_instance_len; i++) {
resource_id_buf[i] = resource_index; resource_id_buf[i] = proto.resource_handle & 0x7FFFFFFFu;
} }
} }
} }