Add support for VK_IMAGE_LAYOUT_PRESENT_SRC_KHR in skia vulkan.
This change allows Skia to handle transfering from the present layout.
Skia currently never changes to the present layout, though we are looking
at adding support for this in a different CL.
With this change a client can wrap a an VkImage into an SkSurface still in
the queue present layout and Skia will handle the transation to color
attachment. If a client uses this functiality they most likely will want
to immediately call wait(GrBackendSemaphore) on the SkSurface so that Skia
waits on the VkSemaphore that came from a call to vulkan aquire image before
doing any work on the wrapped VkImage.
Bug: skia:
Change-Id: Ia9bd12ad4e6cd972daaa972cce8698d396c002fc
Reviewed-on: https://skia-review.googlesource.com/c/194424
Reviewed-by: Jim Van Verth <jvanverth@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 063b72b..d488403 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -1750,7 +1750,7 @@
kAdopt_GrWrapOwnership);
std::unique_ptr<GrOp> waitOp(GrSemaphoreOp::MakeWait(fContext, std::move(sema),
fRenderTargetProxy.get()));
- this->getRTOpList()->addOp(std::move(waitOp), *this->caps());
+ this->getRTOpList()->addWaitOp(std::move(waitOp), *this->caps());
}
return true;
}
diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp
index e01a58f..bab24ca 100644
--- a/src/gpu/GrRenderTargetOpList.cpp
+++ b/src/gpu/GrRenderTargetOpList.cpp
@@ -558,7 +558,9 @@
// Although the clear will ignore the stencil buffer, following draw ops may not so we can't get
// rid of all the preceding ops. Beware! If we ever add any ops that have a side effect beyond
// modifying the stencil buffer we will need a more elaborate tracking system (skbug.com/7002).
- if (this->isEmpty() || !fTarget.get()->asRenderTargetProxy()->needsStencil()) {
+ // Additionally, if we previously recorded a wait op, we cannot delete the wait op. Until we
+ // track the wait ops separately from normal ops, we have to avoid clearing out any ops.
+ if (this->isEmpty() || (!fTarget.get()->asRenderTargetProxy()->needsStencil() && !fHasWaitOp)) {
this->deleteOps();
fDeferredProxies.reset();
diff --git a/src/gpu/GrRenderTargetOpList.h b/src/gpu/GrRenderTargetOpList.h
index 439c7ac..7faae2a 100644
--- a/src/gpu/GrRenderTargetOpList.h
+++ b/src/gpu/GrRenderTargetOpList.h
@@ -72,6 +72,11 @@
this->recordOp(std::move(op), GrProcessorSet::EmptySetAnalysis(), nullptr, nullptr, caps);
}
+ void addWaitOp(std::unique_ptr<GrOp> op, const GrCaps& caps) {
+ fHasWaitOp= true;
+ this->addOp(std::move(op), caps);
+ }
+
void addDrawOp(std::unique_ptr<GrDrawOp> op, const GrProcessorSet::Analysis& processorAnalysis,
GrAppliedClip&& clip, const DstProxy& dstProxy, const GrCaps& caps) {
auto addDependency = [ &caps, this ] (GrSurfaceProxy* p) {
@@ -222,6 +227,9 @@
SkIRect fLastDevClipBounds;
int fLastClipNumAnalyticFPs;
+ // We must track if we have a wait op so that we don't delete the op when we have a full clear.
+ bool fHasWaitOp = false;;
+
// For ops/opList we have mean: 5 stdDev: 28
SkSTArray<25, OpChain, true> fOpChains;
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index 55f632a..9b61fb6 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -241,6 +241,10 @@
SkASSERT(physicalDeviceVersion <= properties.apiVersion);
+ if (extensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 1)) {
+ fSupportsSwapchain = true;
+ }
+
if (physicalDeviceVersion >= VK_MAKE_VERSION(1, 1, 0) ||
extensions.hasExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, 1)) {
fSupportsPhysicalDeviceProperties2 = true;
diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h
index 41c31fb..587102d 100644
--- a/src/gpu/vk/GrVkCaps.h
+++ b/src/gpu/vk/GrVkCaps.h
@@ -98,6 +98,12 @@
return fPreferredStencilFormat;
}
+ // Returns whether the device supports VK_KHR_Swapchain. Internally Skia never uses any of the
+ // swapchain functions, but we may need to transition to and from the
+ // VK_IMAGE_LAYOUT_PRESENT_SRC_KHR image layout, so we must know whether that layout is
+ // supported.
+ bool supportsSwapchain() const { return fSupportsSwapchain; }
+
// Returns whether the device supports the ability to extend VkPhysicalDeviceProperties struct.
bool supportsPhysicalDeviceProperties2() const { return fSupportsPhysicalDeviceProperties2; }
// Returns whether the device supports the ability to extend VkMemoryRequirements struct.
@@ -219,6 +225,8 @@
bool fNewCBOnPipelineChange = false;
bool fShouldAlwaysUseDedicatedImageMemory = false;
+ bool fSupportsSwapchain = false;
+
bool fSupportsPhysicalDeviceProperties2 = false;
bool fSupportsMemoryRequirements2 = false;
bool fSupportsBindMemory2 = false;
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 52b6cb0..4c4bf01 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1022,8 +1022,13 @@
static bool check_image_info(const GrVkCaps& caps,
const GrVkImageInfo& info,
- GrPixelConfig config) {
- if (VK_NULL_HANDLE == info.fImage || VK_NULL_HANDLE == info.fAlloc.fMemory) {
+ GrPixelConfig config,
+ bool isWrappedRT) {
+ if (VK_NULL_HANDLE == info.fImage) {
+ return false;
+ }
+
+ if (VK_NULL_HANDLE == info.fAlloc.fMemory && !isWrappedRT) {
return false;
}
@@ -1033,6 +1038,10 @@
}
}
+ if (info.fImageLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR && !caps.supportsSwapchain()) {
+ return false;
+ }
+
SkASSERT(GrVkFormatPixelConfigPairIsValid(info.fFormat, config));
return true;
}
@@ -1045,7 +1054,7 @@
return nullptr;
}
- if (!check_image_info(this->vkCaps(), imageInfo, backendTex.config())) {
+ if (!check_image_info(this->vkCaps(), imageInfo, backendTex.config(), false)) {
return nullptr;
}
@@ -1071,7 +1080,7 @@
return nullptr;
}
- if (!check_image_info(this->vkCaps(), imageInfo, backendTex.config())) {
+ if (!check_image_info(this->vkCaps(), imageInfo, backendTex.config(), false)) {
return nullptr;
}
@@ -1103,7 +1112,7 @@
return nullptr;
}
- if (VK_NULL_HANDLE == info.fImage) {
+ if (!check_image_info(this->vkCaps(), info, backendRT.config(), true)) {
return nullptr;
}
@@ -1135,10 +1144,11 @@
if (!tex.getVkImageInfo(&imageInfo)) {
return nullptr;
}
- if (VK_NULL_HANDLE == imageInfo.fImage) {
+ if (!check_image_info(this->vkCaps(), imageInfo, tex.config(), false)) {
return nullptr;
}
+
GrSurfaceDesc desc;
desc.fFlags = kRenderTarget_GrSurfaceFlag;
desc.fWidth = tex.width();
diff --git a/src/gpu/vk/GrVkImage.cpp b/src/gpu/vk/GrVkImage.cpp
index a6171fc..6f9a726 100644
--- a/src/gpu/vk/GrVkImage.cpp
+++ b/src/gpu/vk/GrVkImage.cpp
@@ -29,6 +29,8 @@
return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
return VK_PIPELINE_STAGE_HOST_BIT;
+ } else if (VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
+ return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
@@ -64,6 +66,8 @@
flags = VK_ACCESS_TRANSFER_READ_BIT;
} else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
flags = VK_ACCESS_SHADER_READ_BIT;
+ } else if (VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
+ flags = 0;
}
return flags;
}