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);
}
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,
bounds_buf[resource_id].bounding_corners[1].xyz,
bounds_buf[resource_id].bounding_corners[2].xyz,
bounds_buf[resource_id].bounding_corners[3].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[2].xyz,
bounds_buf[_resource_id].bounding_corners[3].xyz);
int clipped = 0;
/* 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)
.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)
.define("WORKBENCH_COLOR_TEXTURE")
.define("WORKBENCH_TEXTURE_IMAGE_ARRAY")
.define("WORKBENCH_COLOR_MATERIAL")
.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(2, ImageType::FLOAT_2D_ARRAY, "imageTileArray", 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
# 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
vec4 data = vec4(0.0);
# endif

View File

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

View File

@ -38,6 +38,8 @@ class Instance {
DofPass dof_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.
* They never get actually used. */
Vector<GPUMaterial *> dummy_gpu_materials = {1, nullptr, {}};
@ -68,6 +70,7 @@ class Instance {
resolution,
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT |
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW);
material_count = 0;
opaque_ps.sync(scene_state, resources);
transparent_ps.sync(scene_state, resources);
@ -82,6 +85,7 @@ class Instance {
void end_sync()
{
resources.material_buf.push_update();
resources.per_obj_material_start_buf.push_update();
}
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)
{
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;
if (object_state.sculpt_pbvh) {
@ -186,7 +191,7 @@ class Instance {
}
else {
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;
if (object_state.color_type == V3D_SHADING_TEXTURE_COLOR) {
@ -194,20 +199,16 @@ class Instance {
}
else {
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) {
for (auto i : IndexRange(material_count)) {
for (auto i : IndexRange(slot_count)) {
if (batches[i] == nullptr) {
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)) {
mat = Material(*_mat);
@ -225,7 +226,10 @@ class Instance {
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) {
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) {
mat = Material(*ob_ref.object);

View File

@ -22,8 +22,9 @@ void MeshPass::init_pass(SceneResources &resources, DRWState state, int clip_pla
PassMain::init();
state_set(state, clip_planes);
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_ssbo(WB_MATERIAL_SLOT, &resources.material_buf);
bind_ssbo(WB_MATERIAL_START_SLOT, &resources.per_obj_material_start_buf);
if (clip_planes > 0) {
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";
StorageVectorBuffer<Material> material_buf = {"material_buf"};
StorageVectorBuffer<uint> per_obj_material_start_buf = {"per_obj_material_start_buf"};
UniformBuffer<WorldData> world_buf = {};
UniformArrayBuffer<float4, 6> clip_planes_buf;

View File

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

View File

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

View File

@ -109,6 +109,9 @@ class Manager {
/** Number of object attribute recorded. */
uint attribute_len_ = 0;
Vector<uint8_t> sub_handle_indices_;
int max_sub_handles_ = 32;
Object *object_active = nullptr;
public:
@ -134,6 +137,12 @@ class Manager {
const float3 &bounds_center,
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.
*/
@ -196,6 +205,7 @@ inline ResourceHandle Manager::resource_handle(const ObjectRef ref)
matrix_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);
sub_handle_indices_.append(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);
bounds_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);
}
@ -214,9 +225,34 @@ inline ResourceHandle Manager::resource_handle(const float4x4 &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);
infos_buf.current().get_or_resize(resource_len_).sync();
sub_handle_indices_.append(0);
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,
const ObjectRef &ref,
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
* have the right resourceId and all the correct ubo datas. */
uniform int drw_ResourceID;
# define resource_id drw_ResourceID
# define _resource_id_ drw_ResourceID
# else
# define resource_id (gpu_BaseInstance + instanceId)
# define _resource_id_ (gpu_BaseInstance + instanceId)
# endif
/* Use this to declare and pass the value if
* the fragment shader uses the resource_id. */
# if defined(EEVEE_GENERATED_INTERFACE)
# define RESOURCE_ID_VARYING
# define PASS_RESOURCE_ID resourceIDFrag = resource_id;
# define PASS_RESOURCE_ID resourceIDFrag = _resource_id_;
# elif defined(USE_GEOMETRY_SHADER)
# define RESOURCE_ID_VARYING flat out int resourceIDGeom;
# define PASS_RESOURCE_ID resourceIDGeom = resource_id;
# define PASS_RESOURCE_ID resourceIDGeom = _resource_id_;
# else
# define RESOURCE_ID_VARYING flat out int resourceIDFrag;
# define PASS_RESOURCE_ID resourceIDFrag = resource_id;
# define PASS_RESOURCE_ID resourceIDFrag = _resource_id_;
# endif
# endif /* USE_GPU_SHADER_CREATE_INFO */
@ -114,23 +114,23 @@ uniform int drw_ResourceID;
#ifdef USE_GPU_SHADER_CREATE_INFO
/* TODO(fclem): Rename PASS_RESOURCE_ID to DRW_RESOURCE_ID_VARYING_SET */
# if defined(UNIFORM_RESOURCE_ID)
# define resource_id drw_ResourceID
# define _resource_id_ drw_ResourceID
# define PASS_RESOURCE_ID
# elif defined(GPU_VERTEX_SHADER)
# if defined(UNIFORM_RESOURCE_ID_NEW)
# define resource_id (drw_ResourceID >> DRW_VIEW_SHIFT)
# define _resource_id_ (drw_ResourceID >> DRW_VIEW_SHIFT)
# else
# define resource_id gpu_InstanceIndex
# define _resource_id_ gpu_InstanceIndex
# 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)
# define resource_id drw_ResourceID_iface_in[0].resource_index
# define PASS_RESOURCE_ID drw_ResourceID_iface_out.resource_index = resource_id;
# define _resource_id_ drw_ResourceID_iface_in[0].resource_index
# define PASS_RESOURCE_ID drw_ResourceID_iface_out.resource_index = _resource_id_;
# elif defined(GPU_FRAGMENT_SHADER)
# define resource_id drw_ResourceID_iface.resource_index
# define _resource_id_ drw_ResourceID_iface.resource_index
# endif
/* TODO(fclem): Remove. */
@ -149,18 +149,21 @@ uniform int drw_ResourceID;
# define RESOURCE_ID_VARYING
# endif
# define resource_id resourceIDGeom
# define PASS_RESOURCE_ID resourceIDFrag = resource_id[0];
# define _resource_id_ resourceIDGeom
# define PASS_RESOURCE_ID resourceIDFrag = _resource_id_[0];
# endif
# if defined(GPU_FRAGMENT_SHADER)
# if !defined(EEVEE_GENERATED_INTERFACE)
flat in int resourceIDFrag;
# endif
# define resource_id resourceIDFrag
# define _resource_id_ resourceIDFrag
# 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. */
/* 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)

View File

@ -53,7 +53,7 @@ void main()
DrawPrototype proto = prototype_buf[proto_id];
uint group_id = proto.group_id;
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. */
uint visible_instance_len = 0;
@ -117,7 +117,7 @@ void main()
}
else {
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;
}
}
}