summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2021-05-05 17:44:36 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2021-05-05 17:44:36 +0000
commitd51f523c443a68f50f0cd9f95735246cb61f8306 (patch)
tree95ac76eff2fc387ee5ebac0a3bf8d18ee0df2459
parente43ad77c4f6a6c4a99e23546563c5383e1173ec1 (diff)
parentcc43342b9ff64d3b7228979f59b89bc7f85951df (diff)
downloadvulkan-cereal-d51f523c443a68f50f0cd9f95735246cb61f8306.tar.gz
Merge "Native VK Swapchain: rcCompose support (basic) cleanup"
-rw-r--r--stream-servers/CompositorVk.cpp280
-rw-r--r--stream-servers/CompositorVk.h39
-rw-r--r--stream-servers/DisplayVk.cpp239
-rw-r--r--stream-servers/DisplayVk.h23
-rw-r--r--stream-servers/FrameBuffer.cpp66
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 &currentComposition = *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);