Merge pull request #112481 from stuartcarnie/2d_canvas_vbos
Massively optimize canvas 2D rendering by using vertex buffers
This commit is contained in:
@ -1165,6 +1165,24 @@ uint8_t *RenderingDeviceDriverD3D12::buffer_persistent_map_advance(BufferID p_bu
|
||||
return buf_info->persistent_ptr + buf_info->frame_idx * buf_info->size;
|
||||
}
|
||||
|
||||
uint64_t RenderingDeviceDriverD3D12::buffer_get_dynamic_offsets(Span<BufferID> p_buffers) {
|
||||
uint64_t mask = 0u;
|
||||
uint64_t shift = 0u;
|
||||
|
||||
for (const BufferID &buf : p_buffers) {
|
||||
const BufferInfo *buf_info = (const BufferInfo *)buf.id;
|
||||
if (!buf_info->is_dynamic()) {
|
||||
continue;
|
||||
}
|
||||
const BufferDynamicInfo *dyn_buf = (const BufferDynamicInfo *)buf.id;
|
||||
mask |= dyn_buf->frame_idx << shift;
|
||||
// We can encode the frame index in 2 bits since frame_count won't be > 4.
|
||||
shift += 2UL;
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
uint64_t RenderingDeviceDriverD3D12::buffer_get_device_address(BufferID p_buffer) {
|
||||
const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;
|
||||
return buf_info->resource->GetGPUVirtualAddress();
|
||||
@ -2183,27 +2201,36 @@ bool RenderingDeviceDriverD3D12::sampler_is_format_supported_for_filter(DataForm
|
||||
/**** VERTEX ARRAY ****/
|
||||
/**********************/
|
||||
|
||||
RDD::VertexFormatID RenderingDeviceDriverD3D12::vertex_format_create(VectorView<VertexAttribute> p_vertex_attribs) {
|
||||
RDD::VertexFormatID RenderingDeviceDriverD3D12::vertex_format_create(Span<VertexAttribute> p_vertex_attribs, const VertexAttributeBindingsMap &p_vertex_bindings) {
|
||||
VertexFormatInfo *vf_info = VersatileResource::allocate<VertexFormatInfo>(resources_allocator);
|
||||
|
||||
vf_info->input_elem_descs.resize(p_vertex_attribs.size());
|
||||
vf_info->vertex_buffer_strides.resize(p_vertex_attribs.size());
|
||||
|
||||
uint32_t max_binding = 0;
|
||||
for (uint32_t i = 0; i < p_vertex_attribs.size(); i++) {
|
||||
vf_info->input_elem_descs[i] = {};
|
||||
vf_info->input_elem_descs[i].SemanticName = "TEXCOORD";
|
||||
vf_info->input_elem_descs[i].SemanticIndex = p_vertex_attribs[i].location;
|
||||
vf_info->input_elem_descs[i].Format = RD_TO_D3D12_FORMAT[p_vertex_attribs[i].format].general_format;
|
||||
vf_info->input_elem_descs[i].InputSlot = i; // TODO: Can the same slot be used if data comes from the same buffer (regardless format)?
|
||||
vf_info->input_elem_descs[i].AlignedByteOffset = p_vertex_attribs[i].offset;
|
||||
if (p_vertex_attribs[i].frequency == VERTEX_FREQUENCY_INSTANCE) {
|
||||
vf_info->input_elem_descs[i].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
|
||||
vf_info->input_elem_descs[i].InstanceDataStepRate = 1;
|
||||
D3D12_INPUT_ELEMENT_DESC &input_element_desc = vf_info->input_elem_descs[i];
|
||||
const VertexAttribute &vertex_attrib = p_vertex_attribs[i];
|
||||
const VertexAttributeBinding &vertex_binding = p_vertex_bindings[vertex_attrib.binding];
|
||||
|
||||
input_element_desc = {};
|
||||
input_element_desc.SemanticName = "TEXCOORD";
|
||||
input_element_desc.SemanticIndex = vertex_attrib.location;
|
||||
input_element_desc.Format = RD_TO_D3D12_FORMAT[vertex_attrib.format].general_format;
|
||||
input_element_desc.InputSlot = vertex_attrib.binding;
|
||||
input_element_desc.AlignedByteOffset = vertex_attrib.offset;
|
||||
if (vertex_binding.frequency == VERTEX_FREQUENCY_INSTANCE) {
|
||||
input_element_desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
|
||||
input_element_desc.InstanceDataStepRate = 1;
|
||||
} else {
|
||||
vf_info->input_elem_descs[i].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
|
||||
vf_info->input_elem_descs[i].InstanceDataStepRate = 0;
|
||||
input_element_desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
|
||||
input_element_desc.InstanceDataStepRate = 0;
|
||||
}
|
||||
|
||||
vf_info->vertex_buffer_strides[i] = p_vertex_attribs[i].stride;
|
||||
max_binding = MAX(max_binding, vertex_attrib.binding + 1);
|
||||
}
|
||||
|
||||
vf_info->vertex_buffer_strides.resize(max_binding);
|
||||
for (const VertexAttributeBindingsMap::KV &vertex_binding_pair : p_vertex_bindings) {
|
||||
vf_info->vertex_buffer_strides[vertex_binding_pair.key] = vertex_binding_pair.value.stride;
|
||||
}
|
||||
|
||||
return VertexFormatID(vf_info);
|
||||
@ -5378,7 +5405,7 @@ void RenderingDeviceDriverD3D12::command_render_draw_indirect_count(CommandBuffe
|
||||
cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw.Get(), p_max_draw_count, indirect_buf_info->resource, p_offset, count_buf_info->resource, p_count_buffer_offset);
|
||||
}
|
||||
|
||||
void RenderingDeviceDriverD3D12::command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets) {
|
||||
void RenderingDeviceDriverD3D12::command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets, uint64_t p_dynamic_offsets) {
|
||||
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
|
||||
|
||||
DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);
|
||||
@ -5390,8 +5417,15 @@ void RenderingDeviceDriverD3D12::command_render_bind_vertex_buffers(CommandBuffe
|
||||
for (uint32_t i = 0; i < p_binding_count; i++) {
|
||||
BufferInfo *buffer_info = (BufferInfo *)p_buffers[i].id;
|
||||
|
||||
uint32_t dynamic_offset = 0;
|
||||
if (buffer_info->is_dynamic()) {
|
||||
uint64_t buffer_frame_idx = p_dynamic_offsets & 0x3; // Assuming max 4 frames.
|
||||
p_dynamic_offsets >>= 2;
|
||||
dynamic_offset = buffer_frame_idx * buffer_info->size;
|
||||
}
|
||||
|
||||
cmd_buf_info->render_pass_state.vertex_buffer_views[i] = {};
|
||||
cmd_buf_info->render_pass_state.vertex_buffer_views[i].BufferLocation = buffer_info->resource->GetGPUVirtualAddress() + p_offsets[i];
|
||||
cmd_buf_info->render_pass_state.vertex_buffer_views[i].BufferLocation = buffer_info->resource->GetGPUVirtualAddress() + dynamic_offset + p_offsets[i];
|
||||
cmd_buf_info->render_pass_state.vertex_buffer_views[i].SizeInBytes = buffer_info->size - p_offsets[i];
|
||||
if (!barrier_capabilities.enhanced_barriers_supported) {
|
||||
_resource_transition_batch(cmd_buf_info, buffer_info, 0, 1, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
|
||||
|
||||
@ -347,6 +347,7 @@ public:
|
||||
virtual uint8_t *buffer_map(BufferID p_buffer) override final;
|
||||
virtual void buffer_unmap(BufferID p_buffer) override final;
|
||||
virtual uint8_t *buffer_persistent_map_advance(BufferID p_buffer, uint64_t p_frames_drawn) override final;
|
||||
virtual uint64_t buffer_get_dynamic_offsets(Span<BufferID> p_buffers) override final;
|
||||
virtual uint64_t buffer_get_device_address(BufferID p_buffer) override final;
|
||||
|
||||
/*****************/
|
||||
@ -429,7 +430,7 @@ private:
|
||||
};
|
||||
|
||||
public:
|
||||
virtual VertexFormatID vertex_format_create(VectorView<VertexAttribute> p_vertex_attribs) override final;
|
||||
virtual VertexFormatID vertex_format_create(Span<VertexAttribute> p_vertex_attribs, const VertexAttributeBindingsMap &p_vertex_bindings) override final;
|
||||
virtual void vertex_format_free(VertexFormatID p_vertex_format) override final;
|
||||
|
||||
/******************/
|
||||
@ -862,7 +863,7 @@ public:
|
||||
virtual void command_render_draw_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) override final;
|
||||
|
||||
// Buffer binding.
|
||||
virtual void command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets) override final;
|
||||
virtual void command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets, uint64_t p_dynamic_offsets) override final;
|
||||
virtual void command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) override final;
|
||||
|
||||
private:
|
||||
|
||||
@ -663,7 +663,7 @@ public:
|
||||
uint32_t p_instance_count,
|
||||
uint32_t p_base_vertex,
|
||||
uint32_t p_first_instance);
|
||||
void render_bind_vertex_buffers(uint32_t p_binding_count, const RDD::BufferID *p_buffers, const uint64_t *p_offsets);
|
||||
void render_bind_vertex_buffers(uint32_t p_binding_count, const RDD::BufferID *p_buffers, const uint64_t *p_offsets, uint64_t p_dynamic_offsets);
|
||||
void render_bind_index_buffer(RDD::BufferID p_buffer, RDD::IndexBufferFormat p_format, uint64_t p_offset);
|
||||
|
||||
void render_draw_indexed(uint32_t p_index_count,
|
||||
|
||||
@ -783,10 +783,12 @@ void MDCommandBuffer::_render_set_dirty_state() {
|
||||
|
||||
if (render.dirty.has_flag(RenderState::DIRTY_VERTEX)) {
|
||||
uint32_t p_binding_count = render.vertex_buffers.size();
|
||||
uint32_t first = device_driver->get_metal_buffer_index_for_vertex_attribute_binding(p_binding_count - 1);
|
||||
[render.encoder setVertexBuffers:render.vertex_buffers.ptr()
|
||||
offsets:render.vertex_offsets.ptr()
|
||||
withRange:NSMakeRange(first, p_binding_count)];
|
||||
if (p_binding_count > 0) {
|
||||
uint32_t first = device_driver->get_metal_buffer_index_for_vertex_attribute_binding(p_binding_count - 1);
|
||||
[render.encoder setVertexBuffers:render.vertex_buffers.ptr()
|
||||
offsets:render.vertex_offsets.ptr()
|
||||
withRange:NSMakeRange(first, p_binding_count)];
|
||||
}
|
||||
}
|
||||
|
||||
render.resource_tracker.encode(render.encoder);
|
||||
@ -1252,24 +1254,47 @@ void MDCommandBuffer::render_draw(uint32_t p_vertex_count,
|
||||
baseInstance:p_first_instance];
|
||||
}
|
||||
|
||||
void MDCommandBuffer::render_bind_vertex_buffers(uint32_t p_binding_count, const RDD::BufferID *p_buffers, const uint64_t *p_offsets) {
|
||||
void MDCommandBuffer::render_bind_vertex_buffers(uint32_t p_binding_count, const RDD::BufferID *p_buffers, const uint64_t *p_offsets, uint64_t p_dynamic_offsets) {
|
||||
DEV_ASSERT(type == MDCommandBufferStateType::Render);
|
||||
|
||||
render.vertex_buffers.resize(p_binding_count);
|
||||
render.vertex_offsets.resize(p_binding_count);
|
||||
|
||||
// Are the existing buffer bindings the same?
|
||||
bool same = true;
|
||||
|
||||
// Reverse the buffers, as their bindings are assigned in descending order.
|
||||
for (uint32_t i = 0; i < p_binding_count; i += 1) {
|
||||
const RenderingDeviceDriverMetal::BufferInfo *buf_info = (const RenderingDeviceDriverMetal::BufferInfo *)p_buffers[p_binding_count - i - 1].id;
|
||||
render.vertex_buffers[i] = buf_info->metal_buffer;
|
||||
render.vertex_offsets[i] = p_offsets[p_binding_count - i - 1];
|
||||
|
||||
NSUInteger dynamic_offset = 0;
|
||||
if (buf_info->is_dynamic()) {
|
||||
const MetalBufferDynamicInfo *dyn_buf = (const MetalBufferDynamicInfo *)buf_info;
|
||||
uint64_t frame_idx = p_dynamic_offsets & 0x3;
|
||||
p_dynamic_offsets >>= 2;
|
||||
dynamic_offset = frame_idx * dyn_buf->size_bytes;
|
||||
}
|
||||
if (render.vertex_buffers[i] != buf_info->metal_buffer) {
|
||||
render.vertex_buffers[i] = buf_info->metal_buffer;
|
||||
same = false;
|
||||
}
|
||||
|
||||
render.vertex_offsets[i] = dynamic_offset + p_offsets[p_binding_count - i - 1];
|
||||
}
|
||||
|
||||
if (render.encoder) {
|
||||
uint32_t first = device_driver->get_metal_buffer_index_for_vertex_attribute_binding(p_binding_count - 1);
|
||||
[render.encoder setVertexBuffers:render.vertex_buffers.ptr()
|
||||
offsets:render.vertex_offsets.ptr()
|
||||
withRange:NSMakeRange(first, p_binding_count)];
|
||||
if (same) {
|
||||
NSUInteger *offset_ptr = render.vertex_offsets.ptr();
|
||||
for (uint32_t i = first; i < first + p_binding_count; i++) {
|
||||
[render.encoder setVertexBufferOffset:*offset_ptr atIndex:i];
|
||||
offset_ptr++;
|
||||
}
|
||||
} else {
|
||||
[render.encoder setVertexBuffers:render.vertex_buffers.ptr()
|
||||
offsets:render.vertex_offsets.ptr()
|
||||
withRange:NSMakeRange(first, p_binding_count)];
|
||||
}
|
||||
render.dirty.clear_flag(RenderState::DIRTY_VERTEX);
|
||||
} else {
|
||||
render.dirty.set_flag(RenderState::DIRTY_VERTEX);
|
||||
@ -1394,7 +1419,9 @@ void MDCommandBuffer::RenderState::reset() {
|
||||
viewports.clear();
|
||||
scissors.clear();
|
||||
blend_constants.reset();
|
||||
bzero(vertex_buffers.ptr(), sizeof(id<MTLBuffer> __unsafe_unretained) * vertex_buffers.size());
|
||||
vertex_buffers.clear();
|
||||
bzero(vertex_offsets.ptr(), sizeof(NSUInteger) * vertex_offsets.size());
|
||||
vertex_offsets.clear();
|
||||
resource_tracker.reset();
|
||||
}
|
||||
|
||||
@ -130,6 +130,7 @@ public:
|
||||
virtual uint8_t *buffer_map(BufferID p_buffer) override final;
|
||||
virtual void buffer_unmap(BufferID p_buffer) override final;
|
||||
virtual uint8_t *buffer_persistent_map_advance(BufferID p_buffer, uint64_t p_frames_drawn) override final;
|
||||
virtual uint64_t buffer_get_dynamic_offsets(Span<BufferID> p_buffers) override final;
|
||||
virtual void buffer_flush(BufferID p_buffer) override final;
|
||||
virtual uint64_t buffer_get_device_address(BufferID p_buffer) override final;
|
||||
|
||||
@ -164,7 +165,7 @@ public:
|
||||
|
||||
private:
|
||||
public:
|
||||
virtual VertexFormatID vertex_format_create(VectorView<VertexAttribute> p_vertex_attribs) override final;
|
||||
virtual VertexFormatID vertex_format_create(Span<VertexAttribute> p_vertex_attribs, const VertexAttributeBindingsMap &p_vertex_bindings) override final;
|
||||
virtual void vertex_format_free(VertexFormatID p_vertex_format) override final;
|
||||
|
||||
#pragma mark - Barriers
|
||||
@ -403,7 +404,7 @@ public:
|
||||
virtual void command_render_draw_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) override final;
|
||||
|
||||
// Buffer binding.
|
||||
virtual void command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets) override final;
|
||||
virtual void command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets, uint64_t p_dynamic_offsets) override final;
|
||||
virtual void command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) override final;
|
||||
|
||||
// Dynamic state.
|
||||
|
||||
@ -186,6 +186,23 @@ uint8_t *RenderingDeviceDriverMetal::buffer_persistent_map_advance(BufferID p_bu
|
||||
return (uint8_t *)buf_info->metal_buffer.contents + buf_info->next_frame_index(_frame_count) * buf_info->size_bytes;
|
||||
}
|
||||
|
||||
uint64_t RenderingDeviceDriverMetal::buffer_get_dynamic_offsets(Span<BufferID> p_buffers) {
|
||||
uint64_t mask = 0u;
|
||||
uint64_t shift = 0u;
|
||||
|
||||
for (const BufferID &buf : p_buffers) {
|
||||
const BufferInfo *buf_info = (const BufferInfo *)buf.id;
|
||||
if (!buf_info->is_dynamic()) {
|
||||
continue;
|
||||
}
|
||||
mask |= buf_info->frame_index() << shift;
|
||||
// We can encode the frame index in 2 bits since frame_count won't be > 4.
|
||||
shift += 2UL;
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
void RenderingDeviceDriverMetal::buffer_flush(BufferID p_buffer) {
|
||||
// Nothing to do.
|
||||
}
|
||||
@ -809,27 +826,33 @@ bool RenderingDeviceDriverMetal::sampler_is_format_supported_for_filter(DataForm
|
||||
|
||||
#pragma mark - Vertex Array
|
||||
|
||||
RDD::VertexFormatID RenderingDeviceDriverMetal::vertex_format_create(VectorView<VertexAttribute> p_vertex_attribs) {
|
||||
RDD::VertexFormatID RenderingDeviceDriverMetal::vertex_format_create(Span<VertexAttribute> p_vertex_attribs, const VertexAttributeBindingsMap &p_vertex_bindings) {
|
||||
MTLVertexDescriptor *desc = MTLVertexDescriptor.vertexDescriptor;
|
||||
|
||||
for (uint32_t i = 0; i < p_vertex_attribs.size(); i++) {
|
||||
VertexAttribute const &vf = p_vertex_attribs[i];
|
||||
|
||||
ERR_FAIL_COND_V_MSG(get_format_vertex_size(vf.format) == 0, VertexFormatID(),
|
||||
"Data format for attachment (" + itos(i) + "), '" + FORMAT_NAMES[vf.format] + "', is not valid for a vertex array.");
|
||||
for (const VertexAttributeBindingsMap::KV &kv : p_vertex_bindings) {
|
||||
uint32_t idx = get_metal_buffer_index_for_vertex_attribute_binding(kv.key);
|
||||
MTLVertexBufferLayoutDescriptor *ld = desc.layouts[idx];
|
||||
if (kv.value.stride != 0) {
|
||||
ld.stepFunction = kv.value.frequency == VERTEX_FREQUENCY_VERTEX ? MTLVertexStepFunctionPerVertex : MTLVertexStepFunctionPerInstance;
|
||||
ld.stepRate = 1;
|
||||
ld.stride = kv.value.stride;
|
||||
} else {
|
||||
ld.stepFunction = MTLVertexStepFunctionConstant;
|
||||
ld.stepRate = 0;
|
||||
ld.stride = 0;
|
||||
}
|
||||
DEV_ASSERT(ld.stride == desc.layouts[idx].stride);
|
||||
}
|
||||
|
||||
for (const VertexAttribute &vf : p_vertex_attribs) {
|
||||
desc.attributes[vf.location].format = pixel_formats->getMTLVertexFormat(vf.format);
|
||||
desc.attributes[vf.location].offset = vf.offset;
|
||||
uint32_t idx = get_metal_buffer_index_for_vertex_attribute_binding(i);
|
||||
uint32_t idx = get_metal_buffer_index_for_vertex_attribute_binding(vf.binding);
|
||||
desc.attributes[vf.location].bufferIndex = idx;
|
||||
if (vf.stride == 0) {
|
||||
desc.layouts[idx].stepFunction = MTLVertexStepFunctionConstant;
|
||||
desc.layouts[idx].stepRate = 0;
|
||||
desc.layouts[idx].stride = pixel_formats->getBytesPerBlock(vf.format);
|
||||
} else {
|
||||
desc.layouts[idx].stepFunction = vf.frequency == VERTEX_FREQUENCY_VERTEX ? MTLVertexStepFunctionPerVertex : MTLVertexStepFunctionPerInstance;
|
||||
desc.layouts[idx].stepRate = 1;
|
||||
desc.layouts[idx].stride = vf.stride;
|
||||
// Constant attribute, so we must determine the stride to satisfy Metal API.
|
||||
uint32_t stride = desc.layouts[idx].stride;
|
||||
desc.layouts[idx].stride = std::max(stride, vf.offset + pixel_formats->getBytesPerBlock(vf.format));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1768,9 +1791,9 @@ void RenderingDeviceDriverMetal::command_render_draw_indirect_count(CommandBuffe
|
||||
cb->render_draw_indirect_count(p_indirect_buffer, p_offset, p_count_buffer, p_count_buffer_offset, p_max_draw_count, p_stride);
|
||||
}
|
||||
|
||||
void RenderingDeviceDriverMetal::command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets) {
|
||||
void RenderingDeviceDriverMetal::command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets, uint64_t p_dynamic_offsets) {
|
||||
MDCommandBuffer *cb = (MDCommandBuffer *)(p_cmd_buffer.id);
|
||||
cb->render_bind_vertex_buffers(p_binding_count, p_buffers, p_offsets);
|
||||
cb->render_bind_vertex_buffers(p_binding_count, p_buffers, p_offsets, p_dynamic_offsets);
|
||||
}
|
||||
|
||||
void RenderingDeviceDriverMetal::command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) {
|
||||
|
||||
@ -1815,6 +1815,23 @@ uint8_t *RenderingDeviceDriverVulkan::buffer_persistent_map_advance(BufferID p_b
|
||||
return buf_info->persistent_ptr + buf_info->frame_idx * buf_info->size;
|
||||
}
|
||||
|
||||
uint64_t RenderingDeviceDriverVulkan::buffer_get_dynamic_offsets(Span<BufferID> p_buffers) {
|
||||
uint64_t mask = 0u;
|
||||
uint64_t shift = 0u;
|
||||
|
||||
for (const BufferID &buf : p_buffers) {
|
||||
const BufferInfo *buf_info = (const BufferInfo *)buf.id;
|
||||
if (!buf_info->is_dynamic()) {
|
||||
continue;
|
||||
}
|
||||
mask |= buf_info->frame_idx << shift;
|
||||
// We can encode the frame index in 2 bits since frame_count won't be > 4.
|
||||
shift += 2UL;
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
void RenderingDeviceDriverVulkan::buffer_flush(BufferID p_buffer) {
|
||||
BufferDynamicInfo *buf_info = (BufferDynamicInfo *)p_buffer.id;
|
||||
|
||||
@ -2525,19 +2542,23 @@ bool RenderingDeviceDriverVulkan::sampler_is_format_supported_for_filter(DataFor
|
||||
/**** VERTEX ARRAY ****/
|
||||
/**********************/
|
||||
|
||||
RDD::VertexFormatID RenderingDeviceDriverVulkan::vertex_format_create(VectorView<VertexAttribute> p_vertex_attribs) {
|
||||
RDD::VertexFormatID RenderingDeviceDriverVulkan::vertex_format_create(Span<VertexAttribute> p_vertex_attribs, const VertexAttributeBindingsMap &p_vertex_bindings) {
|
||||
// Pre-bookkeep.
|
||||
VertexFormatInfo *vf_info = VersatileResource::allocate<VertexFormatInfo>(resources_allocator);
|
||||
|
||||
vf_info->vk_bindings.resize(p_vertex_attribs.size());
|
||||
vf_info->vk_bindings.reserve(p_vertex_bindings.size());
|
||||
for (const VertexAttributeBindingsMap::KV &E : p_vertex_bindings) {
|
||||
const VertexAttributeBinding &binding = E.value;
|
||||
VkVertexInputBindingDescription vk_binding = {};
|
||||
vk_binding.binding = E.key;
|
||||
vk_binding.stride = binding.stride;
|
||||
vk_binding.inputRate = binding.frequency == VERTEX_FREQUENCY_INSTANCE ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
vf_info->vk_bindings.push_back(vk_binding);
|
||||
}
|
||||
vf_info->vk_attributes.resize(p_vertex_attribs.size());
|
||||
for (uint32_t i = 0; i < p_vertex_attribs.size(); i++) {
|
||||
vf_info->vk_bindings[i] = {};
|
||||
vf_info->vk_bindings[i].binding = i;
|
||||
vf_info->vk_bindings[i].stride = p_vertex_attribs[i].stride;
|
||||
vf_info->vk_bindings[i].inputRate = p_vertex_attribs[i].frequency == VERTEX_FREQUENCY_INSTANCE ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
vf_info->vk_attributes[i] = {};
|
||||
vf_info->vk_attributes[i].binding = i;
|
||||
vf_info->vk_attributes[i].binding = p_vertex_attribs[i].binding;
|
||||
vf_info->vk_attributes[i].location = p_vertex_attribs[i].location;
|
||||
vf_info->vk_attributes[i].format = RD_TO_VK_FORMAT[p_vertex_attribs[i].format];
|
||||
vf_info->vk_attributes[i].offset = p_vertex_attribs[i].offset;
|
||||
@ -5097,14 +5118,22 @@ void RenderingDeviceDriverVulkan::command_render_draw_indirect_count(CommandBuff
|
||||
vkCmdDrawIndirectCount(command_buffer->vk_command_buffer, indirect_buf_info->vk_buffer, p_offset, count_buf_info->vk_buffer, p_count_buffer_offset, p_max_draw_count, p_stride);
|
||||
}
|
||||
|
||||
void RenderingDeviceDriverVulkan::command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets) {
|
||||
void RenderingDeviceDriverVulkan::command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets, uint64_t p_dynamic_offsets) {
|
||||
const CommandBufferInfo *command_buffer = (const CommandBufferInfo *)p_cmd_buffer.id;
|
||||
|
||||
VkBuffer *vk_buffers = ALLOCA_ARRAY(VkBuffer, p_binding_count);
|
||||
uint64_t *vk_offsets = ALLOCA_ARRAY(uint64_t, p_binding_count);
|
||||
for (uint32_t i = 0; i < p_binding_count; i++) {
|
||||
const BufferInfo *buf_info = (const BufferInfo *)p_buffers[i].id;
|
||||
uint64_t offset = p_offsets[i];
|
||||
if (buf_info->is_dynamic()) {
|
||||
uint64_t frame_idx = p_dynamic_offsets & 0x3; // Assuming max 4 frames.
|
||||
p_dynamic_offsets >>= 2;
|
||||
offset += frame_idx * buf_info->size;
|
||||
}
|
||||
vk_buffers[i] = ((const BufferInfo *)p_buffers[i].id)->vk_buffer;
|
||||
vk_offsets[i] = offset;
|
||||
}
|
||||
vkCmdBindVertexBuffers(command_buffer->vk_command_buffer, 0, p_binding_count, vk_buffers, p_offsets);
|
||||
vkCmdBindVertexBuffers(command_buffer->vk_command_buffer, 0, p_binding_count, vk_buffers, vk_offsets);
|
||||
}
|
||||
|
||||
void RenderingDeviceDriverVulkan::command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) {
|
||||
|
||||
@ -224,6 +224,7 @@ public:
|
||||
virtual uint8_t *buffer_map(BufferID p_buffer) override final;
|
||||
virtual void buffer_unmap(BufferID p_buffer) override final;
|
||||
virtual uint8_t *buffer_persistent_map_advance(BufferID p_buffer, uint64_t p_frames_drawn) override final;
|
||||
virtual uint64_t buffer_get_dynamic_offsets(Span<BufferID> p_buffers) override final;
|
||||
virtual void buffer_flush(BufferID p_buffer) override final;
|
||||
virtual uint64_t buffer_get_device_address(BufferID p_buffer) override final;
|
||||
|
||||
@ -282,7 +283,7 @@ private:
|
||||
};
|
||||
|
||||
public:
|
||||
virtual VertexFormatID vertex_format_create(VectorView<VertexAttribute> p_vertex_attribs) override final;
|
||||
virtual VertexFormatID vertex_format_create(Span<VertexAttribute> p_vertex_attribs, const VertexAttributeBindingsMap &p_vertex_bindings) override final;
|
||||
virtual void vertex_format_free(VertexFormatID p_vertex_format) override final;
|
||||
|
||||
/******************/
|
||||
@ -603,7 +604,7 @@ public:
|
||||
virtual void command_render_draw_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) override final;
|
||||
|
||||
// Buffer binding.
|
||||
virtual void command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets) override final;
|
||||
virtual void command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets, uint64_t p_dynamic_offsets) override final;
|
||||
virtual void command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) override final;
|
||||
|
||||
// Dynamic state.
|
||||
|
||||
Reference in New Issue
Block a user