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