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, ©Region);
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 ¤tComposition = *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