diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2021-05-05 18:32:08 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-05-05 18:32:08 +0000 |
commit | 85532f3dc56bdb461e1c5b7da20d514aa67ff66d (patch) | |
tree | 95ac76eff2fc387ee5ebac0a3bf8d18ee0df2459 | |
parent | b69f8ceb1fd0bf2862a45609239619bd18e91554 (diff) | |
parent | 441557f8a7b3d9e892f8c067a3907d97f3ffec22 (diff) | |
download | vulkan-cereal-85532f3dc56bdb461e1c5b7da20d514aa67ff66d.tar.gz |
Merge "Native VK Swapchain: rcCompose support (basic) cleanup" am: d51f523c44 am: 56cfd12b54 am: 441557f8a7
Original change: https://android-review.googlesource.com/c/device/generic/vulkan-cereal/+/1696046
Change-Id: Idd3fe850d38cddcab90e4eadfcf0784acc28c236
-rw-r--r-- | stream-servers/CompositorVk.cpp | 280 | ||||
-rw-r--r-- | stream-servers/CompositorVk.h | 39 | ||||
-rw-r--r-- | stream-servers/DisplayVk.cpp | 239 | ||||
-rw-r--r-- | stream-servers/DisplayVk.h | 23 | ||||
-rw-r--r-- | stream-servers/FrameBuffer.cpp | 66 |
5 files changed, 347 insertions, 300 deletions
diff --git a/stream-servers/CompositorVk.cpp b/stream-servers/CompositorVk.cpp index 385e62a3..5e17d26b 100644 --- a/stream-servers/CompositorVk.cpp +++ b/stream-servers/CompositorVk.cpp @@ -2,9 +2,11 @@ #include <string.h> +#include <cinttypes> #include <glm/gtc/matrix_transform.hpp> #include <optional> +#include "ErrorLog.h" #include "vulkan/vk_util.h" namespace CompositorVkShader { @@ -24,123 +26,99 @@ static VkShaderModule createShaderModule(const goldfish_vk::VulkanDispatch &vk, return res; } -Composition::Composition(VkSampler vkSampler, uint32_t width, uint32_t height, - const std::vector<ComposeLayerVk>& composeLayers) +ComposeLayerVk::ComposeLayerVk(VkSampler vkSampler, VkImageView vkImageView, + const LayerTransform &layerTransform) : m_vkSampler(vkSampler), - m_width(width), - m_height(height), - m_composeLayers(composeLayers) { - setTransforms(); -} + m_vkImageView(vkImageView), + m_layerTransform( + {.pos = layerTransform.pos, .texcoord = layerTransform.texcoord}) {} + +std::unique_ptr<ComposeLayerVk> ComposeLayerVk::createFromHwc2ComposeLayer( + VkSampler vkSampler, VkImageView vkImageView, + const ComposeLayer &composeLayer, uint32_t cbWidth, uint32_t cbHeight, + uint32_t dstWidth, uint32_t dstHeight) { + // Calculate the posTransform and the texcoordTransform needed in the + // uniform of the Compositor.vert shader. The posTransform should transform + // the square(top = -1, bottom = 1, left = -1, right = 1) to the position + // where the layer should be drawn in NDC space given the composeLayer. + // texcoordTransform should transform the unit square(top = 0, bottom = 1, + // left = 0, right = 1) to where we should sample the layer in the + // normalized uv space given the composeLayer. + const hwc_rect_t &posRect = composeLayer.displayFrame; + const hwc_frect_t &texcoordRect = composeLayer.crop; + + int posWidth = posRect.right - posRect.left; + int posHeight = posRect.bottom - posRect.top; + + float posScaleX = float(posWidth) / dstWidth; + float posScaleY = float(posHeight) / dstHeight; + + float posTranslateX = + -1.0f + posScaleX + 2.0f * float(posRect.left) / dstWidth; + float posTranslateY = + -1.0f + posScaleY + 2.0f * float(posRect.top) / dstHeight; + + float texcoordScalX = + (texcoordRect.right - texcoordRect.left) / float(cbWidth); + float texCoordScaleY = + (texcoordRect.bottom - texcoordRect.top) / float(cbHeight); + + float texCoordTranslateX = texcoordRect.left / float(cbWidth); + float texCoordTranslateY = texcoordRect.top / float(cbHeight); + + float texcoordRotation = 0.0f; + + const float pi = glm::pi<float>(); + + switch (composeLayer.transform) { + case HWC_TRANSFORM_ROT_90: + texcoordRotation = pi * 0.5f; + break; + case HWC_TRANSFORM_ROT_180: + texcoordRotation = pi; + break; + case HWC_TRANSFORM_ROT_270: + texcoordRotation = pi * 1.5f; + break; + case HWC_TRANSFORM_FLIP_H: + texcoordScalX *= -1.0f; + break; + case HWC_TRANSFORM_FLIP_V: + texCoordScaleY *= -1.0f; + break; + case HWC_TRANSFORM_FLIP_H_ROT_90: + texcoordRotation = pi * 0.5f; + texcoordScalX *= -1.0f; + break; + case HWC_TRANSFORM_FLIP_V_ROT_90: + texcoordRotation = pi * 0.5f; + texCoordScaleY *= -1.0f; + break; + default: + break; + } -Composition::Composition(VkImageView vkImageView, VkSampler vkSampler, uint32_t width, uint32_t height) - : m_vkSampler(vkSampler), - m_width(width), - m_height(height) { - - ComposeLayerVk composeLayer; - composeLayer.imageView = vkImageView; - composeLayer.layerInfo = - (ComposeLayer){ - 0, - HWC2_COMPOSITION_DEVICE, - { 0, 0, static_cast<int>(width), static_cast<int>(height) }, - { 0.0f, 0.0f, (float)width, (float)height }, - HWC2_BLEND_MODE_PREMULTIPLIED, - 1.0f, - { 0, 0, 0, 0}, - (hwc_transform_t)0 /* transform */ - }; - std::vector<ComposeLayerVk> composeLayers = { - composeLayer, + ComposeLayerVk::LayerTransform layerTransform = { + .pos = + glm::translate(glm::mat4(1.0f), + glm::vec3(posTranslateX, posTranslateY, 0.0f)) * + glm::scale(glm::mat4(1.0f), glm::vec3(posScaleX, posScaleY, 1.0f)), + .texcoord = glm::translate(glm::mat4(1.0f), + glm::vec3(texCoordTranslateX, + texCoordTranslateY, 0.0f)) * + glm::scale(glm::mat4(1.0f), + glm::vec3(texcoordScalX, texCoordScaleY, 1.0f)) * + glm::rotate(glm::mat4(1.0f), texcoordRotation, + glm::vec3(0.0f, 0.0f, 1.0f)), }; - m_composeLayers = composeLayers; - setTransforms(); + return std::unique_ptr<ComposeLayerVk>( + new ComposeLayerVk(vkSampler, vkImageView, layerTransform)); } -void Composition::setTransforms() { - float pos_scaleX; - float pos_scaleY; - float pos_trX; - float pos_trY; - - float texcoord_scaleX; - float texcoord_scaleY; - float texcoord_trX; - float texcoord_trY; - - float dst_width = (float)m_width; - float dst_height = (float)m_height; - - uint32_t i = 0; - - for (const auto& info : m_composeLayers) { - uint32_t cbWidth = info.cbWidth; - uint32_t cbHeight = info.cbHeight; - const auto& li = info.layerInfo; - const auto& pos_rect = li.displayFrame; - const auto& texcoord_rect = li.crop; - - int pos_width = pos_rect.right - pos_rect.left; - int pos_height = pos_rect.bottom - pos_rect.top; - - pos_scaleX = float(pos_width) / dst_width; - pos_scaleY = float(pos_height) / dst_height; - - pos_trX = -1.0f + pos_scaleX + 2.0f * float(pos_rect.left) / dst_width; - pos_trY = -1.0f + pos_scaleY + 2.0f * float(pos_rect.top) / dst_height; - - texcoord_scaleX = (texcoord_rect.right - texcoord_rect.left) / float(cbWidth); - texcoord_scaleY = (texcoord_rect.bottom - texcoord_rect.top) / float(cbHeight); - - texcoord_trX = texcoord_rect.left / float(cbWidth); - texcoord_trY = texcoord_rect.top / float(cbHeight); - - float texcoord_rot = 0.0f; - - const float pi = 3.14159265358979324f; - - switch (li.transform) { - case HWC_TRANSFORM_ROT_90: - texcoord_rot = pi * 0.5f; - break; - case HWC_TRANSFORM_ROT_180: - texcoord_rot = pi; - break; - case HWC_TRANSFORM_ROT_270: - texcoord_rot = pi * 1.5f; - break; - case HWC_TRANSFORM_FLIP_H: - texcoord_scaleX *= -1.0f; - break; - case HWC_TRANSFORM_FLIP_V: - texcoord_scaleY *= -1.0f; - break; - case HWC_TRANSFORM_FLIP_H_ROT_90: - texcoord_rot = pi * 0.5f; - texcoord_scaleX *= -1.0f; - break; - case HWC_TRANSFORM_FLIP_V_ROT_90: - texcoord_rot = pi * 0.5f; - texcoord_scaleY *= -1.0f; - break; - default: - break; - - } - - m_transformsPerLayer.push_back({ - glm::translate(glm::mat4(1.0f), glm::vec3(pos_trX, pos_trY, 0.0f)) * - glm::scale(glm::mat4(1.0f), glm::vec3(pos_scaleX, pos_scaleY, 1.0f)), - glm::translate(glm::mat4(1.0f), glm::vec3(texcoord_trX, texcoord_trY, 0.0f)) * - glm::scale(glm::mat4(1.0f), glm::vec3(texcoord_scaleX, texcoord_scaleY, 1.0f)) * - glm::rotate(glm::mat4(1.0f), texcoord_rot, glm::vec3(0.0f, 0.0f, 1.0f)), - }); - - ++i; - } -} +Composition::Composition( + std::vector<std::unique_ptr<ComposeLayerVk>> composeLayers) + : m_composeLayers(std::move(composeLayers)) {} const std::vector<CompositorVk::Vertex> CompositorVk::k_vertices = { {{-1.0f, -1.0f}, {0.0f, 0.0f}}, @@ -171,11 +149,9 @@ std::unique_ptr<CompositorVk> CompositorVk::create( res->setUpEmptyComposition(format); res->m_currentCompositions.resize(renderTargets.size()); for (auto i = 0; i < renderTargets.size(); i++) { - res->setComposition( - i, std::make_unique<Composition>(res->m_emptyCompositionVkImageView, - res->m_emptyCompositionVkSampler, - k_emptyCompositionExtent.width, - k_emptyCompositionExtent.height)); + std::vector<std::unique_ptr<ComposeLayerVk>> emptyCompositionLayers; + res->setComposition(i, std::make_unique<Composition>( + std::move(emptyCompositionLayers))); } return res; } @@ -194,7 +170,6 @@ CompositorVk::CompositorVk(const goldfish_vk::VulkanDispatch &vk, m_emptyCompositionVkSampler(VK_NULL_HANDLE), m_currentCompositions(0), m_uniformStorage({VK_NULL_HANDLE, VK_NULL_HANDLE, nullptr, 0}) { - (void)m_renderTargetWidth; (void)m_renderTargetHeight; @@ -547,6 +522,9 @@ void CompositorVk::setUpFramebuffers( } } +// We don't see composition requests with more than 10 layers from the guest for +// now. If we see rendering error or significant time spent on updating +// descriptors in setComposition, we should tune this number. static const uint32_t kMaxLayersPerFrame = 10; void CompositorVk::setUpDescriptorSets() { @@ -633,9 +611,10 @@ void CompositorVk::setUpCommandBuffers(uint32_t width, uint32_t height) { m_vk.vkCmdBindIndexBuffer(cmdBuffer, m_indexVkBuffer, 0, VK_INDEX_TYPE_UINT16); for (uint32_t j = 0; j < kMaxLayersPerFrame; ++j) { - m_vk.vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - m_vkPipelineLayout, 0, 1, - &m_vkDescriptorSets[i * kMaxLayersPerFrame + j], 0, nullptr); + m_vk.vkCmdBindDescriptorSets( + cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_vkPipelineLayout, + 0, 1, &m_vkDescriptorSets[i * kMaxLayersPerFrame + j], 0, + nullptr); m_vk.vkCmdDrawIndexed( cmdBuffer, static_cast<uint32_t>(k_indices.size()), 1, 0, 0, 0); } @@ -737,7 +716,8 @@ void CompositorVk::setUpEmptyComposition(VkFormat format) { void CompositorVk::setUpUniformBuffers() { auto numOfFrames = m_renderTargetVkFrameBuffers.size(); - VkDeviceSize size = m_uniformStorage.m_stride * numOfFrames * kMaxLayersPerFrame; + VkDeviceSize size = + m_uniformStorage.m_stride * numOfFrames * kMaxLayersPerFrame; auto maybeBuffer = createBuffer(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | @@ -801,33 +781,46 @@ void CompositorVk::setComposition(uint32_t rtIndex, std::unique_ptr<Composition> &&composition) { m_currentCompositions[rtIndex] = std::move(composition); const auto ¤tComposition = *m_currentCompositions[rtIndex]; + if (currentComposition.m_composeLayers.size() > kMaxLayersPerFrame) { + ERR("%s(%s:%d): CompositorVk can't compose more than %" PRIu32 + " layers, %" PRIu32 " layers asked.\n", + __FUNCTION__, __FILE__, static_cast<int>(__LINE__), + kMaxLayersPerFrame, + static_cast<uint32_t>(currentComposition.m_composeLayers.size())); + } memset(reinterpret_cast<uint8_t *>(m_uniformStorage.m_data) + - (rtIndex * kMaxLayersPerFrame + 0) * m_uniformStorage.m_stride, - 0, - sizeof(Composition::LayerTransform) * kMaxLayersPerFrame); + (rtIndex * kMaxLayersPerFrame + 0) * m_uniformStorage.m_stride, + 0, sizeof(ComposeLayerVk::LayerTransform) * kMaxLayersPerFrame); + std::vector<VkDescriptorImageInfo> imageInfos( + currentComposition.m_composeLayers.size()); + std::vector<VkWriteDescriptorSet> descriptorWrites; for (size_t i = 0; i < currentComposition.m_composeLayers.size(); ++i) { - VkDescriptorImageInfo imageInfo = { - .sampler = currentComposition.m_vkSampler, - .imageView = currentComposition.m_composeLayers[i].imageView, - .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; - VkWriteDescriptorSet descriptorSetWrite = { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = m_vkDescriptorSets[rtIndex * kMaxLayersPerFrame + i], - .dstBinding = 0, - .dstArrayElement = 0, - .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .pImageInfo = &imageInfo}; - m_vk.vkUpdateDescriptorSets(m_vkDevice, 1, &descriptorSetWrite, 0, nullptr); - memcpy(reinterpret_cast<uint8_t *>(m_uniformStorage.m_data) + - (rtIndex * kMaxLayersPerFrame + i) * m_uniformStorage.m_stride, - currentComposition.m_transformsPerLayer.data() + i, - sizeof(Composition::LayerTransform)); + const auto &layer = currentComposition.m_composeLayers[i]; + imageInfos[i] = VkDescriptorImageInfo( + {.sampler = layer->m_vkSampler, + .imageView = layer->m_vkImageView, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}); + const VkDescriptorImageInfo &imageInfo = imageInfos[i]; + descriptorWrites.emplace_back(VkWriteDescriptorSet( + {.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = m_vkDescriptorSets[rtIndex * kMaxLayersPerFrame + i], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &imageInfo})); + memcpy( + reinterpret_cast<uint8_t *>(m_uniformStorage.m_data) + + (rtIndex * kMaxLayersPerFrame + i) * m_uniformStorage.m_stride, + &layer->m_layerTransform, sizeof(ComposeLayerVk::LayerTransform)); } + m_vk.vkUpdateDescriptorSets(m_vkDevice, descriptorWrites.size(), + descriptorWrites.data(), 0, nullptr); - for (size_t i = currentComposition.m_composeLayers.size(); i < kMaxLayersPerFrame; ++i) { + for (size_t i = currentComposition.m_composeLayers.size(); + i < kMaxLayersPerFrame; ++i) { VkDescriptorImageInfo imageInfo = { .sampler = m_emptyCompositionVkSampler, .imageView = m_emptyCompositionVkImageView, @@ -840,7 +833,8 @@ void CompositorVk::setComposition(uint32_t rtIndex, .descriptorCount = 1, .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .pImageInfo = &imageInfo}; - m_vk.vkUpdateDescriptorSets(m_vkDevice, 1, &descriptorSetWrite, 0, nullptr); + m_vk.vkUpdateDescriptorSets(m_vkDevice, 1, &descriptorSetWrite, 0, + nullptr); } } diff --git a/stream-servers/CompositorVk.h b/stream-servers/CompositorVk.h index 062c4881..97a21a2d 100644 --- a/stream-servers/CompositorVk.h +++ b/stream-servers/CompositorVk.h @@ -15,31 +15,32 @@ #include "Hwc2.h" class ComposeLayerVk { -public: - VkImageView imageView; - uint32_t cbWidth; - uint32_t cbHeight; - ComposeLayer layerInfo; -}; - -class Composition { -public: + public: VkSampler m_vkSampler; - uint32_t m_width; - uint32_t m_height; - - std::vector<ComposeLayerVk> m_composeLayers; + VkImageView m_vkImageView; struct LayerTransform { glm::mat4 pos; glm::mat4 texcoord; - }; - std::vector<LayerTransform> m_transformsPerLayer; + } m_layerTransform; + + static std::unique_ptr<ComposeLayerVk> createFromHwc2ComposeLayer( + VkSampler, VkImageView, const ComposeLayer &, uint32_t cbWidth, + uint32_t cbHeight, uint32_t dstWidth, uint32_t dstHeight); + + private: + ComposeLayerVk() = delete; + explicit ComposeLayerVk(VkSampler, VkImageView, const LayerTransform &); +}; + +// If we want to apply transform to all layers to rotate/clip/position the +// virtual display, we should add that functionality here. +class Composition { + public: + std::vector<std::unique_ptr<ComposeLayerVk>> m_composeLayers; Composition() = delete; - explicit Composition(VkSampler, uint32_t width, uint32_t height, const std::vector<ComposeLayerVk>& composeLayers); - explicit Composition(VkImageView, VkSampler, uint32_t width, uint32_t height); -private: - void setTransforms(); + explicit Composition( + std::vector<std::unique_ptr<ComposeLayerVk>> composeLayers); }; struct CompositorVkBase diff --git a/stream-servers/DisplayVk.cpp b/stream-servers/DisplayVk.cpp index f49b5910..c1552876 100644 --- a/stream-servers/DisplayVk.cpp +++ b/stream-servers/DisplayVk.cpp @@ -2,8 +2,8 @@ #include <glm/glm.hpp> #include <glm/gtx/matrix_transform_2d.hpp> + #include "ErrorLog.h" -#include "Hwc2.h" DisplayVk::DisplayVk(const goldfish_vk::VulkanDispatch &vk, VkPhysicalDevice vkPhysicalDevice, @@ -116,130 +116,80 @@ std::shared_ptr<DisplayVk::DisplayBufferInfo> DisplayVk::createDisplayBuffer( void DisplayVk::post( const std::shared_ptr<DisplayBufferInfo> &displayBufferPtr) { - if (m_swapChainStateVk == nullptr || m_compositorVk == nullptr) { - ERR("%s(%s:%d): Haven't bound to a surface, can't post color buffer.\n", - __FUNCTION__, __FILE__, static_cast<int>(__LINE__)); + if (!displayBufferPtr) { + fprintf(stderr, "%s: warning: null ptr passed to post buffer\n", + __func__); return; } + ComposeLayer composeLayer = { + 0, + HWC2_COMPOSITION_DEVICE, + {0, 0, static_cast<int>(displayBufferPtr->m_width), + static_cast<int>(displayBufferPtr->m_height)}, + {0.0f, 0.0f, static_cast<float>(displayBufferPtr->m_width), + static_cast<float>(displayBufferPtr->m_height)}, + HWC2_BLEND_MODE_PREMULTIPLIED, + 1.0f, + {0, 0, 0, 0}, + static_cast<hwc_transform_t>(0) /* transform */ + }; + compose(1, &composeLayer, {std::move(displayBufferPtr)}); +} - if (!displayBufferPtr) { +void DisplayVk::compose( + uint32_t numLayers, const ComposeLayer layers[], + const std::vector<std::shared_ptr<DisplayBufferInfo>> &composeBuffers) { + if (!m_swapChainStateVk || !m_compositorVk || !m_surfaceState) { + ERR("%s(%s:%d): Haven't bound to a surface, can't compose color " + "buffer.\n", + __FUNCTION__, __FILE__, static_cast<int>(__LINE__)); return; } auto &surfaceState = *m_surfaceState; - const auto &db = *displayBufferPtr; - - VK_CHECK(m_vk.vkWaitForFences(m_vkDevice, 1, &m_frameDrawCompleteFence, - VK_TRUE, UINT64_MAX)); - uint32_t imageIndex; - VK_CHECK(m_vk.vkAcquireNextImageKHR( - m_vkDevice, m_swapChainStateVk->getSwapChain(), UINT64_MAX, - m_imageReadySem, VK_NULL_HANDLE, &imageIndex)); - auto maybePrevDisplayBuffer = surfaceState.m_prevDisplayBuffer.lock(); - if (!maybePrevDisplayBuffer || maybePrevDisplayBuffer != displayBufferPtr) { + std::vector<std::unique_ptr<ComposeLayerVk>> composeLayers; + for (int i = 0; i < numLayers; ++i) { + if (!composeBuffers[i]) { + fprintf( + stderr, + "%s: warning: null ptr passed to compose buffer for layer %d\n", + __func__, i); + continue; + } + const auto &db = *composeBuffers[i]; if (!canComposite(db.m_vkFormat)) { ERR("%s(%s:%d): Can't composite the DisplayBuffer(0x%" PRIxPTR - "). The image(VkFormat = %" PRIu64 ") can be sampled from.\n", + "). The image(VkFormat = %" PRIu64 ") can't be sampled from.\n", __FUNCTION__, __FILE__, static_cast<int>(__LINE__), - reinterpret_cast<uintptr_t>(displayBufferPtr.get()), + reinterpret_cast<uintptr_t>(&db), static_cast<uint64_t>(db.m_vkFormat)); - return; - } - auto composition = std::make_unique<Composition>( - db.m_vkImageView, m_compositionVkSampler, db.m_width, db.m_height); - m_compositorVk->setComposition(imageIndex, std::move(composition)); - surfaceState.m_prevDisplayBuffer = displayBufferPtr; - } - - auto cmdBuff = m_compositorVk->getCommandBuffer(imageIndex); - - VK_CHECK(m_vk.vkResetFences(m_vkDevice, 1, &m_frameDrawCompleteFence)); - VkPipelineStageFlags waitStages[] = { - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; - VkSubmitInfo submitInfo = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .waitSemaphoreCount = 1, - .pWaitSemaphores = &m_imageReadySem, - .pWaitDstStageMask = waitStages, - .commandBufferCount = 1, - .pCommandBuffers = &cmdBuff, - .signalSemaphoreCount = 1, - .pSignalSemaphores = &m_frameDrawCompleteSem}; - VK_CHECK(m_vk.vkQueueSubmit(m_compositorVkQueue, 1, &submitInfo, - m_frameDrawCompleteFence)); - - auto swapChain = m_swapChainStateVk->getSwapChain(); - VkPresentInfoKHR presentInfo = {.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - .waitSemaphoreCount = 1, - .pWaitSemaphores = &m_frameDrawCompleteSem, - .swapchainCount = 1, - .pSwapchains = &swapChain, - .pImageIndices = &imageIndex}; - VK_CHECK(m_vk.vkQueuePresentKHR(m_swapChainVkQueue, &presentInfo)); - VK_CHECK(m_vk.vkWaitForFences(m_vkDevice, 1, &m_frameDrawCompleteFence, - VK_TRUE, UINT64_MAX)); -} - -void DisplayVk::compose( - const Post& postCmd, - const std::vector<std::shared_ptr<DisplayBufferInfo>>& composeBuffers, - const std::shared_ptr<DisplayBufferInfo>& displayBufferPtr) { - ComposeDevice_v2* composeDevice = (ComposeDevice_v2*)(postCmd.composeBuffer.data()); - uint32_t bufferSize = (uint32_t)postCmd.composeBuffer.size(); - ComposeLayer* l = (ComposeLayer*)composeDevice->layer; - - std::vector<ComposeLayerVk> composeLayers; - for (int i = 0; i < composeDevice->numLayers; ++i, ++l) { - ComposeLayerVk cl; - if (!composeBuffers[i]) { - fprintf(stderr, "%s: warning: null ptr passed to compose bufer\n", __func__); continue; } - cl.imageView = composeBuffers[i]->m_vkImageView; - cl.cbWidth = composeBuffers[i]->m_width; - cl.cbHeight = composeBuffers[i]->m_height; - cl.layerInfo = *l; - composeLayers.push_back(cl); + auto layer = ComposeLayerVk::createFromHwc2ComposeLayer( + m_compositionVkSampler, composeBuffers[i]->m_vkImageView, layers[i], + composeBuffers[i]->m_width, composeBuffers[i]->m_height, + surfaceState.m_width, surfaceState.m_height); + composeLayers.emplace_back(std::move(layer)); } if (composeLayers.empty()) { return; } - if (m_swapChainStateVk == nullptr || m_compositorVk == nullptr) { - ERR("%s(%s:%d): Haven't bound to a surface, can't post color buffer.\n", - __FUNCTION__, __FILE__, static_cast<int>(__LINE__)); - return; - } - - if (!displayBufferPtr) { - return; - } - - auto &surfaceState = *m_surfaceState; - const auto &db = *displayBufferPtr; - VK_CHECK(m_vk.vkWaitForFences(m_vkDevice, 1, &m_frameDrawCompleteFence, VK_TRUE, UINT64_MAX)); uint32_t imageIndex; VK_CHECK(m_vk.vkAcquireNextImageKHR( m_vkDevice, m_swapChainStateVk->getSwapChain(), UINT64_MAX, m_imageReadySem, VK_NULL_HANDLE, &imageIndex)); - auto maybePrevDisplayBuffer = surfaceState.m_prevDisplayBuffer.lock(); - if (!canComposite(db.m_vkFormat)) { - ERR("%s(%s:%d): Can't composite the DisplayBuffer(0x%" PRIxPTR - "). The image(VkFormat = %" PRIu64 ") can be sampled from.\n", - __FUNCTION__, __FILE__, static_cast<int>(__LINE__), - reinterpret_cast<uintptr_t>(displayBufferPtr.get()), - static_cast<uint64_t>(db.m_vkFormat)); - return; + if (compareAndSaveComposition(imageIndex, numLayers, layers, + composeBuffers)) { + auto composition = + std::make_unique<Composition>(std::move(composeLayers)); + m_compositorVk->setComposition(imageIndex, std::move(composition)); } - auto composition = std::make_unique<Composition>( - m_compositionVkSampler, db.m_width, db.m_height, composeLayers); - m_compositorVk->setComposition(imageIndex, std::move(composition)); - surfaceState.m_prevDisplayBuffer = displayBufferPtr; - auto cmdBuff = m_compositorVk->getCommandBuffer(imageIndex); VK_CHECK(m_vk.vkResetFences(m_vkDevice, 1, &m_frameDrawCompleteFence)); @@ -282,6 +232,101 @@ bool DisplayVk::canComposite(VkFormat format) { return res; } +bool DisplayVk::compareAndSaveComposition( + uint32_t renderTargetIndex, uint32_t numLayers, const ComposeLayer layers[], + const std::vector<std::shared_ptr<DisplayBufferInfo>> &composeBuffers) { + if (!m_surfaceState) { + ERR("%s(%s:%d): Haven't bound to a surface, can't compare and save " + "composition\n", + __FUNCTION__, __FILE__, static_cast<int>(__LINE__)); + ::abort(); + } + auto [iPrevComposition, compositionNotFound] = + m_surfaceState->m_prevCompositions.emplace(renderTargetIndex, 0); + auto &prevComposition = iPrevComposition->second; + bool compositionChanged = false; + if (numLayers == prevComposition.size()) { + for (int i = 0; i < numLayers; i++) { + if (composeBuffers[i] == nullptr) { + // If the display buffer of the current layer doesn't exist, we + // check if the layer at the same index in the previous + // composition doesn't exist either. + if (prevComposition[i] == nullptr) { + continue; + } else { + compositionChanged = true; + break; + } + } + if (prevComposition[i] == nullptr) { + // If the display buffer of the current layer exists but the + // layer at the same index in the previous composition doesn't + // exist, the composition is changed. + compositionChanged = true; + break; + } + const auto &prevLayer = *prevComposition[i]; + const auto prevDisplayBufferPtr = prevLayer.m_displayBuffer.lock(); + // prevLayer.m_displayBuffer is a weak pointer, so if + // prevDisplayBufferPtr is null, the color buffer + // prevDisplayBufferPtr pointed to should have been released or + // re-allocated, and we should consider the composition is changed. + // If prevDisplayBufferPtr exists and it points to the same display + // buffer as the input composeBuffers[i] we consider the composition + // not changed. + if (!prevDisplayBufferPtr || + prevDisplayBufferPtr != composeBuffers[i]) { + compositionChanged = true; + break; + } + const auto &prevHwc2Layer = prevLayer.m_hwc2Layer; + const auto hwc2Layer = layers[i]; + compositionChanged = + (prevHwc2Layer.cbHandle != hwc2Layer.cbHandle) || + (prevHwc2Layer.composeMode != hwc2Layer.composeMode) || + (prevHwc2Layer.displayFrame.left != + hwc2Layer.displayFrame.left) || + (prevHwc2Layer.displayFrame.top != + hwc2Layer.displayFrame.top) || + (prevHwc2Layer.displayFrame.right != + hwc2Layer.displayFrame.right) || + (prevHwc2Layer.displayFrame.bottom != + hwc2Layer.displayFrame.bottom) || + (prevHwc2Layer.crop.left != hwc2Layer.crop.left) || + (prevHwc2Layer.crop.top != hwc2Layer.crop.top) || + (prevHwc2Layer.crop.right != hwc2Layer.crop.right) || + (prevHwc2Layer.crop.bottom != hwc2Layer.crop.bottom) || + (prevHwc2Layer.blendMode != hwc2Layer.blendMode) || + (prevHwc2Layer.alpha != hwc2Layer.alpha) || + (prevHwc2Layer.color.r != hwc2Layer.color.r) || + (prevHwc2Layer.color.g != hwc2Layer.color.g) || + (prevHwc2Layer.color.b != hwc2Layer.color.b) || + (prevHwc2Layer.color.a != hwc2Layer.color.a) || + (prevHwc2Layer.transform != hwc2Layer.transform); + if (compositionChanged) { + break; + } + } + } else { + compositionChanged = true; + } + bool needsSave = compositionNotFound || compositionChanged; + if (needsSave) { + prevComposition.clear(); + for (int i = 0; i < numLayers; i++) { + if (composeBuffers[i] == nullptr) { + prevComposition.emplace_back(nullptr); + continue; + } + auto layer = std::make_unique<SurfaceState::Layer>(); + layer->m_hwc2Layer = layers[i]; + layer->m_displayBuffer = composeBuffers[i]; + prevComposition.emplace_back(std::move(layer)); + } + } + return needsSave; +} + DisplayVk::DisplayBufferInfo::DisplayBufferInfo( const goldfish_vk::VulkanDispatch &vk, VkDevice vkDevice, uint32_t width, uint32_t height, VkFormat format, VkImage image) diff --git a/stream-servers/DisplayVk.h b/stream-servers/DisplayVk.h index 4d3d2666..952c28d1 100644 --- a/stream-servers/DisplayVk.h +++ b/stream-servers/DisplayVk.h @@ -6,9 +6,9 @@ #include <unordered_map> #include "CompositorVk.h" +#include "Hwc2.h" #include "RenderContext.h" #include "SwapChainStateVk.h" -#include "PostCommands.h" #include "vulkan/cereal/common/goldfish_vk_dispatch.h" // The DisplayVk class holds the Vulkan and other states required to draw a @@ -51,11 +51,19 @@ class DisplayVk { void post(const std::shared_ptr<DisplayBufferInfo> &); void compose( - const Post& postCmd, const std::vector<std::shared_ptr<DisplayBufferInfo>>& composeBuffers, - const std::shared_ptr<DisplayBufferInfo>& displayBuffer); + uint32_t numLayers, const ComposeLayer layers[], + const std::vector<std::shared_ptr<DisplayBufferInfo>> &composeBuffers); private: bool canComposite(VkFormat); + // Returns if the composition specified by the parameter is different from + // the previous composition. If the composition is different, update the + // previous composition stored in m_surfaceState. Must be called after + // bindToSurface() is called. + bool compareAndSaveComposition( + uint32_t renderTargetIndex, uint32_t numLayers, + const ComposeLayer layers[], + const std::vector<std::shared_ptr<DisplayBufferInfo>> &composeBuffers); const goldfish_vk::VulkanDispatch &m_vk; VkPhysicalDevice m_vkPhysicalDevice; @@ -73,10 +81,15 @@ class DisplayVk { std::unique_ptr<SwapChainStateVk> m_swapChainStateVk; std::unique_ptr<CompositorVk> m_compositorVk; struct SurfaceState { + struct Layer { + ComposeLayer m_hwc2Layer; + std::weak_ptr<DisplayBufferInfo> m_displayBuffer; + }; + uint32_t m_width = 0; uint32_t m_height = 0; - std::weak_ptr<DisplayBufferInfo> m_prevDisplayBuffer = - std::weak_ptr<DisplayBufferInfo>(); + std::unordered_map<uint32_t, std::vector<std::unique_ptr<Layer>>> + m_prevCompositions; }; std::unique_ptr<SurfaceState> m_surfaceState; std::unordered_map<VkFormat, bool> m_canComposite; diff --git a/stream-servers/FrameBuffer.cpp b/stream-servers/FrameBuffer.cpp index 41f8ea3a..bc8327b0 100644 --- a/stream-servers/FrameBuffer.cpp +++ b/stream-servers/FrameBuffer.cpp @@ -2780,52 +2780,46 @@ bool FrameBuffer::compose(uint32_t bufferSize, void* buffer, bool needPost) { // support for multi-display ComposeDevice_v2* p2 = (ComposeDevice_v2*)buffer; if (p2->displayId != 0) { - mutex.unlock(); - setDisplayColorBuffer(p2->displayId, p2->targetHandle); - mutex.lock(); + mutex.unlock(); + setDisplayColorBuffer(p2->displayId, p2->targetHandle); + mutex.lock(); } - Post composeCmd; - composeCmd.composeVersion = 2; - composeCmd.composeBuffer.resize(bufferSize); - memcpy(composeCmd.composeBuffer.data(), buffer, bufferSize); - composeCmd.cmd = PostCmd::Compose; if (m_displayVk) { + // We don't copy the render result to the targetHandle color buffer + // when using the Vulkan native host swapchain, because we directly + // render to the swapchain image instead of rendering onto a + // ColorBuffer, and we don't readback from the ColorBuffer so far. ColorBufferMap::iterator c; std::vector<ColorBufferPtr> cbs; // Keep ColorBuffers alive std::vector<std::shared_ptr<DisplayVk::DisplayBufferInfo>> composeBuffers; - ComposeDevice_v2* composeDevice = (ComposeDevice_v2*)buffer; - ComposeLayer* l = (ComposeLayer*)composeDevice->layer; - for (int i = 0; i < composeDevice->numLayers; ++i, ++l) { - c = m_colorbuffers.find(l->cbHandle); - if (c == m_colorbuffers.end()) { - composeBuffers.push_back(nullptr); - continue; - } - cbs.push_back(c->second.cb); - auto db = c->second.cb->getDisplayBufferVk(); - if (!db) { - mutex.unlock(); - goldfish_vk::setupVkColorBuffer(l->cbHandle); - mutex.lock(); - db = c->second.cb->getDisplayBufferVk(); - } - composeBuffers.push_back(db); - } - - c = m_colorbuffers.find(p2->targetHandle); - auto db = c->second.cb->getDisplayBufferVk(); - - if (!db) { - mutex.unlock(); - goldfish_vk::setupVkColorBuffer(p2->targetHandle); - mutex.lock(); - db = c->second.cb->getDisplayBufferVk(); + ComposeDevice_v2* const composeDevice = p2; + const ComposeLayer* const l = (ComposeLayer*)composeDevice->layer; + for (int i = 0; i < composeDevice->numLayers; ++i) { + c = m_colorbuffers.find(l[i].cbHandle); + if (c == m_colorbuffers.end()) { + composeBuffers.push_back(nullptr); + continue; + } + cbs.push_back(c->second.cb); + auto db = c->second.cb->getDisplayBufferVk(); + if (!db) { + mutex.unlock(); + goldfish_vk::setupVkColorBuffer(l[i].cbHandle); + mutex.lock(); + db = c->second.cb->getDisplayBufferVk(); + } + composeBuffers.push_back(db); } - m_displayVk->compose(composeCmd, composeBuffers, db); + m_displayVk->compose(composeDevice->numLayers, l, composeBuffers); m_justVkComposed = true; } else { + Post composeCmd; + composeCmd.composeVersion = 2; + composeCmd.composeBuffer.resize(bufferSize); + memcpy(composeCmd.composeBuffer.data(), buffer, bufferSize); + composeCmd.cmd = PostCmd::Compose; sendPostWorkerCmd(composeCmd); if (p2->displayId == 0 && needPost) { post(p2->targetHandle, false); |