yum-mirror/slang

Making it easier to work with shaders

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

Ellie Hermaszewskaformatf65d756bf

master
5.2 KiB178 linesraw
1// vk-command-buffer.cpp
2#include "vk-command-buffer.h"
3
4#include "vk-device.h"
5#include "vk-shader-object.h"
6#include "vk-util.h"
7
8namespace gfx
9{
10
11using namespace Slang;
12
13namespace vk
14{
15
16// There are a pair of cyclic references between a `TransientResourceHeap` and
17// a `CommandBuffer` created from the heap. We need to break the cycle when
18// the public reference count of a command buffer drops to 0.
19
20ICommandBuffer* CommandBufferImpl::getInterface(const Guid& guid)
21{
22    if (guid == GfxGUID::IID_ISlangUnknown || guid == GfxGUID::IID_ICommandBuffer)
23        return static_cast<ICommandBuffer*>(this);
24    return nullptr;
25}
26
27void CommandBufferImpl::comFree()
28{
29    m_transientHeap.breakStrongReference();
30}
31
32Result CommandBufferImpl::init(
33    DeviceImpl* renderer,
34    VkCommandPool pool,
35    TransientResourceHeapImpl* transientHeap)
36{
37    m_renderer = renderer;
38    m_transientHeap = transientHeap;
39    m_pool = pool;
40
41    auto& api = renderer->m_api;
42    VkCommandBufferAllocateInfo allocInfo = {};
43    allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
44    allocInfo.commandPool = pool;
45    allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
46    allocInfo.commandBufferCount = 1;
47    SLANG_VK_RETURN_ON_FAIL(
48        api.vkAllocateCommandBuffers(api.m_device, &allocInfo, &m_commandBuffer));
49
50    beginCommandBuffer();
51    return SLANG_OK;
52}
53
54void CommandBufferImpl::beginCommandBuffer()
55{
56    auto& api = m_renderer->m_api;
57    VkCommandBufferBeginInfo beginInfo = {
58        VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
59        nullptr,
60        VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT};
61    api.vkBeginCommandBuffer(m_commandBuffer, &beginInfo);
62    if (m_preCommandBuffer)
63    {
64        api.vkBeginCommandBuffer(m_preCommandBuffer, &beginInfo);
65    }
66    m_isPreCommandBufferEmpty = true;
67}
68
69Result CommandBufferImpl::createPreCommandBuffer()
70{
71    VkCommandBufferAllocateInfo allocInfo = {};
72    allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
73    allocInfo.commandPool = m_pool;
74    allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
75    allocInfo.commandBufferCount = 1;
76    auto& api = m_renderer->m_api;
77    SLANG_VK_RETURN_ON_FAIL(
78        api.vkAllocateCommandBuffers(api.m_device, &allocInfo, &m_preCommandBuffer));
79    VkCommandBufferBeginInfo beginInfo = {
80        VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
81        nullptr,
82        VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT};
83    api.vkBeginCommandBuffer(m_preCommandBuffer, &beginInfo);
84    return SLANG_OK;
85}
86
87VkCommandBuffer CommandBufferImpl::getPreCommandBuffer()
88{
89    m_isPreCommandBufferEmpty = false;
90    if (m_preCommandBuffer)
91        return m_preCommandBuffer;
92    createPreCommandBuffer();
93    return m_preCommandBuffer;
94}
95
96void CommandBufferImpl::encodeRenderCommands(
97    IRenderPassLayout* renderPass,
98    IFramebuffer* framebuffer,
99    IRenderCommandEncoder** outEncoder)
100{
101    if (!m_renderCommandEncoder)
102    {
103        m_renderCommandEncoder = new RenderCommandEncoder();
104        m_renderCommandEncoder->init(this);
105    }
106    m_renderCommandEncoder->beginPass(renderPass, framebuffer);
107    *outEncoder = m_renderCommandEncoder.Ptr();
108}
109
110void CommandBufferImpl::encodeComputeCommands(IComputeCommandEncoder** outEncoder)
111{
112    if (!m_computeCommandEncoder)
113    {
114        m_computeCommandEncoder = new ComputeCommandEncoder();
115        m_computeCommandEncoder->init(this);
116    }
117    *outEncoder = m_computeCommandEncoder.Ptr();
118}
119
120void CommandBufferImpl::encodeResourceCommands(IResourceCommandEncoder** outEncoder)
121{
122    if (!m_resourceCommandEncoder)
123    {
124        m_resourceCommandEncoder = new ResourceCommandEncoder();
125        m_resourceCommandEncoder->init(this);
126    }
127    *outEncoder = m_resourceCommandEncoder.Ptr();
128}
129
130void CommandBufferImpl::encodeRayTracingCommands(IRayTracingCommandEncoder** outEncoder)
131{
132    if (!m_rayTracingCommandEncoder)
133    {
134        if (m_renderer->m_api.vkCmdBuildAccelerationStructuresKHR)
135        {
136            m_rayTracingCommandEncoder = new RayTracingCommandEncoder();
137            m_rayTracingCommandEncoder->init(this);
138        }
139    }
140    *outEncoder = m_rayTracingCommandEncoder.Ptr();
141}
142
143void CommandBufferImpl::close()
144{
145    auto& vkAPI = m_renderer->m_api;
146    if (!m_isPreCommandBufferEmpty)
147    {
148        // `preCmdBuffer` contains buffer transfer commands for shader object
149        // uniform buffers, and we need a memory barrier here to ensure the
150        // transfers are visible to shaders.
151        VkMemoryBarrier memBarrier = {VK_STRUCTURE_TYPE_MEMORY_BARRIER};
152        memBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
153        memBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
154        vkAPI.vkCmdPipelineBarrier(
155            m_preCommandBuffer,
156            VK_PIPELINE_STAGE_TRANSFER_BIT,
157            VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
158            0,
159            1,
160            &memBarrier,
161            0,
162            nullptr,
163            0,
164            nullptr);
165        vkAPI.vkEndCommandBuffer(m_preCommandBuffer);
166    }
167    vkAPI.vkEndCommandBuffer(m_commandBuffer);
168}
169
170Result CommandBufferImpl::getNativeHandle(InteropHandle* outHandle)
171{
172    outHandle->api = InteropHandleAPI::Vulkan;
173    outHandle->handleValue = (uint64_t)m_commandBuffer;
174    return SLANG_OK;
175}
176
177} // namespace vk
178} // namespace gfx