yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

AdamYuanSupport dispatchComputeIndirect and draw(Indexed)Indirect with count buffer for Vulkan (#5929)2ad1f8138

master
55.1 KiB1631 linesraw
1// vk-command-encoder.cpp
2#include "vk-command-encoder.h"
3
4#include "vk-buffer.h"
5#include "vk-command-buffer.h"
6#include "vk-helper-functions.h"
7#include "vk-query.h"
8#include "vk-render-pass.h"
9#include "vk-resource-views.h"
10#include "vk-shader-object.h"
11#include "vk-shader-program.h"
12#include "vk-shader-table.h"
13#include "vk-texture.h"
14#include "vk-transient-heap.h"
15
16namespace gfx
17{
18
19using namespace Slang;
20
21namespace vk
22{
23
24int PipelineCommandEncoder::getBindPointIndex(VkPipelineBindPoint bindPoint)
25{
26    switch (bindPoint)
27    {
28    case VK_PIPELINE_BIND_POINT_GRAPHICS:
29        return 0;
30    case VK_PIPELINE_BIND_POINT_COMPUTE:
31        return 1;
32    case VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR:
33        return 2;
34    default:
35        assert(!"unknown pipeline type.");
36        return -1;
37    }
38}
39
40void PipelineCommandEncoder::init(CommandBufferImpl* commandBuffer)
41{
42    m_commandBuffer = commandBuffer;
43    m_device = commandBuffer->m_renderer;
44    m_vkCommandBuffer = m_commandBuffer->m_commandBuffer;
45    m_api = &m_commandBuffer->m_renderer->m_api;
46}
47
48void PipelineCommandEncoder::endEncodingImpl()
49{
50    for (auto& pipeline : m_boundPipelines)
51        pipeline = VK_NULL_HANDLE;
52}
53
54void PipelineCommandEncoder::_uploadBufferData(
55    VkCommandBuffer commandBuffer,
56    TransientResourceHeapImpl* transientHeap,
57    BufferResourceImpl* buffer,
58    Offset offset,
59    Size size,
60    void* data)
61{
62    auto& api = buffer->m_renderer->m_api;
63    IBufferResource* stagingBuffer = nullptr;
64    Offset stagingBufferOffset = 0;
65    transientHeap
66        ->allocateStagingBuffer(size, stagingBuffer, stagingBufferOffset, MemoryType::Upload);
67
68    BufferResourceImpl* stagingBufferImpl = static_cast<BufferResourceImpl*>(stagingBuffer);
69
70    void* mappedData = nullptr;
71    SLANG_VK_CHECK(api.vkMapMemory(
72        api.m_device,
73        stagingBufferImpl->m_buffer.m_memory,
74        0,
75        stagingBufferOffset + size,
76        0,
77        &mappedData));
78    memcpy((char*)mappedData + stagingBufferOffset, data, size);
79    api.vkUnmapMemory(api.m_device, stagingBufferImpl->m_buffer.m_memory);
80
81    // Copy from staging buffer to real buffer
82    VkBufferCopy copyInfo = {};
83    copyInfo.size = size;
84    copyInfo.dstOffset = offset;
85    copyInfo.srcOffset = stagingBufferOffset;
86    api.vkCmdCopyBuffer(
87        commandBuffer,
88        stagingBufferImpl->m_buffer.m_buffer,
89        buffer->m_buffer.m_buffer,
90        1,
91        &copyInfo);
92}
93
94void PipelineCommandEncoder::uploadBufferDataImpl(
95    IBufferResource* buffer,
96    Offset offset,
97    Size size,
98    void* data)
99{
100    m_vkPreCommandBuffer = m_commandBuffer->getPreCommandBuffer();
101    _uploadBufferData(
102        m_vkPreCommandBuffer,
103        m_commandBuffer->m_transientHeap.get(),
104        static_cast<BufferResourceImpl*>(buffer),
105        offset,
106        size,
107        data);
108}
109
110Result PipelineCommandEncoder::bindRootShaderObjectImpl(
111    RootShaderObjectImpl* rootShaderObject,
112    VkPipelineBindPoint bindPoint)
113{
114    // Obtain specialized root layout.
115    auto specializedLayout = rootShaderObject->getSpecializedLayout();
116    if (!specializedLayout)
117        return SLANG_FAIL;
118
119    // We will set up the context required when binding shader objects
120    // to the pipeline. Note that this is mostly just being packaged
121    // together to minimize the number of parameters that have to
122    // be dealt with in the complex recursive call chains.
123    //
124    RootBindingContext context;
125    context.pipelineLayout = specializedLayout->m_pipelineLayout;
126    context.device = m_device;
127    context.descriptorSetAllocator = &m_commandBuffer->m_transientHeap->m_descSetAllocator;
128    context.pushConstantRanges = specializedLayout->getAllPushConstantRanges().getArrayView();
129
130    // The context includes storage for the descriptor sets we will bind,
131    // and the number of sets we need to make space for is determined
132    // by the specialized program layout.
133    //
134    List<VkDescriptorSet> descriptorSetsStorage;
135
136    context.descriptorSets = &descriptorSetsStorage;
137
138    // We kick off recursive binding of shader objects to the pipeline (plus
139    // the state in `context`).
140    //
141    // Note: this logic will directly write any push-constant ranges needed,
142    // and will also fill in any descriptor sets. Currently it does not
143    // *bind* the descriptor sets it fills in.
144    //
145    // TODO: It could probably bind the descriptor sets as well.
146    //
147    rootShaderObject->bindAsRoot(this, context, specializedLayout);
148
149    // Once we've filled in all the descriptor sets, we bind them
150    // to the pipeline at once.
151    //
152    if (descriptorSetsStorage.getCount() > 0)
153    {
154        m_device->m_api.vkCmdBindDescriptorSets(
155            m_commandBuffer->m_commandBuffer,
156            bindPoint,
157            specializedLayout->m_pipelineLayout,
158            0,
159            (uint32_t)descriptorSetsStorage.getCount(),
160            descriptorSetsStorage.getBuffer(),
161            0,
162            nullptr);
163    }
164
165    return SLANG_OK;
166}
167
168Result PipelineCommandEncoder::setPipelineStateImpl(
169    IPipelineState* state,
170    IShaderObject** outRootObject)
171{
172    m_currentPipeline = static_cast<PipelineStateImpl*>(state);
173    m_commandBuffer->m_mutableRootShaderObject = nullptr;
174    SLANG_RETURN_ON_FAIL(m_commandBuffer->m_rootObject.init(
175        m_commandBuffer->m_renderer,
176        m_currentPipeline->getProgram<ShaderProgramImpl>()->m_rootObjectLayout));
177    *outRootObject = &m_commandBuffer->m_rootObject;
178    return SLANG_OK;
179}
180
181Result PipelineCommandEncoder::setPipelineStateWithRootObjectImpl(
182    IPipelineState* state,
183    IShaderObject* rootObject)
184{
185    m_currentPipeline = static_cast<PipelineStateImpl*>(state);
186    m_commandBuffer->m_mutableRootShaderObject =
187        static_cast<MutableRootShaderObjectImpl*>(rootObject);
188    return SLANG_OK;
189}
190
191Result PipelineCommandEncoder::bindRenderState(VkPipelineBindPoint pipelineBindPoint)
192{
193    auto& api = *m_api;
194
195    // Get specialized pipeline state and bind it.
196    //
197    RootShaderObjectImpl* rootObjectImpl = m_commandBuffer->m_mutableRootShaderObject
198                                               ? m_commandBuffer->m_mutableRootShaderObject.Ptr()
199                                               : &m_commandBuffer->m_rootObject;
200    RefPtr<PipelineStateBase> newPipeline;
201    SLANG_RETURN_ON_FAIL(
202        m_device->maybeSpecializePipeline(m_currentPipeline, rootObjectImpl, newPipeline));
203    PipelineStateImpl* newPipelineImpl = static_cast<PipelineStateImpl*>(newPipeline.Ptr());
204
205    SLANG_RETURN_ON_FAIL(newPipelineImpl->ensureAPIPipelineStateCreated());
206    m_currentPipeline = newPipelineImpl;
207
208    bindRootShaderObjectImpl(rootObjectImpl, pipelineBindPoint);
209
210    auto pipelineBindPointId = getBindPointIndex(pipelineBindPoint);
211    if (m_boundPipelines[pipelineBindPointId] != newPipelineImpl->m_pipeline)
212    {
213        api.vkCmdBindPipeline(m_vkCommandBuffer, pipelineBindPoint, newPipelineImpl->m_pipeline);
214        m_boundPipelines[pipelineBindPointId] = newPipelineImpl->m_pipeline;
215    }
216
217    return SLANG_OK;
218}
219
220void ResourceCommandEncoder::copyBuffer(
221    IBufferResource* dst,
222    Offset dstOffset,
223    IBufferResource* src,
224    Offset srcOffset,
225    Size size)
226{
227    auto& vkAPI = m_commandBuffer->m_renderer->m_api;
228
229    auto dstBuffer = static_cast<BufferResourceImpl*>(dst);
230    auto srcBuffer = static_cast<BufferResourceImpl*>(src);
231
232    VkBufferCopy copyRegion;
233    copyRegion.dstOffset = dstOffset;
234    copyRegion.srcOffset = srcOffset;
235    copyRegion.size = size;
236
237    // Note: Vulkan puts the source buffer first in the copy
238    // command, going against the dominant tradition for copy
239    // operations in C/C++.
240    //
241    vkAPI.vkCmdCopyBuffer(
242        m_commandBuffer->m_commandBuffer,
243        srcBuffer->m_buffer.m_buffer,
244        dstBuffer->m_buffer.m_buffer,
245        /* regionCount: */ 1,
246        &copyRegion);
247}
248
249void ResourceCommandEncoder::uploadBufferData(
250    IBufferResource* buffer,
251    Offset offset,
252    Size size,
253    void* data)
254{
255    PipelineCommandEncoder::_uploadBufferData(
256        m_commandBuffer->m_commandBuffer,
257        m_commandBuffer->m_transientHeap.get(),
258        static_cast<BufferResourceImpl*>(buffer),
259        offset,
260        size,
261        data);
262}
263
264void ResourceCommandEncoder::textureBarrier(
265    GfxCount count,
266    ITextureResource* const* textures,
267    ResourceState src,
268    ResourceState dst)
269{
270    ShortList<VkImageMemoryBarrier, 16> barriers;
271
272    for (GfxIndex i = 0; i < count; i++)
273    {
274        auto image = static_cast<TextureResourceImpl*>(textures[i]);
275        auto desc = image->getDesc();
276
277        VkImageMemoryBarrier barrier = {};
278        barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
279        barrier.image = image->m_image;
280        barrier.oldLayout = translateImageLayout(src);
281        barrier.newLayout = translateImageLayout(dst);
282        barrier.subresourceRange.aspectMask =
283            getAspectMaskFromFormat(VulkanUtil::getVkFormat(desc->format));
284        barrier.subresourceRange.baseArrayLayer = 0;
285        barrier.subresourceRange.baseMipLevel = 0;
286        barrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS;
287        barrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
288        barrier.srcAccessMask = calcAccessFlags(src);
289        barrier.dstAccessMask = calcAccessFlags(dst);
290        barriers.add(barrier);
291    }
292
293    VkPipelineStageFlagBits srcStage = calcPipelineStageFlags(src, true);
294    VkPipelineStageFlagBits dstStage = calcPipelineStageFlags(dst, false);
295
296    auto& vkApi = m_commandBuffer->m_renderer->m_api;
297    vkApi.vkCmdPipelineBarrier(
298        m_commandBuffer->m_commandBuffer,
299        srcStage,
300        dstStage,
301        0,
302        0,
303        nullptr,
304        0,
305        nullptr,
306        (uint32_t)count,
307        barriers.getArrayView().getBuffer());
308}
309
310// TODO: Change size_t to Count?
311void ResourceCommandEncoder::bufferBarrier(
312    GfxCount count,
313    IBufferResource* const* buffers,
314    ResourceState src,
315    ResourceState dst)
316{
317    List<VkBufferMemoryBarrier> barriers;
318    barriers.reserve(count);
319
320    for (GfxIndex i = 0; i < count; i++)
321    {
322        auto bufferImpl = static_cast<BufferResourceImpl*>(buffers[i]);
323
324        VkBufferMemoryBarrier barrier = {};
325        barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
326        barrier.srcAccessMask = calcAccessFlags(src);
327        barrier.dstAccessMask = calcAccessFlags(dst);
328        barrier.buffer = bufferImpl->m_buffer.m_buffer;
329        barrier.offset = 0;
330        barrier.size = bufferImpl->getDesc()->sizeInBytes;
331
332        barriers.add(barrier);
333    }
334
335    VkPipelineStageFlagBits srcStage = calcPipelineStageFlags(src, true);
336    VkPipelineStageFlagBits dstStage = calcPipelineStageFlags(dst, false);
337
338    auto& vkApi = m_commandBuffer->m_renderer->m_api;
339    vkApi.vkCmdPipelineBarrier(
340        m_commandBuffer->m_commandBuffer,
341        srcStage,
342        dstStage,
343        0,
344        0,
345        nullptr,
346        (uint32_t)count,
347        barriers.getBuffer(),
348        0,
349        nullptr);
350}
351
352void ResourceCommandEncoder::endEncoding()
353{
354    // Insert memory barrier to ensure transfers are visible to the GPU.
355    auto& vkAPI = m_commandBuffer->m_renderer->m_api;
356
357    VkMemoryBarrier memBarrier = {VK_STRUCTURE_TYPE_MEMORY_BARRIER};
358    memBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
359    memBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
360    vkAPI.vkCmdPipelineBarrier(
361        m_commandBuffer->m_commandBuffer,
362        VK_PIPELINE_STAGE_TRANSFER_BIT,
363        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
364        0,
365        1,
366        &memBarrier,
367        0,
368        nullptr,
369        0,
370        nullptr);
371}
372
373void ResourceCommandEncoder::writeTimestamp(IQueryPool* queryPool, GfxIndex index)
374{
375    _writeTimestamp(
376        &m_commandBuffer->m_renderer->m_api,
377        m_commandBuffer->m_commandBuffer,
378        queryPool,
379        index);
380}
381
382void ResourceCommandEncoder::copyTexture(
383    ITextureResource* dst,
384    ResourceState dstState,
385    SubresourceRange dstSubresource,
386    ITextureResource::Offset3D dstOffset,
387    ITextureResource* src,
388    ResourceState srcState,
389    SubresourceRange srcSubresource,
390    ITextureResource::Offset3D srcOffset,
391    ITextureResource::Extents extent)
392{
393    auto srcImage = static_cast<TextureResourceImpl*>(src);
394    auto srcDesc = srcImage->getDesc();
395    auto srcImageLayout = VulkanUtil::getImageLayoutFromState(srcState);
396    auto dstImage = static_cast<TextureResourceImpl*>(dst);
397    auto dstDesc = dstImage->getDesc();
398    auto dstImageLayout = VulkanUtil::getImageLayoutFromState(dstState);
399    if (dstSubresource.layerCount == 0 && dstSubresource.mipLevelCount == 0)
400    {
401        extent = dstDesc->size;
402        dstSubresource.layerCount = dstDesc->arraySize;
403        if (dstSubresource.layerCount == 0)
404            dstSubresource.layerCount = 1;
405        dstSubresource.mipLevelCount = dstDesc->numMipLevels;
406    }
407    if (srcSubresource.layerCount == 0 && srcSubresource.mipLevelCount == 0)
408    {
409        extent = srcDesc->size;
410        srcSubresource.layerCount = srcDesc->arraySize;
411        if (srcSubresource.layerCount == 0)
412            srcSubresource.layerCount = 1;
413        srcSubresource.mipLevelCount = dstDesc->numMipLevels;
414    }
415    VkImageCopy region = {};
416    region.srcSubresource.aspectMask =
417        VulkanUtil::getAspectMask(srcSubresource.aspectMask, srcImage->m_vkformat);
418    region.srcSubresource.baseArrayLayer = srcSubresource.baseArrayLayer;
419    region.srcSubresource.mipLevel = srcSubresource.mipLevel;
420    region.srcSubresource.layerCount = srcSubresource.layerCount;
421    region.srcOffset = {(int32_t)srcOffset.x, (int32_t)srcOffset.y, (int32_t)srcOffset.z};
422    region.dstSubresource.aspectMask =
423        VulkanUtil::getAspectMask(dstSubresource.aspectMask, dstImage->m_vkformat);
424    region.dstSubresource.baseArrayLayer = dstSubresource.baseArrayLayer;
425    region.dstSubresource.mipLevel = dstSubresource.mipLevel;
426    region.dstSubresource.layerCount = dstSubresource.layerCount;
427    region.dstOffset = {(int32_t)dstOffset.x, (int32_t)dstOffset.y, (int32_t)dstOffset.z};
428    region.extent = {(uint32_t)extent.width, (uint32_t)extent.height, (uint32_t)extent.depth};
429
430    auto& vkApi = m_commandBuffer->m_renderer->m_api;
431    vkApi.vkCmdCopyImage(
432        m_commandBuffer->m_commandBuffer,
433        srcImage->m_image,
434        srcImageLayout,
435        dstImage->m_image,
436        dstImageLayout,
437        1,
438        &region);
439}
440
441void ResourceCommandEncoder::uploadTextureData(
442    ITextureResource* dst,
443    SubresourceRange subResourceRange,
444    ITextureResource::Offset3D offset,
445    ITextureResource::Extents extend,
446    ITextureResource::SubresourceData* subResourceData,
447    GfxCount subResourceDataCount)
448{
449    // VALIDATION: dst must be in TransferDst state.
450
451    auto& vkApi = m_commandBuffer->m_renderer->m_api;
452    auto dstImpl = static_cast<TextureResourceImpl*>(dst);
453    List<TextureResource::Extents> mipSizes;
454
455    VkCommandBuffer commandBuffer = m_commandBuffer->m_commandBuffer;
456    auto& desc = *dstImpl->getDesc();
457    // Calculate how large the buffer has to be
458    Size bufferSize = 0;
459    // Calculate how large an array entry is
460    for (GfxIndex j = subResourceRange.mipLevel;
461         j < subResourceRange.mipLevel + subResourceRange.mipLevelCount;
462         ++j)
463    {
464        const TextureResource::Extents mipSize = calcMipSize(desc.size, j);
465
466        auto rowSizeInBytes = calcRowSize(desc.format, mipSize.width);
467        auto numRows = calcNumRows(desc.format, mipSize.height);
468
469        mipSizes.add(mipSize);
470
471        bufferSize += (rowSizeInBytes * numRows) * mipSize.depth;
472    }
473
474    // Calculate the total size taking into account the array
475    bufferSize *= subResourceRange.layerCount;
476
477    IBufferResource* uploadBuffer = nullptr;
478    Offset uploadBufferOffset = 0;
479    m_commandBuffer->m_transientHeap
480        ->allocateStagingBuffer(bufferSize, uploadBuffer, uploadBufferOffset, MemoryType::Upload);
481
482    // Copy into upload buffer
483    {
484        int subResourceCounter = 0;
485
486        uint8_t* dstData;
487        uploadBuffer->map(nullptr, (void**)&dstData);
488        dstData += uploadBufferOffset;
489        uint8_t* dstDataStart;
490        dstDataStart = dstData;
491
492        Offset dstSubresourceOffset = 0;
493        for (GfxIndex i = 0; i < subResourceRange.layerCount; ++i)
494        {
495            for (GfxIndex j = 0; j < (GfxCount)mipSizes.getCount(); ++j)
496            {
497                const auto& mipSize = mipSizes[j];
498
499                int subResourceIndex = subResourceCounter++;
500                auto initSubresource = subResourceData[subResourceIndex];
501
502                const ptrdiff_t srcRowStride = (ptrdiff_t)initSubresource.strideY;
503                const ptrdiff_t srcLayerStride = (ptrdiff_t)initSubresource.strideZ;
504
505                auto dstRowSizeInBytes = calcRowSize(desc.format, mipSize.width);
506                auto numRows = calcNumRows(desc.format, mipSize.height);
507                auto dstLayerSizeInBytes = dstRowSizeInBytes * numRows;
508
509                const uint8_t* srcLayer = (const uint8_t*)initSubresource.data;
510                uint8_t* dstLayer = dstData + dstSubresourceOffset;
511
512                for (int k = 0; k < mipSize.depth; k++)
513                {
514                    const uint8_t* srcRow = srcLayer;
515                    uint8_t* dstRow = dstLayer;
516
517                    for (GfxCount l = 0; l < numRows; l++)
518                    {
519                        ::memcpy(dstRow, srcRow, dstRowSizeInBytes);
520
521                        dstRow += dstRowSizeInBytes;
522                        srcRow += srcRowStride;
523                    }
524
525                    dstLayer += dstLayerSizeInBytes;
526                    srcLayer += srcLayerStride;
527                }
528
529                dstSubresourceOffset += dstLayerSizeInBytes * mipSize.depth;
530            }
531        }
532        uploadBuffer->unmap(nullptr);
533    }
534    {
535        Offset srcOffset = uploadBufferOffset;
536        for (GfxIndex i = 0; i < subResourceRange.layerCount; ++i)
537        {
538            for (GfxIndex j = 0; j < (GfxCount)mipSizes.getCount(); ++j)
539            {
540                const auto& mipSize = mipSizes[j];
541
542                auto rowSizeInBytes = calcRowSize(desc.format, mipSize.width);
543                auto numRows = calcNumRows(desc.format, mipSize.height);
544
545                // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkBufferImageCopy.html
546                // bufferRowLength and bufferImageHeight specify the data in buffer
547                // memory as a subregion of a larger two- or three-dimensional image,
548                // and control the addressing calculations of data in buffer memory. If
549                // either of these values is zero, that aspect of the buffer memory is
550                // considered to be tightly packed according to the imageExtent.
551
552                VkBufferImageCopy region = {};
553
554                region.bufferOffset = srcOffset;
555                region.bufferRowLength = 0; // rowSizeInBytes;
556                region.bufferImageHeight = 0;
557
558                region.imageSubresource.aspectMask = getAspectMaskFromFormat(dstImpl->m_vkformat);
559                region.imageSubresource.mipLevel = subResourceRange.mipLevel + uint32_t(j);
560                region.imageSubresource.baseArrayLayer = subResourceRange.baseArrayLayer + i;
561                region.imageSubresource.layerCount = 1;
562                region.imageOffset = {0, 0, 0};
563                region.imageExtent = {
564                    uint32_t(mipSize.width),
565                    uint32_t(mipSize.height),
566                    uint32_t(mipSize.depth)};
567
568                // Do the copy (do all depths in a single go)
569                vkApi.vkCmdCopyBufferToImage(
570                    commandBuffer,
571                    static_cast<BufferResourceImpl*>(uploadBuffer)->m_buffer.m_buffer,
572                    dstImpl->m_image,
573                    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
574                    1,
575                    &region);
576
577                // Next
578                srcOffset += rowSizeInBytes * numRows * mipSize.depth;
579            }
580        }
581    }
582}
583
584void ResourceCommandEncoder::_clearColorImage(
585    TextureResourceViewImpl* viewImpl,
586    ClearValue* clearValue)
587{
588    auto& api = m_commandBuffer->m_renderer->m_api;
589    auto layout = viewImpl->m_layout;
590    if (layout != VK_IMAGE_LAYOUT_GENERAL && layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
591    {
592        layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
593        m_commandBuffer->m_renderer->_transitionImageLayout(
594            m_commandBuffer->m_commandBuffer,
595            viewImpl->m_texture->m_image,
596            viewImpl->m_texture->m_vkformat,
597            *viewImpl->m_texture->getDesc(),
598            viewImpl->m_layout,
599            layout);
600    }
601
602    VkImageSubresourceRange subresourceRange = {};
603    subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
604    subresourceRange.baseArrayLayer = viewImpl->m_desc.subresourceRange.baseArrayLayer;
605    subresourceRange.baseMipLevel = viewImpl->m_desc.subresourceRange.mipLevel;
606    subresourceRange.layerCount = viewImpl->m_desc.subresourceRange.layerCount;
607    subresourceRange.levelCount = 1;
608
609    VkClearColorValue vkClearColor = {};
610    memcpy(vkClearColor.float32, clearValue->color.floatValues, sizeof(float) * 4);
611
612    api.vkCmdClearColorImage(
613        m_commandBuffer->m_commandBuffer,
614        viewImpl->m_texture->m_image,
615        layout,
616        &vkClearColor,
617        1,
618        &subresourceRange);
619
620    if (layout != viewImpl->m_layout)
621    {
622        m_commandBuffer->m_renderer->_transitionImageLayout(
623            m_commandBuffer->m_commandBuffer,
624            viewImpl->m_texture->m_image,
625            viewImpl->m_texture->m_vkformat,
626            *viewImpl->m_texture->getDesc(),
627            layout,
628            viewImpl->m_layout);
629    }
630}
631
632void ResourceCommandEncoder::_clearDepthImage(
633    TextureResourceViewImpl* viewImpl,
634    ClearValue* clearValue,
635    ClearResourceViewFlags::Enum flags)
636{
637    auto& api = m_commandBuffer->m_renderer->m_api;
638    auto layout = viewImpl->m_layout;
639    if (layout != VK_IMAGE_LAYOUT_GENERAL && layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
640    {
641        layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
642        m_commandBuffer->m_renderer->_transitionImageLayout(
643            m_commandBuffer->m_commandBuffer,
644            viewImpl->m_texture->m_image,
645            viewImpl->m_texture->m_vkformat,
646            *viewImpl->m_texture->getDesc(),
647            viewImpl->m_layout,
648            layout);
649    }
650
651    VkImageSubresourceRange subresourceRange = {};
652    if (flags & ClearResourceViewFlags::ClearDepth)
653    {
654        if (VulkanUtil::isDepthFormat(viewImpl->m_texture->m_vkformat))
655        {
656            subresourceRange.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
657        }
658    }
659    if (flags & ClearResourceViewFlags::ClearStencil)
660    {
661        if (VulkanUtil::isStencilFormat(viewImpl->m_texture->m_vkformat))
662        {
663            subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
664        }
665    }
666    subresourceRange.baseArrayLayer = viewImpl->m_desc.subresourceRange.baseArrayLayer;
667    subresourceRange.baseMipLevel = viewImpl->m_desc.subresourceRange.mipLevel;
668    subresourceRange.layerCount = viewImpl->m_desc.subresourceRange.layerCount;
669    subresourceRange.levelCount = 1;
670
671    VkClearDepthStencilValue vkClearValue = {};
672    vkClearValue.depth = clearValue->depthStencil.depth;
673    vkClearValue.stencil = clearValue->depthStencil.stencil;
674
675    api.vkCmdClearDepthStencilImage(
676        m_commandBuffer->m_commandBuffer,
677        viewImpl->m_texture->m_image,
678        layout,
679        &vkClearValue,
680        1,
681        &subresourceRange);
682
683    if (layout != viewImpl->m_layout)
684    {
685        m_commandBuffer->m_renderer->_transitionImageLayout(
686            m_commandBuffer->m_commandBuffer,
687            viewImpl->m_texture->m_image,
688            viewImpl->m_texture->m_vkformat,
689            *viewImpl->m_texture->getDesc(),
690            layout,
691            viewImpl->m_layout);
692    }
693}
694
695void ResourceCommandEncoder::_clearBuffer(
696    VkBuffer buffer,
697    uint64_t bufferSize,
698    const IResourceView::Desc& desc,
699    uint32_t clearValue)
700{
701    auto& api = m_commandBuffer->m_renderer->m_api;
702    auto clearOffset = desc.bufferRange.offset;
703    auto clearSize = desc.bufferRange.size == 0 ? bufferSize - clearOffset : desc.bufferRange.size;
704    api.vkCmdFillBuffer(
705        m_commandBuffer->m_commandBuffer,
706        buffer,
707        clearOffset,
708        clearSize,
709        clearValue);
710}
711
712void ResourceCommandEncoder::clearResourceView(
713    IResourceView* view,
714    ClearValue* clearValue,
715    ClearResourceViewFlags::Enum flags)
716{
717    auto& api = m_commandBuffer->m_renderer->m_api;
718    switch (view->getViewDesc()->type)
719    {
720    case IResourceView::Type::RenderTarget:
721        {
722            auto viewImpl = static_cast<TextureResourceViewImpl*>(view);
723            _clearColorImage(viewImpl, clearValue);
724        }
725        break;
726    case IResourceView::Type::DepthStencil:
727        {
728            auto viewImpl = static_cast<TextureResourceViewImpl*>(view);
729            _clearDepthImage(viewImpl, clearValue, flags);
730        }
731        break;
732    case IResourceView::Type::UnorderedAccess:
733        {
734            auto viewImplBase = static_cast<ResourceViewImpl*>(view);
735            switch (viewImplBase->m_type)
736            {
737            case ResourceViewImpl::ViewType::Texture:
738                {
739                    auto viewImpl = static_cast<TextureResourceViewImpl*>(viewImplBase);
740                    if ((flags & ClearResourceViewFlags::ClearDepth) ||
741                        (flags & ClearResourceViewFlags::ClearStencil))
742                    {
743                        _clearDepthImage(viewImpl, clearValue, flags);
744                    }
745                    else
746                    {
747                        _clearColorImage(viewImpl, clearValue);
748                    }
749                }
750                break;
751            case ResourceViewImpl::ViewType::PlainBuffer:
752                {
753                    assert(
754                        clearValue->color.uintValues[1] == clearValue->color.uintValues[0] &&
755                        clearValue->color.uintValues[2] == clearValue->color.uintValues[0] &&
756                        clearValue->color.uintValues[3] == clearValue->color.uintValues[0]);
757                    auto viewImpl = static_cast<PlainBufferResourceViewImpl*>(viewImplBase);
758                    uint64_t clearStart = viewImpl->m_desc.bufferRange.offset;
759                    uint64_t clearSize = viewImpl->m_desc.bufferRange.size;
760                    if (clearSize == 0)
761                        clearSize = viewImpl->m_buffer->getDesc()->sizeInBytes - clearStart;
762                    api.vkCmdFillBuffer(
763                        m_commandBuffer->m_commandBuffer,
764                        viewImpl->m_buffer->m_buffer.m_buffer,
765                        clearStart,
766                        clearSize,
767                        clearValue->color.uintValues[0]);
768                }
769                break;
770            case ResourceViewImpl::ViewType::TexelBuffer:
771                {
772                    assert(
773                        clearValue->color.uintValues[1] == clearValue->color.uintValues[0] &&
774                        clearValue->color.uintValues[2] == clearValue->color.uintValues[0] &&
775                        clearValue->color.uintValues[3] == clearValue->color.uintValues[0]);
776                    auto viewImpl = static_cast<TexelBufferResourceViewImpl*>(viewImplBase);
777                    _clearBuffer(
778                        viewImpl->m_buffer->m_buffer.m_buffer,
779                        viewImpl->m_buffer->getDesc()->sizeInBytes,
780                        viewImpl->m_desc,
781                        clearValue->color.uintValues[0]);
782                }
783                break;
784            }
785        }
786        break;
787    }
788}
789
790void ResourceCommandEncoder::resolveResource(
791    ITextureResource* source,
792    ResourceState sourceState,
793    SubresourceRange sourceRange,
794    ITextureResource* dest,
795    ResourceState destState,
796    SubresourceRange destRange)
797{
798    auto srcTexture = static_cast<TextureResourceImpl*>(source);
799    auto srcExtent = srcTexture->getDesc()->size;
800    auto dstTexture = static_cast<TextureResourceImpl*>(dest);
801
802    auto srcImage = srcTexture->m_image;
803    auto dstImage = dstTexture->m_image;
804
805    auto srcImageLayout = VulkanUtil::getImageLayoutFromState(sourceState);
806    auto dstImageLayout = VulkanUtil::getImageLayoutFromState(destState);
807
808    for (GfxIndex layer = 0; layer < sourceRange.layerCount; ++layer)
809    {
810        for (GfxIndex mip = 0; mip < sourceRange.mipLevelCount; ++mip)
811        {
812            VkImageResolve region = {};
813            region.srcSubresource.aspectMask =
814                VulkanUtil::getAspectMask(sourceRange.aspectMask, srcTexture->m_vkformat);
815            region.srcSubresource.baseArrayLayer = layer + sourceRange.baseArrayLayer;
816            region.srcSubresource.layerCount = 1;
817            region.srcSubresource.mipLevel = mip + sourceRange.mipLevel;
818            region.srcOffset = {0, 0, 0};
819            region.dstSubresource.aspectMask =
820                VulkanUtil::getAspectMask(destRange.aspectMask, dstTexture->m_vkformat);
821            region.dstSubresource.baseArrayLayer = layer + destRange.baseArrayLayer;
822            region.dstSubresource.layerCount = 1;
823            region.dstSubresource.mipLevel = mip + destRange.mipLevel;
824            region.dstOffset = {0, 0, 0};
825            region.extent = {
826                (uint32_t)srcExtent.width,
827                (uint32_t)srcExtent.height,
828                (uint32_t)srcExtent.depth};
829
830            auto& vkApi = m_commandBuffer->m_renderer->m_api;
831            vkApi.vkCmdResolveImage(
832                m_commandBuffer->m_commandBuffer,
833                srcImage,
834                srcImageLayout,
835                dstImage,
836                dstImageLayout,
837                1,
838                &region);
839        }
840    }
841}
842
843void ResourceCommandEncoder::resolveQuery(
844    IQueryPool* queryPool,
845    GfxIndex index,
846    GfxCount count,
847    IBufferResource* buffer,
848    Offset offset)
849{
850    auto& vkApi = m_commandBuffer->m_renderer->m_api;
851    auto poolImpl = static_cast<QueryPoolImpl*>(queryPool);
852    auto bufferImpl = static_cast<BufferResourceImpl*>(buffer);
853    vkApi.vkCmdCopyQueryPoolResults(
854        m_commandBuffer->m_commandBuffer,
855        poolImpl->m_pool,
856        index,
857        count,
858        bufferImpl->m_buffer.m_buffer,
859        offset,
860        sizeof(uint64_t),
861        VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
862}
863
864void ResourceCommandEncoder::copyTextureToBuffer(
865    IBufferResource* dst,
866    Offset dstOffset,
867    Size dstSize,
868    Size dstRowStride,
869    ITextureResource* src,
870    ResourceState srcState,
871    SubresourceRange srcSubresource,
872    ITextureResource::Offset3D srcOffset,
873    ITextureResource::Extents extent)
874{
875    assert(srcSubresource.mipLevelCount <= 1);
876
877    auto image = static_cast<TextureResourceImpl*>(src);
878    auto desc = image->getDesc();
879    auto buffer = static_cast<BufferResourceImpl*>(dst);
880    auto srcImageLayout = VulkanUtil::getImageLayoutFromState(srcState);
881
882    VkBufferImageCopy region = {};
883    region.bufferOffset = dstOffset;
884    region.bufferRowLength = 0;
885    region.bufferImageHeight = 0;
886    region.imageSubresource.aspectMask =
887        VulkanUtil::getAspectMask(srcSubresource.aspectMask, image->m_vkformat);
888    region.imageSubresource.mipLevel = srcSubresource.mipLevel;
889    region.imageSubresource.baseArrayLayer = srcSubresource.baseArrayLayer;
890    region.imageSubresource.layerCount = srcSubresource.layerCount;
891    region.imageOffset = {(int32_t)srcOffset.x, (int32_t)srcOffset.y, (int32_t)srcOffset.z};
892    region.imageExtent = {uint32_t(extent.width), uint32_t(extent.height), uint32_t(extent.depth)};
893
894    auto& vkApi = m_commandBuffer->m_renderer->m_api;
895    vkApi.vkCmdCopyImageToBuffer(
896        m_commandBuffer->m_commandBuffer,
897        image->m_image,
898        srcImageLayout,
899        buffer->m_buffer.m_buffer,
900        1,
901        &region);
902}
903
904void ResourceCommandEncoder::textureSubresourceBarrier(
905    ITextureResource* texture,
906    SubresourceRange subresourceRange,
907    ResourceState src,
908    ResourceState dst)
909{
910    ShortList<VkImageMemoryBarrier> barriers;
911    auto image = static_cast<TextureResourceImpl*>(texture);
912    auto desc = image->getDesc();
913
914    VkImageMemoryBarrier barrier = {};
915    barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
916    barrier.image = image->m_image;
917    barrier.oldLayout = translateImageLayout(src);
918    barrier.newLayout = translateImageLayout(dst);
919    barrier.subresourceRange.aspectMask =
920        VulkanUtil::getAspectMask(subresourceRange.aspectMask, image->m_vkformat);
921    barrier.subresourceRange.baseArrayLayer = subresourceRange.baseArrayLayer;
922    barrier.subresourceRange.baseMipLevel = subresourceRange.mipLevel;
923    barrier.subresourceRange.layerCount = subresourceRange.layerCount;
924    barrier.subresourceRange.levelCount = subresourceRange.mipLevelCount;
925    barrier.srcAccessMask = calcAccessFlags(src);
926    barrier.dstAccessMask = calcAccessFlags(dst);
927    barriers.add(barrier);
928
929    VkPipelineStageFlagBits srcStage = calcPipelineStageFlags(src, true);
930    VkPipelineStageFlagBits dstStage = calcPipelineStageFlags(dst, false);
931
932    auto& vkApi = m_commandBuffer->m_renderer->m_api;
933    vkApi.vkCmdPipelineBarrier(
934        m_commandBuffer->m_commandBuffer,
935        srcStage,
936        dstStage,
937        0,
938        0,
939        nullptr,
940        0,
941        nullptr,
942        (uint32_t)barriers.getCount(),
943        barriers.getArrayView().getBuffer());
944}
945
946void ResourceCommandEncoder::beginDebugEvent(const char* name, float rgbColor[3])
947{
948    auto& vkApi = m_commandBuffer->m_renderer->m_api;
949    if (vkApi.vkCmdDebugMarkerBeginEXT)
950    {
951        VkDebugMarkerMarkerInfoEXT eventInfo = {};
952        eventInfo.sType = VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT;
953        eventInfo.pMarkerName = name;
954        eventInfo.color[0] = rgbColor[0];
955        eventInfo.color[1] = rgbColor[1];
956        eventInfo.color[2] = rgbColor[2];
957        eventInfo.color[3] = 1.0f;
958        vkApi.vkCmdDebugMarkerBeginEXT(m_commandBuffer->m_commandBuffer, &eventInfo);
959    }
960}
961
962void ResourceCommandEncoder::endDebugEvent()
963{
964    auto& vkApi = m_commandBuffer->m_renderer->m_api;
965    if (vkApi.vkCmdDebugMarkerEndEXT)
966    {
967        vkApi.vkCmdDebugMarkerEndEXT(m_commandBuffer->m_commandBuffer);
968    }
969}
970
971void RenderCommandEncoder::beginPass(IRenderPassLayout* renderPass, IFramebuffer* framebuffer)
972{
973    FramebufferImpl* framebufferImpl = static_cast<FramebufferImpl*>(framebuffer);
974    if (!framebuffer)
975        framebufferImpl = this->m_device->m_emptyFramebuffer;
976    RenderPassLayoutImpl* renderPassImpl = static_cast<RenderPassLayoutImpl*>(renderPass);
977    VkClearValue clearValues[kMaxTargets] = {};
978    VkRenderPassBeginInfo beginInfo = {};
979    beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
980    beginInfo.framebuffer = framebufferImpl->m_handle;
981    beginInfo.renderPass = renderPassImpl->m_renderPass;
982    uint32_t targetCount = (uint32_t)framebufferImpl->renderTargetViews.getCount();
983    if (framebufferImpl->depthStencilView)
984        targetCount++;
985    beginInfo.clearValueCount = targetCount;
986    beginInfo.renderArea.extent.width = framebufferImpl->m_width;
987    beginInfo.renderArea.extent.height = framebufferImpl->m_height;
988    beginInfo.pClearValues = framebufferImpl->m_clearValues;
989    auto& api = *m_api;
990    api.vkCmdBeginRenderPass(m_vkCommandBuffer, &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
991}
992
993void RenderCommandEncoder::endEncoding()
994{
995    auto& api = *m_api;
996    api.vkCmdEndRenderPass(m_vkCommandBuffer);
997    endEncodingImpl();
998}
999
1000Result RenderCommandEncoder::bindPipeline(
1001    IPipelineState* pipelineState,
1002    IShaderObject** outRootObject)
1003{
1004    return setPipelineStateImpl(pipelineState, outRootObject);
1005}
1006
1007Result RenderCommandEncoder::bindPipelineWithRootObject(
1008    IPipelineState* pipelineState,
1009    IShaderObject* rootObject)
1010{
1011    return setPipelineStateWithRootObjectImpl(pipelineState, rootObject);
1012}
1013
1014void RenderCommandEncoder::setViewports(GfxCount count, const Viewport* viewports)
1015{
1016    static const int kMaxViewports = 8; // TODO: base on device caps
1017    assert(count <= kMaxViewports);
1018
1019    m_viewports.setCount(count);
1020    for (GfxIndex ii = 0; ii < count; ++ii)
1021    {
1022        auto& inViewport = viewports[ii];
1023        auto& vkViewport = m_viewports[ii];
1024
1025        vkViewport.x = inViewport.originX;
1026        vkViewport.y = inViewport.originY + inViewport.extentY;
1027        vkViewport.width = inViewport.extentX;
1028        vkViewport.height = -inViewport.extentY;
1029        vkViewport.minDepth = inViewport.minZ;
1030        vkViewport.maxDepth = inViewport.maxZ;
1031    }
1032
1033    auto& api = *m_api;
1034    api.vkCmdSetViewport(m_vkCommandBuffer, 0, uint32_t(count), m_viewports.getBuffer());
1035}
1036
1037void RenderCommandEncoder::setScissorRects(GfxCount count, const ScissorRect* rects)
1038{
1039    static const int kMaxScissorRects = 8; // TODO: base on device caps
1040    assert(count <= kMaxScissorRects);
1041
1042    m_scissorRects.setCount(count);
1043    for (GfxIndex ii = 0; ii < count; ++ii)
1044    {
1045        auto& inRect = rects[ii];
1046        auto& vkRect = m_scissorRects[ii];
1047
1048        vkRect.offset.x = int32_t(inRect.minX);
1049        vkRect.offset.y = int32_t(inRect.minY);
1050        vkRect.extent.width = uint32_t(inRect.maxX - inRect.minX);
1051        vkRect.extent.height = uint32_t(inRect.maxY - inRect.minY);
1052    }
1053
1054    auto& api = *m_api;
1055    api.vkCmdSetScissor(m_vkCommandBuffer, 0, uint32_t(count), m_scissorRects.getBuffer());
1056}
1057
1058void RenderCommandEncoder::setPrimitiveTopology(PrimitiveTopology topology)
1059{
1060    auto& api = *m_api;
1061    if (api.vkCmdSetPrimitiveTopologyEXT)
1062    {
1063        api.vkCmdSetPrimitiveTopologyEXT(
1064            m_vkCommandBuffer,
1065            VulkanUtil::getVkPrimitiveTopology(topology));
1066    }
1067    else
1068    {
1069        switch (topology)
1070        {
1071        case PrimitiveTopology::TriangleList:
1072            break;
1073        default:
1074            // We are using a non-list topology, but we don't have dynmaic state
1075            // extension, error out.
1076            assert(!"Non-list topology requires VK_EXT_extended_dynamic_states, which "
1077                    "is not present.");
1078            break;
1079        }
1080    }
1081}
1082
1083void RenderCommandEncoder::setVertexBuffers(
1084    GfxIndex startSlot,
1085    GfxCount slotCount,
1086    IBufferResource* const* buffers,
1087    const Offset* offsets)
1088{
1089    for (GfxIndex i = 0; i < GfxIndex(slotCount); i++)
1090    {
1091        GfxIndex slotIndex = startSlot + i;
1092        BufferResourceImpl* buffer = static_cast<BufferResourceImpl*>(buffers[i]);
1093        if (buffer)
1094        {
1095            VkBuffer vertexBuffers[] = {buffer->m_buffer.m_buffer};
1096            VkDeviceSize offset = VkDeviceSize(offsets[i]);
1097
1098            m_api->vkCmdBindVertexBuffers(
1099                m_vkCommandBuffer,
1100                (uint32_t)slotIndex,
1101                1,
1102                vertexBuffers,
1103                &offset);
1104        }
1105    }
1106}
1107
1108void RenderCommandEncoder::setIndexBuffer(
1109    IBufferResource* buffer,
1110    Format indexFormat,
1111    Offset offset)
1112{
1113    VkIndexType indexType = VK_INDEX_TYPE_UINT16;
1114    switch (indexFormat)
1115    {
1116    case Format::R16_UINT:
1117        indexType = VK_INDEX_TYPE_UINT16;
1118        break;
1119    case Format::R32_UINT:
1120        indexType = VK_INDEX_TYPE_UINT32;
1121        break;
1122    default:
1123        assert(!"unsupported index format");
1124    }
1125
1126    BufferResourceImpl* bufferImpl = static_cast<BufferResourceImpl*>(buffer);
1127
1128    m_api->vkCmdBindIndexBuffer(
1129        m_vkCommandBuffer,
1130        bufferImpl->m_buffer.m_buffer,
1131        (VkDeviceSize)offset,
1132        indexType);
1133}
1134
1135Result RenderCommandEncoder::prepareDraw()
1136{
1137    auto pipeline = static_cast<PipelineStateImpl*>(m_currentPipeline.Ptr());
1138    if (!pipeline)
1139    {
1140        return SLANG_FAIL;
1141    }
1142    SLANG_RETURN_ON_FAIL(bindRenderState(VK_PIPELINE_BIND_POINT_GRAPHICS));
1143    return SLANG_OK;
1144}
1145
1146Result RenderCommandEncoder::draw(GfxCount vertexCount, GfxIndex startVertex)
1147{
1148    SLANG_RETURN_ON_FAIL(prepareDraw());
1149    auto& api = *m_api;
1150    api.vkCmdDraw(m_vkCommandBuffer, vertexCount, 1, 0, 0);
1151    return SLANG_OK;
1152}
1153
1154Result RenderCommandEncoder::drawIndexed(
1155    GfxCount indexCount,
1156    GfxIndex startIndex,
1157    GfxIndex baseVertex)
1158{
1159    SLANG_RETURN_ON_FAIL(prepareDraw());
1160    auto& api = *m_api;
1161    api.vkCmdDrawIndexed(m_vkCommandBuffer, indexCount, 1, startIndex, baseVertex, 0);
1162    return SLANG_OK;
1163}
1164
1165void RenderCommandEncoder::setStencilReference(uint32_t referenceValue)
1166{
1167    auto& api = *m_api;
1168    api.vkCmdSetStencilReference(m_vkCommandBuffer, VK_STENCIL_FRONT_AND_BACK, referenceValue);
1169}
1170
1171Result RenderCommandEncoder::drawIndirect(
1172    GfxCount maxDrawCount,
1173    IBufferResource* argBuffer,
1174    Offset argOffset,
1175    IBufferResource* countBuffer,
1176    Offset countOffset)
1177{
1178    SLANG_RETURN_ON_FAIL(prepareDraw());
1179    auto& api = *m_api;
1180    auto argBufferImpl = static_cast<BufferResourceImpl*>(argBuffer);
1181
1182    if (countBuffer)
1183    {
1184        auto countBufferImpl = static_cast<BufferResourceImpl*>(countBuffer);
1185        api.vkCmdDrawIndirectCount(
1186            m_vkCommandBuffer,
1187            argBufferImpl->m_buffer.m_buffer,
1188            argOffset,
1189            countBufferImpl->m_buffer.m_buffer,
1190            countOffset,
1191            maxDrawCount,
1192            sizeof(VkDrawIndirectCommand));
1193    }
1194    else
1195    {
1196        api.vkCmdDrawIndirect(
1197            m_vkCommandBuffer,
1198            argBufferImpl->m_buffer.m_buffer,
1199            argOffset,
1200            maxDrawCount,
1201            sizeof(VkDrawIndirectCommand));
1202    }
1203    return SLANG_OK;
1204}
1205
1206Result RenderCommandEncoder::drawIndexedIndirect(
1207    GfxCount maxDrawCount,
1208    IBufferResource* argBuffer,
1209    Offset argOffset,
1210    IBufferResource* countBuffer,
1211    Offset countOffset)
1212{
1213    SLANG_RETURN_ON_FAIL(prepareDraw());
1214    auto& api = *m_api;
1215    auto argBufferImpl = static_cast<BufferResourceImpl*>(argBuffer);
1216
1217    if (countBuffer)
1218    {
1219        auto countBufferImpl = static_cast<BufferResourceImpl*>(countBuffer);
1220        api.vkCmdDrawIndexedIndirectCount(
1221            m_vkCommandBuffer,
1222            argBufferImpl->m_buffer.m_buffer,
1223            argOffset,
1224            countBufferImpl->m_buffer.m_buffer,
1225            countOffset,
1226            maxDrawCount,
1227            sizeof(VkDrawIndexedIndirectCommand));
1228    }
1229    else
1230    {
1231        api.vkCmdDrawIndexedIndirect(
1232            m_vkCommandBuffer,
1233            argBufferImpl->m_buffer.m_buffer,
1234            argOffset,
1235            maxDrawCount,
1236            sizeof(VkDrawIndexedIndirectCommand));
1237    }
1238    return SLANG_OK;
1239}
1240
1241Result RenderCommandEncoder::setSamplePositions(
1242    GfxCount samplesPerPixel,
1243    GfxCount pixelCount,
1244    const SamplePosition* samplePositions)
1245{
1246    if (m_api->vkCmdSetSampleLocationsEXT)
1247    {
1248        VkSampleLocationsInfoEXT sampleLocInfo = {};
1249        sampleLocInfo.sType = VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT;
1250        sampleLocInfo.sampleLocationsCount = samplesPerPixel * pixelCount;
1251        sampleLocInfo.sampleLocationsPerPixel = (VkSampleCountFlagBits)samplesPerPixel;
1252        m_api->vkCmdSetSampleLocationsEXT(m_vkCommandBuffer, &sampleLocInfo);
1253        return SLANG_OK;
1254    }
1255    return SLANG_E_NOT_AVAILABLE;
1256}
1257
1258Result RenderCommandEncoder::drawInstanced(
1259    GfxCount vertexCount,
1260    GfxCount instanceCount,
1261    GfxIndex startVertex,
1262    GfxIndex startInstanceLocation)
1263{
1264    SLANG_RETURN_ON_FAIL(prepareDraw());
1265    auto& api = *m_api;
1266    api.vkCmdDraw(
1267        m_vkCommandBuffer,
1268        vertexCount,
1269        instanceCount,
1270        startVertex,
1271        startInstanceLocation);
1272    return SLANG_OK;
1273}
1274
1275Result RenderCommandEncoder::drawIndexedInstanced(
1276    GfxCount indexCount,
1277    GfxCount instanceCount,
1278    GfxIndex startIndexLocation,
1279    GfxIndex baseVertexLocation,
1280    GfxIndex startInstanceLocation)
1281{
1282    SLANG_RETURN_ON_FAIL(prepareDraw());
1283    auto& api = *m_api;
1284    api.vkCmdDrawIndexed(
1285        m_vkCommandBuffer,
1286        indexCount,
1287        instanceCount,
1288        startIndexLocation,
1289        baseVertexLocation,
1290        startInstanceLocation);
1291    return SLANG_OK;
1292}
1293
1294Result RenderCommandEncoder::drawMeshTasks(int x, int y, int z)
1295{
1296    SLANG_RETURN_ON_FAIL(prepareDraw());
1297    auto& api = *m_api;
1298    api.vkCmdDrawMeshTasksEXT(m_vkCommandBuffer, x, y, z);
1299    return SLANG_OK;
1300}
1301
1302void ComputeCommandEncoder::endEncoding()
1303{
1304    endEncodingImpl();
1305}
1306
1307Result ComputeCommandEncoder::bindPipeline(
1308    IPipelineState* pipelineState,
1309    IShaderObject** outRootObject)
1310{
1311    return setPipelineStateImpl(pipelineState, outRootObject);
1312}
1313
1314Result ComputeCommandEncoder::bindPipelineWithRootObject(
1315    IPipelineState* pipelineState,
1316    IShaderObject* rootObject)
1317{
1318    return setPipelineStateWithRootObjectImpl(pipelineState, rootObject);
1319}
1320
1321Result ComputeCommandEncoder::dispatchCompute(int x, int y, int z)
1322{
1323    auto pipeline = static_cast<PipelineStateImpl*>(m_currentPipeline.Ptr());
1324    if (!pipeline)
1325    {
1326        return SLANG_FAIL;
1327    }
1328
1329    // Also create descriptor sets based on the given pipeline layout
1330    SLANG_RETURN_ON_FAIL(bindRenderState(VK_PIPELINE_BIND_POINT_COMPUTE));
1331    m_api->vkCmdDispatch(m_vkCommandBuffer, x, y, z);
1332    return SLANG_OK;
1333}
1334
1335Result ComputeCommandEncoder::dispatchComputeIndirect(IBufferResource* argBuffer, Offset offset)
1336{
1337    auto pipeline = static_cast<PipelineStateImpl*>(m_currentPipeline.Ptr());
1338    if (!pipeline)
1339    {
1340        return SLANG_FAIL;
1341    }
1342
1343    // Also create descriptor sets based on the given pipeline layout
1344    SLANG_RETURN_ON_FAIL(bindRenderState(VK_PIPELINE_BIND_POINT_COMPUTE));
1345    auto argBufferImpl = static_cast<BufferResourceImpl*>(argBuffer);
1346    m_api->vkCmdDispatchIndirect(m_vkCommandBuffer, argBufferImpl->m_buffer.m_buffer, offset);
1347    return SLANG_OK;
1348}
1349
1350void RayTracingCommandEncoder::_memoryBarrier(
1351    int count,
1352    IAccelerationStructure* const* structures,
1353    AccessFlag srcAccess,
1354    AccessFlag destAccess)
1355{
1356    ShortList<VkBufferMemoryBarrier> memBarriers;
1357    memBarriers.setCount(count);
1358    for (int i = 0; i < count; i++)
1359    {
1360        memBarriers[i].sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
1361        memBarriers[i].pNext = nullptr;
1362        memBarriers[i].dstAccessMask = translateAccelerationStructureAccessFlag(destAccess);
1363        memBarriers[i].srcAccessMask = translateAccelerationStructureAccessFlag(srcAccess);
1364        memBarriers[i].srcQueueFamilyIndex = m_commandBuffer->m_renderer->m_queueFamilyIndex;
1365        memBarriers[i].dstQueueFamilyIndex = m_commandBuffer->m_renderer->m_queueFamilyIndex;
1366
1367        auto asImpl = static_cast<AccelerationStructureImpl*>(structures[i]);
1368        memBarriers[i].buffer = asImpl->m_buffer->m_buffer.m_buffer;
1369        memBarriers[i].offset = asImpl->m_offset;
1370        memBarriers[i].size = asImpl->m_size;
1371    }
1372    m_commandBuffer->m_renderer->m_api.vkCmdPipelineBarrier(
1373        m_commandBuffer->m_commandBuffer,
1374        VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR |
1375            VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1376        VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT |
1377            VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
1378            VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
1379            VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
1380        0,
1381        0,
1382        nullptr,
1383        (uint32_t)memBarriers.getCount(),
1384        memBarriers.getArrayView().getBuffer(),
1385        0,
1386        nullptr);
1387}
1388
1389void RayTracingCommandEncoder::_queryAccelerationStructureProperties(
1390    GfxCount accelerationStructureCount,
1391    IAccelerationStructure* const* accelerationStructures,
1392    GfxCount queryCount,
1393    AccelerationStructureQueryDesc* queryDescs)
1394{
1395    ShortList<VkAccelerationStructureKHR> vkHandles;
1396    vkHandles.setCount(accelerationStructureCount);
1397    for (GfxIndex i = 0; i < accelerationStructureCount; i++)
1398    {
1399        vkHandles[i] =
1400            static_cast<AccelerationStructureImpl*>(accelerationStructures[i])->m_vkHandle;
1401    }
1402    auto vkHandlesView = vkHandles.getArrayView();
1403    for (GfxIndex i = 0; i < queryCount; i++)
1404    {
1405        VkQueryType queryType;
1406        switch (queryDescs[i].queryType)
1407        {
1408        case QueryType::AccelerationStructureCompactedSize:
1409            queryType = VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_KHR;
1410            break;
1411        case QueryType::AccelerationStructureSerializedSize:
1412            queryType = VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_SIZE_KHR;
1413            break;
1414        case QueryType::AccelerationStructureCurrentSize:
1415            continue;
1416        default:
1417            getDebugCallback()->handleMessage(
1418                DebugMessageType::Error,
1419                DebugMessageSource::Layer,
1420                "Invalid query type for use in queryAccelerationStructureProperties.");
1421            return;
1422        }
1423        auto queryPool = static_cast<QueryPoolImpl*>(queryDescs[i].queryPool)->m_pool;
1424        m_commandBuffer->m_renderer->m_api.vkCmdResetQueryPool(
1425            m_commandBuffer->m_commandBuffer,
1426            queryPool,
1427            (uint32_t)queryDescs[i].firstQueryIndex,
1428            1);
1429        m_commandBuffer->m_renderer->m_api.vkCmdWriteAccelerationStructuresPropertiesKHR(
1430            m_commandBuffer->m_commandBuffer,
1431            accelerationStructureCount,
1432            vkHandlesView.getBuffer(),
1433            queryType,
1434            queryPool,
1435            queryDescs[i].firstQueryIndex);
1436    }
1437}
1438
1439void RayTracingCommandEncoder::buildAccelerationStructure(
1440    const IAccelerationStructure::BuildDesc& desc,
1441    GfxCount propertyQueryCount,
1442    AccelerationStructureQueryDesc* queryDescs)
1443{
1444    AccelerationStructureBuildGeometryInfoBuilder geomInfoBuilder;
1445    if (geomInfoBuilder.build(desc.inputs, getDebugCallback()) != SLANG_OK)
1446        return;
1447
1448    if (desc.dest)
1449    {
1450        geomInfoBuilder.buildInfo.dstAccelerationStructure =
1451            static_cast<AccelerationStructureImpl*>(desc.dest)->m_vkHandle;
1452    }
1453    if (desc.source)
1454    {
1455        geomInfoBuilder.buildInfo.srcAccelerationStructure =
1456            static_cast<AccelerationStructureImpl*>(desc.source)->m_vkHandle;
1457    }
1458    geomInfoBuilder.buildInfo.scratchData.deviceAddress = desc.scratchData;
1459
1460    List<VkAccelerationStructureBuildRangeInfoKHR> rangeInfos;
1461    rangeInfos.setCount(geomInfoBuilder.primitiveCounts.getCount());
1462    for (Index i = 0; i < geomInfoBuilder.primitiveCounts.getCount(); i++)
1463    {
1464        auto& rangeInfo = rangeInfos[i];
1465        rangeInfo.primitiveCount = geomInfoBuilder.primitiveCounts[i];
1466        rangeInfo.firstVertex = 0;
1467        rangeInfo.primitiveOffset = 0;
1468        rangeInfo.transformOffset = 0;
1469    }
1470
1471    auto rangeInfoPtr = rangeInfos.getBuffer();
1472    m_commandBuffer->m_renderer->m_api.vkCmdBuildAccelerationStructuresKHR(
1473        m_commandBuffer->m_commandBuffer,
1474        1,
1475        &geomInfoBuilder.buildInfo,
1476        &rangeInfoPtr);
1477
1478    if (propertyQueryCount)
1479    {
1480        _memoryBarrier(1, &desc.dest, AccessFlag::Write, AccessFlag::Read);
1481        _queryAccelerationStructureProperties(1, &desc.dest, propertyQueryCount, queryDescs);
1482    }
1483}
1484
1485void RayTracingCommandEncoder::copyAccelerationStructure(
1486    IAccelerationStructure* dest,
1487    IAccelerationStructure* src,
1488    AccelerationStructureCopyMode mode)
1489{
1490    VkCopyAccelerationStructureInfoKHR copyInfo = {
1491        VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR};
1492    copyInfo.src = static_cast<AccelerationStructureImpl*>(src)->m_vkHandle;
1493    copyInfo.dst = static_cast<AccelerationStructureImpl*>(dest)->m_vkHandle;
1494    switch (mode)
1495    {
1496    case AccelerationStructureCopyMode::Clone:
1497        copyInfo.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_KHR;
1498        break;
1499    case AccelerationStructureCopyMode::Compact:
1500        copyInfo.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_KHR;
1501        break;
1502    default:
1503        getDebugCallback()->handleMessage(
1504            DebugMessageType::Error,
1505            DebugMessageSource::Layer,
1506            "Unsupported AccelerationStructureCopyMode.");
1507        return;
1508    }
1509    m_commandBuffer->m_renderer->m_api.vkCmdCopyAccelerationStructureKHR(
1510        m_commandBuffer->m_commandBuffer,
1511        &copyInfo);
1512}
1513
1514void RayTracingCommandEncoder::queryAccelerationStructureProperties(
1515    GfxCount accelerationStructureCount,
1516    IAccelerationStructure* const* accelerationStructures,
1517    GfxCount queryCount,
1518    AccelerationStructureQueryDesc* queryDescs)
1519{
1520    _queryAccelerationStructureProperties(
1521        accelerationStructureCount,
1522        accelerationStructures,
1523        queryCount,
1524        queryDescs);
1525}
1526
1527void RayTracingCommandEncoder::serializeAccelerationStructure(
1528    DeviceAddress dest,
1529    IAccelerationStructure* source)
1530{
1531    VkCopyAccelerationStructureToMemoryInfoKHR copyInfo = {
1532        VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_TO_MEMORY_INFO_KHR};
1533    copyInfo.src = static_cast<AccelerationStructureImpl*>(source)->m_vkHandle;
1534    copyInfo.dst.deviceAddress = dest;
1535    copyInfo.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_SERIALIZE_KHR;
1536    m_commandBuffer->m_renderer->m_api.vkCmdCopyAccelerationStructureToMemoryKHR(
1537        m_commandBuffer->m_commandBuffer,
1538        &copyInfo);
1539}
1540
1541void RayTracingCommandEncoder::deserializeAccelerationStructure(
1542    IAccelerationStructure* dest,
1543    DeviceAddress source)
1544{
1545    VkCopyMemoryToAccelerationStructureInfoKHR copyInfo = {
1546        VK_STRUCTURE_TYPE_COPY_MEMORY_TO_ACCELERATION_STRUCTURE_INFO_KHR};
1547    copyInfo.src.deviceAddress = source;
1548    copyInfo.dst = static_cast<AccelerationStructureImpl*>(dest)->m_vkHandle;
1549    copyInfo.mode = VK_COPY_ACCELERATION_STRUCTURE_MODE_DESERIALIZE_KHR;
1550    m_commandBuffer->m_renderer->m_api.vkCmdCopyMemoryToAccelerationStructureKHR(
1551        m_commandBuffer->m_commandBuffer,
1552        &copyInfo);
1553}
1554
1555Result RayTracingCommandEncoder::bindPipeline(
1556    IPipelineState* pipeline,
1557    IShaderObject** outRootObject)
1558{
1559    return setPipelineStateImpl(pipeline, outRootObject);
1560}
1561
1562Result RayTracingCommandEncoder::bindPipelineWithRootObject(
1563    IPipelineState* pipelineState,
1564    IShaderObject* rootObject)
1565{
1566    return setPipelineStateWithRootObjectImpl(pipelineState, rootObject);
1567}
1568
1569Result RayTracingCommandEncoder::dispatchRays(
1570    GfxIndex raygenShaderIndex,
1571    IShaderTable* shaderTable,
1572    GfxCount width,
1573    GfxCount height,
1574    GfxCount depth)
1575{
1576    auto vkApi = m_commandBuffer->m_renderer->m_api;
1577    auto vkCommandBuffer = m_commandBuffer->m_commandBuffer;
1578
1579    SLANG_RETURN_ON_FAIL(bindRenderState(VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR));
1580
1581    auto rtProps = vkApi.m_rtProperties;
1582    auto shaderTableImpl = (ShaderTableImpl*)shaderTable;
1583    auto alignedHandleSize =
1584        VulkanUtil::calcAligned(rtProps.shaderGroupHandleSize, rtProps.shaderGroupHandleAlignment);
1585
1586    auto shaderTableBuffer = shaderTableImpl->getOrCreateBuffer(
1587        m_currentPipeline,
1588        m_commandBuffer->m_transientHeap,
1589        static_cast<ResourceCommandEncoder*>(this));
1590    auto shaderTableAddr = shaderTableBuffer->getDeviceAddress();
1591
1592    VkStridedDeviceAddressRegionKHR raygenSBT;
1593    raygenSBT.stride = VulkanUtil::calcAligned(alignedHandleSize, rtProps.shaderGroupBaseAlignment);
1594    raygenSBT.deviceAddress = shaderTableAddr + raygenShaderIndex * raygenSBT.stride;
1595    raygenSBT.size = raygenSBT.stride;
1596
1597    VkStridedDeviceAddressRegionKHR missSBT;
1598    missSBT.deviceAddress = shaderTableAddr + shaderTableImpl->m_raygenTableSize;
1599    missSBT.stride = alignedHandleSize;
1600    missSBT.size = shaderTableImpl->m_missTableSize;
1601
1602    VkStridedDeviceAddressRegionKHR hitSBT;
1603    hitSBT.deviceAddress = missSBT.deviceAddress + missSBT.size;
1604    hitSBT.stride = alignedHandleSize;
1605    hitSBT.size = shaderTableImpl->m_hitTableSize;
1606
1607    VkStridedDeviceAddressRegionKHR callableSBT;
1608    callableSBT.deviceAddress = hitSBT.deviceAddress + hitSBT.size;
1609    callableSBT.stride = alignedHandleSize;
1610    callableSBT.size = shaderTableImpl->m_callableTableSize;
1611
1612    vkApi.vkCmdTraceRaysKHR(
1613        vkCommandBuffer,
1614        &raygenSBT,
1615        &missSBT,
1616        &hitSBT,
1617        &callableSBT,
1618        (uint32_t)width,
1619        (uint32_t)height,
1620        (uint32_t)depth);
1621
1622    return SLANG_OK;
1623}
1624
1625void RayTracingCommandEncoder::endEncoding()
1626{
1627    endEncodingImpl();
1628}
1629
1630} // namespace vk
1631} // namespace gfx