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