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