kronos_compute/implementation/
pipeline.rs

1//! Pipeline and command buffer implementation
2
3use crate::sys::*;
4use crate::core::*;
5use crate::ffi::*;
6// keep single import
7use crate::implementation::icd_loader;
8
9/// Create shader module
10// SAFETY: This function is called from C code. Caller must ensure:
11// 1. device is a valid VkDevice
12// 2. pCreateInfo points to a valid VkShaderModuleCreateInfo structure
13// 3. pAllocator is either null or points to valid allocation callbacks
14// 4. pShaderModule points to valid memory for writing the shader module handle
15// 5. The SPIR-V code in pCreateInfo is valid and contains only compute shader stages
16// 6. Code size matches the actual SPIR-V bytecode length
17#[no_mangle]
18pub unsafe extern "C" fn vkCreateShaderModule(
19    device: VkDevice,
20    pCreateInfo: *const VkShaderModuleCreateInfo,
21    pAllocator: *const VkAllocationCallbacks,
22    pShaderModule: *mut VkShaderModule,
23) -> VkResult {
24    if device.is_null() || pCreateInfo.is_null() || pShaderModule.is_null() {
25        return VkResult::ErrorInitializationFailed;
26    }
27    
28    if let Some(icd) = icd_loader::icd_for_device(device) {
29        if let Some(f) = icd.create_shader_module { return f(device, pCreateInfo, pAllocator, pShaderModule); }
30    }
31    if let Some(icd) = super::forward::get_icd_if_enabled() {
32        if let Some(create_shader_module) = icd.create_shader_module { return create_shader_module(device, pCreateInfo, pAllocator, pShaderModule); }
33    }
34    VkResult::ErrorInitializationFailed
35}
36
37/// Destroy shader module
38// SAFETY: This function is called from C code. Caller must ensure:
39// 1. device is a valid VkDevice
40// 2. shaderModule is a valid VkShaderModule, or VK_NULL_HANDLE
41// 3. pAllocator matches the allocator used in vkCreateShaderModule
42// 4. No pipelines are currently using this shader module
43// 5. The shader module is not referenced by any pending operations
44#[no_mangle]
45pub unsafe extern "C" fn vkDestroyShaderModule(
46    device: VkDevice,
47    shaderModule: VkShaderModule,
48    pAllocator: *const VkAllocationCallbacks,
49) {
50    if device.is_null() || shaderModule.is_null() {
51        return;
52    }
53    
54    if let Some(icd) = icd_loader::icd_for_device(device) {
55        if let Some(f) = icd.destroy_shader_module { f(device, shaderModule, pAllocator); }
56        return;
57    }
58    if let Some(icd) = super::forward::get_icd_if_enabled() {
59        if let Some(destroy_shader_module) = icd.destroy_shader_module { destroy_shader_module(device, shaderModule, pAllocator); }
60    }
61}
62
63/// Create compute pipelines
64// SAFETY: This function is called from C code. Caller must ensure:
65// 1. device is a valid VkDevice
66// 2. pipelineCache is either VK_NULL_HANDLE or a valid VkPipelineCache
67// 3. createInfoCount > 0 and matches the array sizes
68// 4. pCreateInfos points to an array of createInfoCount valid pipeline create info structures
69// 5. pAllocator is either null or points to valid allocation callbacks
70// 6. pPipelines points to an array with space for createInfoCount pipeline handles
71// 7. All shader modules, layouts, and descriptor set layouts referenced are valid
72#[no_mangle]
73pub unsafe extern "C" fn vkCreateComputePipelines(
74    device: VkDevice,
75    pipelineCache: VkPipelineCache,
76    createInfoCount: u32,
77    pCreateInfos: *const VkComputePipelineCreateInfo,
78    pAllocator: *const VkAllocationCallbacks,
79    pPipelines: *mut VkPipeline,
80) -> VkResult {
81    if device.is_null() || pCreateInfos.is_null() || pPipelines.is_null() || createInfoCount == 0 {
82        return VkResult::ErrorInitializationFailed;
83    }
84    
85    if let Some(icd) = icd_loader::icd_for_device(device) {
86        if let Some(f) = icd.create_compute_pipelines { return f(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); }
87    }
88    if let Some(icd) = super::forward::get_icd_if_enabled() {
89        if let Some(create_compute_pipelines) = icd.create_compute_pipelines { return create_compute_pipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); }
90    }
91    VkResult::ErrorInitializationFailed
92}
93
94/// Destroy pipeline
95// SAFETY: This function is called from C code. Caller must ensure:
96// 1. device is a valid VkDevice
97// 2. pipeline is a valid VkPipeline, or VK_NULL_HANDLE
98// 3. pAllocator matches the allocator used in vkCreateComputePipelines
99// 4. The pipeline is not currently bound to any command buffers
100// 5. No command buffers using this pipeline are executing on the GPU
101#[no_mangle]
102pub unsafe extern "C" fn vkDestroyPipeline(
103    device: VkDevice,
104    pipeline: VkPipeline,
105    pAllocator: *const VkAllocationCallbacks,
106) {
107    if device.is_null() || pipeline.is_null() {
108        return;
109    }
110    
111    if let Some(icd) = icd_loader::icd_for_device(device) {
112        if let Some(f) = icd.destroy_pipeline { f(device, pipeline, pAllocator); }
113        return;
114    }
115    if let Some(icd) = super::forward::get_icd_if_enabled() {
116        if let Some(destroy_pipeline) = icd.destroy_pipeline { destroy_pipeline(device, pipeline, pAllocator); }
117    }
118}
119
120/// Create pipeline layout
121// SAFETY: This function is called from C code. Caller must ensure:
122// 1. device is a valid VkDevice
123// 2. pCreateInfo points to a valid VkPipelineLayoutCreateInfo structure
124// 3. pAllocator is either null or points to valid allocation callbacks
125// 4. pPipelineLayout points to valid memory for writing the layout handle
126// 5. All descriptor set layouts referenced in pCreateInfo are valid
127// 6. Push constant ranges do not overlap and are within device limits
128#[no_mangle]
129pub unsafe extern "C" fn vkCreatePipelineLayout(
130    device: VkDevice,
131    pCreateInfo: *const VkPipelineLayoutCreateInfo,
132    pAllocator: *const VkAllocationCallbacks,
133    pPipelineLayout: *mut VkPipelineLayout,
134) -> VkResult {
135    if device.is_null() || pCreateInfo.is_null() || pPipelineLayout.is_null() {
136        return VkResult::ErrorInitializationFailed;
137    }
138    
139    if let Some(icd) = icd_loader::icd_for_device(device) {
140        if let Some(f) = icd.create_pipeline_layout { return f(device, pCreateInfo, pAllocator, pPipelineLayout); }
141    }
142    if let Some(icd) = super::forward::get_icd_if_enabled() {
143        if let Some(create_pipeline_layout) = icd.create_pipeline_layout { return create_pipeline_layout(device, pCreateInfo, pAllocator, pPipelineLayout); }
144    }
145    VkResult::ErrorInitializationFailed
146}
147
148/// Destroy pipeline layout
149// SAFETY: This function is called from C code. Caller must ensure:
150// 1. device is a valid VkDevice
151// 2. pipelineLayout is a valid VkPipelineLayout, or VK_NULL_HANDLE
152// 3. pAllocator matches the allocator used in vkCreatePipelineLayout
153// 4. No pipelines are currently using this layout
154// 5. No command buffers reference this layout in their current recordings
155#[no_mangle]
156pub unsafe extern "C" fn vkDestroyPipelineLayout(
157    device: VkDevice,
158    pipelineLayout: VkPipelineLayout,
159    pAllocator: *const VkAllocationCallbacks,
160) {
161    if device.is_null() || pipelineLayout.is_null() {
162        return;
163    }
164    
165    if let Some(icd) = icd_loader::icd_for_device(device) {
166        if let Some(f) = icd.destroy_pipeline_layout { f(device, pipelineLayout, pAllocator); }
167        return;
168    }
169    if let Some(icd) = super::forward::get_icd_if_enabled() {
170        if let Some(destroy_pipeline_layout) = icd.destroy_pipeline_layout { destroy_pipeline_layout(device, pipelineLayout, pAllocator); }
171    }
172}
173
174/// Create command pool
175// SAFETY: This function is called from C code. Caller must ensure:
176// 1. device is a valid VkDevice
177// 2. pCreateInfo points to a valid VkCommandPoolCreateInfo structure
178// 3. pAllocator is either null or points to valid allocation callbacks
179// 4. pCommandPool points to valid memory for writing the pool handle
180// 5. The queue family index in pCreateInfo is valid for this device
181// 6. Pool creation flags are appropriate for intended usage
182#[no_mangle]
183pub unsafe extern "C" fn vkCreateCommandPool(
184    device: VkDevice,
185    pCreateInfo: *const VkCommandPoolCreateInfo,
186    pAllocator: *const VkAllocationCallbacks,
187    pCommandPool: *mut VkCommandPool,
188) -> VkResult {
189    if device.is_null() || pCreateInfo.is_null() || pCommandPool.is_null() {
190        return VkResult::ErrorInitializationFailed;
191    }
192    // Route via owning ICD if known
193    if let Some(icd) = icd_loader::icd_for_device(device) {
194        if let Some(f) = icd.create_command_pool {
195            let res = f(device, pCreateInfo, pAllocator, pCommandPool);
196            if res == VkResult::Success {
197                icd_loader::register_command_pool_icd(*pCommandPool, &icd);
198            }
199            return res;
200        }
201    }
202    // Fallback
203    if let Some(icd) = super::forward::get_icd_if_enabled() {
204        if let Some(create_command_pool) = icd.create_command_pool {
205            return create_command_pool(device, pCreateInfo, pAllocator, pCommandPool);
206        }
207    }
208    VkResult::ErrorInitializationFailed
209}
210
211/// Destroy command pool
212// SAFETY: This function is called from C code. Caller must ensure:
213// 1. device is a valid VkDevice
214// 2. commandPool is a valid VkCommandPool, or VK_NULL_HANDLE
215// 3. pAllocator matches the allocator used in vkCreateCommandPool
216// 4. All command buffers allocated from this pool have finished execution
217// 5. No command buffers from this pool are currently being recorded
218#[no_mangle]
219pub unsafe extern "C" fn vkDestroyCommandPool(
220    device: VkDevice,
221    commandPool: VkCommandPool,
222    pAllocator: *const VkAllocationCallbacks,
223) {
224    if device.is_null() || commandPool.is_null() {
225        return;
226    }
227    if let Some(icd) = icd_loader::icd_for_command_pool(commandPool) {
228        if let Some(f) = icd.destroy_command_pool { f(device, commandPool, pAllocator); }
229        icd_loader::unregister_command_pool(commandPool);
230        return;
231    }
232    if let Some(icd) = super::forward::get_icd_if_enabled() {
233        if let Some(destroy_command_pool) = icd.destroy_command_pool {
234            destroy_command_pool(device, commandPool, pAllocator);
235        }
236    }
237}
238
239/// Allocate command buffers
240// SAFETY: This function is called from C code. Caller must ensure:
241// 1. device is a valid VkDevice
242// 2. pAllocateInfo points to a valid VkCommandBufferAllocateInfo structure
243// 3. pCommandBuffers points to an array with space for commandBufferCount handles
244// 4. The command pool in pAllocateInfo is valid and supports the requested level
245// 5. The command pool has sufficient space for the requested buffers
246#[no_mangle]
247pub unsafe extern "C" fn vkAllocateCommandBuffers(
248    device: VkDevice,
249    pAllocateInfo: *const VkCommandBufferAllocateInfo,
250    pCommandBuffers: *mut VkCommandBuffer,
251) -> VkResult {
252    if device.is_null() || pAllocateInfo.is_null() || pCommandBuffers.is_null() {
253        return VkResult::ErrorInitializationFailed;
254    }
255    // Prefer routing by command pool owner
256    let pool = (*pAllocateInfo).commandPool;
257    if let Some(icd) = icd_loader::icd_for_command_pool(pool) {
258        if let Some(f) = icd.allocate_command_buffers {
259            let res = f(device, pAllocateInfo, pCommandBuffers);
260            if res == VkResult::Success {
261                let count = (*pAllocateInfo).commandBufferCount as isize;
262                for i in 0..count {
263                    let cb = *pCommandBuffers.offset(i);
264                    icd_loader::register_command_buffer_icd(cb, &icd);
265                }
266            }
267            return res;
268        }
269    }
270    if let Some(icd) = super::forward::get_icd_if_enabled() {
271        if let Some(allocate_command_buffers) = icd.allocate_command_buffers {
272            return allocate_command_buffers(device, pAllocateInfo, pCommandBuffers);
273        }
274    }
275    VkResult::ErrorInitializationFailed
276}
277
278/// Free command buffers
279// SAFETY: This function is called from C code. Caller must ensure:
280// 1. device is a valid VkDevice
281// 2. commandPool is a valid VkCommandPool
282// 3. commandBufferCount > 0 and matches the array size
283// 4. pCommandBuffers points to an array of commandBufferCount valid command buffers
284// 5. All command buffers were allocated from the specified pool
285// 6. None of the command buffers are currently executing on the GPU
286// 7. Command buffers are not in the recording state
287#[no_mangle]
288pub unsafe extern "C" fn vkFreeCommandBuffers(
289    device: VkDevice,
290    commandPool: VkCommandPool,
291    commandBufferCount: u32,
292    pCommandBuffers: *const VkCommandBuffer,
293) {
294    if device.is_null() || commandPool.is_null() || pCommandBuffers.is_null() || commandBufferCount == 0 {
295        return;
296    }
297    if let Some(icd) = icd_loader::icd_for_command_pool(commandPool) {
298        if let Some(f) = icd.free_command_buffers { f(device, commandPool, commandBufferCount, pCommandBuffers); }
299        for i in 0..(commandBufferCount as isize) {
300            let cb = *pCommandBuffers.offset(i);
301            icd_loader::unregister_command_buffer(cb);
302        }
303        return;
304    }
305    if let Some(icd) = super::forward::get_icd_if_enabled() {
306        if let Some(free_command_buffers) = icd.free_command_buffers {
307            free_command_buffers(device, commandPool, commandBufferCount, pCommandBuffers);
308        }
309    }
310}
311
312/// Begin command buffer recording
313// SAFETY: This function is called from C code. Caller must ensure:
314// 1. commandBuffer is a valid VkCommandBuffer in the initial state
315// 2. pBeginInfo points to a valid VkCommandBufferBeginInfo structure
316// 3. The command buffer is not currently being recorded
317// 4. The command buffer is not currently executing on the GPU
318// 5. Usage flags in pBeginInfo match the intended recording pattern
319#[no_mangle]
320pub unsafe extern "C" fn vkBeginCommandBuffer(
321    commandBuffer: VkCommandBuffer,
322    pBeginInfo: *const VkCommandBufferBeginInfo,
323) -> VkResult {
324    if commandBuffer.is_null() || pBeginInfo.is_null() {
325        return VkResult::ErrorInitializationFailed;
326    }
327    if let Some(icd) = icd_loader::icd_for_command_buffer(commandBuffer) {
328        if let Some(f) = icd.begin_command_buffer { return f(commandBuffer, pBeginInfo); }
329    }
330    if let Some(icd) = super::forward::get_icd_if_enabled() {
331        if let Some(begin_command_buffer) = icd.begin_command_buffer {
332            return begin_command_buffer(commandBuffer, pBeginInfo);
333        }
334    }
335    VkResult::ErrorInitializationFailed
336}
337
338/// End command buffer recording
339// SAFETY: This function is called from C code. Caller must ensure:
340// 1. commandBuffer is a valid VkCommandBuffer in the recording state
341// 2. All commands recorded since vkBeginCommandBuffer are valid
342// 3. The command buffer was successfully put into recording state
343// 4. All nested command buffer recordings have been properly ended
344#[no_mangle]
345pub unsafe extern "C" fn vkEndCommandBuffer(
346    commandBuffer: VkCommandBuffer,
347) -> VkResult {
348    if commandBuffer.is_null() {
349        return VkResult::ErrorInitializationFailed;
350    }
351    if let Some(icd) = icd_loader::icd_for_command_buffer(commandBuffer) {
352        if let Some(f) = icd.end_command_buffer { return f(commandBuffer); }
353    }
354    if let Some(icd) = super::forward::get_icd_if_enabled() {
355        if let Some(end_command_buffer) = icd.end_command_buffer {
356            return end_command_buffer(commandBuffer);
357        }
358    }
359    VkResult::ErrorInitializationFailed
360}
361
362/// Bind pipeline
363// SAFETY: This function is called from C code. Caller must ensure:
364// 1. commandBuffer is a valid VkCommandBuffer in the recording state
365// 2. pipelineBindPoint is VK_PIPELINE_BIND_POINT_COMPUTE for compute pipelines
366// 3. pipeline is a valid VkPipeline compatible with the bind point
367// 4. The pipeline's layout is compatible with subsequently bound descriptor sets
368// 5. The command buffer supports the queue family that created the pipeline
369#[no_mangle]
370pub unsafe extern "C" fn vkCmdBindPipeline(
371    commandBuffer: VkCommandBuffer,
372    pipelineBindPoint: VkPipelineBindPoint,
373    pipeline: VkPipeline,
374) {
375    if commandBuffer.is_null() || pipeline.is_null() {
376        return;
377    }
378    if let Some(icd) = icd_loader::icd_for_command_buffer(commandBuffer) {
379        if let Some(f) = icd.cmd_bind_pipeline { f(commandBuffer, pipelineBindPoint, pipeline); }
380        return;
381    }
382    if let Some(icd) = super::forward::get_icd_if_enabled() {
383        if let Some(cmd_bind_pipeline) = icd.cmd_bind_pipeline {
384            cmd_bind_pipeline(commandBuffer, pipelineBindPoint, pipeline);
385        }
386    }
387}
388
389/// Bind descriptor sets
390// SAFETY: This function is called from C code. Caller must ensure:
391// 1. commandBuffer is a valid VkCommandBuffer in the recording state
392// 2. pipelineBindPoint is VK_PIPELINE_BIND_POINT_COMPUTE
393// 3. layout is a valid VkPipelineLayout
394// 4. descriptorSetCount > 0 and pDescriptorSets points to that many valid descriptor sets
395// 5. All descriptor sets are compatible with the pipeline layout
396// 6. Dynamic offsets array matches the dynamic descriptors in the sets
397// 7. firstSet + descriptorSetCount <= max sets supported by layout
398#[no_mangle]
399pub unsafe extern "C" fn vkCmdBindDescriptorSets(
400    commandBuffer: VkCommandBuffer,
401    pipelineBindPoint: VkPipelineBindPoint,
402    layout: VkPipelineLayout,
403    firstSet: u32,
404    descriptorSetCount: u32,
405    pDescriptorSets: *const VkDescriptorSet,
406    dynamicOffsetCount: u32,
407    pDynamicOffsets: *const u32,
408) {
409    if commandBuffer.is_null() || layout.is_null() || pDescriptorSets.is_null() || descriptorSetCount == 0 {
410        return;
411    }
412    if let Some(icd) = icd_loader::icd_for_command_buffer(commandBuffer) {
413        if let Some(f) = icd.cmd_bind_descriptor_sets { f(commandBuffer, pipelineBindPoint, layout, firstSet, descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets); }
414        return;
415    }
416    if let Some(icd) = super::forward::get_icd_if_enabled() {
417        if let Some(cmd_bind_descriptor_sets) = icd.cmd_bind_descriptor_sets {
418            cmd_bind_descriptor_sets(commandBuffer, pipelineBindPoint, layout, firstSet, 
419                                   descriptorSetCount, pDescriptorSets, dynamicOffsetCount, pDynamicOffsets);
420        }
421    }
422}
423
424/// Push constants
425// SAFETY: This function is called from C code. Caller must ensure:
426// 1. commandBuffer is a valid VkCommandBuffer in the recording state
427// 2. layout is a valid VkPipelineLayout with push constant ranges
428// 3. stageFlags specifies valid pipeline stages (VK_SHADER_STAGE_COMPUTE_BIT)
429// 4. offset and size are within the push constant range defined in the layout
430// 5. pValues points to at least size bytes of valid memory
431// 6. The push constant data is properly aligned for the target architecture
432#[no_mangle]
433pub unsafe extern "C" fn vkCmdPushConstants(
434    commandBuffer: VkCommandBuffer,
435    layout: VkPipelineLayout,
436    stageFlags: VkShaderStageFlags,
437    offset: u32,
438    size: u32,
439    pValues: *const libc::c_void,
440) {
441    if commandBuffer.is_null() || layout.is_null() || pValues.is_null() || size == 0 {
442        return;
443    }
444    if let Some(icd) = icd_loader::icd_for_command_buffer(commandBuffer) {
445        if let Some(f) = icd.cmd_push_constants { f(commandBuffer, layout, stageFlags, offset, size, pValues); }
446        return;
447    }
448    if let Some(icd) = super::forward::get_icd_if_enabled() {
449        if let Some(cmd_push_constants) = icd.cmd_push_constants {
450            cmd_push_constants(commandBuffer, layout, stageFlags, offset, size, pValues);
451        }
452    }
453}
454
455/// Dispatch compute work
456// SAFETY: This function is called from C code. Caller must ensure:
457// 1. commandBuffer is a valid VkCommandBuffer in the recording state
458// 2. A compute pipeline is currently bound to the command buffer
459// 3. groupCountX, Y, Z are within device limits and > 0
460// 4. All descriptor sets required by the pipeline are bound
461// 5. All resources referenced by descriptors are valid and accessible
462#[no_mangle]
463pub unsafe extern "C" fn vkCmdDispatch(
464    commandBuffer: VkCommandBuffer,
465    groupCountX: u32,
466    groupCountY: u32,
467    groupCountZ: u32,
468) {
469    if commandBuffer.is_null() {
470        return;
471    }
472    if let Some(icd) = icd_loader::icd_for_command_buffer(commandBuffer) {
473        if let Some(f) = icd.cmd_dispatch { f(commandBuffer, groupCountX, groupCountY, groupCountZ); }
474        return;
475    }
476    if let Some(icd) = super::forward::get_icd_if_enabled() {
477        if let Some(cmd_dispatch) = icd.cmd_dispatch {
478            cmd_dispatch(commandBuffer, groupCountX, groupCountY, groupCountZ);
479        }
480    }
481}
482
483/// Dispatch compute work with indirect buffer
484// SAFETY: This function is called from C code. Caller must ensure:
485// 1. commandBuffer is a valid VkCommandBuffer in the recording state
486// 2. A compute pipeline is currently bound to the command buffer
487// 3. buffer is a valid VkBuffer containing dispatch parameters
488// 4. offset is within the buffer bounds and properly aligned
489// 5. The buffer contains valid VkDispatchIndirectCommand structure at offset
490// 6. All descriptor sets required by the pipeline are bound
491#[no_mangle]
492pub unsafe extern "C" fn vkCmdDispatchIndirect(
493    commandBuffer: VkCommandBuffer,
494    buffer: VkBuffer,
495    offset: VkDeviceSize,
496) {
497    if commandBuffer.is_null() || buffer.is_null() {
498        return;
499    }
500    if let Some(icd) = icd_loader::icd_for_command_buffer(commandBuffer) {
501        if let Some(f) = icd.cmd_dispatch_indirect { f(commandBuffer, buffer, offset); }
502        return;
503    }
504    if let Some(icd) = super::forward::get_icd_if_enabled() {
505        if let Some(cmd_dispatch_indirect) = icd.cmd_dispatch_indirect {
506            cmd_dispatch_indirect(commandBuffer, buffer, offset);
507        }
508    }
509}
510
511/// Pipeline barrier
512// SAFETY: This function is called from C code. Caller must ensure:
513// 1. commandBuffer is a valid VkCommandBuffer in the recording state
514// 2. srcStageMask and dstStageMask specify valid pipeline stages
515// 3. dependencyFlags is a valid combination of dependency flags
516// 4. Memory barrier arrays match their respective counts
517// 5. All buffer memory barriers reference valid buffers and ranges
518// 6. Pipeline stages are appropriate for compute operations
519// 7. Memory barriers provide necessary synchronization guarantees
520#[no_mangle]
521pub unsafe extern "C" fn vkCmdPipelineBarrier(
522    commandBuffer: VkCommandBuffer,
523    srcStageMask: VkPipelineStageFlags,
524    dstStageMask: VkPipelineStageFlags,
525    dependencyFlags: VkDependencyFlags,
526    memoryBarrierCount: u32,
527    pMemoryBarriers: *const VkMemoryBarrier,
528    bufferMemoryBarrierCount: u32,
529    pBufferMemoryBarriers: *const VkBufferMemoryBarrier,
530    imageMemoryBarrierCount: u32,
531    pImageMemoryBarriers: *const libc::c_void,
532) {
533    if commandBuffer.is_null() {
534        return;
535    }
536    if let Some(icd) = icd_loader::icd_for_command_buffer(commandBuffer) {
537        if let Some(f) = icd.cmd_pipeline_barrier { f(commandBuffer, srcStageMask, dstStageMask, dependencyFlags,
538                               memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
539                               pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); }
540        return;
541    }
542    if let Some(icd) = super::forward::get_icd_if_enabled() {
543        if let Some(cmd_pipeline_barrier) = icd.cmd_pipeline_barrier {
544            cmd_pipeline_barrier(commandBuffer, srcStageMask, dstStageMask, dependencyFlags,
545                               memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
546                               pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
547        }
548    }
549}
550
551/// Copy buffer
552// SAFETY: This function is called from C code. Caller must ensure:
553// 1. commandBuffer is a valid VkCommandBuffer in the recording state
554// 2. srcBuffer and dstBuffer are valid VkBuffer objects
555// 3. regionCount > 0 and pRegions points to that many VkBufferCopy structures
556// 4. All copy regions are within the bounds of their respective buffers
557// 5. Source and destination ranges do not overlap (unless same buffer with identical ranges)
558// 6. Buffers support the required usage flags for transfer operations
559#[no_mangle]
560pub unsafe extern "C" fn vkCmdCopyBuffer(
561    commandBuffer: VkCommandBuffer,
562    srcBuffer: VkBuffer,
563    dstBuffer: VkBuffer,
564    regionCount: u32,
565    pRegions: *const VkBufferCopy,
566) {
567    if commandBuffer.is_null() || srcBuffer.is_null() || dstBuffer.is_null() || 
568       regionCount == 0 || pRegions.is_null() {
569        return;
570    }
571    if let Some(icd) = icd_loader::icd_for_command_buffer(commandBuffer) {
572        if let Some(f) = icd.cmd_copy_buffer { f(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions); }
573        return;
574    }
575    if let Some(icd) = super::forward::get_icd_if_enabled() {
576        if let Some(cmd_copy_buffer) = icd.cmd_copy_buffer {
577            cmd_copy_buffer(commandBuffer, srcBuffer, dstBuffer, regionCount, pRegions);
578        }
579    }
580}
581
582/// Set event
583// SAFETY: This function is called from C code. Caller must ensure:
584// 1. commandBuffer is a valid VkCommandBuffer in the recording state
585// 2. event is a valid VkEvent object
586// 3. stageMask specifies valid pipeline stages for compute operations
587// 4. The event will be signaled when the specified pipeline stages complete
588// 5. Subsequent vkCmdWaitEvents calls can safely wait on this event
589#[no_mangle]
590pub unsafe extern "C" fn vkCmdSetEvent(
591    commandBuffer: VkCommandBuffer,
592    event: VkEvent,
593    stageMask: VkPipelineStageFlags,
594) {
595    if commandBuffer.is_null() || event.is_null() {
596        return;
597    }
598    if let Some(icd) = icd_loader::icd_for_command_buffer(commandBuffer) {
599        if let Some(f) = icd.cmd_set_event { f(commandBuffer, event, stageMask); }
600        return;
601    }
602    if let Some(icd) = super::forward::get_icd_if_enabled() {
603        if let Some(cmd_set_event) = icd.cmd_set_event {
604            cmd_set_event(commandBuffer, event, stageMask);
605        }
606    }
607}
608
609/// Reset event
610// SAFETY: This function is called from C code. Caller must ensure:
611// 1. commandBuffer is a valid VkCommandBuffer in the recording state
612// 2. event is a valid VkEvent object
613// 3. stageMask specifies valid pipeline stages for compute operations
614// 4. The event will be reset when the specified pipeline stages complete
615// 5. No other command buffers should be waiting on this event when it's reset
616#[no_mangle]
617pub unsafe extern "C" fn vkCmdResetEvent(
618    commandBuffer: VkCommandBuffer,
619    event: VkEvent,
620    stageMask: VkPipelineStageFlags,
621) {
622    if commandBuffer.is_null() || event.is_null() {
623        return;
624    }
625    if let Some(icd) = icd_loader::icd_for_command_buffer(commandBuffer) {
626        if let Some(f) = icd.cmd_reset_event { f(commandBuffer, event, stageMask); }
627        return;
628    }
629    if let Some(icd) = super::forward::get_icd_if_enabled() {
630        if let Some(cmd_reset_event) = icd.cmd_reset_event {
631            cmd_reset_event(commandBuffer, event, stageMask);
632        }
633    }
634}
635
636/// Wait for events
637// SAFETY: This function is called from C code. Caller must ensure:
638// 1. commandBuffer is a valid VkCommandBuffer in the recording state
639// 2. eventCount > 0 and pEvents points to that many valid VkEvent objects
640// 3. srcStageMask and dstStageMask specify valid pipeline stages
641// 4. All events in pEvents have been signaled by previous commands
642// 5. Memory barrier arrays match their respective counts and are valid
643// 6. All buffer memory barriers reference valid buffers and ranges
644// 7. Pipeline stages and barriers provide necessary synchronization
645#[no_mangle]
646pub unsafe extern "C" fn vkCmdWaitEvents(
647    commandBuffer: VkCommandBuffer,
648    eventCount: u32,
649    pEvents: *const VkEvent,
650    srcStageMask: VkPipelineStageFlags,
651    dstStageMask: VkPipelineStageFlags,
652    memoryBarrierCount: u32,
653    pMemoryBarriers: *const VkMemoryBarrier,
654    bufferMemoryBarrierCount: u32,
655    pBufferMemoryBarriers: *const VkBufferMemoryBarrier,
656    imageMemoryBarrierCount: u32,
657    pImageMemoryBarriers: *const libc::c_void,
658) {
659    if commandBuffer.is_null() || eventCount == 0 || pEvents.is_null() {
660        return;
661    }
662    if let Some(icd) = icd_loader::icd_for_command_buffer(commandBuffer) {
663        if let Some(f) = icd.cmd_wait_events { f(commandBuffer, eventCount, pEvents, srcStageMask, dstStageMask,
664                          memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
665                          pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers); }
666        return;
667    }
668    if let Some(icd) = super::forward::get_icd_if_enabled() {
669        if let Some(cmd_wait_events) = icd.cmd_wait_events {
670            cmd_wait_events(commandBuffer, eventCount, pEvents, srcStageMask, dstStageMask,
671                          memoryBarrierCount, pMemoryBarriers, bufferMemoryBarrierCount,
672                          pBufferMemoryBarriers, imageMemoryBarrierCount, pImageMemoryBarriers);
673        }
674    }
675}