Skip to content

Commit 7822386

Browse files
committed
ext descriptor heap
1 parent d73948a commit 7822386

67 files changed

Lines changed: 450 additions & 584 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

sources/HAL/API/Vulkan/HAL.Vulkan.CommandList.cpp

Lines changed: 75 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ module HAL:API.CommandList;
66
import stl.core;
77
import Core;
88
import :CommandAllocator; // full definition needed: allocator.vk_command_pool
9-
import :RootSignature; // API::RootSignature::get_vk_pipeline_layout()
9+
import :RootSignature; // HAL::RootSignature::ptr (signature parameter types)
1010
import :API.Device; // API::Device::get_native_device()
11-
import :API.DescriptorHeap; // API::DescriptorHeap::get_vk_set()
11+
import :API.DescriptorHeap; // API::DescriptorHeap::get_device_address() etc.
1212
import :API.QueryHeap; // API::QueryHeap::get_native()
1313

1414
namespace HAL::API
@@ -448,28 +448,39 @@ namespace HAL::API
448448
// Re-set topology — dynamic topology state doesn't survive a CB split.
449449
vkCmdSetPrimitiveTopology(vk_cmd, current_topology);
450450

451-
// Re-push the staged push-constant block (carries the bindless descriptor
452-
// indices the shader reads as _hal_push.sN). 128 bytes = the range declared
453-
// by the root signature's VkPushConstantRange.
454-
if (current_pipeline_layout != VK_NULL_HANDLE)
455-
vkCmdPushConstants(vk_cmd, current_pipeline_layout, VK_SHADER_STAGE_ALL,
456-
0, 128, push_constants.data());
451+
// Re-push the staged push-data block (carries the bindless descriptor
452+
// indices the shader reads as _hal_push.sN). No pipeline layout required
453+
// with VK_EXT_descriptor_heap — vkCmdPushDataEXT takes a raw host pointer.
454+
{
455+
VkPushDataInfoEXT pi{ VK_STRUCTURE_TYPE_PUSH_DATA_INFO_EXT };
456+
pi.offset = 0;
457+
pi.data.address = push_constants.data();
458+
pi.data.size = push_constants.size() * sizeof(uint32_t);
459+
vkCmdPushDataEXT(vk_cmd, &pi);
460+
}
457461
}
458462

459-
void CommandList::flush_descriptor_sets()
463+
void CommandList::flush_heaps()
460464
{
461-
if (!descriptor_sets_dirty || current_pipeline_layout == VK_NULL_HANDLE) return;
462-
descriptor_sets_dirty = false;
463-
464-
VkDescriptorSet sets[2] = { cbv_srv_uav_set, sampler_set };
465-
uint32_t set_count = 0;
466-
if (sets[0] != VK_NULL_HANDLE) set_count = 1;
467-
if (sets[1] != VK_NULL_HANDLE) set_count = 2;
468-
if (set_count == 0) return;
465+
if (!heaps_dirty) return;
466+
heaps_dirty = false;
469467

470-
// Bind for both graphics and compute so set is available regardless of pipeline type.
471-
vkCmdBindDescriptorSets(vk_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
472-
current_pipeline_layout, 0, set_count, sets, 0, nullptr);
468+
if (cbv_srv_uav_addr != 0)
469+
{
470+
VkBindHeapInfoEXT bi{ VK_STRUCTURE_TYPE_BIND_HEAP_INFO_EXT };
471+
bi.heapRange = { cbv_srv_uav_addr, cbv_srv_uav_size };
472+
bi.reservedRangeOffset = 0;
473+
bi.reservedRangeSize = cbv_srv_uav_reserved;
474+
vkCmdBindResourceHeapEXT(vk_cmd, &bi);
475+
}
476+
if (sampler_addr != 0)
477+
{
478+
VkBindHeapInfoEXT bi{ VK_STRUCTURE_TYPE_BIND_HEAP_INFO_EXT };
479+
bi.heapRange = { sampler_addr, sampler_size };
480+
bi.reservedRangeOffset = 0;
481+
bi.reservedRangeSize = sampler_reserved;
482+
vkCmdBindSamplerHeapEXT(vk_cmd, &bi);
483+
}
473484
}
474485

475486
// ---- Pipeline binding ---------------------------------------------------
@@ -493,22 +504,12 @@ namespace HAL::API
493504
}
494505

495506
vkCmdBindPipeline(vk_cmd, bind_point, pipeline->vk_pipeline);
496-
flush_descriptor_sets();
507+
flush_heaps();
497508
}
498509

