WIP: Draw: Sub Handles #105175
|
@ -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). */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue