1 #include "CompositorVk.h"
2
3 #include <string.h>
4
5 #include <cinttypes>
6 #include <glm/gtc/matrix_transform.hpp>
7 #include <optional>
8
9 #include "host-common/logging.h"
10 #include "vulkan/vk_enum_string_helper.h"
11 #include "vulkan/vk_util.h"
12
13 namespace gfxstream {
14 namespace vk {
15
16 using emugl::ABORT_REASON_OTHER;
17 using emugl::FatalError;
18
19 namespace CompositorVkShader {
20 #include "vulkan/CompositorFragmentShader.h"
21 #include "vulkan/CompositorVertexShader.h"
22 } // namespace CompositorVkShader
23
24 namespace {
25
26 constexpr const VkImageLayout kSourceImageInitialLayoutUsed =
27 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
28 constexpr const VkImageLayout kSourceImageFinalLayoutUsed =
29 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
30
31 constexpr const VkImageLayout kTargetImageInitialLayoutUsed = VK_IMAGE_LAYOUT_UNDEFINED;
32 constexpr const VkImageLayout kTargetImageFinalLayoutUsed = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
33
getInfoOrAbort(const std::unique_ptr<BorrowedImageInfo> & info)34 const BorrowedImageInfoVk* getInfoOrAbort(const std::unique_ptr<BorrowedImageInfo>& info) {
35 auto imageVk = static_cast<const BorrowedImageInfoVk*>(info.get());
36 if (imageVk != nullptr) {
37 return imageVk;
38 }
39
40 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
41 << "CompositorVk did not find BorrowedImageInfoVk";
42 }
43
44 struct Vertex {
45 alignas(8) glm::vec2 pos;
46 alignas(8) glm::vec2 tex;
47
getBindingDescriptiongfxstream::vk::__anonf4ee8ed60111::Vertex48 static VkVertexInputBindingDescription getBindingDescription() {
49 return VkVertexInputBindingDescription{
50 .binding = 0,
51 .stride = sizeof(struct Vertex),
52 .inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
53 };
54 }
55
getAttributeDescriptiongfxstream::vk::__anonf4ee8ed60111::Vertex56 static std::array<VkVertexInputAttributeDescription, 2> getAttributeDescription() {
57 return {
58 VkVertexInputAttributeDescription{
59 .location = 0,
60 .binding = 0,
61 .format = VK_FORMAT_R32G32_SFLOAT,
62 .offset = offsetof(struct Vertex, pos),
63 },
64 VkVertexInputAttributeDescription{
65 .location = 1,
66 .binding = 0,
67 .format = VK_FORMAT_R32G32_SFLOAT,
68 .offset = offsetof(struct Vertex, tex),
69 },
70 };
71 }
72 };
73
74 static const std::vector<Vertex> k_vertices = {
75 // clang-format off
76 { .pos = {-1.0f, -1.0f}, .tex = {0.0f, 0.0f}},
77 { .pos = { 1.0f, -1.0f}, .tex = {1.0f, 0.0f}},
78 { .pos = { 1.0f, 1.0f}, .tex = {1.0f, 1.0f}},
79 { .pos = {-1.0f, 1.0f}, .tex = {0.0f, 1.0f}},
80 // clang-format on
81 };
82
83 static const std::vector<uint16_t> k_indices = {0, 1, 2, 2, 3, 0};
84
createShaderModule(const VulkanDispatch & vk,VkDevice device,const std::vector<uint32_t> & code)85 static VkShaderModule createShaderModule(const VulkanDispatch& vk, VkDevice device,
86 const std::vector<uint32_t>& code) {
87 const VkShaderModuleCreateInfo shaderModuleCi = {
88 .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
89 .codeSize = static_cast<uint32_t>(code.size() * sizeof(uint32_t)),
90 .pCode = code.data(),
91 };
92 VkShaderModule res;
93 VK_CHECK(vk.vkCreateShaderModule(device, &shaderModuleCi, nullptr, &res));
94 return res;
95 }
96
97 } // namespace
98
RenderTarget(const VulkanDispatch & vk,VkDevice vkDevice,VkImage vkImage,VkImageView vkImageView,uint32_t width,uint32_t height,VkRenderPass vkRenderPass)99 CompositorVk::RenderTarget::RenderTarget(const VulkanDispatch& vk, VkDevice vkDevice,
100 VkImage vkImage, VkImageView vkImageView, uint32_t width,
101 uint32_t height, VkRenderPass vkRenderPass)
102 : m_vk(vk),
103 m_vkDevice(vkDevice),
104 m_vkImage(vkImage),
105 m_vkFramebuffer(VK_NULL_HANDLE),
106 m_width(width),
107 m_height(height) {
108 if (vkImageView == VK_NULL_HANDLE) {
109 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
110 << "CompositorVk found empty image view handle when creating RenderTarget.";
111 }
112
113 const VkFramebufferCreateInfo framebufferCi = {
114 .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
115 .flags = 0,
116 .renderPass = vkRenderPass,
117 .attachmentCount = 1,
118 .pAttachments = &vkImageView,
119 .width = width,
120 .height = height,
121 .layers = 1,
122 };
123 VK_CHECK(m_vk.vkCreateFramebuffer(vkDevice, &framebufferCi, nullptr, &m_vkFramebuffer));
124 }
125
~RenderTarget()126 CompositorVk::RenderTarget::~RenderTarget() {
127 if (m_vkFramebuffer != VK_NULL_HANDLE) {
128 m_vk.vkDestroyFramebuffer(m_vkDevice, m_vkFramebuffer, nullptr);
129 }
130 }
131
create(const VulkanDispatch & vk,VkDevice vkDevice,VkPhysicalDevice vkPhysicalDevice,VkQueue vkQueue,std::shared_ptr<android::base::Lock> queueLock,uint32_t queueFamilyIndex,uint32_t maxFramesInFlight,DebugUtilsHelper debugUtils)132 std::unique_ptr<CompositorVk> CompositorVk::create(
133 const VulkanDispatch& vk, VkDevice vkDevice, VkPhysicalDevice vkPhysicalDevice, VkQueue vkQueue,
134 std::shared_ptr<android::base::Lock> queueLock, uint32_t queueFamilyIndex,
135 uint32_t maxFramesInFlight, DebugUtilsHelper debugUtils) {
136 auto res = std::unique_ptr<CompositorVk>(new CompositorVk(vk, vkDevice, vkPhysicalDevice,
137 vkQueue, queueLock, queueFamilyIndex,
138 maxFramesInFlight, debugUtils));
139 res->setUpCommandPool();
140 res->setUpSampler();
141 res->setUpGraphicsPipeline();
142 res->setUpVertexBuffers();
143 res->setUpUniformBuffers();
144 res->setUpDescriptorSets();
145 res->setUpFences();
146 res->setUpDefaultImage();
147 res->setUpFrameResourceFutures();
148 return res;
149 }
150
CompositorVk(const VulkanDispatch & vk,VkDevice vkDevice,VkPhysicalDevice vkPhysicalDevice,VkQueue vkQueue,std::shared_ptr<android::base::Lock> queueLock,uint32_t queueFamilyIndex,uint32_t maxFramesInFlight,DebugUtilsHelper debugUtilsHelper)151 CompositorVk::CompositorVk(const VulkanDispatch& vk, VkDevice vkDevice,
152 VkPhysicalDevice vkPhysicalDevice, VkQueue vkQueue,
153 std::shared_ptr<android::base::Lock> queueLock,
154 uint32_t queueFamilyIndex, uint32_t maxFramesInFlight,
155 DebugUtilsHelper debugUtilsHelper)
156 : CompositorVkBase(vk, vkDevice, vkPhysicalDevice, vkQueue, queueLock, queueFamilyIndex,
157 maxFramesInFlight, debugUtilsHelper),
158 m_maxFramesInFlight(maxFramesInFlight),
159 m_renderTargetCache(k_renderTargetCacheSize) {}
160
~CompositorVk()161 CompositorVk::~CompositorVk() {
162 {
163 android::base::AutoLock lock(*m_vkQueueLock);
164 VK_CHECK(vk_util::waitForVkQueueIdleWithRetry(m_vk, m_vkQueue));
165 }
166 if (m_defaultImage.m_vkImageView != VK_NULL_HANDLE) {
167 m_vk.vkDestroyImageView(m_vkDevice, m_defaultImage.m_vkImageView, nullptr);
168 }
169 if (m_defaultImage.m_vkImage != VK_NULL_HANDLE) {
170 m_vk.vkDestroyImage(m_vkDevice, m_defaultImage.m_vkImage, nullptr);
171 }
172 if (m_defaultImage.m_vkImageMemory != VK_NULL_HANDLE) {
173 m_vk.vkFreeMemory(m_vkDevice, m_defaultImage.m_vkImageMemory, nullptr);
174 }
175 m_vk.vkDestroyDescriptorPool(m_vkDevice, m_vkDescriptorPool, nullptr);
176 if (m_uniformStorage.m_vkDeviceMemory != VK_NULL_HANDLE) {
177 m_vk.vkUnmapMemory(m_vkDevice, m_uniformStorage.m_vkDeviceMemory);
178 }
179 m_vk.vkDestroyBuffer(m_vkDevice, m_uniformStorage.m_vkBuffer, nullptr);
180 m_vk.vkFreeMemory(m_vkDevice, m_uniformStorage.m_vkDeviceMemory, nullptr);
181 m_vk.vkFreeMemory(m_vkDevice, m_vertexVkDeviceMemory, nullptr);
182 m_vk.vkDestroyBuffer(m_vkDevice, m_vertexVkBuffer, nullptr);
183 m_vk.vkFreeMemory(m_vkDevice, m_indexVkDeviceMemory, nullptr);
184 m_vk.vkDestroyBuffer(m_vkDevice, m_indexVkBuffer, nullptr);
185 for (auto& [_, formatResources] : m_formatResources) {
186 m_vk.vkDestroyPipeline(m_vkDevice, formatResources.m_graphicsVkPipeline, nullptr);
187 m_vk.vkDestroyRenderPass(m_vkDevice, formatResources.m_vkRenderPass, nullptr);
188 }
189 m_vk.vkDestroyPipelineLayout(m_vkDevice, m_vkPipelineLayout, nullptr);
190 m_vk.vkDestroySampler(m_vkDevice, m_vkSampler, nullptr);
191 m_vk.vkDestroyDescriptorSetLayout(m_vkDevice, m_vkDescriptorSetLayout, nullptr);
192 m_vk.vkDestroyCommandPool(m_vkDevice, m_vkCommandPool, nullptr);
193 for (PerFrameResources& frameResources : m_frameResources) {
194 m_vk.vkDestroyFence(m_vkDevice, frameResources.m_vkFence, nullptr);
195 }
196 }
197
setUpGraphicsPipeline()198 void CompositorVk::setUpGraphicsPipeline() {
199 const std::vector<uint32_t> vertSpvBuff(CompositorVkShader::compositorVertexShader,
200 std::end(CompositorVkShader::compositorVertexShader));
201 const std::vector<uint32_t> fragSpvBuff(CompositorVkShader::compositorFragmentShader,
202 std::end(CompositorVkShader::compositorFragmentShader));
203 const auto vertShaderMod = createShaderModule(m_vk, m_vkDevice, vertSpvBuff);
204 const auto fragShaderMod = createShaderModule(m_vk, m_vkDevice, fragSpvBuff);
205
206 const VkPipelineShaderStageCreateInfo shaderStageCis[2] = {
207 VkPipelineShaderStageCreateInfo{
208 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
209 .stage = VK_SHADER_STAGE_VERTEX_BIT,
210 .module = vertShaderMod,
211 .pName = "main",
212 },
213 VkPipelineShaderStageCreateInfo{
214 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
215 .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
216 .module = fragShaderMod,
217 .pName = "main",
218 },
219 };
220
221 const auto vertexAttributeDescription = Vertex::getAttributeDescription();
222 const auto vertexBindingDescription = Vertex::getBindingDescription();
223 const VkPipelineVertexInputStateCreateInfo vertexInputStateCi = {
224 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
225 .vertexBindingDescriptionCount = 1,
226 .pVertexBindingDescriptions = &vertexBindingDescription,
227 .vertexAttributeDescriptionCount = static_cast<uint32_t>(vertexAttributeDescription.size()),
228 .pVertexAttributeDescriptions = vertexAttributeDescription.data(),
229 };
230 const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCi = {
231 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
232 .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
233 .primitiveRestartEnable = VK_FALSE,
234 };
235
236 const VkPipelineViewportStateCreateInfo viewportStateCi = {
237 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
238 .viewportCount = 1,
239 // The viewport state is dynamic.
240 .pViewports = nullptr,
241 .scissorCount = 1,
242 // The scissor state is dynamic.
243 .pScissors = nullptr,
244 };
245
246 const VkPipelineRasterizationStateCreateInfo rasterizerStateCi = {
247 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
248 .depthClampEnable = VK_FALSE,
249 .rasterizerDiscardEnable = VK_FALSE,
250 .polygonMode = VK_POLYGON_MODE_FILL,
251 .cullMode = VK_CULL_MODE_BACK_BIT,
252 .frontFace = VK_FRONT_FACE_CLOCKWISE,
253 .depthBiasEnable = VK_FALSE,
254 .depthBiasConstantFactor = 0.0f,
255 .depthBiasClamp = 0.0f,
256 .depthBiasSlopeFactor = 0.0f,
257 .lineWidth = 1.0f,
258 };
259
260 const VkPipelineMultisampleStateCreateInfo multisampleStateCi = {
261 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
262 .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
263 .sampleShadingEnable = VK_FALSE,
264 .minSampleShading = 1.0f,
265 .pSampleMask = nullptr,
266 .alphaToCoverageEnable = VK_FALSE,
267 .alphaToOneEnable = VK_FALSE,
268 };
269
270 const VkPipelineColorBlendAttachmentState colorBlendAttachment = {
271 .blendEnable = VK_TRUE,
272 .srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
273 .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
274 .colorBlendOp = VK_BLEND_OP_ADD,
275 .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
276 .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
277 .alphaBlendOp = VK_BLEND_OP_ADD,
278 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
279 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
280 };
281
282 const VkPipelineColorBlendStateCreateInfo colorBlendStateCi = {
283 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
284 .logicOpEnable = VK_FALSE,
285 .attachmentCount = 1,
286 .pAttachments = &colorBlendAttachment,
287 };
288
289 const VkDynamicState dynamicStates[] = {
290 VK_DYNAMIC_STATE_VIEWPORT,
291 VK_DYNAMIC_STATE_SCISSOR,
292 };
293 const VkPipelineDynamicStateCreateInfo dynamicStateCi = {
294 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
295 .dynamicStateCount = std::size(dynamicStates),
296 .pDynamicStates = dynamicStates,
297 };
298
299 const VkDescriptorSetLayoutBinding layoutBindings[2] = {
300 VkDescriptorSetLayoutBinding{
301 .binding = 0,
302 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
303 .descriptorCount = 1,
304 .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
305 .pImmutableSamplers = &m_vkSampler,
306 },
307 VkDescriptorSetLayoutBinding{
308 .binding = 1,
309 .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
310 .descriptorCount = 1,
311 .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
312 .pImmutableSamplers = nullptr,
313 },
314 };
315
316 const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCi = {
317 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
318 .pNext = nullptr,
319 .flags = 0,
320 .bindingCount = static_cast<uint32_t>(std::size(layoutBindings)),
321 .pBindings = layoutBindings,
322 };
323 VK_CHECK(m_vk.vkCreateDescriptorSetLayout(m_vkDevice, &descriptorSetLayoutCi, nullptr,
324 &m_vkDescriptorSetLayout));
325
326 const VkPipelineLayoutCreateInfo pipelineLayoutCi = {
327 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
328 .setLayoutCount = 1,
329 .pSetLayouts = &m_vkDescriptorSetLayout,
330 .pushConstantRangeCount = 0,
331 };
332
333 VK_CHECK(
334 m_vk.vkCreatePipelineLayout(m_vkDevice, &pipelineLayoutCi, nullptr, &m_vkPipelineLayout));
335
336 VkAttachmentDescription colorAttachment = {
337 .format = VK_FORMAT_UNDEFINED,
338 .samples = VK_SAMPLE_COUNT_1_BIT,
339 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
340 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
341 .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
342 .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
343 .initialLayout = kTargetImageInitialLayoutUsed,
344 .finalLayout = kTargetImageFinalLayoutUsed,
345 };
346
347 const VkAttachmentReference colorAttachmentRef = {
348 .attachment = 0,
349 .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
350 };
351
352 const VkSubpassDescription subpass = {
353 .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
354 .colorAttachmentCount = 1,
355 .pColorAttachments = &colorAttachmentRef,
356 };
357
358 // TODO: to support multiple layer composition, we could run the same render
359 // pass for multiple time. In that case, we should use explicit
360 // VkImageMemoryBarriers to transform the image layout instead of relying on
361 // renderpass to do it.
362 const VkSubpassDependency subpassDependency = {
363 .srcSubpass = VK_SUBPASS_EXTERNAL,
364 .dstSubpass = 0,
365 .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
366 .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
367 .srcAccessMask = 0,
368 .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
369 };
370
371 const VkRenderPassCreateInfo renderPassCi = {
372 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
373 .attachmentCount = 1,
374 .pAttachments = &colorAttachment,
375 .subpassCount = 1,
376 .pSubpasses = &subpass,
377 .dependencyCount = 1,
378 .pDependencies = &subpassDependency,
379 };
380
381 VkGraphicsPipelineCreateInfo graphicsPipelineCi = {
382 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
383 .stageCount = static_cast<uint32_t>(std::size(shaderStageCis)),
384 .pStages = shaderStageCis,
385 .pVertexInputState = &vertexInputStateCi,
386 .pInputAssemblyState = &inputAssemblyStateCi,
387 .pViewportState = &viewportStateCi,
388 .pRasterizationState = &rasterizerStateCi,
389 .pMultisampleState = &multisampleStateCi,
390 .pDepthStencilState = nullptr,
391 .pColorBlendState = &colorBlendStateCi,
392 .pDynamicState = &dynamicStateCi,
393 .layout = m_vkPipelineLayout,
394 .renderPass = VK_NULL_HANDLE,
395 .subpass = 0,
396 .basePipelineHandle = VK_NULL_HANDLE,
397 .basePipelineIndex = -1,
398 };
399
400 const std::vector<VkFormat> kRenderTargetFormats = {
401 VK_FORMAT_R8G8B8A8_UNORM,
402 VK_FORMAT_B8G8R8A8_UNORM,
403 };
404 for (VkFormat renderTargetFormat : kRenderTargetFormats) {
405 colorAttachment.format = renderTargetFormat;
406
407 VkRenderPass renderPass = VK_NULL_HANDLE;
408 VK_CHECK(m_vk.vkCreateRenderPass(m_vkDevice, &renderPassCi, nullptr, &renderPass));
409
410 graphicsPipelineCi.renderPass = renderPass;
411
412 VkPipeline pipeline = VK_NULL_HANDLE;
413 VK_CHECK(m_vk.vkCreateGraphicsPipelines(m_vkDevice, VK_NULL_HANDLE, 1, &graphicsPipelineCi,
414 nullptr, &pipeline));
415
416 m_formatResources[renderTargetFormat] = PerFormatResources{
417 .m_vkRenderPass = renderPass,
418 .m_graphicsVkPipeline = pipeline,
419 };
420 }
421
422 m_vk.vkDestroyShaderModule(m_vkDevice, vertShaderMod, nullptr);
423 m_vk.vkDestroyShaderModule(m_vkDevice, fragShaderMod, nullptr);
424 }
425
setUpVertexBuffers()426 void CompositorVk::setUpVertexBuffers() {
427 const VkDeviceSize vertexBufferSize = sizeof(Vertex) * k_vertices.size();
428 std::tie(m_vertexVkBuffer, m_vertexVkDeviceMemory) =
429 createBuffer(vertexBufferSize,
430 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
431 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
432 .value();
433 auto [vertexStagingBuffer, vertexStagingBufferMemory] =
434 createStagingBufferWithData(k_vertices.data(), vertexBufferSize);
435 copyBuffer(vertexStagingBuffer, m_vertexVkBuffer, vertexBufferSize);
436 m_vk.vkDestroyBuffer(m_vkDevice, vertexStagingBuffer, nullptr);
437 m_vk.vkFreeMemory(m_vkDevice, vertexStagingBufferMemory, nullptr);
438
439 VkDeviceSize indexBufferSize = sizeof(k_indices[0]) * k_indices.size();
440 auto [indexStagingBuffer, indexStagingBufferMemory] =
441 createStagingBufferWithData(k_indices.data(), indexBufferSize);
442 std::tie(m_indexVkBuffer, m_indexVkDeviceMemory) =
443 createBuffer(indexBufferSize,
444 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
445 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
446 .value();
447
448 copyBuffer(indexStagingBuffer, m_indexVkBuffer, indexBufferSize);
449 m_vk.vkDestroyBuffer(m_vkDevice, indexStagingBuffer, nullptr);
450 m_vk.vkFreeMemory(m_vkDevice, indexStagingBufferMemory, nullptr);
451 }
452
setUpDescriptorSets()453 void CompositorVk::setUpDescriptorSets() {
454 const uint32_t descriptorSetsPerFrame = kMaxLayersPerFrame;
455 const uint32_t descriptorSetsTotal = descriptorSetsPerFrame * m_maxFramesInFlight;
456
457 const uint32_t descriptorsOfEachTypePerSet = 1;
458 const uint32_t descriptorsOfEachTypePerFrame =
459 descriptorSetsPerFrame * descriptorsOfEachTypePerSet;
460 const uint32_t descriptorsOfEachTypeTotal = descriptorsOfEachTypePerFrame * m_maxFramesInFlight;
461
462 const VkDescriptorPoolSize descriptorPoolSizes[2] = {
463 VkDescriptorPoolSize{
464 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
465 .descriptorCount = descriptorsOfEachTypeTotal,
466 },
467 VkDescriptorPoolSize{
468 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
469 .descriptorCount = descriptorsOfEachTypeTotal,
470 }};
471 const VkDescriptorPoolCreateInfo descriptorPoolCi = {
472 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
473 .flags = 0,
474 .maxSets = descriptorSetsTotal,
475 .poolSizeCount = static_cast<uint32_t>(std::size(descriptorPoolSizes)),
476 .pPoolSizes = descriptorPoolSizes,
477 };
478 VK_CHECK(
479 m_vk.vkCreateDescriptorPool(m_vkDevice, &descriptorPoolCi, nullptr, &m_vkDescriptorPool));
480
481 const std::vector<VkDescriptorSetLayout> frameDescriptorSetLayouts(descriptorSetsPerFrame,
482 m_vkDescriptorSetLayout);
483 const VkDescriptorSetAllocateInfo frameDescriptorSetAllocInfo = {
484 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
485 .descriptorPool = m_vkDescriptorPool,
486 .descriptorSetCount = descriptorSetsPerFrame,
487 .pSetLayouts = frameDescriptorSetLayouts.data(),
488 };
489
490 VkDeviceSize uniformBufferOffset = 0;
491 for (uint32_t frameIndex = 0; frameIndex < m_maxFramesInFlight; ++frameIndex) {
492 PerFrameResources& frameResources = m_frameResources[frameIndex];
493 frameResources.m_layerDescriptorSets.resize(descriptorSetsPerFrame);
494
495 VK_CHECK(m_vk.vkAllocateDescriptorSets(m_vkDevice, &frameDescriptorSetAllocInfo,
496 frameResources.m_layerDescriptorSets.data()));
497
498 for (uint32_t layerIndex = 0; layerIndex < kMaxLayersPerFrame; ++layerIndex) {
499 const VkDescriptorBufferInfo bufferInfo = {
500 .buffer = m_uniformStorage.m_vkBuffer,
501 .offset = uniformBufferOffset,
502 .range = sizeof(UniformBufferBinding),
503 };
504 const VkWriteDescriptorSet descriptorSetWrite = {
505 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
506 .dstSet = frameResources.m_layerDescriptorSets[layerIndex],
507 .dstBinding = 1,
508 .dstArrayElement = 0,
509 .descriptorCount = 1,
510 .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
511 .pBufferInfo = &bufferInfo,
512 };
513 m_vk.vkUpdateDescriptorSets(m_vkDevice, 1, &descriptorSetWrite, 0, nullptr);
514
515 uniformBufferOffset += m_uniformStorage.m_stride;
516 }
517 }
518 }
519
setUpCommandPool()520 void CompositorVk::setUpCommandPool() {
521 const VkCommandPoolCreateInfo commandPoolCreateInfo = {
522 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
523 .flags = 0,
524 .queueFamilyIndex = m_queueFamilyIndex,
525 };
526
527 VkCommandPool commandPool = VK_NULL_HANDLE;
528 VK_CHECK(m_vk.vkCreateCommandPool(m_vkDevice, &commandPoolCreateInfo, nullptr, &commandPool));
529 m_vkCommandPool = commandPool;
530 m_debugUtilsHelper.addDebugLabel(m_vkCommandPool, "CompositorVk command pool");
531 }
532
setUpFences()533 void CompositorVk::setUpFences() {
534 for (uint32_t frameIndex = 0; frameIndex < m_maxFramesInFlight; ++frameIndex) {
535 PerFrameResources& frameResources = m_frameResources[frameIndex];
536
537 const VkFenceCreateInfo fenceCi = {
538 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
539 };
540
541 VkFence fence;
542 VK_CHECK(m_vk.vkCreateFence(m_vkDevice, &fenceCi, nullptr, &fence));
543
544 frameResources.m_vkFence = fence;
545 }
546 }
547
setUpDefaultImage()548 void CompositorVk::setUpDefaultImage() {
549 const VkImageCreateInfo imageCreateInfo = {
550 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
551 .pNext = nullptr,
552 .flags = 0,
553 .imageType = VK_IMAGE_TYPE_2D,
554 .format = VK_FORMAT_R8G8B8A8_UNORM,
555 .extent =
556 {
557 .width = 2,
558 .height = 2,
559 .depth = 1,
560 },
561 .mipLevels = 1,
562 .arrayLayers = 1,
563 .samples = VK_SAMPLE_COUNT_1_BIT,
564 .tiling = VK_IMAGE_TILING_OPTIMAL,
565 .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
566 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
567 .queueFamilyIndexCount = 0,
568 .pQueueFamilyIndices = nullptr,
569 .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
570 };
571 VkImage image = VK_NULL_HANDLE;
572 VK_CHECK(m_vk.vkCreateImage(m_vkDevice, &imageCreateInfo, nullptr, &image));
573
574 VkMemoryRequirements imageMemoryRequirements;
575 m_vk.vkGetImageMemoryRequirements(m_vkDevice, image, &imageMemoryRequirements);
576
577 auto memoryTypeIndexOpt =
578 findMemoryType(imageMemoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
579 if (!memoryTypeIndexOpt) {
580 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
581 << "CompositorVk failed to find memory type for default image.";
582 }
583
584 const VkMemoryAllocateInfo imageMemoryAllocInfo = {
585 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
586 .pNext = nullptr,
587 .allocationSize = imageMemoryRequirements.size,
588 .memoryTypeIndex = *memoryTypeIndexOpt,
589 };
590 VkDeviceMemory imageMemory = VK_NULL_HANDLE;
591 VK_CHECK_MEMALLOC(
592 m_vk.vkAllocateMemory(m_vkDevice, &imageMemoryAllocInfo, nullptr, &imageMemory),
593 imageMemoryAllocInfo);
594
595 VK_CHECK(m_vk.vkBindImageMemory(m_vkDevice, image, imageMemory, 0));
596
597 const VkImageViewCreateInfo imageViewCreateInfo = {
598 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
599 .pNext = nullptr,
600 .flags = 0,
601 .image = image,
602 .viewType = VK_IMAGE_VIEW_TYPE_2D,
603 .format = VK_FORMAT_R8G8B8A8_UNORM,
604 .components =
605 {
606 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
607 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
608 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
609 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
610 },
611 .subresourceRange =
612 {
613 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
614 .baseMipLevel = 0,
615 .levelCount = 1,
616 .baseArrayLayer = 0,
617 .layerCount = 1,
618 },
619 };
620 VkImageView imageView = VK_NULL_HANDLE;
621 VK_CHECK(m_vk.vkCreateImageView(m_vkDevice, &imageViewCreateInfo, nullptr, &imageView));
622
623 const std::vector<uint8_t> pixels = {
624 0xFF, 0x00, 0xFF, 0xFF, //
625 0xFF, 0x00, 0xFF, 0xFF, //
626 0xFF, 0x00, 0xFF, 0xFF, //
627 0xFF, 0x00, 0xFF, 0xFF, //
628 };
629 VkBuffer stagingBuffer = VK_NULL_HANDLE;
630 VkDeviceMemory stagingBufferMemory = VK_NULL_HANDLE;
631 std::tie(stagingBuffer, stagingBufferMemory) =
632 createStagingBufferWithData(pixels.data(), pixels.size());
633
634 runSingleTimeCommands(m_vkQueue, m_vkQueueLock, [&, this](const VkCommandBuffer& cmdBuff) {
635 const VkImageMemoryBarrier toTransferDstImageBarrier = {
636 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
637 .pNext = nullptr,
638 .srcAccessMask = 0,
639 .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
640 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
641 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
642 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
643 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
644 .image = image,
645 .subresourceRange =
646 {
647 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
648 .baseMipLevel = 0,
649 .levelCount = 1,
650 .baseArrayLayer = 0,
651 .layerCount = 1,
652 },
653 };
654 m_vk.vkCmdPipelineBarrier(cmdBuff,
655 /*srcStageMask=*/VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
656 /*dstStageMask=*/VK_PIPELINE_STAGE_TRANSFER_BIT,
657 /*dependencyFlags=*/0,
658 /*memoryBarrierCount=*/0,
659 /*pMemoryBarriers=*/nullptr,
660 /*bufferMemoryBarrierCount=*/0,
661 /*pBufferMemoryBarriers=*/nullptr, 1, &toTransferDstImageBarrier);
662
663 const VkBufferImageCopy bufferToImageCopy = {
664 .bufferOffset = 0,
665 .bufferRowLength = 0,
666 .bufferImageHeight = 0,
667 .imageSubresource =
668 {
669 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
670 .mipLevel = 0,
671 .baseArrayLayer = 0,
672 .layerCount = 1,
673 },
674 .imageOffset =
675 {
676 .x = 0,
677 .y = 0,
678 .z = 0,
679 },
680 .imageExtent =
681 {
682 .width = 2,
683 .height = 2,
684 .depth = 1,
685 },
686 };
687 m_vk.vkCmdCopyBufferToImage(cmdBuff, stagingBuffer, image,
688 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferToImageCopy);
689
690 const VkImageMemoryBarrier toSampledImageImageBarrier = {
691 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
692 .pNext = nullptr,
693 .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
694 .dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
695 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
696 .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
697 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
698 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
699 .image = image,
700 .subresourceRange =
701 {
702 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
703 .baseMipLevel = 0,
704 .levelCount = 1,
705 .baseArrayLayer = 0,
706 .layerCount = 1,
707 },
708 };
709 m_vk.vkCmdPipelineBarrier(cmdBuff,
710 /*srcStageMask=*/VK_PIPELINE_STAGE_TRANSFER_BIT,
711 /*dstStageMask=*/VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
712 /*dependencyFlags=*/0,
713 /*memoryBarrierCount=*/0,
714 /*pMemoryBarriers=*/nullptr,
715 /*bufferMemoryBarrierCount=*/0,
716 /*pBufferMemoryBarriers=*/nullptr, 1,
717 &toSampledImageImageBarrier);
718 });
719
720 m_vk.vkDestroyBuffer(m_vkDevice, stagingBuffer, nullptr);
721 m_vk.vkFreeMemory(m_vkDevice, stagingBufferMemory, nullptr);
722
723 m_defaultImage.m_vkImage = image;
724 m_defaultImage.m_vkImageView = imageView;
725 m_defaultImage.m_vkImageMemory = imageMemory;
726 }
727
setUpFrameResourceFutures()728 void CompositorVk::setUpFrameResourceFutures() {
729 for (uint32_t frameIndex = 0; frameIndex < m_maxFramesInFlight; ++frameIndex) {
730 std::shared_future<PerFrameResources*> availableFrameResourceFuture =
731 std::async(std::launch::deferred, [this, frameIndex] {
732 return &m_frameResources[frameIndex];
733 }).share();
734
735 m_availableFrameResources.push_back(std::move(availableFrameResourceFuture));
736 }
737 }
738
setUpUniformBuffers()739 void CompositorVk::setUpUniformBuffers() {
740 VkPhysicalDeviceProperties physicalDeviceProperties;
741 m_vk.vkGetPhysicalDeviceProperties(m_vkPhysicalDevice, &physicalDeviceProperties);
742 const VkDeviceSize alignment = physicalDeviceProperties.limits.minUniformBufferOffsetAlignment;
743 m_uniformStorage.m_stride = ((sizeof(UniformBufferBinding) - 1) / alignment + 1) * alignment;
744
745 VkDeviceSize size = m_uniformStorage.m_stride * m_maxFramesInFlight * kMaxLayersPerFrame;
746 auto maybeBuffer =
747 createBuffer(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
748 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
749 VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
750 auto buffer = std::make_tuple<VkBuffer, VkDeviceMemory>(VK_NULL_HANDLE, VK_NULL_HANDLE);
751 if (maybeBuffer.has_value()) {
752 buffer = maybeBuffer.value();
753 } else {
754 buffer =
755 createBuffer(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
756 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
757 .value();
758 }
759 std::tie(m_uniformStorage.m_vkBuffer, m_uniformStorage.m_vkDeviceMemory) = buffer;
760
761 void* mapped = nullptr;
762 VK_CHECK(m_vk.vkMapMemory(m_vkDevice, m_uniformStorage.m_vkDeviceMemory, 0, size, 0, &mapped));
763
764 uint8_t* data = reinterpret_cast<uint8_t*>(mapped);
765 for (uint32_t frameIndex = 0; frameIndex < m_maxFramesInFlight; ++frameIndex) {
766 PerFrameResources& frameResources = m_frameResources[frameIndex];
767 for (uint32_t layerIndex = 0; layerIndex < kMaxLayersPerFrame; ++layerIndex) {
768 auto* layerUboStorage = reinterpret_cast<UniformBufferBinding*>(data);
769 frameResources.m_layerUboStorages.push_back(layerUboStorage);
770 data += m_uniformStorage.m_stride;
771 }
772 }
773 }
774
setUpSampler()775 void CompositorVk::setUpSampler() {
776 // The texture coordinate transformation matrices for flip/rotate/etc
777 // currently depends on this being repeat.
778 constexpr const VkSamplerAddressMode kSamplerMode = VK_SAMPLER_ADDRESS_MODE_REPEAT;
779
780 const VkSamplerCreateInfo samplerCi = {
781 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
782 .magFilter = VK_FILTER_LINEAR,
783 .minFilter = VK_FILTER_LINEAR,
784 .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
785 .addressModeU = kSamplerMode,
786 .addressModeV = kSamplerMode,
787 .addressModeW = kSamplerMode,
788 .mipLodBias = 0.0f,
789 .anisotropyEnable = VK_FALSE,
790 .maxAnisotropy = 1.0f,
791 .compareEnable = VK_FALSE,
792 .compareOp = VK_COMPARE_OP_ALWAYS,
793 .minLod = 0.0f,
794 .maxLod = 0.0f,
795 .borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK,
796 .unnormalizedCoordinates = VK_FALSE,
797 };
798 VK_CHECK(m_vk.vkCreateSampler(m_vkDevice, &samplerCi, nullptr, &m_vkSampler));
799 }
800
801 // Create a VkBuffer and a bound VkDeviceMemory. When the specified memory type
802 // can't be found, return std::nullopt. When Vulkan call fails, terminate the
803 // program.
createBuffer(VkDeviceSize size,VkBufferUsageFlags usage,VkMemoryPropertyFlags memProperty) const804 std::optional<std::tuple<VkBuffer, VkDeviceMemory>> CompositorVk::createBuffer(
805 VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags memProperty) const {
806 const VkBufferCreateInfo bufferCi = {
807 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
808 .size = size,
809 .usage = usage,
810 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
811 };
812 VkBuffer resBuffer;
813 VK_CHECK(m_vk.vkCreateBuffer(m_vkDevice, &bufferCi, nullptr, &resBuffer));
814 VkMemoryRequirements memRequirements;
815 m_vk.vkGetBufferMemoryRequirements(m_vkDevice, resBuffer, &memRequirements);
816 VkPhysicalDeviceMemoryProperties physicalMemProperties;
817 m_vk.vkGetPhysicalDeviceMemoryProperties(m_vkPhysicalDevice, &physicalMemProperties);
818 auto maybeMemoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, memProperty);
819 if (!maybeMemoryTypeIndex.has_value()) {
820 ERR("Failed to find memory type for creating buffer.");
821 m_vk.vkDestroyBuffer(m_vkDevice, resBuffer, nullptr);
822 return std::nullopt;
823 }
824 const VkMemoryAllocateInfo memAllocInfo = {
825 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
826 .allocationSize = memRequirements.size,
827 .memoryTypeIndex = maybeMemoryTypeIndex.value(),
828 };
829 VkDeviceMemory resMemory;
830 VK_CHECK_MEMALLOC(m_vk.vkAllocateMemory(m_vkDevice, &memAllocInfo, nullptr, &resMemory),
831 memAllocInfo);
832 VK_CHECK(m_vk.vkBindBufferMemory(m_vkDevice, resBuffer, resMemory, 0));
833 return std::make_tuple(resBuffer, resMemory);
834 }
835
createStagingBufferWithData(const void * srcData,VkDeviceSize size) const836 std::tuple<VkBuffer, VkDeviceMemory> CompositorVk::createStagingBufferWithData(
837 const void* srcData, VkDeviceSize size) const {
838 auto [stagingBuffer, stagingBufferMemory] =
839 createBuffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
840 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
841 .value();
842 void* data;
843 VK_CHECK(m_vk.vkMapMemory(m_vkDevice, stagingBufferMemory, 0, size, 0, &data));
844 memcpy(data, srcData, size);
845 m_vk.vkUnmapMemory(m_vkDevice, stagingBufferMemory);
846 return std::make_tuple(stagingBuffer, stagingBufferMemory);
847 }
848
copyBuffer(VkBuffer src,VkBuffer dst,VkDeviceSize size) const849 void CompositorVk::copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size) const {
850 runSingleTimeCommands(m_vkQueue, m_vkQueueLock, [&, this](const auto& cmdBuff) {
851 VkBufferCopy copyRegion = {};
852 copyRegion.srcOffset = 0;
853 copyRegion.dstOffset = 0;
854 copyRegion.size = size;
855 m_vk.vkCmdCopyBuffer(cmdBuff, src, dst, 1, ©Region);
856 });
857 }
858
859 // TODO: move this to another common CRTP helper class in vk_util.h.
getFormatFeatures(VkFormat format,VkImageTiling tiling)860 VkFormatFeatureFlags CompositorVk::getFormatFeatures(VkFormat format, VkImageTiling tiling) {
861 auto i = m_vkFormatProperties.find(format);
862 if (i == m_vkFormatProperties.end()) {
863 VkFormatProperties formatProperties;
864 m_vk.vkGetPhysicalDeviceFormatProperties(m_vkPhysicalDevice, format, &formatProperties);
865 i = m_vkFormatProperties.emplace(format, formatProperties).first;
866 }
867 const VkFormatProperties& formatProperties = i->second;
868 VkFormatFeatureFlags formatFeatures = 0;
869 if (tiling == VK_IMAGE_TILING_LINEAR) {
870 formatFeatures = formatProperties.linearTilingFeatures;
871 } else if (tiling == VK_IMAGE_TILING_OPTIMAL) {
872 formatFeatures = formatProperties.optimalTilingFeatures;
873 } else {
874 ERR("Unknown tiling:%#" PRIx64 ".", static_cast<uint64_t>(tiling));
875 }
876 return formatFeatures;
877 }
878
getOrCreateRenderTargetInfo(const BorrowedImageInfoVk & imageInfo)879 CompositorVk::RenderTarget* CompositorVk::getOrCreateRenderTargetInfo(
880 const BorrowedImageInfoVk& imageInfo) {
881 auto* renderTargetPtr = m_renderTargetCache.get(imageInfo.id);
882 if (renderTargetPtr != nullptr) {
883 return renderTargetPtr->get();
884 }
885
886 auto formatResourcesIt = m_formatResources.find(imageInfo.imageCreateInfo.format);
887 if (formatResourcesIt == m_formatResources.end()) {
888 return nullptr;
889 }
890 auto& formatResources = formatResourcesIt->second;
891
892 auto* renderTarget =
893 new RenderTarget(m_vk, m_vkDevice, imageInfo.image, imageInfo.imageView,
894 imageInfo.imageCreateInfo.extent.width,
895 imageInfo.imageCreateInfo.extent.height, formatResources.m_vkRenderPass);
896
897 m_renderTargetCache.set(imageInfo.id, std::unique_ptr<RenderTarget>(renderTarget));
898
899 return renderTarget;
900 }
901
canCompositeFrom(const VkImageCreateInfo & imageCi)902 bool CompositorVk::canCompositeFrom(const VkImageCreateInfo& imageCi) {
903 VkFormatFeatureFlags formatFeatures = getFormatFeatures(imageCi.format, imageCi.tiling);
904 if (!(formatFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
905 ERR("The format, %s, with tiling, %s, doesn't support the "
906 "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT feature. All supported features are %s.",
907 string_VkFormat(imageCi.format), string_VkImageTiling(imageCi.tiling),
908 string_VkFormatFeatureFlags(formatFeatures).c_str());
909 return false;
910 }
911 return true;
912 }
913
canCompositeTo(const VkImageCreateInfo & imageCi)914 bool CompositorVk::canCompositeTo(const VkImageCreateInfo& imageCi) {
915 VkFormatFeatureFlags formatFeatures = getFormatFeatures(imageCi.format, imageCi.tiling);
916 if (!(formatFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
917 ERR("The format, %s, with tiling, %s, doesn't support the "
918 "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT feature. All supported features are %s.",
919 string_VkFormat(imageCi.format), string_VkImageTiling(imageCi.tiling),
920 string_VkFormatFeatureFlags(formatFeatures).c_str());
921 return false;
922 }
923 if (!(imageCi.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
924 ERR("The VkImage is not created with the VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT usage flag. "
925 "The usage flags are %s.",
926 string_VkImageUsageFlags(imageCi.usage).c_str());
927 return false;
928 }
929
930 if (m_formatResources.find(imageCi.format) == m_formatResources.end()) {
931 ERR("The format of the image, %s, is not supported by the CompositorVk as the render "
932 "target.",
933 string_VkFormat(imageCi.format));
934 return false;
935 }
936 return true;
937 }
938
buildCompositionVk(const CompositionRequest & compositionRequest,CompositionVk * compositionVk)939 void CompositorVk::buildCompositionVk(const CompositionRequest& compositionRequest,
940 CompositionVk* compositionVk) {
941 const BorrowedImageInfoVk* targetImage = getInfoOrAbort(compositionRequest.target);
942
943 auto formatResourcesIt = m_formatResources.find(targetImage->imageCreateInfo.format);
944 if (formatResourcesIt == m_formatResources.end()) {
945 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
946 << "CompositorVk did not find format resource for format "
947 << targetImage->imageCreateInfo.format;
948 }
949 const auto& formatResources = formatResourcesIt->second;
950
951 RenderTarget* targetImageRenderTarget = getOrCreateRenderTargetInfo(*targetImage);
952
953 const uint32_t targetWidth = targetImage->width;
954 const uint32_t targetHeight = targetImage->height;
955
956 compositionVk->targetImage = targetImage;
957 compositionVk->targetRenderPass = formatResources.m_vkRenderPass;
958 compositionVk->targetFramebuffer = targetImageRenderTarget->m_vkFramebuffer;
959 compositionVk->pipeline = formatResources.m_graphicsVkPipeline;
960
961 for (const CompositionRequestLayer& layer : compositionRequest.layers) {
962 uint32_t sourceImageWidth = 0;
963 uint32_t sourceImageHeight = 0;
964 const BorrowedImageInfoVk* sourceImage = nullptr;
965
966 if (layer.props.composeMode == HWC2_COMPOSITION_SOLID_COLOR) {
967 sourceImageWidth = targetWidth;
968 sourceImageHeight = targetHeight;
969 } else {
970 sourceImage = getInfoOrAbort(layer.source);
971 if (!canCompositeFrom(sourceImage->imageCreateInfo)) {
972 continue;
973 }
974
975 sourceImageWidth = sourceImage->width;
976 sourceImageHeight = sourceImage->height;
977 }
978
979 // Calculate the posTransform and the texcoordTransform needed in the
980 // uniform of the Compositor.vert shader. The posTransform should transform
981 // the square(top = -1, bottom = 1, left = -1, right = 1) to the position
982 // where the layer should be drawn in NDC space given the layer.
983 // texcoordTransform should transform the unit square(top = 0, bottom = 1,
984 // left = 0, right = 1) to where we should sample the layer in the
985 // normalized uv space given the composeLayer.
986 const hwc_rect_t& posRect = layer.props.displayFrame;
987 const hwc_frect_t& texcoordRect = layer.props.crop;
988
989 const int posWidth = posRect.right - posRect.left;
990 const int posHeight = posRect.bottom - posRect.top;
991
992 const float posScaleX = float(posWidth) / targetWidth;
993 const float posScaleY = float(posHeight) / targetHeight;
994
995 const float posTranslateX = -1.0f + posScaleX + 2.0f * float(posRect.left) / targetWidth;
996 const float posTranslateY = -1.0f + posScaleY + 2.0f * float(posRect.top) / targetHeight;
997
998 float texCoordScaleX = (texcoordRect.right - texcoordRect.left) / float(sourceImageWidth);
999 float texCoordScaleY = (texcoordRect.bottom - texcoordRect.top) / float(sourceImageHeight);
1000
1001 const float texCoordTranslateX = texcoordRect.left / float(sourceImageWidth);
1002 const float texCoordTranslateY = texcoordRect.top / float(sourceImageHeight);
1003
1004 float texcoordRotation = 0.0f;
1005
1006 const float pi = glm::pi<float>();
1007
1008 switch (layer.props.transform) {
1009 case HWC_TRANSFORM_NONE:
1010 break;
1011 case HWC_TRANSFORM_ROT_90:
1012 texcoordRotation = pi * 0.5f;
1013 break;
1014 case HWC_TRANSFORM_ROT_180:
1015 texcoordRotation = pi;
1016 break;
1017 case HWC_TRANSFORM_ROT_270:
1018 texcoordRotation = pi * 1.5f;
1019 break;
1020 case HWC_TRANSFORM_FLIP_H:
1021 texCoordScaleX *= -1.0f;
1022 break;
1023 case HWC_TRANSFORM_FLIP_V:
1024 texCoordScaleY *= -1.0f;
1025 break;
1026 case HWC_TRANSFORM_FLIP_H_ROT_90:
1027 texcoordRotation = pi * 0.5f;
1028 texCoordScaleX *= -1.0f;
1029 break;
1030 case HWC_TRANSFORM_FLIP_V_ROT_90:
1031 texcoordRotation = pi * 0.5f;
1032 texCoordScaleY *= -1.0f;
1033 break;
1034 default:
1035 ERR("Unknown transform:%d", static_cast<int>(layer.props.transform));
1036 break;
1037 }
1038
1039 DescriptorSetContents descriptorSetContents = {
1040 .binding1 =
1041 {
1042 .positionTransform =
1043 glm::translate(glm::mat4(1.0f),
1044 glm::vec3(posTranslateX, posTranslateY, 0.0f)) *
1045 glm::scale(glm::mat4(1.0f), glm::vec3(posScaleX, posScaleY, 1.0f)),
1046 .texCoordTransform =
1047 glm::translate(glm::mat4(1.0f),
1048 glm::vec3(texCoordTranslateX, texCoordTranslateY, 0.0f)) *
1049 glm::scale(glm::mat4(1.0f),
1050 glm::vec3(texCoordScaleX, texCoordScaleY, 1.0f)) *
1051 glm::rotate(glm::mat4(1.0f), texcoordRotation, glm::vec3(0.0f, 0.0f, 1.0f)),
1052 .mode = glm::uvec4(static_cast<uint32_t>(layer.props.composeMode), 0, 0, 0),
1053 .alpha =
1054 glm::vec4(layer.props.alpha, layer.props.alpha, layer.props.alpha,
1055 layer.props.alpha),
1056 },
1057 };
1058
1059 if (layer.props.composeMode == HWC2_COMPOSITION_SOLID_COLOR) {
1060 descriptorSetContents.binding0.sampledImageId = 0;
1061 descriptorSetContents.binding0.sampledImageView = m_defaultImage.m_vkImageView;
1062 descriptorSetContents.binding1.color =
1063 glm::vec4(static_cast<float>(layer.props.color.r) / 255.0f,
1064 static_cast<float>(layer.props.color.g) / 255.0f,
1065 static_cast<float>(layer.props.color.b) / 255.0f,
1066 static_cast<float>(layer.props.color.a) / 255.0f);
1067
1068 } else {
1069 if (sourceImage == nullptr) {
1070 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
1071 << "CompositorVk failed to find sourceImage.";
1072 }
1073 descriptorSetContents.binding0.sampledImageId = sourceImage->id;
1074 descriptorSetContents.binding0.sampledImageView = sourceImage->imageView;
1075 compositionVk->layersSourceImages.emplace_back(sourceImage);
1076 }
1077
1078 compositionVk->layersDescriptorSets.descriptorSets.emplace_back(descriptorSetContents);
1079 }
1080 }
1081
compose(const CompositionRequest & compositionRequest)1082 CompositorVk::CompositionFinishedWaitable CompositorVk::compose(
1083 const CompositionRequest& compositionRequest) {
1084 CompositionVk compositionVk;
1085 buildCompositionVk(compositionRequest, &compositionVk);
1086
1087 // Grab and wait for the next available resources.
1088 if (m_availableFrameResources.empty()) {
1089 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
1090 << "CompositorVk failed to get PerFrameResources.";
1091 }
1092 auto frameResourceFuture = std::move(m_availableFrameResources.front());
1093 m_availableFrameResources.pop_front();
1094 PerFrameResources* frameResources = frameResourceFuture.get();
1095
1096 updateDescriptorSetsIfChanged(compositionVk.layersDescriptorSets, frameResources);
1097
1098 std::vector<VkImageMemoryBarrier> preCompositionQueueTransferBarriers;
1099 std::vector<VkImageMemoryBarrier> preCompositionLayoutTransitionBarriers;
1100 std::vector<VkImageMemoryBarrier> postCompositionLayoutTransitionBarriers;
1101 std::vector<VkImageMemoryBarrier> postCompositionQueueTransferBarriers;
1102 addNeededBarriersToUseBorrowedImage(
1103 *compositionVk.targetImage, m_queueFamilyIndex, kTargetImageInitialLayoutUsed,
1104 kTargetImageFinalLayoutUsed, VK_ACCESS_MEMORY_WRITE_BIT,
1105 &preCompositionQueueTransferBarriers, &preCompositionLayoutTransitionBarriers,
1106 &postCompositionLayoutTransitionBarriers, &postCompositionQueueTransferBarriers);
1107 for (const BorrowedImageInfoVk* sourceImage : compositionVk.layersSourceImages) {
1108 addNeededBarriersToUseBorrowedImage(
1109 *sourceImage, m_queueFamilyIndex, kSourceImageInitialLayoutUsed,
1110 kSourceImageFinalLayoutUsed, VK_ACCESS_SHADER_READ_BIT,
1111 &preCompositionQueueTransferBarriers, &preCompositionLayoutTransitionBarriers,
1112 &postCompositionLayoutTransitionBarriers, &postCompositionQueueTransferBarriers);
1113 }
1114
1115 static uint32_t sCompositionNumber = 0;
1116 const uint32_t thisCompositionNumber = sCompositionNumber++;
1117
1118 VkCommandBuffer& commandBuffer = frameResources->m_vkCommandBuffer;
1119 if (commandBuffer != VK_NULL_HANDLE) {
1120 m_vk.vkFreeCommandBuffers(m_vkDevice, m_vkCommandPool, 1, &commandBuffer);
1121 }
1122
1123 const VkCommandBufferAllocateInfo commandBufferAllocInfo = {
1124 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1125 .commandPool = m_vkCommandPool,
1126 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1127 .commandBufferCount = 1,
1128 };
1129 VK_CHECK(m_vk.vkAllocateCommandBuffers(m_vkDevice, &commandBufferAllocInfo, &commandBuffer));
1130
1131 m_debugUtilsHelper.addDebugLabel(commandBuffer, "CompositorVk composition:%d command buffer",
1132 thisCompositionNumber);
1133
1134 const VkCommandBufferBeginInfo beginInfo = {
1135 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
1136 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
1137 };
1138 VK_CHECK(m_vk.vkBeginCommandBuffer(commandBuffer, &beginInfo));
1139
1140 m_debugUtilsHelper.cmdBeginDebugLabel(commandBuffer,
1141 "CompositorVk composition:%d into ColorBuffer:%d",
1142 thisCompositionNumber, compositionVk.targetImage->id);
1143
1144 if (!preCompositionQueueTransferBarriers.empty()) {
1145 m_vk.vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
1146 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr,
1147 static_cast<uint32_t>(preCompositionQueueTransferBarriers.size()),
1148 preCompositionQueueTransferBarriers.data());
1149 }
1150 if (!preCompositionLayoutTransitionBarriers.empty()) {
1151 m_vk.vkCmdPipelineBarrier(
1152 commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
1153 0, 0, nullptr, 0, nullptr,
1154 static_cast<uint32_t>(preCompositionLayoutTransitionBarriers.size()),
1155 preCompositionLayoutTransitionBarriers.data());
1156 }
1157
1158 const VkClearValue renderTargetClearColor = {
1159 .color =
1160 {
1161 .float32 = {0.0f, 0.0f, 0.0f, 1.0f},
1162 },
1163 };
1164 const VkRenderPassBeginInfo renderPassBeginInfo = {
1165 .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
1166 .renderPass = compositionVk.targetRenderPass,
1167 .framebuffer = compositionVk.targetFramebuffer,
1168 .renderArea =
1169 {
1170 .offset =
1171 {
1172 .x = 0,
1173 .y = 0,
1174 },
1175 .extent =
1176 {
1177 .width = compositionVk.targetImage->imageCreateInfo.extent.width,
1178 .height = compositionVk.targetImage->imageCreateInfo.extent.height,
1179 },
1180 },
1181 .clearValueCount = 1,
1182 .pClearValues = &renderTargetClearColor,
1183 };
1184 m_vk.vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1185
1186 m_vk.vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, compositionVk.pipeline);
1187
1188 const VkRect2D scissor = {
1189 .offset =
1190 {
1191 .x = 0,
1192 .y = 0,
1193 },
1194 .extent =
1195 {
1196 .width = compositionVk.targetImage->imageCreateInfo.extent.width,
1197 .height = compositionVk.targetImage->imageCreateInfo.extent.height,
1198 },
1199 };
1200 m_vk.vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
1201
1202 const VkViewport viewport = {
1203 .x = 0.0f,
1204 .y = 0.0f,
1205 .width = static_cast<float>(compositionVk.targetImage->imageCreateInfo.extent.width),
1206 .height = static_cast<float>(compositionVk.targetImage->imageCreateInfo.extent.height),
1207 .minDepth = 0.0f,
1208 .maxDepth = 1.0f,
1209 };
1210 m_vk.vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
1211
1212 const VkDeviceSize offsets[] = {0};
1213 m_vk.vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_vertexVkBuffer, offsets);
1214
1215 m_vk.vkCmdBindIndexBuffer(commandBuffer, m_indexVkBuffer, 0, VK_INDEX_TYPE_UINT16);
1216
1217 const uint32_t numLayers = compositionVk.layersDescriptorSets.descriptorSets.size();
1218 for (uint32_t layerIndex = 0; layerIndex < numLayers; ++layerIndex) {
1219 m_debugUtilsHelper.cmdBeginDebugLabel(commandBuffer, "CompositorVk compose layer:%d",
1220 layerIndex);
1221
1222 VkDescriptorSet layerDescriptorSet = frameResources->m_layerDescriptorSets[layerIndex];
1223
1224 m_vk.vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
1225 m_vkPipelineLayout,
1226 /*firstSet=*/0,
1227 /*descriptorSetCount=*/1, &layerDescriptorSet,
1228 /*dynamicOffsetCount=*/0,
1229 /*pDynamicOffsets=*/nullptr);
1230
1231 m_vk.vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(k_indices.size()), 1, 0, 0, 0);
1232
1233 m_debugUtilsHelper.cmdEndDebugLabel(commandBuffer);
1234 }
1235
1236 m_vk.vkCmdEndRenderPass(commandBuffer);
1237
1238 // Insert a VkImageMemoryBarrier so that the vkCmdBlitImage in post will wait for the rendering
1239 // to the render target to complete.
1240 const VkImageMemoryBarrier renderTargetBarrier = {
1241 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
1242 .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
1243 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT,
1244 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1245 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1246 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1247 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1248 .image = compositionVk.targetImage->image,
1249 .subresourceRange =
1250 {
1251 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1252 .baseMipLevel = 0,
1253 .levelCount = 1,
1254 .baseArrayLayer = 0,
1255 .layerCount = 1,
1256 },
1257 };
1258 m_vk.vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
1259 VK_PIPELINE_STAGE_TRANSFER_BIT,
1260 /*dependencyFlags=*/0,
1261 /*memoryBarrierCount=*/0,
1262 /*pMemoryBarriers=*/nullptr,
1263 /*bufferMemoryBarrierCount=*/0,
1264 /*pBufferMemoryBarriers=*/nullptr, 1, &renderTargetBarrier);
1265
1266 if (!postCompositionLayoutTransitionBarriers.empty()) {
1267 m_vk.vkCmdPipelineBarrier(
1268 commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
1269 0, 0, nullptr, 0, nullptr,
1270 static_cast<uint32_t>(postCompositionLayoutTransitionBarriers.size()),
1271 postCompositionLayoutTransitionBarriers.data());
1272 }
1273 if (!postCompositionQueueTransferBarriers.empty()) {
1274 m_vk.vkCmdPipelineBarrier(
1275 commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
1276 0, 0, nullptr, 0, nullptr,
1277 static_cast<uint32_t>(postCompositionQueueTransferBarriers.size()),
1278 postCompositionQueueTransferBarriers.data());
1279 }
1280
1281 m_debugUtilsHelper.cmdEndDebugLabel(commandBuffer);
1282
1283 VK_CHECK(m_vk.vkEndCommandBuffer(commandBuffer));
1284
1285 VkFence composeCompleteFence = frameResources->m_vkFence;
1286 m_debugUtilsHelper.addDebugLabel(
1287 composeCompleteFence, "CompositorVk composition:%d complete fence", thisCompositionNumber);
1288
1289 VK_CHECK(m_vk.vkResetFences(m_vkDevice, 1, &composeCompleteFence));
1290
1291 const VkPipelineStageFlags submitWaitStages[] = {
1292 VK_PIPELINE_STAGE_TRANSFER_BIT,
1293 };
1294 const VkSubmitInfo submitInfo = {
1295 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1296 .waitSemaphoreCount = 0,
1297 .pWaitSemaphores = nullptr,
1298 .pWaitDstStageMask = submitWaitStages,
1299 .commandBufferCount = 1,
1300 .pCommandBuffers = &commandBuffer,
1301 .signalSemaphoreCount = 0,
1302 .pSignalSemaphores = nullptr,
1303 };
1304
1305 {
1306 android::base::AutoLock lock(*m_vkQueueLock);
1307 VK_CHECK(m_vk.vkQueueSubmit(m_vkQueue, 1, &submitInfo, composeCompleteFence));
1308 }
1309
1310 // Create a future that will return the PerFrameResources to the next
1311 // iteration of CompostiorVk::compose() once this current composition
1312 // completes.
1313 std::shared_future<PerFrameResources*> composeCompleteFutureForResources =
1314 std::async(std::launch::deferred, [composeCompleteFence, frameResources, this]() mutable {
1315 VkResult res = m_vk.vkWaitForFences(m_vkDevice, 1, &composeCompleteFence, VK_TRUE,
1316 kVkWaitForFencesTimeoutNsecs);
1317 if (res == VK_SUCCESS) {
1318 return frameResources;
1319 }
1320 if (res == VK_TIMEOUT) {
1321 // Retry. If device lost, hopefully this returns immediately.
1322 res = m_vk.vkWaitForFences(m_vkDevice, 1, &composeCompleteFence, VK_TRUE,
1323 kVkWaitForFencesTimeoutNsecs);
1324 }
1325 VK_CHECK(res);
1326 return frameResources;
1327 }).share();
1328 m_availableFrameResources.push_back(composeCompleteFutureForResources);
1329
1330 // Create a future that will return once this current composition
1331 // completes that can be shared outside of CompositorVk.
1332 std::shared_future<void> composeCompleteFuture =
1333 std::async(std::launch::deferred, [composeCompleteFutureForResources]() {
1334 composeCompleteFutureForResources.get();
1335 }).share();
1336
1337 return composeCompleteFuture;
1338 }
1339
onImageDestroyed(uint32_t imageId)1340 void CompositorVk::onImageDestroyed(uint32_t imageId) { m_renderTargetCache.remove(imageId); }
1341
operator ==(const CompositorVkBase::DescriptorSetContents & lhs,const CompositorVkBase::DescriptorSetContents & rhs)1342 bool operator==(const CompositorVkBase::DescriptorSetContents& lhs,
1343 const CompositorVkBase::DescriptorSetContents& rhs) {
1344 return std::tie(lhs.binding0.sampledImageId, //
1345 lhs.binding0.sampledImageView, //
1346 lhs.binding1.mode, //
1347 lhs.binding1.alpha, //
1348 lhs.binding1.color, //
1349 lhs.binding1.positionTransform, //
1350 lhs.binding1.texCoordTransform) //
1351 == //
1352 std::tie(rhs.binding0.sampledImageId, //
1353 rhs.binding0.sampledImageView, //
1354 rhs.binding1.mode, //
1355 rhs.binding1.alpha, //
1356 rhs.binding1.color, //
1357 rhs.binding1.positionTransform, //
1358 rhs.binding1.texCoordTransform);
1359 }
1360
operator ==(const CompositorVkBase::FrameDescriptorSetsContents & lhs,const CompositorVkBase::FrameDescriptorSetsContents & rhs)1361 bool operator==(const CompositorVkBase::FrameDescriptorSetsContents& lhs,
1362 const CompositorVkBase::FrameDescriptorSetsContents& rhs) {
1363 return lhs.descriptorSets == rhs.descriptorSets;
1364 }
1365
updateDescriptorSetsIfChanged(const FrameDescriptorSetsContents & descriptorSetsContents,PerFrameResources * frameResources)1366 void CompositorVk::updateDescriptorSetsIfChanged(
1367 const FrameDescriptorSetsContents& descriptorSetsContents, PerFrameResources* frameResources) {
1368 if (frameResources->m_vkDescriptorSetsContents == descriptorSetsContents) {
1369 return;
1370 }
1371
1372 const uint32_t numRequestedLayers =
1373 static_cast<uint32_t>(descriptorSetsContents.descriptorSets.size());
1374 if (numRequestedLayers > kMaxLayersPerFrame) {
1375 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
1376 << "CompositorVk can't compose more than " << kMaxLayersPerFrame
1377 << " layers. layers asked: " << numRequestedLayers;
1378 return;
1379 }
1380
1381 std::vector<VkDescriptorImageInfo> descriptorImageInfos(numRequestedLayers);
1382 std::vector<VkWriteDescriptorSet> descriptorWrites;
1383 for (uint32_t layerIndex = 0; layerIndex < numRequestedLayers; ++layerIndex) {
1384 const DescriptorSetContents& layerDescriptorSetContents =
1385 descriptorSetsContents.descriptorSets[layerIndex];
1386
1387 descriptorImageInfos[layerIndex] = VkDescriptorImageInfo{
1388 // Empty as we only use immutable samplers.
1389 .sampler = VK_NULL_HANDLE,
1390 .imageView = layerDescriptorSetContents.binding0.sampledImageView,
1391 .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
1392 };
1393
1394 descriptorWrites.emplace_back(VkWriteDescriptorSet{
1395 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
1396 .dstSet = frameResources->m_layerDescriptorSets[layerIndex],
1397 .dstBinding = 0,
1398 .dstArrayElement = 0,
1399 .descriptorCount = 1,
1400 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1401 .pImageInfo = &descriptorImageInfos[layerIndex],
1402 });
1403
1404 UniformBufferBinding* layerUboStorage = frameResources->m_layerUboStorages[layerIndex];
1405 *layerUboStorage = layerDescriptorSetContents.binding1;
1406 }
1407
1408 m_vk.vkUpdateDescriptorSets(m_vkDevice, descriptorWrites.size(), descriptorWrites.data(), 0,
1409 nullptr);
1410
1411 frameResources->m_vkDescriptorSetsContents = descriptorSetsContents;
1412 }
1413
1414 } // namespace vk
1415 } // namespace gfxstream
1416