499-
void CommandList::set_graphics_signature(const HAL::RootSignature::ptr& sig)
500-
{
501-
if (!sig) return;
502-
current_pipeline_layout = static_cast<API::RootSignature&>(*sig).get_vk_pipeline_layout();
503-
descriptor_sets_dirty = true;
504-
}
505-
506-
void CommandList::set_compute_signature(const HAL::RootSignature::ptr& sig)
507-
{
508-
if (!sig) return;
509-
current_pipeline_layout = static_cast<API::RootSignature&>(*sig).get_vk_pipeline_layout();
510-
descriptor_sets_dirty = true;
511-
}
510+
// With VK_EXT_descriptor_heap there is no VkPipelineLayout — no-ops.
511+
void CommandList::set_graphics_signature(const HAL::RootSignature::ptr&) {}
512+
void CommandList::set_compute_signature(const HAL::RootSignature::ptr&) {}
512513

513514
// ---- Descriptor heap binding -------------------------------------------
514515

@@ -517,9 +518,23 @@ namespace HAL::API
517518
auto* api_cbv = static_cast<API::DescriptorHeap*>(cbv);
518519
auto* api_sampler = static_cast<API::DescriptorHeap*>(sampler);
519520

520-
cbv_srv_uav_set = api_cbv ? api_cbv->get_vk_set() : VK_NULL_HANDLE;
521-
sampler_set = api_sampler ? api_sampler->get_vk_set() : VK_NULL_HANDLE;
522-
descriptor_sets_dirty = true;
521+
if (api_cbv)
522+
{
523+
cbv_srv_uav_addr = api_cbv->get_device_address();
524+
cbv_srv_uav_size = api_cbv->get_total_size();
525+
cbv_srv_uav_reserved = api_cbv->get_reserved_size();
526+
}
527+
else { cbv_srv_uav_addr = 0; cbv_srv_uav_size = 0; cbv_srv_uav_reserved = 0; }
528+
529+
if (api_sampler)
530+
{
531+
sampler_addr = api_sampler->get_device_address();
532+
sampler_size = api_sampler->get_total_size();
533+
sampler_reserved = api_sampler->get_reserved_size();
534+
}
535+
else { sampler_addr = 0; sampler_size = 0; sampler_reserved = 0; }
536+
537+
heaps_dirty = true;
523538
}
524539

525540
// ---- Draw / dispatch ---------------------------------------------------
@@ -531,7 +546,7 @@ namespace HAL::API
531546
ensure_rendering_active();
532547
if (!in_render_pass) return; // no RTV set — skip rather than crash validation
533548
reapply_draw_state();
534-
flush_descriptor_sets();
549+
flush_heaps();
535550
vkCmdDraw(vk_cmd, vertex_count, instance_count, vertex_offset, instance_offset);
536551
}
537552

@@ -544,24 +559,16 @@ namespace HAL::API
544559
reapply_draw_state();
545560
if (current_index_buffer != VK_NULL_HANDLE)
546561
vkCmdBindIndexBuffer(vk_cmd, current_index_buffer, current_index_offset, current_index_type);
547-
flush_descriptor_sets();
562+
flush_heaps();
548563
vkCmdDrawIndexed(vk_cmd, index_count, instance_count,
549564
index_offset, static_cast<int32_t>(vertex_offset), instance_offset);
550565
}
551566

