• 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 "ErrorLog.h"
10 #include "vulkan/vk_util.h"
11 
12 namespace CompositorVkShader {
13 #include "vulkan/CompositorFragmentShader.h"
14 #include "vulkan/CompositorVertexShader.h"
15 }  // namespace CompositorVkShader
16 
createShaderModule(const goldfish_vk::VulkanDispatch & vk,VkDevice device,const std::vector<uint32_t> & code)17 static VkShaderModule createShaderModule(const goldfish_vk::VulkanDispatch &vk,
18                                          VkDevice device,
19                                          const std::vector<uint32_t> &code) {
20     VkShaderModuleCreateInfo shaderModuleCi = {
21         .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
22         .codeSize = static_cast<uint32_t>(code.size() * sizeof(uint32_t)),
23         .pCode = code.data()};
24     VkShaderModule res;
25     VK_CHECK(vk.vkCreateShaderModule(device, &shaderModuleCi, nullptr, &res));
26     return res;
27 }
28 
ComposeLayerVk(VkSampler vkSampler,VkImageView vkImageView,const LayerTransform & layerTransform)29 ComposeLayerVk::ComposeLayerVk(VkSampler vkSampler, VkImageView vkImageView,
30                                const LayerTransform &layerTransform)
31     : m_vkSampler(vkSampler),
32       m_vkImageView(vkImageView),
33       m_layerTransform(
34           {.pos = layerTransform.pos, .texcoord = layerTransform.texcoord}) {}
35 
createFromHwc2ComposeLayer(VkSampler vkSampler,VkImageView vkImageView,const ComposeLayer & composeLayer,uint32_t cbWidth,uint32_t cbHeight,uint32_t dstWidth,uint32_t dstHeight)36 std::unique_ptr<ComposeLayerVk> ComposeLayerVk::createFromHwc2ComposeLayer(
37     VkSampler vkSampler, VkImageView vkImageView,
38     const ComposeLayer &composeLayer, uint32_t cbWidth, uint32_t cbHeight,
39     uint32_t dstWidth, uint32_t dstHeight) {
40     // Calculate the posTransform and the texcoordTransform needed in the
41     // uniform of the Compositor.vert shader. The posTransform should transform
42     // the square(top = -1, bottom = 1, left = -1, right = 1) to the position
43     // where the layer should be drawn in NDC space given the composeLayer.
44     // texcoordTransform should transform the unit square(top = 0, bottom = 1,
45     // left = 0, right = 1) to where we should sample the layer in the
46     // normalized uv space given the composeLayer.
47     const hwc_rect_t &posRect = composeLayer.displayFrame;
48     const hwc_frect_t &texcoordRect = composeLayer.crop;
49 
50     int posWidth = posRect.right - posRect.left;
51     int posHeight = posRect.bottom - posRect.top;
52 
53     float posScaleX = float(posWidth) / dstWidth;
54     float posScaleY = float(posHeight) / dstHeight;
55 
56     float posTranslateX =
57         -1.0f + posScaleX + 2.0f * float(posRect.left) / dstWidth;
58     float posTranslateY =
59         -1.0f + posScaleY + 2.0f * float(posRect.top) / dstHeight;
60 
61     float texcoordScalX =
62         (texcoordRect.right - texcoordRect.left) / float(cbWidth);
63     float texCoordScaleY =
64         (texcoordRect.bottom - texcoordRect.top) / float(cbHeight);
65 
66     float texCoordTranslateX = texcoordRect.left / float(cbWidth);
67     float texCoordTranslateY = texcoordRect.top / float(cbHeight);
68 
69     float texcoordRotation = 0.0f;
70 
71     const float pi = glm::pi<float>();
72 
73     switch (composeLayer.transform) {
74         case HWC_TRANSFORM_ROT_90:
75             texcoordRotation = pi * 0.5f;
76             break;
77         case HWC_TRANSFORM_ROT_180:
78             texcoordRotation = pi;
79             break;
80         case HWC_TRANSFORM_ROT_270:
81             texcoordRotation = pi * 1.5f;
82             break;
83         case HWC_TRANSFORM_FLIP_H:
84             texcoordScalX *= -1.0f;
85             break;
86         case HWC_TRANSFORM_FLIP_V:
87             texCoordScaleY *= -1.0f;
88             break;
89         case HWC_TRANSFORM_FLIP_H_ROT_90:
90             texcoordRotation = pi * 0.5f;
91             texcoordScalX *= -1.0f;
92             break;
93         case HWC_TRANSFORM_FLIP_V_ROT_90:
94             texcoordRotation = pi * 0.5f;
95             texCoordScaleY *= -1.0f;
96             break;
97         default:
98             break;
99     }
100 
101     ComposeLayerVk::LayerTransform layerTransform = {
102         .pos =
103             glm::translate(glm::mat4(1.0f),
104                            glm::vec3(posTranslateX, posTranslateY, 0.0f)) *
105             glm::scale(glm::mat4(1.0f), glm::vec3(posScaleX, posScaleY, 1.0f)),
106         .texcoord = glm::translate(glm::mat4(1.0f),
107                                    glm::vec3(texCoordTranslateX,
108                                              texCoordTranslateY, 0.0f)) *
109                     glm::scale(glm::mat4(1.0f),
110                                glm::vec3(texcoordScalX, texCoordScaleY, 1.0f)) *
111                     glm::rotate(glm::mat4(1.0f), texcoordRotation,
112                                 glm::vec3(0.0f, 0.0f, 1.0f)),
113     };
114 
115     return std::unique_ptr<ComposeLayerVk>(
116         new ComposeLayerVk(vkSampler, vkImageView, layerTransform));
117 }
118 
Composition(std::vector<std::unique_ptr<ComposeLayerVk>> composeLayers)119 Composition::Composition(
120     std::vector<std::unique_ptr<ComposeLayerVk>> composeLayers)
121     : m_composeLayers(std::move(composeLayers)) {}
122 
123 const std::vector<CompositorVk::Vertex> CompositorVk::k_vertices = {
124     {{-1.0f, -1.0f}, {0.0f, 0.0f}},
125     {{1.0f, -1.0f}, {1.0f, 0.0f}},
126     {{1.0f, 1.0f}, {1.0f, 1.0f}},
127     {{-1.0f, 1.0f}, {0.0f, 1.0f}},
128 };
129 
130 const std::vector<uint16_t> CompositorVk::k_indices = {0, 1, 2, 2, 3, 0};
131 
132 const VkExtent2D CompositorVk::k_emptyCompositionExtent = {1, 1};
133 
create(const goldfish_vk::VulkanDispatch & vk,VkDevice vkDevice,VkPhysicalDevice vkPhysicalDevice,VkQueue vkQueue,VkFormat format,VkImageLayout initialLayout,VkImageLayout finalLayout,uint32_t width,uint32_t height,const std::vector<VkImageView> & renderTargets,VkCommandPool commandPool)134 std::unique_ptr<CompositorVk> CompositorVk::create(
135     const goldfish_vk::VulkanDispatch &vk, VkDevice vkDevice,
136     VkPhysicalDevice vkPhysicalDevice, VkQueue vkQueue, VkFormat format,
137     VkImageLayout initialLayout, VkImageLayout finalLayout, uint32_t width,
138     uint32_t height, const std::vector<VkImageView> &renderTargets,
139     VkCommandPool commandPool) {
140     auto res = std::unique_ptr<CompositorVk>(new CompositorVk(
141         vk, vkDevice, vkPhysicalDevice, vkQueue, commandPool, width, height));
142     res->setUpGraphicsPipeline(width, height, format, initialLayout,
143                                finalLayout);
144     res->setUpVertexBuffers();
145     res->setUpFramebuffers(renderTargets, width, height);
146     res->setUpUniformBuffers();
147     res->setUpDescriptorSets();
148     res->setUpCommandBuffers(width, height);
149     res->setUpEmptyComposition(format);
150     res->m_currentCompositions.resize(renderTargets.size());
151     for (auto i = 0; i < renderTargets.size(); i++) {
152         std::vector<std::unique_ptr<ComposeLayerVk>> emptyCompositionLayers;
153         res->setComposition(i, std::make_unique<Composition>(
154                                    std::move(emptyCompositionLayers)));
155     }
156     return res;
157 }
158 
CompositorVk(const goldfish_vk::VulkanDispatch & vk,VkDevice vkDevice,VkPhysicalDevice vkPhysicalDevice,VkQueue vkQueue,VkCommandPool vkCommandPool,uint32_t renderTargetWidth,uint32_t renderTargetHeight)159 CompositorVk::CompositorVk(const goldfish_vk::VulkanDispatch &vk,
160                            VkDevice vkDevice, VkPhysicalDevice vkPhysicalDevice,
161                            VkQueue vkQueue, VkCommandPool vkCommandPool,
162                            uint32_t renderTargetWidth,
163                            uint32_t renderTargetHeight)
164     : CompositorVkBase(vk, vkDevice, vkPhysicalDevice, vkQueue, vkCommandPool),
165       m_renderTargetWidth(renderTargetWidth),
166       m_renderTargetHeight(renderTargetHeight),
167       m_emptyCompositionVkImage(VK_NULL_HANDLE),
168       m_emptyCompositionVkDeviceMemory(VK_NULL_HANDLE),
169       m_emptyCompositionVkImageView(VK_NULL_HANDLE),
170       m_emptyCompositionVkSampler(VK_NULL_HANDLE),
171       m_currentCompositions(0),
172       m_uniformStorage({VK_NULL_HANDLE, VK_NULL_HANDLE, nullptr, 0}) {
173     (void)m_renderTargetWidth;
174     (void)m_renderTargetHeight;
175 
176     VkPhysicalDeviceProperties physicalDeviceProperties;
177     m_vk.vkGetPhysicalDeviceProperties(m_vkPhysicalDevice,
178                                        &physicalDeviceProperties);
179     auto alignment =
180         physicalDeviceProperties.limits.minUniformBufferOffsetAlignment;
181     m_uniformStorage.m_stride =
182         ((sizeof(UniformBufferObject) - 1) / alignment + 1) * alignment;
183 }
184 
~CompositorVk()185 CompositorVk::~CompositorVk() {
186     m_vk.vkDestroySampler(m_vkDevice, m_emptyCompositionVkSampler, nullptr);
187     m_vk.vkDestroyImageView(m_vkDevice, m_emptyCompositionVkImageView, nullptr);
188     m_vk.vkFreeMemory(m_vkDevice, m_emptyCompositionVkDeviceMemory, nullptr);
189     m_vk.vkDestroyImage(m_vkDevice, m_emptyCompositionVkImage, nullptr);
190     m_vk.vkDestroyDescriptorPool(m_vkDevice, m_vkDescriptorPool, nullptr);
191     m_vk.vkFreeCommandBuffers(m_vkDevice, m_vkCommandPool,
192                               static_cast<uint32_t>(m_vkCommandBuffers.size()),
193                               m_vkCommandBuffers.data());
194     if (m_uniformStorage.m_vkDeviceMemory != VK_NULL_HANDLE) {
195         m_vk.vkUnmapMemory(m_vkDevice, m_uniformStorage.m_vkDeviceMemory);
196     }
197     m_vk.vkDestroyBuffer(m_vkDevice, m_uniformStorage.m_vkBuffer, nullptr);
198     m_vk.vkFreeMemory(m_vkDevice, m_uniformStorage.m_vkDeviceMemory, nullptr);
199     while (!m_renderTargetVkFrameBuffers.empty()) {
200         m_vk.vkDestroyFramebuffer(m_vkDevice,
201                                   m_renderTargetVkFrameBuffers.back(), nullptr);
202         m_renderTargetVkFrameBuffers.pop_back();
203     }
204     m_vk.vkFreeMemory(m_vkDevice, m_vertexVkDeviceMemory, nullptr);
205     m_vk.vkDestroyBuffer(m_vkDevice, m_vertexVkBuffer, nullptr);
206     m_vk.vkFreeMemory(m_vkDevice, m_indexVkDeviceMemory, nullptr);
207     m_vk.vkDestroyBuffer(m_vkDevice, m_indexVkBuffer, nullptr);
208     m_vk.vkDestroyPipeline(m_vkDevice, m_graphicsVkPipeline, nullptr);
209     m_vk.vkDestroyRenderPass(m_vkDevice, m_vkRenderPass, nullptr);
210     m_vk.vkDestroyPipelineLayout(m_vkDevice, m_vkPipelineLayout, nullptr);
211     m_vk.vkDestroyDescriptorSetLayout(m_vkDevice, m_vkDescriptorSetLayout,
212                                       nullptr);
213 }
214 
setUpGraphicsPipeline(uint32_t width,uint32_t height,VkFormat renderTargetFormat,VkImageLayout initialLayout,VkImageLayout finalLayout)215 void CompositorVk::setUpGraphicsPipeline(uint32_t width, uint32_t height,
216                                          VkFormat renderTargetFormat,
217                                          VkImageLayout initialLayout,
218                                          VkImageLayout finalLayout) {
219     const std::vector<uint32_t> vertSpvBuff(
220         CompositorVkShader::compositorVertexShader,
221         std::end(CompositorVkShader::compositorVertexShader));
222     const std::vector<uint32_t> fragSpvBuff(
223         CompositorVkShader::compositorFragmentShader,
224         std::end(CompositorVkShader::compositorFragmentShader));
225     const auto vertShaderMod =
226         createShaderModule(m_vk, m_vkDevice, vertSpvBuff);
227     const auto fragShaderMod =
228         createShaderModule(m_vk, m_vkDevice, fragSpvBuff);
229 
230     VkPipelineShaderStageCreateInfo shaderStageCis[2] = {
231         {.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
232          .stage = VK_SHADER_STAGE_VERTEX_BIT,
233          .module = vertShaderMod,
234          .pName = "main"},
235         {.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
236          .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
237          .module = fragShaderMod,
238          .pName = "main"}};
239 
240     auto bindingDescription = Vertex::getBindingDescription();
241     auto attributeDescription = Vertex::getAttributeDescription();
242     VkPipelineVertexInputStateCreateInfo vertexInputStateCi = {
243         .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
244         .vertexBindingDescriptionCount = 1,
245         .pVertexBindingDescriptions = &bindingDescription,
246         .vertexAttributeDescriptionCount =
247             static_cast<uint32_t>(attributeDescription.size()),
248         .pVertexAttributeDescriptions = attributeDescription.data()};
249     VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCi = {
250         .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
251         .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
252         .primitiveRestartEnable = VK_FALSE,
253     };
254 
255     VkViewport viewport = {.x = 0.0f,
256                            .y = 0.0f,
257                            .width = static_cast<float>(width),
258                            .height = static_cast<float>(height),
259                            .minDepth = 0.0f,
260                            .maxDepth = 1.0f};
261 
262     VkRect2D scissor = {.offset = {0, 0}, .extent = {width, height}};
263 
264     VkPipelineViewportStateCreateInfo viewportStateCi = {
265         .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
266         .viewportCount = 1,
267         .pViewports = &viewport,
268         .scissorCount = 1,
269         .pScissors = &scissor};
270 
271     VkPipelineRasterizationStateCreateInfo rasterizerStateCi = {
272         .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
273         .depthClampEnable = VK_FALSE,
274         .rasterizerDiscardEnable = VK_FALSE,
275         .polygonMode = VK_POLYGON_MODE_FILL,
276         .cullMode = VK_CULL_MODE_BACK_BIT,
277         .frontFace = VK_FRONT_FACE_CLOCKWISE,
278         .depthBiasEnable = VK_FALSE,
279         .depthBiasConstantFactor = 0.0f,
280         .depthBiasClamp = 0.0f,
281         .depthBiasSlopeFactor = 0.0f,
282         .lineWidth = 1.0f};
283 
284     VkPipelineMultisampleStateCreateInfo multisampleStateCi = {
285         .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
286         .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
287         .sampleShadingEnable = VK_FALSE,
288         .minSampleShading = 1.0f,
289         .pSampleMask = nullptr,
290         .alphaToCoverageEnable = VK_FALSE,
291         .alphaToOneEnable = VK_FALSE};
292 
293     VkPipelineColorBlendAttachmentState colorBlendAttachment = {
294         .blendEnable = VK_TRUE,
295         .srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
296         .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
297         .colorBlendOp = VK_BLEND_OP_ADD,
298         .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
299         .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
300         .alphaBlendOp = VK_BLEND_OP_ADD,
301         .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
302                           VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
303 
304     VkPipelineColorBlendStateCreateInfo colorBlendStateCi = {
305         .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
306         .logicOpEnable = VK_FALSE,
307         .attachmentCount = 1,
308         .pAttachments = &colorBlendAttachment};
309 
310     VkDescriptorSetLayoutBinding layoutBindings[2] = {
311         {.binding = 0,
312          .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
313          .descriptorCount = 1,
314          .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
315          .pImmutableSamplers = nullptr},
316         {.binding = 1,
317          .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
318          .descriptorCount = 1,
319          .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
320          .pImmutableSamplers = nullptr}};
321 
322     VkDescriptorBindingFlagsEXT bindingFlags[] = {
323         VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT, 0};
324     VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlagsCi = {
325         .sType =
326             VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT,
327         .bindingCount = static_cast<uint32_t>(std::size(bindingFlags)),
328         .pBindingFlags = bindingFlags,
329     };
330     VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCi = {
331         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
332         .pNext = &bindingFlagsCi,
333         .flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT,
334         .bindingCount = static_cast<uint32_t>(std::size(layoutBindings)),
335         .pBindings = layoutBindings};
336     VK_CHECK(m_vk.vkCreateDescriptorSetLayout(
337         m_vkDevice, &descriptorSetLayoutCi, nullptr, &m_vkDescriptorSetLayout));
338 
339     VkPipelineLayoutCreateInfo pipelineLayoutCi = {
340         .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
341         .setLayoutCount = 1,
342         .pSetLayouts = &m_vkDescriptorSetLayout,
343         .pushConstantRangeCount = 0};
344 
345     VK_CHECK(m_vk.vkCreatePipelineLayout(m_vkDevice, &pipelineLayoutCi, nullptr,
346                                          &m_vkPipelineLayout));
347 
348     VkAttachmentDescription colorAttachment = {
349         .format = renderTargetFormat,
350         .samples = VK_SAMPLE_COUNT_1_BIT,
351         .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
352         .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
353         .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
354         .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
355         .initialLayout = initialLayout,
356         .finalLayout = finalLayout};
357 
358     VkAttachmentReference colorAttachmentRef = {
359         .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
360 
361     VkSubpassDescription subpass = {
362         .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
363         .colorAttachmentCount = 1,
364         .pColorAttachments = &colorAttachmentRef};
365 
366     // TODO: to support multiple layer composition, we could run the same render
367     // pass for multiple time. In that case, we should use explicit
368     // VkImageMemoryBarriers to transform the image layout instead of relying on
369     // renderpass to do it.
370     VkSubpassDependency subpassDependency = {
371         .srcSubpass = VK_SUBPASS_EXTERNAL,
372         .dstSubpass = 0,
373         .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
374         .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
375         .srcAccessMask = 0,
376         .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT};
377 
378     VkRenderPassCreateInfo renderPassCi = {
379         .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
380         .attachmentCount = 1,
381         .pAttachments = &colorAttachment,
382         .subpassCount = 1,
383         .pSubpasses = &subpass,
384         .dependencyCount = 1,
385         .pDependencies = &subpassDependency};
386 
387     VK_CHECK(m_vk.vkCreateRenderPass(m_vkDevice, &renderPassCi, nullptr,
388                                      &m_vkRenderPass));
389 
390     VkGraphicsPipelineCreateInfo graphicsPipelineCi = {
391         .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
392         .stageCount = static_cast<uint32_t>(std::size(shaderStageCis)),
393         .pStages = shaderStageCis,
394         .pVertexInputState = &vertexInputStateCi,
395         .pInputAssemblyState = &inputAssemblyStateCi,
396         .pViewportState = &viewportStateCi,
397         .pRasterizationState = &rasterizerStateCi,
398         .pMultisampleState = &multisampleStateCi,
399         .pDepthStencilState = nullptr,
400         .pColorBlendState = &colorBlendStateCi,
401         .pDynamicState = nullptr,
402         .layout = m_vkPipelineLayout,
403         .renderPass = m_vkRenderPass,
404         .subpass = 0,
405         .basePipelineHandle = VK_NULL_HANDLE,
406         .basePipelineIndex = -1};
407 
408     VK_CHECK(m_vk.vkCreateGraphicsPipelines(m_vkDevice, VK_NULL_HANDLE, 1,
409                                             &graphicsPipelineCi, nullptr,
410                                             &m_graphicsVkPipeline));
411 
412     m_vk.vkDestroyShaderModule(m_vkDevice, vertShaderMod, nullptr);
413     m_vk.vkDestroyShaderModule(m_vkDevice, fragShaderMod, nullptr);
414 }
415 
416 // Create a VkBuffer and a bound VkDeviceMemory. When the specified memory type
417 // can't be found, return std::nullopt. When Vulkan call fails, terminate the
418 // program.
createBuffer(VkDeviceSize size,VkBufferUsageFlags usage,VkMemoryPropertyFlags memProperty) const419 std::optional<std::tuple<VkBuffer, VkDeviceMemory>> CompositorVk::createBuffer(
420     VkDeviceSize size, VkBufferUsageFlags usage,
421     VkMemoryPropertyFlags memProperty) const {
422     VkBufferCreateInfo bufferCi = {
423         .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
424         .size = size,
425         .usage = usage,
426         .sharingMode = VK_SHARING_MODE_EXCLUSIVE};
427     VkBuffer resBuffer;
428     VK_CHECK(m_vk.vkCreateBuffer(m_vkDevice, &bufferCi, nullptr, &resBuffer));
429     VkMemoryRequirements memRequirements;
430     m_vk.vkGetBufferMemoryRequirements(m_vkDevice, resBuffer, &memRequirements);
431     VkPhysicalDeviceMemoryProperties physicalMemProperties;
432     m_vk.vkGetPhysicalDeviceMemoryProperties(m_vkPhysicalDevice,
433                                              &physicalMemProperties);
434     auto maybeMemoryTypeIndex =
435         findMemoryType(memRequirements.memoryTypeBits, memProperty);
436     if (!maybeMemoryTypeIndex.has_value()) {
437         m_vk.vkDestroyBuffer(m_vkDevice, resBuffer, nullptr);
438         return std::nullopt;
439     }
440     VkMemoryAllocateInfo memAllocInfo = {
441         .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
442         .allocationSize = memRequirements.size,
443         .memoryTypeIndex = maybeMemoryTypeIndex.value()};
444     VkDeviceMemory resMemory;
445     VK_CHECK(
446         m_vk.vkAllocateMemory(m_vkDevice, &memAllocInfo, nullptr, &resMemory));
447     VK_CHECK(m_vk.vkBindBufferMemory(m_vkDevice, resBuffer, resMemory, 0));
448     return std::make_tuple(resBuffer, resMemory);
449 }
450 
createStagingBufferWithData(const void * srcData,VkDeviceSize size) const451 std::tuple<VkBuffer, VkDeviceMemory> CompositorVk::createStagingBufferWithData(
452     const void *srcData, VkDeviceSize size) const {
453     auto [stagingBuffer, stagingBufferMemory] =
454         createBuffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
455                      VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
456                          VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
457             .value();
458     void *data;
459     VK_CHECK(
460         m_vk.vkMapMemory(m_vkDevice, stagingBufferMemory, 0, size, 0, &data));
461     memcpy(data, srcData, size);
462     m_vk.vkUnmapMemory(m_vkDevice, stagingBufferMemory);
463     return std::make_tuple(stagingBuffer, stagingBufferMemory);
464 }
465 
copyBuffer(VkBuffer src,VkBuffer dst,VkDeviceSize size) const466 void CompositorVk::copyBuffer(VkBuffer src, VkBuffer dst,
467                               VkDeviceSize size) const {
468     runSingleTimeCommands(m_vkQueue, [&, this](const auto &cmdBuff) {
469         VkBufferCopy copyRegion = {};
470         copyRegion.srcOffset = 0;
471         copyRegion.dstOffset = 0;
472         copyRegion.size = size;
473         m_vk.vkCmdCopyBuffer(cmdBuff, src, dst, 1, &copyRegion);
474     });
475 }
476 
setUpVertexBuffers()477 void CompositorVk::setUpVertexBuffers() {
478     const VkDeviceSize vertexBufferSize =
479         sizeof(k_vertices[0]) * k_vertices.size();
480     std::tie(m_vertexVkBuffer, m_vertexVkDeviceMemory) =
481         createBuffer(vertexBufferSize,
482                      VK_BUFFER_USAGE_TRANSFER_DST_BIT |
483                          VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
484                      VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
485             .value();
486     auto [vertexStagingBuffer, vertexStagingBufferMemory] =
487         createStagingBufferWithData(k_vertices.data(), vertexBufferSize);
488     copyBuffer(vertexStagingBuffer, m_vertexVkBuffer, vertexBufferSize);
489     m_vk.vkDestroyBuffer(m_vkDevice, vertexStagingBuffer, nullptr);
490     m_vk.vkFreeMemory(m_vkDevice, vertexStagingBufferMemory, nullptr);
491 
492     VkDeviceSize indexBufferSize = sizeof(k_indices[0]) * k_indices.size();
493     auto [indexStagingBuffer, indexStagingBufferMemory] =
494         createStagingBufferWithData(k_indices.data(), indexBufferSize);
495     std::tie(m_indexVkBuffer, m_indexVkDeviceMemory) =
496         createBuffer(
497             indexBufferSize,
498             VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
499             VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
500             .value();
501     copyBuffer(indexStagingBuffer, m_indexVkBuffer, indexBufferSize);
502     m_vk.vkDestroyBuffer(m_vkDevice, indexStagingBuffer, nullptr);
503     m_vk.vkFreeMemory(m_vkDevice, indexStagingBufferMemory, nullptr);
504 }
505 
setUpFramebuffers(const std::vector<VkImageView> & renderTargets,uint32_t width,uint32_t height)506 void CompositorVk::setUpFramebuffers(
507     const std::vector<VkImageView> &renderTargets, uint32_t width,
508     uint32_t height) {
509     for (size_t i = 0; i < renderTargets.size(); i++) {
510         VkFramebufferCreateInfo fbCi = {
511             .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
512             .renderPass = m_vkRenderPass,
513             .attachmentCount = 1,
514             .pAttachments = &renderTargets[i],
515             .width = width,
516             .height = height,
517             .layers = 1};
518         VkFramebuffer framebuffer;
519         VK_CHECK(
520             m_vk.vkCreateFramebuffer(m_vkDevice, &fbCi, nullptr, &framebuffer));
521         m_renderTargetVkFrameBuffers.push_back(framebuffer);
522     }
523 }
524 
525 // We don't see composition requests with more than 10 layers from the guest for
526 // now. If we see rendering error or significant time spent on updating
527 // descriptors in setComposition, we should tune this number.
528 static const uint32_t kMaxLayersPerFrame = 10;
529 
setUpDescriptorSets()530 void CompositorVk::setUpDescriptorSets() {
531     uint32_t numOfFrames =
532         static_cast<uint32_t>(m_renderTargetVkFrameBuffers.size());
533 
534     uint32_t setsPerDescriptorType = numOfFrames * kMaxLayersPerFrame;
535 
536     VkDescriptorPoolSize descriptorPoolSizes[2] = {
537         {.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
538          .descriptorCount = setsPerDescriptorType},
539         {.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
540          .descriptorCount = setsPerDescriptorType}};
541 
542     VkDescriptorPoolCreateInfo descriptorPoolCi = {
543         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
544         .flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT,
545         .maxSets = static_cast<uint32_t>(setsPerDescriptorType),
546         .poolSizeCount = static_cast<uint32_t>(std::size(descriptorPoolSizes)),
547         .pPoolSizes = descriptorPoolSizes};
548     VK_CHECK(m_vk.vkCreateDescriptorPool(m_vkDevice, &descriptorPoolCi, nullptr,
549                                          &m_vkDescriptorPool));
550     std::vector<VkDescriptorSetLayout> layouts(setsPerDescriptorType,
551                                                m_vkDescriptorSetLayout);
552     VkDescriptorSetAllocateInfo descriptorSetAllocInfo = {
553         .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
554         .descriptorPool = m_vkDescriptorPool,
555         .descriptorSetCount = setsPerDescriptorType,
556         .pSetLayouts = layouts.data()};
557     m_vkDescriptorSets.resize(setsPerDescriptorType);
558     VK_CHECK(m_vk.vkAllocateDescriptorSets(m_vkDevice, &descriptorSetAllocInfo,
559                                            m_vkDescriptorSets.data()));
560     for (size_t i = 0; i < setsPerDescriptorType; i++) {
561         VkDescriptorBufferInfo bufferInfo = {
562             .buffer = m_uniformStorage.m_vkBuffer,
563             .offset = i * m_uniformStorage.m_stride,
564             .range = sizeof(UniformBufferObject)};
565         VkWriteDescriptorSet descriptorSetWrite = {
566             .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
567             .dstSet = m_vkDescriptorSets[i],
568             .dstBinding = 1,
569             .dstArrayElement = 0,
570             .descriptorCount = 1,
571             .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
572             .pBufferInfo = &bufferInfo};
573         m_vk.vkUpdateDescriptorSets(m_vkDevice, 1, &descriptorSetWrite, 0,
574                                     nullptr);
575     }
576 }
577 
setUpCommandBuffers(uint32_t width,uint32_t height)578 void CompositorVk::setUpCommandBuffers(uint32_t width, uint32_t height) {
579     VkCommandBufferAllocateInfo cmdBuffAllocInfo = {
580         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
581         .commandPool = m_vkCommandPool,
582         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
583         .commandBufferCount =
584             static_cast<uint32_t>(m_renderTargetVkFrameBuffers.size())};
585     m_vkCommandBuffers.resize(m_renderTargetVkFrameBuffers.size());
586     VK_CHECK(m_vk.vkAllocateCommandBuffers(m_vkDevice, &cmdBuffAllocInfo,
587                                            m_vkCommandBuffers.data()));
588 
589     for (size_t i = 0; i < m_vkCommandBuffers.size(); i++) {
590         VkCommandBufferBeginInfo beginInfo = {
591             beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
592         const auto &cmdBuffer = m_vkCommandBuffers[i];
593         VK_CHECK(m_vk.vkBeginCommandBuffer(cmdBuffer, &beginInfo));
594 
595         VkClearValue clearColor = {
596             .color = {.float32 = {0.0f, 0.0f, 0.0f, 1.0f}}};
597         VkRenderPassBeginInfo renderPassBeginInfo = {
598             .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
599             .renderPass = m_vkRenderPass,
600             .framebuffer = m_renderTargetVkFrameBuffers[i],
601             .renderArea = {.offset = {0, 0}, .extent = {width, height}},
602             .clearValueCount = 1,
603             .pClearValues = &clearColor};
604         m_vk.vkCmdBeginRenderPass(cmdBuffer, &renderPassBeginInfo,
605                                   VK_SUBPASS_CONTENTS_INLINE);
606         m_vk.vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
607                                m_graphicsVkPipeline);
608         VkDeviceSize offsets[] = {0};
609         m_vk.vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &m_vertexVkBuffer,
610                                     offsets);
611         m_vk.vkCmdBindIndexBuffer(cmdBuffer, m_indexVkBuffer, 0,
612                                   VK_INDEX_TYPE_UINT16);
613         for (uint32_t j = 0; j < kMaxLayersPerFrame; ++j) {
614             m_vk.vkCmdBindDescriptorSets(
615                 cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_vkPipelineLayout,
616                 0, 1, &m_vkDescriptorSets[i * kMaxLayersPerFrame + j], 0,
617                 nullptr);
618             m_vk.vkCmdDrawIndexed(
619                 cmdBuffer, static_cast<uint32_t>(k_indices.size()), 1, 0, 0, 0);
620         }
621         m_vk.vkCmdEndRenderPass(cmdBuffer);
622 
623         VK_CHECK(m_vk.vkEndCommandBuffer(cmdBuffer));
624     }
625 }
626 
setUpEmptyComposition(VkFormat format)627 void CompositorVk::setUpEmptyComposition(VkFormat format) {
628     VkImageCreateInfo imageCi = {
629         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
630         .flags = 0,
631         .imageType = VK_IMAGE_TYPE_2D,
632         .format = format,
633         .extent = {.width = k_emptyCompositionExtent.width,
634                    .height = k_emptyCompositionExtent.height,
635                    .depth = 1},
636         .mipLevels = 1,
637         .arrayLayers = 1,
638         .samples = VK_SAMPLE_COUNT_1_BIT,
639         .tiling = VK_IMAGE_TILING_OPTIMAL,
640         .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
641         .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
642         .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED};
643     VK_CHECK(m_vk.vkCreateImage(m_vkDevice, &imageCi, nullptr,
644                                 &m_emptyCompositionVkImage));
645 
646     VkMemoryRequirements memRequirements;
647     m_vk.vkGetImageMemoryRequirements(m_vkDevice, m_emptyCompositionVkImage,
648                                       &memRequirements);
649     VkMemoryAllocateInfo allocInfo = {
650         .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
651         .allocationSize = memRequirements.size,
652         .memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits,
653                                           VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
654                                .value()};
655     VK_CHECK(m_vk.vkAllocateMemory(m_vkDevice, &allocInfo, nullptr,
656                                    &m_emptyCompositionVkDeviceMemory));
657     VK_CHECK(m_vk.vkBindImageMemory(m_vkDevice, m_emptyCompositionVkImage,
658                                     m_emptyCompositionVkDeviceMemory, 0));
659     runSingleTimeCommands(m_vkQueue, [&, this](const auto &cmdBuff) {
660         recordImageLayoutTransformCommands(
661             cmdBuff, m_emptyCompositionVkImage, VK_IMAGE_LAYOUT_UNDEFINED,
662             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
663         VkClearColorValue clearColor = {.float32 = {0.0, 0.0, 0.0, 1.0}};
664         VkImageSubresourceRange range = {
665             .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
666             .baseMipLevel = 0,
667             .levelCount = 1,
668             .baseArrayLayer = 0,
669             .layerCount = 1};
670         m_vk.vkCmdClearColorImage(cmdBuff, m_emptyCompositionVkImage,
671                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
672                                   &clearColor, 1, &range);
673         recordImageLayoutTransformCommands(
674             cmdBuff, m_emptyCompositionVkImage,
675             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
676             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
677     });
678 
679     VkImageViewCreateInfo imageViewCi = {
680         .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
681         .image = m_emptyCompositionVkImage,
682         .viewType = VK_IMAGE_VIEW_TYPE_2D,
683         .format = format,
684         .components = {.r = VK_COMPONENT_SWIZZLE_IDENTITY,
685                        .g = VK_COMPONENT_SWIZZLE_IDENTITY,
686                        .b = VK_COMPONENT_SWIZZLE_IDENTITY,
687                        .a = VK_COMPONENT_SWIZZLE_IDENTITY},
688         .subresourceRange{.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
689                           .baseMipLevel = 0,
690                           .levelCount = 1,
691                           .baseArrayLayer = 0,
692                           .layerCount = 1}};
693     VK_CHECK(m_vk.vkCreateImageView(m_vkDevice, &imageViewCi, nullptr,
694                                     &m_emptyCompositionVkImageView));
695 
696     VkSamplerCreateInfo samplerCi = {
697         .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
698         .magFilter = VK_FILTER_LINEAR,
699         .minFilter = VK_FILTER_LINEAR,
700         .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
701         .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
702         .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
703         .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
704         .mipLodBias = 0.0f,
705         .anisotropyEnable = VK_FALSE,
706         .maxAnisotropy = 1.0f,
707         .compareEnable = VK_FALSE,
708         .compareOp = VK_COMPARE_OP_ALWAYS,
709         .minLod = 0.0f,
710         .maxLod = 0.0f,
711         .borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK,
712         .unnormalizedCoordinates = VK_FALSE};
713     VK_CHECK(m_vk.vkCreateSampler(m_vkDevice, &samplerCi, nullptr,
714                                   &m_emptyCompositionVkSampler));
715 }
716 
setUpUniformBuffers()717 void CompositorVk::setUpUniformBuffers() {
718     auto numOfFrames = m_renderTargetVkFrameBuffers.size();
719     VkDeviceSize size =
720         m_uniformStorage.m_stride * numOfFrames * kMaxLayersPerFrame;
721     auto maybeBuffer = createBuffer(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
722                                     VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
723                                         VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
724                                         VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
725     auto buffer = std::make_tuple<VkBuffer, VkDeviceMemory>(VK_NULL_HANDLE,
726                                                             VK_NULL_HANDLE);
727     if (maybeBuffer.has_value()) {
728         buffer = maybeBuffer.value();
729     } else {
730         buffer = createBuffer(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
731                               VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
732                                   VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
733                      .value();
734     }
735     std::tie(m_uniformStorage.m_vkBuffer, m_uniformStorage.m_vkDeviceMemory) =
736         buffer;
737     VK_CHECK(m_vk.vkMapMemory(
738         m_vkDevice, m_uniformStorage.m_vkDeviceMemory, 0, size, 0,
739         reinterpret_cast<void **>(&m_uniformStorage.m_data)));
740 }
741 
validatePhysicalDeviceFeatures(const VkPhysicalDeviceFeatures2 & features)742 bool CompositorVk::validatePhysicalDeviceFeatures(
743     const VkPhysicalDeviceFeatures2 &features) {
744     auto descIndexingFeatures =
745         vk_find_struct<VkPhysicalDeviceDescriptorIndexingFeaturesEXT>(
746             &features);
747     if (descIndexingFeatures == nullptr) {
748         return false;
749     }
750     return descIndexingFeatures->descriptorBindingSampledImageUpdateAfterBind ==
751            VK_TRUE;
752 }
753 
validateQueueFamilyProperties(const VkQueueFamilyProperties & properties)754 bool CompositorVk::validateQueueFamilyProperties(
755     const VkQueueFamilyProperties &properties) {
756     return properties.queueFlags & VK_QUEUE_GRAPHICS_BIT;
757 }
758 
enablePhysicalDeviceFeatures(VkPhysicalDeviceFeatures2 & features)759 bool CompositorVk::enablePhysicalDeviceFeatures(
760     VkPhysicalDeviceFeatures2 &features) {
761     auto descIndexingFeatures =
762         vk_find_struct<VkPhysicalDeviceDescriptorIndexingFeaturesEXT>(
763             &features);
764     if (descIndexingFeatures == nullptr) {
765         return false;
766     }
767     descIndexingFeatures->descriptorBindingSampledImageUpdateAfterBind =
768         VK_TRUE;
769     return true;
770 }
771 
getRequiredDeviceExtensions()772 std::vector<const char *> CompositorVk::getRequiredDeviceExtensions() {
773     return {VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME};
774 }
775 
getCommandBuffer(uint32_t i) const776 VkCommandBuffer CompositorVk::getCommandBuffer(uint32_t i) const {
777     return m_vkCommandBuffers[i];
778 }
779 
setComposition(uint32_t rtIndex,std::unique_ptr<Composition> && composition)780 void CompositorVk::setComposition(uint32_t rtIndex,
781                                   std::unique_ptr<Composition> &&composition) {
782     m_currentCompositions[rtIndex] = std::move(composition);
783     const auto &currentComposition = *m_currentCompositions[rtIndex];
784     if (currentComposition.m_composeLayers.size() > kMaxLayersPerFrame) {
785         ERR("%s(%s:%d): CompositorVk can't compose more than %" PRIu32
786             " layers, %" PRIu32 " layers asked.\n",
787             __FUNCTION__, __FILE__, static_cast<int>(__LINE__),
788             kMaxLayersPerFrame,
789             static_cast<uint32_t>(currentComposition.m_composeLayers.size()));
790     }
791 
792     memset(reinterpret_cast<uint8_t *>(m_uniformStorage.m_data) +
793                (rtIndex * kMaxLayersPerFrame + 0) * m_uniformStorage.m_stride,
794            0, sizeof(ComposeLayerVk::LayerTransform) * kMaxLayersPerFrame);
795 
796     std::vector<VkDescriptorImageInfo> imageInfos(
797         currentComposition.m_composeLayers.size());
798     std::vector<VkWriteDescriptorSet> descriptorWrites;
799     for (size_t i = 0; i < currentComposition.m_composeLayers.size(); ++i) {
800         const auto &layer = currentComposition.m_composeLayers[i];
801         imageInfos[i] = VkDescriptorImageInfo(
802             {.sampler = layer->m_vkSampler,
803              .imageView = layer->m_vkImageView,
804              .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL});
805         const VkDescriptorImageInfo &imageInfo = imageInfos[i];
806         descriptorWrites.emplace_back(VkWriteDescriptorSet(
807             {.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
808              .dstSet = m_vkDescriptorSets[rtIndex * kMaxLayersPerFrame + i],
809              .dstBinding = 0,
810              .dstArrayElement = 0,
811              .descriptorCount = 1,
812              .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
813              .pImageInfo = &imageInfo}));
814         memcpy(
815             reinterpret_cast<uint8_t *>(m_uniformStorage.m_data) +
816                 (rtIndex * kMaxLayersPerFrame + i) * m_uniformStorage.m_stride,
817             &layer->m_layerTransform, sizeof(ComposeLayerVk::LayerTransform));
818     }
819     m_vk.vkUpdateDescriptorSets(m_vkDevice, descriptorWrites.size(),
820                                 descriptorWrites.data(), 0, nullptr);
821 
822     for (size_t i = currentComposition.m_composeLayers.size();
823          i < kMaxLayersPerFrame; ++i) {
824         VkDescriptorImageInfo imageInfo = {
825             .sampler = m_emptyCompositionVkSampler,
826             .imageView = m_emptyCompositionVkImageView,
827             .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
828         VkWriteDescriptorSet descriptorSetWrite = {
829             .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
830             .dstSet = m_vkDescriptorSets[rtIndex * kMaxLayersPerFrame + i],
831             .dstBinding = 0,
832             .dstArrayElement = 0,
833             .descriptorCount = 1,
834             .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
835             .pImageInfo = &imageInfo};
836         m_vk.vkUpdateDescriptorSets(m_vkDevice, 1, &descriptorSetWrite, 0,
837                                     nullptr);
838     }
839 }
840 
getBindingDescription()841 VkVertexInputBindingDescription CompositorVk::Vertex::getBindingDescription() {
842     return {.binding = 0,
843             .stride = sizeof(struct Vertex),
844             .inputRate = VK_VERTEX_INPUT_RATE_VERTEX};
845 }
846 
847 std::array<VkVertexInputAttributeDescription, 2>
getAttributeDescription()848 CompositorVk::Vertex::getAttributeDescription() {
849     return {VkVertexInputAttributeDescription{
850                 .location = 0,
851                 .binding = 0,
852                 .format = VK_FORMAT_R32G32_SFLOAT,
853                 .offset = offsetof(struct Vertex, pos)},
854             VkVertexInputAttributeDescription{
855                 .location = 1,
856                 .binding = 0,
857                 .format = VK_FORMAT_R32G32_SFLOAT,
858                 .offset = offsetof(struct Vertex, texPos)}};
859 }
860