Line data Source code
1 : /* Copyright (C) 2023 Wildfire Games.
2 : * This file is part of 0 A.D.
3 : *
4 : * 0 A.D. is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * 0 A.D. is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include "precompiled.h"
19 :
20 : #include "DeviceCommandContext.h"
21 :
22 : #include "maths/MathUtil.h"
23 : #include "ps/CLogger.h"
24 : #include "ps/containers/Span.h"
25 : #include "ps/containers/StaticVector.h"
26 : #include "renderer/backend/vulkan/Buffer.h"
27 : #include "renderer/backend/vulkan/DescriptorManager.h"
28 : #include "renderer/backend/vulkan/Device.h"
29 : #include "renderer/backend/vulkan/Framebuffer.h"
30 : #include "renderer/backend/vulkan/PipelineState.h"
31 : #include "renderer/backend/vulkan/RingCommandContext.h"
32 : #include "renderer/backend/vulkan/ShaderProgram.h"
33 : #include "renderer/backend/vulkan/Texture.h"
34 : #include "renderer/backend/vulkan/Utilities.h"
35 :
36 : #include <algorithm>
37 :
38 : namespace Renderer
39 : {
40 :
41 : namespace Backend
42 : {
43 :
44 : namespace Vulkan
45 : {
46 :
47 : namespace
48 : {
49 :
50 : constexpr uint32_t UNIFORM_BUFFER_SIZE = 8 * 1024 * 1024;
51 : constexpr uint32_t FRAME_INPLACE_BUFFER_SIZE = 1024 * 1024;
52 :
53 : struct SBaseImageState
54 : {
55 : VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
56 : VkAccessFlags accessMask = 0;
57 : VkPipelineStageFlags stageMask = 0;
58 : };
59 :
60 0 : SBaseImageState GetBaseImageState(CTexture* texture)
61 : {
62 0 : if (texture->GetUsage() & ITexture::Usage::SAMPLED)
63 : {
64 : return {
65 : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
66 : VK_ACCESS_SHADER_READ_BIT,
67 0 : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT};
68 : }
69 0 : else if (texture->GetUsage() & ITexture::Usage::COLOR_ATTACHMENT)
70 : {
71 : return {
72 : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
73 : VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
74 0 : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
75 : }
76 0 : else if (texture->GetUsage() & ITexture::Usage::DEPTH_STENCIL_ATTACHMENT)
77 : {
78 : return {
79 : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
80 : VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
81 0 : VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT};
82 : }
83 0 : return {};
84 : }
85 :
86 : class ScopedImageLayoutTransition
87 : {
88 : public:
89 0 : ScopedImageLayoutTransition(
90 : CRingCommandContext& commandContext, const PS::span<CTexture* const> textures,
91 : const VkImageLayout layout, const VkAccessFlags accessMask, const VkPipelineStageFlags stageMask)
92 0 : : m_CommandContext(commandContext), m_Textures(textures), m_Layout(layout),
93 0 : m_AccessMask(accessMask), m_StageMask(stageMask)
94 : {
95 0 : for (CTexture* const texture : m_Textures)
96 : {
97 0 : const auto state = GetBaseImageState(texture);
98 :
99 0 : VkImageLayout oldLayout = state.layout;
100 0 : if (!texture->IsInitialized())
101 0 : oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
102 :
103 0 : Utilities::SetTextureLayout(
104 0 : m_CommandContext.GetCommandBuffer(), texture,
105 0 : oldLayout, m_Layout,
106 0 : state.accessMask, m_AccessMask, state.stageMask, m_StageMask);
107 : }
108 0 : }
109 :
110 0 : ~ScopedImageLayoutTransition()
111 0 : {
112 0 : for (CTexture* const texture : m_Textures)
113 : {
114 0 : const auto state = GetBaseImageState(texture);
115 :
116 0 : Utilities::SetTextureLayout(
117 0 : m_CommandContext.GetCommandBuffer(), texture,
118 0 : m_Layout, state.layout,
119 0 : m_AccessMask, state.accessMask, m_StageMask, state.stageMask);
120 : }
121 0 : }
122 :
123 : private:
124 : CRingCommandContext& m_CommandContext;
125 : const PS::span<CTexture* const> m_Textures;
126 : const VkImageLayout m_Layout = VK_IMAGE_LAYOUT_UNDEFINED;
127 : const VkAccessFlags m_AccessMask = 0;
128 : const VkPipelineStageFlags m_StageMask = 0;
129 : };
130 :
131 : } // anonymous namespace
132 :
133 : // static
134 0 : std::unique_ptr<IDeviceCommandContext> CDeviceCommandContext::Create(CDevice* device)
135 : {
136 0 : std::unique_ptr<CDeviceCommandContext> deviceCommandContext(new CDeviceCommandContext());
137 0 : deviceCommandContext->m_Device = device;
138 0 : deviceCommandContext->m_DebugScopedLabels = device->GetCapabilities().debugScopedLabels;
139 0 : deviceCommandContext->m_PrependCommandContext =
140 0 : device->CreateRingCommandContext(NUMBER_OF_FRAMES_IN_FLIGHT);
141 0 : deviceCommandContext->m_CommandContext =
142 0 : device->CreateRingCommandContext(NUMBER_OF_FRAMES_IN_FLIGHT);
143 :
144 0 : deviceCommandContext->m_InPlaceVertexBuffer = device->CreateCBuffer(
145 0 : "InPlaceVertexBuffer", IBuffer::Type::VERTEX, FRAME_INPLACE_BUFFER_SIZE, true);
146 0 : deviceCommandContext->m_InPlaceIndexBuffer = device->CreateCBuffer(
147 0 : "InPlaceIndexBuffer", IBuffer::Type::INDEX, FRAME_INPLACE_BUFFER_SIZE, true);
148 :
149 0 : deviceCommandContext->m_InPlaceVertexStagingBuffer = device->CreateCBuffer(
150 0 : "InPlaceVertexStagingBuffer", IBuffer::Type::UPLOAD, NUMBER_OF_FRAMES_IN_FLIGHT * FRAME_INPLACE_BUFFER_SIZE, true);
151 0 : deviceCommandContext->m_InPlaceIndexStagingBuffer = device->CreateCBuffer(
152 0 : "InPlaceIndexStagingBuffer", IBuffer::Type::UPLOAD, NUMBER_OF_FRAMES_IN_FLIGHT * FRAME_INPLACE_BUFFER_SIZE, true);
153 :
154 0 : deviceCommandContext->m_UniformBuffer = device->CreateCBuffer(
155 0 : "UniformBuffer", IBuffer::Type::UNIFORM, UNIFORM_BUFFER_SIZE, true);
156 0 : deviceCommandContext->m_UniformStagingBuffer = device->CreateCBuffer(
157 0 : "UniformStagingBuffer", IBuffer::Type::UPLOAD, NUMBER_OF_FRAMES_IN_FLIGHT * UNIFORM_BUFFER_SIZE, true);
158 :
159 0 : deviceCommandContext->m_InPlaceVertexStagingBufferMappedData =
160 0 : deviceCommandContext->m_InPlaceVertexStagingBuffer->GetMappedData();
161 0 : ENSURE(deviceCommandContext->m_InPlaceVertexStagingBufferMappedData);
162 0 : deviceCommandContext->m_InPlaceIndexStagingBufferMappedData =
163 0 : deviceCommandContext->m_InPlaceIndexStagingBuffer->GetMappedData();
164 0 : ENSURE(deviceCommandContext->m_InPlaceIndexStagingBufferMappedData);
165 0 : deviceCommandContext->m_UniformStagingBufferMappedData =
166 0 : deviceCommandContext->m_UniformStagingBuffer->GetMappedData();
167 0 : ENSURE(deviceCommandContext->m_UniformStagingBufferMappedData);
168 :
169 : // TODO: reduce the code duplication.
170 0 : VkDescriptorPoolSize descriptorPoolSize{};
171 0 : descriptorPoolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
172 0 : descriptorPoolSize.descriptorCount = 1;
173 :
174 0 : VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{};
175 0 : descriptorPoolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
176 0 : descriptorPoolCreateInfo.poolSizeCount = 1;
177 0 : descriptorPoolCreateInfo.pPoolSizes = &descriptorPoolSize;
178 0 : descriptorPoolCreateInfo.maxSets = 1;
179 0 : ENSURE_VK_SUCCESS(vkCreateDescriptorPool(
180 : device->GetVkDevice(), &descriptorPoolCreateInfo, nullptr, &deviceCommandContext->m_UniformDescriptorPool));
181 :
182 0 : VkDescriptorSetAllocateInfo descriptorSetAllocateInfo{};
183 0 : descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
184 0 : descriptorSetAllocateInfo.descriptorPool = deviceCommandContext->m_UniformDescriptorPool;
185 0 : descriptorSetAllocateInfo.descriptorSetCount = 1;
186 0 : descriptorSetAllocateInfo.pSetLayouts = &device->GetDescriptorManager().GetUniformDescriptorSetLayout();
187 :
188 0 : ENSURE_VK_SUCCESS(vkAllocateDescriptorSets(
189 : device->GetVkDevice(), &descriptorSetAllocateInfo, &deviceCommandContext->m_UniformDescriptorSet));
190 :
191 : // TODO: fix the hard-coded size.
192 0 : const VkDescriptorBufferInfo descriptorBufferInfos[1] =
193 : {
194 0 : {deviceCommandContext->m_UniformBuffer->GetVkBuffer(), 0u, 512u}
195 0 : };
196 :
197 0 : VkWriteDescriptorSet writeDescriptorSet{};
198 0 : writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
199 0 : writeDescriptorSet.dstSet = deviceCommandContext->m_UniformDescriptorSet;
200 0 : writeDescriptorSet.dstBinding = 0;
201 0 : writeDescriptorSet.dstArrayElement = 0;
202 0 : writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
203 0 : writeDescriptorSet.descriptorCount = 1;
204 0 : writeDescriptorSet.pBufferInfo = descriptorBufferInfos;
205 :
206 0 : vkUpdateDescriptorSets(
207 : device->GetVkDevice(), 1, &writeDescriptorSet, 0, nullptr);
208 :
209 0 : return deviceCommandContext;
210 : }
211 :
212 : CDeviceCommandContext::CDeviceCommandContext() = default;
213 :
214 0 : CDeviceCommandContext::~CDeviceCommandContext()
215 : {
216 0 : VkDevice device = m_Device->GetVkDevice();
217 :
218 0 : vkDeviceWaitIdle(device);
219 :
220 0 : if (m_UniformDescriptorPool != VK_NULL_HANDLE)
221 0 : vkDestroyDescriptorPool(device, m_UniformDescriptorPool, nullptr);
222 0 : }
223 :
224 0 : IDevice* CDeviceCommandContext::GetDevice()
225 : {
226 0 : return m_Device;
227 : }
228 :
229 0 : void CDeviceCommandContext::SetGraphicsPipelineState(
230 : IGraphicsPipelineState* pipelineState)
231 : {
232 0 : ENSURE(pipelineState);
233 0 : m_GraphicsPipelineState = pipelineState->As<CGraphicsPipelineState>();
234 :
235 0 : CShaderProgram* shaderProgram = m_GraphicsPipelineState->GetShaderProgram()->As<CShaderProgram>();
236 0 : if (m_ShaderProgram != shaderProgram)
237 : {
238 0 : if (m_ShaderProgram)
239 0 : m_ShaderProgram->Unbind();
240 0 : m_ShaderProgram = shaderProgram;
241 : }
242 0 : m_IsPipelineStateDirty = true;
243 0 : }
244 :
245 0 : void CDeviceCommandContext::BlitFramebuffer(IFramebuffer* destinationFramebuffer, IFramebuffer* sourceFramebuffer)
246 : {
247 0 : ENSURE(!m_InsideFramebufferPass);
248 : const auto& sourceColorAttachments =
249 0 : sourceFramebuffer->As<CFramebuffer>()->GetColorAttachments();
250 : const auto& destinationColorAttachments =
251 0 : destinationFramebuffer->As<CFramebuffer>()->GetColorAttachments();
252 0 : ENSURE(sourceColorAttachments.size() == destinationColorAttachments.size());
253 : // TODO: account depth.
254 : //ENSURE(
255 : // static_cast<bool>(sourceFramebuffer->As<CFramebuffer>()->GetDepthStencilAttachment()) ==
256 : // static_cast<bool>(destinationFramebuffer->As<CFramebuffer>()->GetDepthStencilAttachment()));
257 :
258 0 : for (CTexture* sourceColorAttachment : sourceColorAttachments)
259 : {
260 0 : ENSURE(sourceColorAttachment->GetUsage() & ITexture::Usage::TRANSFER_SRC);
261 : }
262 0 : for (CTexture* destinationColorAttachment : destinationColorAttachments)
263 : {
264 0 : ENSURE(destinationColorAttachment->GetUsage() & ITexture::Usage::TRANSFER_DST);
265 : }
266 :
267 : // TODO: combine barriers, reduce duplication, add depth.
268 : ScopedImageLayoutTransition scopedColorAttachmentsTransition{
269 0 : *m_CommandContext,
270 : {sourceColorAttachments.begin(), sourceColorAttachments.end()},
271 : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
272 : VK_ACCESS_TRANSFER_READ_BIT,
273 0 : VK_PIPELINE_STAGE_TRANSFER_BIT};
274 : ScopedImageLayoutTransition destinationColorAttachmentsTransition{
275 0 : *m_CommandContext,
276 : {destinationColorAttachments.begin(), destinationColorAttachments.end()},
277 : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
278 : VK_ACCESS_TRANSFER_WRITE_BIT,
279 0 : VK_PIPELINE_STAGE_TRANSFER_BIT};
280 :
281 : // TODO: split BlitFramebuffer into ResolveFramebuffer and BlitFramebuffer.
282 0 : if (sourceFramebuffer->As<CFramebuffer>()->GetSampleCount() == 1)
283 : {
284 : // TODO: we need to check for VK_FORMAT_FEATURE_BLIT_*_BIT for used formats.
285 0 : for (CFramebuffer::ColorAttachments::size_type index = 0; index < destinationColorAttachments.size(); ++index)
286 : {
287 0 : CTexture* sourceColorAttachment = sourceColorAttachments[index];
288 0 : CTexture* destinationColorAttachment = destinationColorAttachments[index];
289 :
290 0 : VkImageBlit region{};
291 0 : region.srcOffsets[1].x = sourceColorAttachment->GetWidth();
292 0 : region.srcOffsets[1].y = sourceColorAttachment->GetHeight();
293 0 : region.srcOffsets[1].z = 1;
294 0 : region.dstOffsets[1].x = destinationColorAttachment->GetWidth();
295 0 : region.dstOffsets[1].y = destinationColorAttachment->GetHeight();
296 0 : region.dstOffsets[1].z = 1;
297 0 : region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
298 0 : region.srcSubresource.mipLevel = 0;
299 0 : region.srcSubresource.baseArrayLayer = 0;
300 0 : region.srcSubresource.layerCount = 1;
301 0 : region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
302 0 : region.dstSubresource.mipLevel = 0;
303 0 : region.dstSubresource.baseArrayLayer = 0;
304 0 : region.dstSubresource.layerCount = 1;
305 :
306 0 : ENSURE(sourceColorAttachment->GetImage() != VK_NULL_HANDLE);
307 0 : ENSURE(destinationColorAttachment->GetImage() != VK_NULL_HANDLE);
308 0 : vkCmdBlitImage(
309 : m_CommandContext->GetCommandBuffer(),
310 : sourceColorAttachment->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
311 : destinationColorAttachment->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
312 : 1, ®ion, VK_FILTER_NEAREST);
313 : }
314 : }
315 : else
316 : {
317 0 : ENSURE(sourceFramebuffer->As<CFramebuffer>()->GetSampleCount() > 1);
318 0 : ENSURE(destinationFramebuffer->As<CFramebuffer>()->GetSampleCount() == 1);
319 0 : ENSURE(sourceFramebuffer->As<CFramebuffer>()->GetWidth() == destinationFramebuffer->As<CFramebuffer>()->GetWidth());
320 0 : ENSURE(sourceFramebuffer->As<CFramebuffer>()->GetHeight() == destinationFramebuffer->As<CFramebuffer>()->GetHeight());
321 0 : for (CFramebuffer::ColorAttachments::size_type index = 0; index < destinationColorAttachments.size(); ++index)
322 : {
323 0 : CTexture* sourceColorAttachment = sourceColorAttachments[index];
324 0 : CTexture* destinationColorAttachment = destinationColorAttachments[index];
325 :
326 0 : VkImageResolve region{};
327 0 : region.extent.width = sourceColorAttachment->GetWidth();
328 0 : region.extent.height = sourceColorAttachment->GetHeight();
329 0 : region.extent.depth = 1;
330 0 : region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
331 0 : region.srcSubresource.mipLevel = 0;
332 0 : region.srcSubresource.baseArrayLayer = 0;
333 0 : region.srcSubresource.layerCount = 1;
334 0 : region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
335 0 : region.dstSubresource.mipLevel = 0;
336 0 : region.dstSubresource.baseArrayLayer = 0;
337 0 : region.dstSubresource.layerCount = 1;
338 :
339 0 : vkCmdResolveImage(
340 : m_CommandContext->GetCommandBuffer(),
341 : sourceColorAttachment->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
342 : destinationColorAttachment->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
343 : 1, ®ion);
344 : }
345 : }
346 0 : }
347 :
348 0 : void CDeviceCommandContext::ClearFramebuffer(const bool color, const bool depth, const bool stencil)
349 : {
350 0 : ENSURE(m_InsideFramebufferPass);
351 0 : ENSURE(m_Framebuffer);
352 0 : PS::StaticVector<VkClearAttachment, 4> clearAttachments;
353 0 : if (color)
354 : {
355 0 : ENSURE(!m_Framebuffer->GetColorAttachments().empty());
356 0 : for (size_t index = 0; index < m_Framebuffer->GetColorAttachments().size(); ++index)
357 : {
358 0 : VkClearAttachment clearAttachment{};
359 0 : clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
360 0 : const CColor& clearColor = m_Framebuffer->GetClearColor();
361 0 : clearAttachment.clearValue.color.float32[0] = clearColor.r;
362 0 : clearAttachment.clearValue.color.float32[1] = clearColor.g;
363 0 : clearAttachment.clearValue.color.float32[2] = clearColor.b;
364 0 : clearAttachment.clearValue.color.float32[3] = clearColor.a;
365 0 : clearAttachment.colorAttachment = index;
366 0 : clearAttachments.emplace_back(std::move(clearAttachment));
367 : }
368 : }
369 0 : if (depth || stencil)
370 : {
371 0 : ENSURE(m_Framebuffer->GetDepthStencilAttachment());
372 0 : if (stencil)
373 : {
374 : const Format depthStencilFormat =
375 0 : m_Framebuffer->GetDepthStencilAttachment()->GetFormat();
376 0 : ENSURE(depthStencilFormat == Format::D24_UNORM_S8_UINT ||
377 : depthStencilFormat == Format::D32_SFLOAT_S8_UINT);
378 : }
379 0 : VkClearAttachment clearAttachment{};
380 0 : if (depth)
381 0 : clearAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
382 0 : if (stencil)
383 0 : clearAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
384 0 : clearAttachment.clearValue.depthStencil.depth = 1.0f;
385 0 : clearAttachment.clearValue.depthStencil.stencil = 0;
386 0 : clearAttachments.emplace_back(std::move(clearAttachment));
387 : }
388 0 : VkClearRect clearRect{};
389 0 : clearRect.layerCount = 1;
390 0 : clearRect.rect.offset.x = 0;
391 0 : clearRect.rect.offset.y = 0;
392 0 : clearRect.rect.extent.width = m_Framebuffer->GetWidth();
393 0 : clearRect.rect.extent.height = m_Framebuffer->GetHeight();
394 0 : vkCmdClearAttachments(
395 : m_CommandContext->GetCommandBuffer(),
396 0 : clearAttachments.size(), clearAttachments.data(),
397 : 1, &clearRect);
398 0 : }
399 :
400 0 : void CDeviceCommandContext::BeginFramebufferPass(IFramebuffer* framebuffer)
401 : {
402 0 : ENSURE(framebuffer);
403 0 : m_IsPipelineStateDirty = true;
404 0 : m_Framebuffer = framebuffer->As<CFramebuffer>();
405 0 : m_GraphicsPipelineState = nullptr;
406 0 : m_VertexInputLayout = nullptr;
407 :
408 0 : SetScissors(0, nullptr);
409 :
410 0 : for (CTexture* colorAttachment : m_Framebuffer->GetColorAttachments())
411 : {
412 0 : if (!(colorAttachment->GetUsage() & ITexture::Usage::SAMPLED) && colorAttachment->IsInitialized())
413 0 : continue;
414 0 : VkImageLayout oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
415 0 : if (!colorAttachment->IsInitialized())
416 0 : oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
417 0 : Utilities::SetTextureLayout(
418 : m_CommandContext->GetCommandBuffer(), colorAttachment,
419 : oldLayout,
420 : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
421 : VK_ACCESS_SHADER_READ_BIT,
422 : VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
423 : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
424 : }
425 :
426 0 : CTexture* depthStencilAttachment = m_Framebuffer->GetDepthStencilAttachment();
427 0 : if (depthStencilAttachment && ((depthStencilAttachment->GetUsage() & ITexture::Usage::SAMPLED) || !depthStencilAttachment->IsInitialized()))
428 : {
429 0 : VkImageLayout oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
430 0 : if (!depthStencilAttachment->IsInitialized())
431 0 : oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
432 0 : Utilities::SetTextureLayout(
433 : m_CommandContext->GetCommandBuffer(), depthStencilAttachment, oldLayout,
434 : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
435 : VK_ACCESS_SHADER_READ_BIT,
436 : VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
437 : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
438 : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
439 : }
440 :
441 0 : m_InsideFramebufferPass = true;
442 :
443 0 : VkRenderPassBeginInfo renderPassBeginInfo{};
444 0 : renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
445 0 : renderPassBeginInfo.renderPass = m_Framebuffer->GetRenderPass();
446 0 : renderPassBeginInfo.framebuffer = m_Framebuffer->GetFramebuffer();
447 0 : renderPassBeginInfo.renderArea.offset = { 0, 0 };
448 0 : renderPassBeginInfo.renderArea.extent = { m_Framebuffer->GetWidth(), m_Framebuffer->GetHeight() };
449 :
450 0 : PS::StaticVector<VkClearValue, 4> clearValues;
451 : const bool needsClearValues =
452 0 : m_Framebuffer->GetColorAttachmentLoadOp() == AttachmentLoadOp::CLEAR ||
453 0 : (m_Framebuffer->GetDepthStencilAttachment() &&
454 0 : m_Framebuffer->GetDepthStencilAttachmentLoadOp() == AttachmentLoadOp::CLEAR);
455 0 : if (needsClearValues)
456 : {
457 0 : for (CTexture* colorAttachment : m_Framebuffer->GetColorAttachments())
458 : {
459 : UNUSED2(colorAttachment);
460 0 : const CColor& clearColor = m_Framebuffer->GetClearColor();
461 : // The four array elements of the clear color map to R, G, B, and A
462 : // components of image formats, in order.
463 0 : clearValues.emplace_back();
464 0 : clearValues.back().color.float32[0] = clearColor.r;
465 0 : clearValues.back().color.float32[1] = clearColor.g;
466 0 : clearValues.back().color.float32[2] = clearColor.b;
467 0 : clearValues.back().color.float32[3] = clearColor.a;
468 : }
469 0 : if (m_Framebuffer->GetDepthStencilAttachment())
470 : {
471 0 : clearValues.emplace_back();
472 0 : clearValues.back().depthStencil.depth = 1.0f;
473 0 : clearValues.back().depthStencil.stencil = 0;
474 : }
475 0 : renderPassBeginInfo.clearValueCount = clearValues.size();
476 0 : renderPassBeginInfo.pClearValues = clearValues.data();
477 : }
478 :
479 0 : vkCmdBeginRenderPass(m_CommandContext->GetCommandBuffer(), &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
480 0 : }
481 :
482 0 : void CDeviceCommandContext::EndFramebufferPass()
483 : {
484 0 : ENSURE(m_InsideFramebufferPass);
485 0 : vkCmdEndRenderPass(m_CommandContext->GetCommandBuffer());
486 :
487 0 : m_InsideFramebufferPass = false;
488 0 : m_BoundIndexBuffer = nullptr;
489 :
490 0 : ENSURE(m_Framebuffer);
491 0 : for (CTexture* colorAttachment : m_Framebuffer->GetColorAttachments())
492 : {
493 0 : if (!(colorAttachment->GetUsage() & ITexture::Usage::SAMPLED))
494 0 : continue;
495 0 : Utilities::SetTextureLayout(
496 : m_CommandContext->GetCommandBuffer(), colorAttachment,
497 : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
498 : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
499 : VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
500 : VK_ACCESS_SHADER_READ_BIT,
501 : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
502 : }
503 :
504 0 : CTexture* depthStencilAttachment = m_Framebuffer->GetDepthStencilAttachment();
505 0 : if (depthStencilAttachment && (depthStencilAttachment->GetUsage() & ITexture::Usage::SAMPLED))
506 : {
507 0 : Utilities::SetTextureLayout(
508 : m_CommandContext->GetCommandBuffer(), depthStencilAttachment,
509 : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
510 : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
511 : VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
512 : VK_ACCESS_SHADER_READ_BIT,
513 : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
514 : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
515 : }
516 :
517 0 : m_LastBoundPipeline = VK_NULL_HANDLE;
518 0 : if (m_ShaderProgram)
519 0 : m_ShaderProgram->Unbind();
520 0 : m_ShaderProgram = nullptr;
521 0 : }
522 :
523 0 : void CDeviceCommandContext::ReadbackFramebufferSync(
524 : const uint32_t x, const uint32_t y, const uint32_t width, const uint32_t height,
525 : void* data)
526 : {
527 : UNUSED2(x);
528 : UNUSED2(y);
529 : UNUSED2(width);
530 : UNUSED2(height);
531 : UNUSED2(data);
532 0 : LOGERROR("Vulkan: framebuffer readback is not implemented yet.");
533 0 : }
534 :
535 0 : void CDeviceCommandContext::UploadTexture(ITexture* texture, const Format dataFormat,
536 : const void* data, const size_t dataSize,
537 : const uint32_t level, const uint32_t layer)
538 : {
539 0 : (m_InsideFramebufferPass ? m_PrependCommandContext : m_CommandContext)->ScheduleUpload(
540 : texture->As<CTexture>(), dataFormat, data, dataSize, level, layer);
541 0 : }
542 :
543 0 : void CDeviceCommandContext::UploadTextureRegion(ITexture* texture, const Format dataFormat,
544 : const void* data, const size_t dataSize,
545 : const uint32_t xOffset, const uint32_t yOffset,
546 : const uint32_t width, const uint32_t height,
547 : const uint32_t level, const uint32_t layer)
548 : {
549 0 : (m_InsideFramebufferPass ? m_PrependCommandContext : m_CommandContext)->ScheduleUpload(
550 : texture->As<CTexture>(), dataFormat, data, dataSize, xOffset, yOffset, width, height, level, layer);
551 0 : }
552 :
553 0 : void CDeviceCommandContext::UploadBuffer(IBuffer* buffer, const void* data, const uint32_t dataSize)
554 : {
555 0 : ENSURE(!m_InsideFramebufferPass);
556 0 : m_CommandContext->ScheduleUpload(
557 : buffer->As<CBuffer>(), data, 0, dataSize);
558 0 : }
559 :
560 0 : void CDeviceCommandContext::UploadBuffer(IBuffer* buffer, const UploadBufferFunction& uploadFunction)
561 : {
562 0 : ENSURE(!m_InsideFramebufferPass);
563 0 : m_CommandContext->ScheduleUpload(
564 : buffer->As<CBuffer>(), 0, buffer->As<CBuffer>()->GetSize(), uploadFunction);
565 0 : }
566 :
567 0 : void CDeviceCommandContext::UploadBufferRegion(
568 : IBuffer* buffer, const void* data, const uint32_t dataOffset, const uint32_t dataSize)
569 : {
570 0 : ENSURE(!m_InsideFramebufferPass);
571 0 : m_CommandContext->ScheduleUpload(
572 : buffer->As<CBuffer>(), data, dataOffset, dataSize);
573 0 : }
574 :
575 0 : void CDeviceCommandContext::UploadBufferRegion(
576 : IBuffer* buffer, const uint32_t dataOffset, const uint32_t dataSize,
577 : const UploadBufferFunction& uploadFunction)
578 : {
579 0 : m_CommandContext->ScheduleUpload(
580 : buffer->As<CBuffer>(), dataOffset, dataSize, uploadFunction);
581 0 : }
582 :
583 0 : void CDeviceCommandContext::SetScissors(const uint32_t scissorCount, const Rect* scissors)
584 : {
585 0 : ENSURE(m_Framebuffer);
586 0 : ENSURE(scissorCount <= 1);
587 0 : VkRect2D scissor{};
588 0 : if (scissorCount == 1)
589 : {
590 : // the x and y members of offset member of any element of pScissors must be
591 : // greater than or equal to 0.
592 0 : int32_t x = scissors[0].x;
593 0 : int32_t y = m_Framebuffer->GetHeight() - scissors[0].y - scissors[0].height;
594 0 : int32_t width = scissors[0].width;
595 0 : int32_t height = scissors[0].height;
596 0 : if (x < 0)
597 : {
598 0 : width = std::max(0, width + x);
599 0 : x = 0;
600 : }
601 0 : if (y < 0)
602 : {
603 0 : height = std::max(0, height + y);
604 0 : y = 0;
605 : }
606 0 : scissor.offset.x = x;
607 0 : scissor.offset.y = y;
608 0 : scissor.extent.width = width;
609 0 : scissor.extent.height = height;
610 : }
611 : else
612 : {
613 0 : scissor.extent.width = m_Framebuffer->GetWidth();
614 0 : scissor.extent.height = m_Framebuffer->GetHeight();
615 : }
616 0 : vkCmdSetScissor(m_CommandContext->GetCommandBuffer(), 0, 1, &scissor);
617 0 : }
618 :
619 0 : void CDeviceCommandContext::SetViewports(const uint32_t viewportCount, const Rect* viewports)
620 : {
621 0 : ENSURE(m_Framebuffer);
622 0 : ENSURE(viewportCount == 1);
623 :
624 0 : VkViewport viewport{};
625 0 : viewport.minDepth = 0.0f;
626 0 : viewport.maxDepth = 1.0f;
627 0 : viewport.x = static_cast<float>(viewports[0].x);
628 0 : viewport.y = static_cast<float>(static_cast<int32_t>(m_Framebuffer->GetHeight()) - viewports[0].y - viewports[0].height);
629 0 : viewport.width = static_cast<float>(viewports[0].width);
630 0 : viewport.height = static_cast<float>(viewports[0].height);
631 :
632 0 : vkCmdSetViewport(m_CommandContext->GetCommandBuffer(), 0, 1, &viewport);
633 0 : }
634 :
635 0 : void CDeviceCommandContext::SetVertexInputLayout(
636 : IVertexInputLayout* vertexInputLayout)
637 : {
638 0 : ENSURE(vertexInputLayout);
639 0 : m_IsPipelineStateDirty = true;
640 0 : m_VertexInputLayout = vertexInputLayout->As<CVertexInputLayout>();
641 0 : }
642 :
643 0 : void CDeviceCommandContext::SetVertexBuffer(
644 : const uint32_t bindingSlot, IBuffer* buffer, const uint32_t offset)
645 : {
646 0 : BindVertexBuffer(bindingSlot, buffer->As<CBuffer>(), offset);
647 0 : }
648 :
649 0 : void CDeviceCommandContext::SetVertexBufferData(
650 : const uint32_t bindingSlot, const void* data, const uint32_t dataSize)
651 : {
652 : // TODO: check vertex buffer alignment.
653 0 : const uint32_t ALIGNMENT = 32;
654 :
655 0 : uint32_t destination = m_InPlaceBlockIndex * FRAME_INPLACE_BUFFER_SIZE + m_InPlaceBlockVertexOffset;
656 0 : uint32_t destination2 = m_InPlaceBlockVertexOffset;
657 : // TODO: add overflow checks.
658 0 : m_InPlaceBlockVertexOffset = (m_InPlaceBlockVertexOffset + dataSize + ALIGNMENT - 1) & ~(ALIGNMENT - 1);
659 0 : std::memcpy(static_cast<uint8_t*>(m_InPlaceVertexStagingBufferMappedData) + destination, data, dataSize);
660 :
661 0 : BindVertexBuffer(bindingSlot, m_InPlaceVertexBuffer.get(), destination2);
662 0 : }
663 :
664 0 : void CDeviceCommandContext::SetIndexBuffer(IBuffer* buffer)
665 : {
666 0 : BindIndexBuffer(buffer->As<CBuffer>(), 0);
667 0 : }
668 :
669 0 : void CDeviceCommandContext::SetIndexBufferData(
670 : const void* data, const uint32_t dataSize)
671 : {
672 : // TODO: check index buffer alignment.
673 0 : const uint32_t ALIGNMENT = 32;
674 :
675 0 : uint32_t destination = m_InPlaceBlockIndex * FRAME_INPLACE_BUFFER_SIZE + m_InPlaceBlockIndexOffset;
676 0 : uint32_t destination2 = m_InPlaceBlockIndexOffset;
677 : // TODO: add overflow checks.
678 0 : m_InPlaceBlockIndexOffset = (m_InPlaceBlockIndexOffset + dataSize + ALIGNMENT - 1) & (~(ALIGNMENT - 1));
679 0 : std::memcpy(static_cast<uint8_t*>(m_InPlaceIndexStagingBufferMappedData) + destination, data, dataSize);
680 :
681 0 : BindIndexBuffer(m_InPlaceIndexBuffer.get(), destination2);
682 0 : }
683 :
684 0 : void CDeviceCommandContext::BeginPass()
685 : {
686 0 : ENSURE(m_InsideFramebufferPass);
687 0 : m_InsidePass = true;
688 0 : }
689 :
690 0 : void CDeviceCommandContext::EndPass()
691 : {
692 0 : ENSURE(m_InsidePass);
693 0 : m_InsidePass = false;
694 0 : }
695 :
696 0 : void CDeviceCommandContext::Draw(const uint32_t firstVertex, const uint32_t vertexCount)
697 : {
698 0 : PreDraw();
699 0 : vkCmdDraw(m_CommandContext->GetCommandBuffer(), vertexCount, 1, firstVertex, 0);
700 0 : }
701 :
702 0 : void CDeviceCommandContext::DrawIndexed(
703 : const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset)
704 : {
705 0 : ENSURE(vertexOffset == 0);
706 0 : PreDraw();
707 0 : vkCmdDrawIndexed(m_CommandContext->GetCommandBuffer(), indexCount, 1, firstIndex, 0, 0);
708 0 : }
709 :
710 0 : void CDeviceCommandContext::DrawInstanced(
711 : const uint32_t firstVertex, const uint32_t vertexCount,
712 : const uint32_t firstInstance, const uint32_t instanceCount)
713 : {
714 0 : PreDraw();
715 0 : vkCmdDraw(
716 : m_CommandContext->GetCommandBuffer(), vertexCount, instanceCount, firstVertex, firstInstance);
717 0 : }
718 :
719 0 : void CDeviceCommandContext::DrawIndexedInstanced(
720 : const uint32_t firstIndex, const uint32_t indexCount,
721 : const uint32_t firstInstance, const uint32_t instanceCount,
722 : const int32_t vertexOffset)
723 : {
724 0 : PreDraw();
725 0 : vkCmdDrawIndexed(
726 : m_CommandContext->GetCommandBuffer(), indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
727 0 : }
728 :
729 0 : void CDeviceCommandContext::DrawIndexedInRange(
730 : const uint32_t firstIndex, const uint32_t indexCount,
731 : const uint32_t UNUSED(start), const uint32_t UNUSED(end))
732 : {
733 0 : DrawIndexed(firstIndex, indexCount, 0);
734 0 : }
735 :
736 0 : void CDeviceCommandContext::SetTexture(const int32_t bindingSlot, ITexture* texture)
737 : {
738 0 : if (bindingSlot < 0)
739 0 : return;
740 :
741 0 : ENSURE(m_InsidePass);
742 0 : ENSURE(texture);
743 0 : CTexture* textureToBind = texture->As<CTexture>();
744 0 : ENSURE(textureToBind->GetUsage() & ITexture::Usage::SAMPLED);
745 :
746 0 : if (!m_Device->GetDescriptorManager().UseDescriptorIndexing())
747 : {
748 : // We can't bind textures which are used as color attachments.
749 0 : const auto& colorAttachments = m_Framebuffer->GetColorAttachments();
750 0 : ENSURE(std::find(
751 : colorAttachments.begin(), colorAttachments.end(), textureToBind) == colorAttachments.end());
752 0 : ENSURE(m_Framebuffer->GetDepthStencilAttachment() != textureToBind);
753 :
754 0 : ENSURE(textureToBind->IsInitialized());
755 : }
756 :
757 0 : m_ShaderProgram->SetTexture(bindingSlot, textureToBind);
758 : }
759 :
760 0 : void CDeviceCommandContext::SetUniform(
761 : const int32_t bindingSlot,
762 : const float value)
763 : {
764 0 : ENSURE(m_InsidePass);
765 0 : m_ShaderProgram->SetUniform(bindingSlot, value);
766 0 : }
767 :
768 0 : void CDeviceCommandContext::SetUniform(
769 : const int32_t bindingSlot,
770 : const float valueX, const float valueY)
771 : {
772 0 : ENSURE(m_InsidePass);
773 0 : m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY);
774 0 : }
775 :
776 0 : void CDeviceCommandContext::SetUniform(
777 : const int32_t bindingSlot,
778 : const float valueX, const float valueY,
779 : const float valueZ)
780 : {
781 0 : ENSURE(m_InsidePass);
782 0 : m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY, valueZ);
783 0 : }
784 :
785 0 : void CDeviceCommandContext::SetUniform(
786 : const int32_t bindingSlot,
787 : const float valueX, const float valueY,
788 : const float valueZ, const float valueW)
789 : {
790 0 : ENSURE(m_InsidePass);
791 0 : m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY, valueZ, valueW);
792 0 : }
793 :
794 0 : void CDeviceCommandContext::SetUniform(
795 : const int32_t bindingSlot, PS::span<const float> values)
796 : {
797 0 : ENSURE(m_InsidePass);
798 0 : m_ShaderProgram->SetUniform(bindingSlot, values);
799 0 : }
800 :
801 0 : void CDeviceCommandContext::BeginScopedLabel(const char* name)
802 : {
803 0 : if (!m_DebugScopedLabels)
804 0 : return;
805 0 : VkDebugUtilsLabelEXT label{};
806 0 : label.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT;
807 0 : label.pLabelName = name;
808 0 : vkCmdBeginDebugUtilsLabelEXT(m_CommandContext->GetCommandBuffer(), &label);
809 : }
810 :
811 0 : void CDeviceCommandContext::EndScopedLabel()
812 : {
813 0 : if (!m_DebugScopedLabels)
814 0 : return;
815 0 : vkCmdEndDebugUtilsLabelEXT(m_CommandContext->GetCommandBuffer());
816 : }
817 :
818 0 : void CDeviceCommandContext::Flush()
819 : {
820 0 : ENSURE(!m_InsideFramebufferPass);
821 : // TODO: remove hard-coded values and reduce duplication.
822 : // TODO: fix unsafe copying when overlaping flushes/frames.
823 :
824 0 : if (m_InPlaceBlockVertexOffset > 0)
825 : {
826 0 : VkBufferCopy region{};
827 0 : region.srcOffset = m_InPlaceBlockIndex * FRAME_INPLACE_BUFFER_SIZE;
828 0 : region.dstOffset = 0;
829 0 : region.size = m_InPlaceBlockVertexOffset;
830 :
831 0 : vkCmdCopyBuffer(
832 : m_PrependCommandContext->GetCommandBuffer(),
833 : m_InPlaceVertexStagingBuffer->GetVkBuffer(),
834 : m_InPlaceVertexBuffer->GetVkBuffer(), 1, ®ion);
835 : }
836 :
837 0 : if (m_InPlaceBlockIndexOffset > 0)
838 : {
839 0 : VkBufferCopy region{};
840 0 : region.srcOffset = m_InPlaceBlockIndex * FRAME_INPLACE_BUFFER_SIZE;
841 0 : region.dstOffset = 0;
842 0 : region.size = m_InPlaceBlockIndexOffset;
843 0 : vkCmdCopyBuffer(
844 : m_PrependCommandContext->GetCommandBuffer(),
845 : m_InPlaceIndexStagingBuffer->GetVkBuffer(),
846 : m_InPlaceIndexBuffer->GetVkBuffer(), 1, ®ion);
847 : }
848 :
849 0 : if (m_InPlaceBlockVertexOffset > 0 || m_InPlaceBlockIndexOffset > 0)
850 : {
851 0 : VkMemoryBarrier memoryBarrier{};
852 0 : memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
853 0 : memoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT;
854 0 : memoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
855 :
856 0 : vkCmdPipelineBarrier(
857 : m_PrependCommandContext->GetCommandBuffer(),
858 : VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0,
859 : 1, &memoryBarrier, 0, nullptr, 0, nullptr);
860 : }
861 :
862 0 : if (m_UniformOffset > 0)
863 : {
864 0 : VkBufferCopy region{};
865 : // TODO: fix values
866 0 : region.srcOffset = (m_UniformStagingBuffer->GetSize() / NUMBER_OF_FRAMES_IN_FLIGHT) * m_UniformIndexOffset;
867 0 : region.dstOffset = 0;
868 0 : region.size = m_UniformOffset;
869 0 : vkCmdCopyBuffer(
870 : m_PrependCommandContext->GetCommandBuffer(),
871 : m_UniformStagingBuffer->GetVkBuffer(),
872 : m_UniformBuffer->GetVkBuffer(), 1, ®ion);
873 0 : m_UniformIndexOffset = (m_UniformIndexOffset + 1) % NUMBER_OF_FRAMES_IN_FLIGHT;
874 0 : m_UniformOffset = 0;
875 : }
876 :
877 0 : m_IsPipelineStateDirty = true;
878 : // TODO: maybe move management to CDevice.
879 0 : m_InPlaceBlockIndex = (m_InPlaceBlockIndex + 1) % NUMBER_OF_FRAMES_IN_FLIGHT;
880 0 : m_InPlaceBlockVertexOffset = 0;
881 0 : m_InPlaceBlockIndexOffset = 0;
882 :
883 0 : m_PrependCommandContext->Flush();
884 0 : m_CommandContext->Flush();
885 0 : }
886 :
887 0 : void CDeviceCommandContext::PreDraw()
888 : {
889 0 : ENSURE(m_InsidePass);
890 0 : ApplyPipelineStateIfDirty();
891 0 : m_ShaderProgram->PreDraw(m_CommandContext->GetCommandBuffer());
892 0 : if (m_ShaderProgram->IsMaterialConstantsDataOutdated())
893 : {
894 : const VkDeviceSize alignment =
895 0 : std::max(static_cast<VkDeviceSize>(16), m_Device->GetChoosenPhysicalDevice().properties.limits.minUniformBufferOffsetAlignment);
896 0 : const uint32_t offset = m_UniformOffset + m_UniformIndexOffset * (m_UniformStagingBuffer->GetSize() / NUMBER_OF_FRAMES_IN_FLIGHT);
897 0 : std::memcpy(static_cast<uint8_t*>(m_UniformStagingBufferMappedData) + offset,
898 0 : m_ShaderProgram->GetMaterialConstantsData(),
899 0 : m_ShaderProgram->GetMaterialConstantsDataSize());
900 0 : m_ShaderProgram->UpdateMaterialConstantsData();
901 :
902 : // TODO: maybe move inside shader program to reduce the # of bind calls.
903 0 : vkCmdBindDescriptorSets(
904 0 : m_CommandContext->GetCommandBuffer(), m_ShaderProgram->GetPipelineBindPoint(),
905 0 : m_ShaderProgram->GetPipelineLayout(), m_Device->GetDescriptorManager().GetUniformSet(),
906 0 : 1, &m_UniformDescriptorSet, 1, &m_UniformOffset);
907 :
908 0 : m_UniformOffset += (m_ShaderProgram->GetMaterialConstantsDataSize() + alignment - 1) & ~(alignment - 1);
909 : }
910 0 : }
911 :
912 0 : void CDeviceCommandContext::ApplyPipelineStateIfDirty()
913 : {
914 0 : if (!m_IsPipelineStateDirty)
915 0 : return;
916 0 : m_IsPipelineStateDirty = false;
917 :
918 0 : ENSURE(m_GraphicsPipelineState);
919 0 : ENSURE(m_VertexInputLayout);
920 0 : ENSURE(m_Framebuffer);
921 :
922 0 : VkPipeline pipeline = m_GraphicsPipelineState->GetOrCreatePipeline(
923 0 : m_VertexInputLayout, m_Framebuffer);
924 0 : ENSURE(pipeline != VK_NULL_HANDLE);
925 :
926 0 : if (m_LastBoundPipeline != pipeline)
927 : {
928 0 : m_LastBoundPipeline = pipeline;
929 0 : vkCmdBindPipeline(m_CommandContext->GetCommandBuffer(), m_ShaderProgram->GetPipelineBindPoint(), pipeline);
930 :
931 0 : m_ShaderProgram->Bind();
932 :
933 0 : if (m_Device->GetDescriptorManager().UseDescriptorIndexing())
934 : {
935 0 : vkCmdBindDescriptorSets(
936 0 : m_CommandContext->GetCommandBuffer(), m_ShaderProgram->GetPipelineBindPoint(),
937 0 : m_ShaderProgram->GetPipelineLayout(), 0,
938 0 : 1, &m_Device->GetDescriptorManager().GetDescriptorIndexingSet(), 0, nullptr);
939 : }
940 : }
941 : }
942 :
943 0 : void CDeviceCommandContext::BindVertexBuffer(
944 : const uint32_t bindingSlot, CBuffer* buffer, uint32_t offset)
945 : {
946 0 : VkBuffer vertexBuffers[] = { buffer->GetVkBuffer() };
947 0 : VkDeviceSize offsets[] = { offset };
948 0 : vkCmdBindVertexBuffers(
949 0 : m_CommandContext->GetCommandBuffer(), bindingSlot, std::size(vertexBuffers), vertexBuffers, offsets);
950 0 : }
951 :
952 0 : void CDeviceCommandContext::BindIndexBuffer(CBuffer* buffer, uint32_t offset)
953 : {
954 0 : if (buffer == m_BoundIndexBuffer && offset == m_BoundIndexBufferOffset)
955 0 : return;
956 0 : m_BoundIndexBuffer = buffer;
957 0 : m_BoundIndexBufferOffset = offset;
958 0 : vkCmdBindIndexBuffer(
959 : m_CommandContext->GetCommandBuffer(), buffer->GetVkBuffer(), offset, VK_INDEX_TYPE_UINT16);
960 : }
961 :
962 : } // namespace Vulkan
963 :
964 : } // namespace Backend
965 :
966 3 : } // namespace Renderer
|