552567
void CommandList::dispatch(ivec3 v)
553568
{
554569
if (vk_cmd == VK_NULL_HANDLE) return;
555-
// Compute doesn't use a render pass — end any active one first.
556570
end_rendering_if_active();
557-
if (current_pipeline_layout != VK_NULL_HANDLE &&
558-
(cbv_srv_uav_set != VK_NULL_HANDLE || sampler_set != VK_NULL_HANDLE))
559-
{
560-
VkDescriptorSet sets[2] = { cbv_srv_uav_set, sampler_set };
561-
uint32_t count = (sampler_set != VK_NULL_HANDLE) ? 2 : 1;
562-
vkCmdBindDescriptorSets(vk_cmd, VK_PIPELINE_BIND_POINT_COMPUTE,
563-
current_pipeline_layout, 0, count, sets, 0, nullptr);
564-
}
571+
flush_heaps();
565572
vkCmdDispatch(vk_cmd, static_cast<uint32_t>(v.x),
566573
static_cast<uint32_t>(v.y),
567574
static_cast<uint32_t>(v.z));
@@ -638,25 +645,30 @@ namespace HAL::API
638645

639646
void CommandList::graphics_set_constant(UINT slot, UINT offset, UINT value)
640647
{
641-
if (vk_cmd == VK_NULL_HANDLE || current_pipeline_layout == VK_NULL_HANDLE) return;
642-
uint32_t byte_offset = (slot + offset) * sizeof(uint32_t);
643-
// Stage so reapply_draw_state() can re-push before each draw — vkCmdPushConstants
644-
// does not survive a command-buffer split; without re-pushing, the shader reads 0
645-
// for every bindless descriptor index (s4, …) → all bindless reads fail → black UI.
646-
if ((slot + offset) < push_constants.size())
647-
push_constants[slot + offset] = value;
648-
vkCmdPushConstants(vk_cmd, current_pipeline_layout,
649-
VK_SHADER_STAGE_ALL, // must cover all stages in pipeline layout range
650-
byte_offset, sizeof(uint32_t), &value);
648+
if (vk_cmd == VK_NULL_HANDLE) return;
649+
uint32_t idx = slot + offset;
650+
// Stage so reapply_draw_state() can re-push before each draw — push data state
651+
// does not survive a command-buffer split; without re-pushing, bindless indices fail.
652+
if (idx < push_constants.size())
653+
push_constants[idx] = value;
654+
VkPushDataInfoEXT pi{ VK_STRUCTURE_TYPE_PUSH_DATA_INFO_EXT };
655+
pi.offset = idx * sizeof(uint32_t);
656+
pi.data.address = &value;
657+
pi.data.size = sizeof(uint32_t);
658+
vkCmdPushDataEXT(vk_cmd, &pi);
651659
}
652660

653661
void CommandList::compute_set_constant(UINT slot, UINT offset, UINT value)
654662
{
655-
if (vk_cmd == VK_NULL_HANDLE || current_pipeline_layout == VK_NULL_HANDLE) return;
656-
uint32_t byte_offset = (slot + offset) * sizeof(uint32_t);
657-
vkCmdPushConstants(vk_cmd, current_pipeline_layout,
658-
VK_SHADER_STAGE_ALL, // must cover all stages in pipeline layout range
659-
byte_offset, sizeof(uint32_t), &value);
663+
if (vk_cmd == VK_NULL_HANDLE) return;
664+
uint32_t idx = slot + offset;
665+
if (idx < push_constants.size())
666+
push_constants[idx] = value;
667+
VkPushDataInfoEXT pi{ VK_STRUCTURE_TYPE_PUSH_DATA_INFO_EXT };
668+
pi.offset = idx * sizeof(uint32_t);
669+
pi.data.address = &value;
670+
pi.data.size = sizeof(uint32_t);
671+
vkCmdPushDataEXT(vk_cmd, &pi);
660672
}
661673

662674
// Phase 5: push descriptors for inline CBV binding

sources/HAL/API/Vulkan/HAL.Vulkan.CommandList.ixx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,7 @@ export namespace HAL
4747
VkExtent2D current_extent = {};
4848
bool in_render_pass = false;
4949

50-
// Pipeline state
51-
VkPipelineLayout current_pipeline_layout = VK_NULL_HANDLE;
52-
bool descriptor_sets_dirty = false;
50+
// Pipeline state (no VkPipelineLayout with VK_EXT_descriptor_heap)
5351
// Last bound graphics pipeline — re-bound before each draw because the
5452
// recorder may split set_pipeline and the draw across command buffers.
5553
VkPipeline current_graphics_pipeline = VK_NULL_HANDLE;
@@ -67,10 +65,16 @@ export namespace HAL
6765
VkPrimitiveTopology current_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
6866

6967
// Bound descriptor heaps (set by set_descriptor_heaps())
70-
VkDescriptorSet cbv_srv_uav_set = VK_NULL_HANDLE;
71-
VkDescriptorSet sampler_set = VK_NULL_HANDLE;
72-
73-
// Push constant staging (for graphics_set_constant / compute_set_constant)
68+
VkDeviceAddress cbv_srv_uav_addr = 0;
69+
VkDeviceSize cbv_srv_uav_size = 0;
70+
VkDeviceSize cbv_srv_uav_reserved = 0;
71+
VkDeviceAddress sampler_addr = 0;
72+
VkDeviceSize sampler_size = 0;
73+
VkDeviceSize sampler_reserved = 0;
74+
bool heaps_dirty = false;
75+
76+
// Push data staging (for graphics_set_constant / compute_set_constant).
77+
// Re-pushed before each draw via reapply_draw_state() to survive CB splits.
7478
std::array<uint32_t, 32> push_constants = {};
7579

7680
// Deferred PRESENT_SRC_KHR transitions.
@@ -96,7 +100,7 @@ export namespace HAL
96100
void begin_rendering(VkAttachmentLoadOp color_load, VkClearValue color_clear,
97101
VkAttachmentLoadOp depth_load, VkClearValue depth_clear);
98102
void ensure_rendering_active(); // lazily start render pass for draw calls
99-
void flush_descriptor_sets(); // bind pending descriptor sets
103+
void flush_heaps(); // bind pending descriptor heaps
100104
void reapply_draw_state(); // re-bind pipeline + viewport/scissor before a draw
101105

102106
public:

0 commit comments

Comments
 (0)