1 #include "DisplayVk.h"
2
3 #include <glm/glm.hpp>
4 #include <glm/gtx/matrix_transform_2d.hpp>
5
6 #include "ErrorLog.h"
7
DisplayVk(const goldfish_vk::VulkanDispatch & vk,VkPhysicalDevice vkPhysicalDevice,uint32_t swapChainQueueFamilyIndex,uint32_t compositorQueueFamilyIndex,VkDevice vkDevice,VkQueue compositorVkQueue,VkQueue swapChainVkqueue)8 DisplayVk::DisplayVk(const goldfish_vk::VulkanDispatch &vk,
9 VkPhysicalDevice vkPhysicalDevice,
10 uint32_t swapChainQueueFamilyIndex,
11 uint32_t compositorQueueFamilyIndex, VkDevice vkDevice,
12 VkQueue compositorVkQueue, VkQueue swapChainVkqueue)
13 : m_vk(vk),
14 m_vkPhysicalDevice(vkPhysicalDevice),
15 m_swapChainQueueFamilyIndex(swapChainQueueFamilyIndex),
16 m_compositorQueueFamilyIndex(compositorQueueFamilyIndex),
17 m_vkDevice(vkDevice),
18 m_compositorVkQueue(compositorVkQueue),
19 m_swapChainVkQueue(swapChainVkqueue),
20 m_vkCommandPool(VK_NULL_HANDLE),
21 m_swapChainStateVk(nullptr),
22 m_compositorVk(nullptr),
23 m_surfaceState(nullptr),
24 m_canComposite() {
25 // TODO(kaiyili): validate the capabilites of the passed in Vulkan
26 // components.
27 VkCommandPoolCreateInfo commandPoolCi = {
28 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
29 .queueFamilyIndex = m_compositorQueueFamilyIndex,
30 };
31 VK_CHECK(m_vk.vkCreateCommandPool(m_vkDevice, &commandPoolCi, nullptr,
32 &m_vkCommandPool));
33 VkFenceCreateInfo fenceCi = {.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
34 .flags = VK_FENCE_CREATE_SIGNALED_BIT};
35 VK_CHECK(m_vk.vkCreateFence(m_vkDevice, &fenceCi, nullptr,
36 &m_frameDrawCompleteFence));
37 VkSemaphoreCreateInfo semaphoreCi = {
38 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
39 VK_CHECK(m_vk.vkCreateSemaphore(m_vkDevice, &semaphoreCi, nullptr,
40 &m_imageReadySem));
41 VK_CHECK(m_vk.vkCreateSemaphore(m_vkDevice, &semaphoreCi, nullptr,
42 &m_frameDrawCompleteSem));
43
44 VkSamplerCreateInfo samplerCi = {
45 .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
46 .magFilter = VK_FILTER_NEAREST,
47 .minFilter = VK_FILTER_NEAREST,
48 .mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
49 .addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
50 .addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
51 .addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
52 .mipLodBias = 0.0f,
53 .anisotropyEnable = VK_FALSE,
54 .maxAnisotropy = 1.0f,
55 .compareEnable = VK_FALSE,
56 .compareOp = VK_COMPARE_OP_ALWAYS,
57 .minLod = 0.0f,
58 .maxLod = 0.0f,
59 .borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK,
60 .unnormalizedCoordinates = VK_FALSE};
61 VK_CHECK(m_vk.vkCreateSampler(m_vkDevice, &samplerCi, nullptr,
62 &m_compositionVkSampler));
63 }
64
~DisplayVk()65 DisplayVk::~DisplayVk() {
66 m_vk.vkDestroySampler(m_vkDevice, m_compositionVkSampler, nullptr);
67 m_vk.vkDestroySemaphore(m_vkDevice, m_imageReadySem, nullptr);
68 m_vk.vkDestroySemaphore(m_vkDevice, m_frameDrawCompleteSem, nullptr);
69 m_vk.vkDestroyFence(m_vkDevice, m_frameDrawCompleteFence, nullptr);
70 m_compositorVk.reset();
71 m_swapChainStateVk.reset();
72 m_vk.vkDestroyCommandPool(m_vkDevice, m_vkCommandPool, nullptr);
73 }
74
bindToSurface(VkSurfaceKHR surface,uint32_t width,uint32_t height)75 void DisplayVk::bindToSurface(VkSurfaceKHR surface, uint32_t width,
76 uint32_t height) {
77 if (!SwapChainStateVk::validateQueueFamilyProperties(
78 m_vk, m_vkPhysicalDevice, surface, m_swapChainQueueFamilyIndex)) {
79 ERR("%s(%s:%d): DisplayVk can't create VkSwapchainKHR with given "
80 "VkDevice and VkSurfaceKHR.\n",
81 __FUNCTION__, __FILE__, static_cast<int>(__LINE__));
82 ::abort();
83 }
84 auto swapChainCi = SwapChainStateVk::createSwapChainCi(
85 m_vk, surface, m_vkPhysicalDevice, width, height,
86 {m_swapChainQueueFamilyIndex, m_compositorQueueFamilyIndex});
87 VkFormatProperties formatProps;
88 m_vk.vkGetPhysicalDeviceFormatProperties(
89 m_vkPhysicalDevice, swapChainCi->imageFormat, &formatProps);
90 if (!(formatProps.optimalTilingFeatures &
91 VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
92 ERR("%s(%s:%d): DisplayVk: The image format chosen for present VkImage "
93 "can't be used as the color attachment, and therefore can't be "
94 "used as the render target of CompositorVk.\n",
95 __FUNCTION__, __FILE__, static_cast<int>(__LINE__));
96 ::abort();
97 }
98 m_swapChainStateVk =
99 std::make_unique<SwapChainStateVk>(m_vk, m_vkDevice, *swapChainCi);
100 m_compositorVk = CompositorVk::create(
101 m_vk, m_vkDevice, m_vkPhysicalDevice, m_compositorVkQueue,
102 m_swapChainStateVk->getFormat(), VK_IMAGE_LAYOUT_UNDEFINED,
103 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, width, height,
104 m_swapChainStateVk->getVkImageViews(), m_vkCommandPool);
105 auto surfaceState = std::make_unique<SurfaceState>();
106 surfaceState->m_height = height;
107 surfaceState->m_width = width;
108 m_surfaceState = std::move(surfaceState);
109 }
110
createDisplayBuffer(VkImage image,VkFormat format,uint32_t width,uint32_t height)111 std::shared_ptr<DisplayVk::DisplayBufferInfo> DisplayVk::createDisplayBuffer(
112 VkImage image, VkFormat format, uint32_t width, uint32_t height) {
113 return std::shared_ptr<DisplayBufferInfo>(
114 new DisplayBufferInfo(m_vk, m_vkDevice, width, height, format, image));
115 }
116
post(const std::shared_ptr<DisplayBufferInfo> & displayBufferPtr)117 void DisplayVk::post(
118 const std::shared_ptr<DisplayBufferInfo> &displayBufferPtr) {
119 if (!displayBufferPtr) {
120 fprintf(stderr, "%s: warning: null ptr passed to post buffer\n",
121 __func__);
122 return;
123 }
124 ComposeLayer composeLayer = {
125 0,
126 HWC2_COMPOSITION_DEVICE,
127 {0, 0, static_cast<int>(displayBufferPtr->m_width),
128 static_cast<int>(displayBufferPtr->m_height)},
129 {0.0f, 0.0f, static_cast<float>(displayBufferPtr->m_width),
130 static_cast<float>(displayBufferPtr->m_height)},
131 HWC2_BLEND_MODE_PREMULTIPLIED,
132 1.0f,
133 {0, 0, 0, 0},
134 static_cast<hwc_transform_t>(0) /* transform */
135 };
136 compose(1, &composeLayer, {std::move(displayBufferPtr)});
137 }
138
compose(uint32_t numLayers,const ComposeLayer layers[],const std::vector<std::shared_ptr<DisplayBufferInfo>> & composeBuffers)139 void DisplayVk::compose(
140 uint32_t numLayers, const ComposeLayer layers[],
141 const std::vector<std::shared_ptr<DisplayBufferInfo>> &composeBuffers) {
142 if (!m_swapChainStateVk || !m_compositorVk || !m_surfaceState) {
143 ERR("%s(%s:%d): Haven't bound to a surface, can't compose color "
144 "buffer.\n",
145 __FUNCTION__, __FILE__, static_cast<int>(__LINE__));
146 return;
147 }
148
149 auto &surfaceState = *m_surfaceState;
150 std::vector<std::unique_ptr<ComposeLayerVk>> composeLayers;
151 for (int i = 0; i < numLayers; ++i) {
152 if (!composeBuffers[i]) {
153 fprintf(
154 stderr,
155 "%s: warning: null ptr passed to compose buffer for layer %d\n",
156 __func__, i);
157 continue;
158 }
159 const auto &db = *composeBuffers[i];
160 if (!canComposite(db.m_vkFormat)) {
161 ERR("%s(%s:%d): Can't composite the DisplayBuffer(0x%" PRIxPTR
162 "). The image(VkFormat = %" PRIu64 ") can't be sampled from.\n",
163 __FUNCTION__, __FILE__, static_cast<int>(__LINE__),
164 reinterpret_cast<uintptr_t>(&db),
165 static_cast<uint64_t>(db.m_vkFormat));
166 continue;
167 }
168 auto layer = ComposeLayerVk::createFromHwc2ComposeLayer(
169 m_compositionVkSampler, composeBuffers[i]->m_vkImageView, layers[i],
170 composeBuffers[i]->m_width, composeBuffers[i]->m_height,
171 surfaceState.m_width, surfaceState.m_height);
172 composeLayers.emplace_back(std::move(layer));
173 }
174
175 if (composeLayers.empty()) {
176 return;
177 }
178
179 VK_CHECK(m_vk.vkWaitForFences(m_vkDevice, 1, &m_frameDrawCompleteFence,
180 VK_TRUE, UINT64_MAX));
181 uint32_t imageIndex;
182 VK_CHECK(m_vk.vkAcquireNextImageKHR(
183 m_vkDevice, m_swapChainStateVk->getSwapChain(), UINT64_MAX,
184 m_imageReadySem, VK_NULL_HANDLE, &imageIndex));
185
186 if (compareAndSaveComposition(imageIndex, numLayers, layers,
187 composeBuffers)) {
188 auto composition =
189 std::make_unique<Composition>(std::move(composeLayers));
190 m_compositorVk->setComposition(imageIndex, std::move(composition));
191 }
192
193 auto cmdBuff = m_compositorVk->getCommandBuffer(imageIndex);
194
195 VK_CHECK(m_vk.vkResetFences(m_vkDevice, 1, &m_frameDrawCompleteFence));
196 VkPipelineStageFlags waitStages[] = {
197 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
198 VkSubmitInfo submitInfo = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
199 .waitSemaphoreCount = 1,
200 .pWaitSemaphores = &m_imageReadySem,
201 .pWaitDstStageMask = waitStages,
202 .commandBufferCount = 1,
203 .pCommandBuffers = &cmdBuff,
204 .signalSemaphoreCount = 1,
205 .pSignalSemaphores = &m_frameDrawCompleteSem};
206 VK_CHECK(m_vk.vkQueueSubmit(m_compositorVkQueue, 1, &submitInfo,
207 m_frameDrawCompleteFence));
208
209 auto swapChain = m_swapChainStateVk->getSwapChain();
210 VkPresentInfoKHR presentInfo = {.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
211 .waitSemaphoreCount = 1,
212 .pWaitSemaphores = &m_frameDrawCompleteSem,
213 .swapchainCount = 1,
214 .pSwapchains = &swapChain,
215 .pImageIndices = &imageIndex};
216 VK_CHECK(m_vk.vkQueuePresentKHR(m_swapChainVkQueue, &presentInfo));
217 VK_CHECK(m_vk.vkWaitForFences(m_vkDevice, 1, &m_frameDrawCompleteFence,
218 VK_TRUE, UINT64_MAX));
219 }
220
canComposite(VkFormat format)221 bool DisplayVk::canComposite(VkFormat format) {
222 auto it = m_canComposite.find(format);
223 if (it != m_canComposite.end()) {
224 return it->second;
225 }
226 VkFormatProperties formatProps = {};
227 m_vk.vkGetPhysicalDeviceFormatProperties(m_vkPhysicalDevice, format,
228 &formatProps);
229 bool res =
230 formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
231 m_canComposite.emplace(format, res);
232 return res;
233 }
234
compareAndSaveComposition(uint32_t renderTargetIndex,uint32_t numLayers,const ComposeLayer layers[],const std::vector<std::shared_ptr<DisplayBufferInfo>> & composeBuffers)235 bool DisplayVk::compareAndSaveComposition(
236 uint32_t renderTargetIndex, uint32_t numLayers, const ComposeLayer layers[],
237 const std::vector<std::shared_ptr<DisplayBufferInfo>> &composeBuffers) {
238 if (!m_surfaceState) {
239 ERR("%s(%s:%d): Haven't bound to a surface, can't compare and save "
240 "composition\n",
241 __FUNCTION__, __FILE__, static_cast<int>(__LINE__));
242 ::abort();
243 }
244 auto [iPrevComposition, compositionNotFound] =
245 m_surfaceState->m_prevCompositions.emplace(renderTargetIndex, 0);
246 auto &prevComposition = iPrevComposition->second;
247 bool compositionChanged = false;
248 if (numLayers == prevComposition.size()) {
249 for (int i = 0; i < numLayers; i++) {
250 if (composeBuffers[i] == nullptr) {
251 // If the display buffer of the current layer doesn't exist, we
252 // check if the layer at the same index in the previous
253 // composition doesn't exist either.
254 if (prevComposition[i] == nullptr) {
255 continue;
256 } else {
257 compositionChanged = true;
258 break;
259 }
260 }
261 if (prevComposition[i] == nullptr) {
262 // If the display buffer of the current layer exists but the
263 // layer at the same index in the previous composition doesn't
264 // exist, the composition is changed.
265 compositionChanged = true;
266 break;
267 }
268 const auto &prevLayer = *prevComposition[i];
269 const auto prevDisplayBufferPtr = prevLayer.m_displayBuffer.lock();
270 // prevLayer.m_displayBuffer is a weak pointer, so if
271 // prevDisplayBufferPtr is null, the color buffer
272 // prevDisplayBufferPtr pointed to should have been released or
273 // re-allocated, and we should consider the composition is changed.
274 // If prevDisplayBufferPtr exists and it points to the same display
275 // buffer as the input composeBuffers[i] we consider the composition
276 // not changed.
277 if (!prevDisplayBufferPtr ||
278 prevDisplayBufferPtr != composeBuffers[i]) {
279 compositionChanged = true;
280 break;
281 }
282 const auto &prevHwc2Layer = prevLayer.m_hwc2Layer;
283 const auto hwc2Layer = layers[i];
284 compositionChanged =
285 (prevHwc2Layer.cbHandle != hwc2Layer.cbHandle) ||
286 (prevHwc2Layer.composeMode != hwc2Layer.composeMode) ||
287 (prevHwc2Layer.displayFrame.left !=
288 hwc2Layer.displayFrame.left) ||
289 (prevHwc2Layer.displayFrame.top !=
290 hwc2Layer.displayFrame.top) ||
291 (prevHwc2Layer.displayFrame.right !=
292 hwc2Layer.displayFrame.right) ||
293 (prevHwc2Layer.displayFrame.bottom !=
294 hwc2Layer.displayFrame.bottom) ||
295 (prevHwc2Layer.crop.left != hwc2Layer.crop.left) ||
296 (prevHwc2Layer.crop.top != hwc2Layer.crop.top) ||
297 (prevHwc2Layer.crop.right != hwc2Layer.crop.right) ||
298 (prevHwc2Layer.crop.bottom != hwc2Layer.crop.bottom) ||
299 (prevHwc2Layer.blendMode != hwc2Layer.blendMode) ||
300 (prevHwc2Layer.alpha != hwc2Layer.alpha) ||
301 (prevHwc2Layer.color.r != hwc2Layer.color.r) ||
302 (prevHwc2Layer.color.g != hwc2Layer.color.g) ||
303 (prevHwc2Layer.color.b != hwc2Layer.color.b) ||
304 (prevHwc2Layer.color.a != hwc2Layer.color.a) ||
305 (prevHwc2Layer.transform != hwc2Layer.transform);
306 if (compositionChanged) {
307 break;
308 }
309 }
310 } else {
311 compositionChanged = true;
312 }
313 bool needsSave = compositionNotFound || compositionChanged;
314 if (needsSave) {
315 prevComposition.clear();
316 for (int i = 0; i < numLayers; i++) {
317 if (composeBuffers[i] == nullptr) {
318 prevComposition.emplace_back(nullptr);
319 continue;
320 }
321 auto layer = std::make_unique<SurfaceState::Layer>();
322 layer->m_hwc2Layer = layers[i];
323 layer->m_displayBuffer = composeBuffers[i];
324 prevComposition.emplace_back(std::move(layer));
325 }
326 }
327 return needsSave;
328 }
329
DisplayBufferInfo(const goldfish_vk::VulkanDispatch & vk,VkDevice vkDevice,uint32_t width,uint32_t height,VkFormat format,VkImage image)330 DisplayVk::DisplayBufferInfo::DisplayBufferInfo(
331 const goldfish_vk::VulkanDispatch &vk, VkDevice vkDevice, uint32_t width,
332 uint32_t height, VkFormat format, VkImage image)
333 : m_vk(vk),
334 m_vkDevice(vkDevice),
335 m_width(width),
336 m_height(height),
337 m_vkFormat(format),
338 m_vkImageView(VK_NULL_HANDLE) {
339 VkImageViewCreateInfo imageViewCi = {
340 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
341 .image = image,
342 .viewType = VK_IMAGE_VIEW_TYPE_2D,
343 .format = format,
344 .components = {.r = VK_COMPONENT_SWIZZLE_IDENTITY,
345 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
346 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
347 .a = VK_COMPONENT_SWIZZLE_IDENTITY},
348 .subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
349 .baseMipLevel = 0,
350 .levelCount = 1,
351 .baseArrayLayer = 0,
352 .layerCount = 1}};
353 VK_CHECK(m_vk.vkCreateImageView(m_vkDevice, &imageViewCi, nullptr,
354 &m_vkImageView));
355 }
356
~DisplayBufferInfo()357 DisplayVk::DisplayBufferInfo::~DisplayBufferInfo() {
358 m_vk.vkDestroyImageView(m_vkDevice, m_vkImageView, nullptr);
359 }
360