Add optional param to setBackendTextureState to return previous state.
Bug: skia:10742
Change-Id: I334e7896d0a1509eb666c46d5731d2573a5c1aba
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/318698
Reviewed-by: Austin Eng <enga@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index 7a5ccbf..2b64f0f 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -9,6 +9,10 @@
* <insert new release notes here>
+ * Add new optional parameter to GrContext::setBackend[Texture/RenderTarget]State which can
+ be used to return the previous GrBackendSurfaceMutableState before the requested change.
+ https://review.skia.org/318698
+
* New optimized clip stack for GPU backends. Enabled by default but old behavior based on
SkClipStack can be restored by defining SK_DISABLE_NEW_GR_CLIP_STACK when building. It is not
compatible with SK_SUPPORT_DEPRECATED_CLIPOPS and we are targeting the removal of support for
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 0690900..2c91236 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -38,6 +38,7 @@
"$_src/gpu/GrAutoLocaleSetter.h",
"$_src/gpu/GrBackendSemaphore.cpp",
"$_src/gpu/GrBackendSurface.cpp",
+ "$_src/gpu/GrBackendSurfaceMutableState.cpp",
"$_src/gpu/GrBackendSurfaceMutableStateImpl.h",
"$_src/gpu/GrBackendTextureImageGenerator.cpp",
"$_src/gpu/GrBackendTextureImageGenerator.h",
diff --git a/include/gpu/GrBackendSurfaceMutableState.h b/include/gpu/GrBackendSurfaceMutableState.h
index 6425cb5..b3d3f79 100644
--- a/include/gpu/GrBackendSurfaceMutableState.h
+++ b/include/gpu/GrBackendSurfaceMutableState.h
@@ -24,35 +24,59 @@
*
* Vulkan: VkImageLayout and QueueFamilyIndex
*/
-class GrBackendSurfaceMutableState {
+class SK_API GrBackendSurfaceMutableState {
public:
+ GrBackendSurfaceMutableState() {}
+
#ifdef SK_VULKAN
GrBackendSurfaceMutableState(VkImageLayout layout, uint32_t queueFamilyIndex)
: fVkState(layout, queueFamilyIndex)
- , fBackend(GrBackend::kVulkan) {}
+ , fBackend(GrBackend::kVulkan)
+ , fIsValid(true) {}
#endif
- GrBackendSurfaceMutableState& operator=(const GrBackendSurfaceMutableState& that) {
- switch (fBackend) {
- case GrBackend::kVulkan:
+ GrBackendSurfaceMutableState(const GrBackendSurfaceMutableState& that);
+ GrBackendSurfaceMutableState& operator=(const GrBackendSurfaceMutableState& that);
+
#ifdef SK_VULKAN
- SkASSERT(that.fBackend == GrBackend::kVulkan);
- fVkState = that.fVkState;
-#endif
- break;
-
- default:
- (void)that;
- SkUNREACHABLE;
+ // If this class is not Vulkan backed it will return value of VK_IMAGE_LAYOUT_UNDEFINED.
+ // Otherwise it will return the VkImageLayout.
+ VkImageLayout getVkImageLayout() const {
+ if (this->isValid() && fBackend != GrBackendApi::kVulkan) {
+ return VK_IMAGE_LAYOUT_UNDEFINED;
}
- fBackend = that.fBackend;
- return *this;
+ return fVkState.getImageLayout();
}
+ // If this class is not Vulkan backed it will return value of VK_QUEUE_FAMILY_IGNORED.
+ // Otherwise it will return the VkImageLayout.
+ uint32_t getQueueFamilyIndex() const {
+ if (this->isValid() && fBackend != GrBackendApi::kVulkan) {
+ return VK_QUEUE_FAMILY_IGNORED;
+ }
+ return fVkState.getQueueFamilyIndex();
+ }
+#endif
+
+ // Returns true if the backend mutable state has been initialized.
+ bool isValid() const { return fIsValid; }
+
+ GrBackendApi backend() const { return fBackend; }
+
private:
friend class GrBackendSurfaceMutableStateImpl;
friend class GrVkGpu;
+#ifdef SK_VULKAN
+ void setVulkanState(VkImageLayout layout, uint32_t queueFamilyIndex) {
+ SkASSERT(!this->isValid() || fBackend == GrBackendApi::kVulkan);
+ fVkState.setImageLayout(layout);
+ fVkState.setQueueFamilyIndex(queueFamilyIndex);
+ fBackend = GrBackendApi::kVulkan;
+ fIsValid = true;
+ }
+#endif
+
union {
char fDummy;
#ifdef SK_VULKAN
@@ -60,7 +84,8 @@
#endif
};
- GrBackend fBackend;
+ GrBackend fBackend = GrBackendApi::kMock;
+ bool fIsValid = false;
};
#endif
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 5f4b2a8..0a96abc 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -687,18 +687,23 @@
* called (e.g updateBackendTexture and flush). If finishedProc is not null then it will be
* called with finishedContext after the state transition is known to have occurred on the GPU.
*
+ * See GrBackendSurfaceMutableState to see what state can be set via this call.
+ *
* If the backend API is Vulkan, the caller can set the GrBackendSurfaceMutableState's
* VkImageLayout to VK_IMAGE_LAYOUT_UNDEFINED or queueFamilyIndex to VK_QUEUE_FAMILY_IGNORED to
* tell Skia to not change those respective states.
*
- * See GrBackendSurfaceMutableState to see what state can be set via this call.
+ * If previousState is not null and this returns true, then Skia will have filled in
+ * previousState to have the values of the state before this call.
*/
bool setBackendTextureState(const GrBackendTexture&,
const GrBackendSurfaceMutableState&,
+ GrBackendSurfaceMutableState* previousState = nullptr,
GrGpuFinishedProc finishedProc = nullptr,
GrGpuFinishedContext finishedContext = nullptr);
bool setBackendRenderTargetState(const GrBackendRenderTarget&,
const GrBackendSurfaceMutableState&,
+ GrBackendSurfaceMutableState* previousState = nullptr,
GrGpuFinishedProc finishedProc = nullptr,
GrGpuFinishedContext finishedContext = nullptr);
diff --git a/src/gpu/GrBackendSurfaceMutableState.cpp b/src/gpu/GrBackendSurfaceMutableState.cpp
new file mode 100644
index 0000000..dec31d7
--- /dev/null
+++ b/src/gpu/GrBackendSurfaceMutableState.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/gpu/GrBackendSurfaceMutableState.h"
+
+#include <new>
+
+GrBackendSurfaceMutableState::GrBackendSurfaceMutableState(const GrBackendSurfaceMutableState& that)
+ : fBackend(that.fBackend), fIsValid(that.fIsValid) {
+ if (!fIsValid) {
+ return;
+ }
+ switch (fBackend) {
+ case GrBackend::kVulkan:
+#ifdef SK_VULKAN
+ SkASSERT(that.fBackend == GrBackend::kVulkan);
+ fVkState = that.fVkState;
+#endif
+ break;
+ default:
+ (void)that;
+ SkUNREACHABLE;
+ }
+}
+
+GrBackendSurfaceMutableState& GrBackendSurfaceMutableState::operator=(
+ const GrBackendSurfaceMutableState& that) {
+ if (this != &that) {
+ this->~GrBackendSurfaceMutableState();
+ new (this) GrBackendSurfaceMutableState(that);
+ }
+ return *this;
+}
+
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index e6100c8..96edd6f 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -754,6 +754,7 @@
bool GrContext::setBackendTextureState(const GrBackendTexture& backendTexture,
const GrBackendSurfaceMutableState& state,
+ GrBackendSurfaceMutableState* previousState,
GrGpuFinishedProc finishedProc,
GrGpuFinishedContext finishedContext) {
sk_sp<GrRefCntedCallback> callback;
@@ -769,7 +770,7 @@
return false;
}
- return fGpu->setBackendTextureState(backendTexture, state, std::move(callback));
+ return fGpu->setBackendTextureState(backendTexture, state, previousState, std::move(callback));
}
bool GrContext::updateCompressedBackendTexture(const GrBackendTexture& backendTexture,
@@ -824,6 +825,7 @@
bool GrContext::setBackendRenderTargetState(const GrBackendRenderTarget& backendRenderTarget,
const GrBackendSurfaceMutableState& state,
+ GrBackendSurfaceMutableState* previousState,
GrGpuFinishedProc finishedProc,
GrGpuFinishedContext finishedContext) {
sk_sp<GrRefCntedCallback> callback;
@@ -839,7 +841,8 @@
return false;
}
- return fGpu->setBackendRenderTargetState(backendRenderTarget, state, std::move(callback));
+ return fGpu->setBackendRenderTargetState(backendRenderTarget, state, previousState,
+ std::move(callback));
}
void GrContext::deleteBackendTexture(GrBackendTexture backendTex) {
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 5cacf8a..a5f5e8c 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -635,12 +635,14 @@
virtual bool setBackendTextureState(const GrBackendTexture&,
const GrBackendSurfaceMutableState&,
+ GrBackendSurfaceMutableState* previousState,
sk_sp<GrRefCntedCallback> finishedCallback) {
return false;
}
virtual bool setBackendRenderTargetState(const GrBackendRenderTarget&,
const GrBackendSurfaceMutableState&,
+ GrBackendSurfaceMutableState* previousState,
sk_sp<GrRefCntedCallback> finishedCallback) {
return false;
}
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 701fd8a..307210ca 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1816,7 +1816,8 @@
bool GrVkGpu::setBackendSurfaceState(GrVkImageInfo info,
sk_sp<GrBackendSurfaceMutableStateImpl> currentState,
SkISize dimensions,
- const GrVkSharedImageInfo& newInfo) {
+ const GrVkSharedImageInfo& newInfo,
+ GrBackendSurfaceMutableState* previousState) {
sk_sp<GrVkTexture> texture = GrVkTexture::MakeWrappedTexture(
this, dimensions, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType, info,
std::move(currentState));
@@ -1824,32 +1825,39 @@
if (!texture) {
return false;
}
+ if (previousState) {
+ previousState->setVulkanState(texture->currentLayout(),
+ texture->currentQueueFamilyIndex());
+ }
set_layout_and_queue_from_mutable_state(this, texture.get(), newInfo);
return true;
}
bool GrVkGpu::setBackendTextureState(const GrBackendTexture& backendTeture,
const GrBackendSurfaceMutableState& newState,
+ GrBackendSurfaceMutableState* previousState,
sk_sp<GrRefCntedCallback> finishedCallback) {
GrVkImageInfo info;
SkAssertResult(backendTeture.getVkImageInfo(&info));
sk_sp<GrBackendSurfaceMutableStateImpl> currentState = backendTeture.getMutableState();
SkASSERT(currentState);
- SkASSERT(newState.fBackend == GrBackend::kVulkan);
+ SkASSERT(newState.isValid() && newState.fBackend == GrBackend::kVulkan);
return this->setBackendSurfaceState(info, std::move(currentState), backendTeture.dimensions(),
- newState.fVkState);
+ newState.fVkState, previousState);
}
bool GrVkGpu::setBackendRenderTargetState(const GrBackendRenderTarget& backendRenderTarget,
const GrBackendSurfaceMutableState& newState,
- sk_sp<GrRefCntedCallback> finishedCallback) {
+ GrBackendSurfaceMutableState* previousState,
+ sk_sp<GrRefCntedCallback> finishedCallback) {
GrVkImageInfo info;
SkAssertResult(backendRenderTarget.getVkImageInfo(&info));
sk_sp<GrBackendSurfaceMutableStateImpl> currentState = backendRenderTarget.getMutableState();
SkASSERT(currentState);
SkASSERT(newState.fBackend == GrBackend::kVulkan);
return this->setBackendSurfaceState(info, std::move(currentState),
- backendRenderTarget.dimensions(), newState.fVkState);
+ backendRenderTarget.dimensions(), newState.fVkState,
+ previousState);
}
void GrVkGpu::querySampleLocations(GrRenderTarget* renderTarget,
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index bd27d93..63abc61 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -79,10 +79,12 @@
bool setBackendTextureState(const GrBackendTexture&,
const GrBackendSurfaceMutableState&,
+ GrBackendSurfaceMutableState* previousState,
sk_sp<GrRefCntedCallback> finishedCallback) override;
bool setBackendRenderTargetState(const GrBackendRenderTarget&,
const GrBackendSurfaceMutableState&,
+ GrBackendSurfaceMutableState* previousState,
sk_sp<GrRefCntedCallback> finishedCallback) override;
void deleteBackendTexture(const GrBackendTexture&) override;
@@ -215,7 +217,8 @@
bool setBackendSurfaceState(GrVkImageInfo info,
sk_sp<GrBackendSurfaceMutableStateImpl> currentState,
SkISize dimensions,
- const GrVkSharedImageInfo& newInfo);
+ const GrVkSharedImageInfo& newInfo,
+ GrBackendSurfaceMutableState* previousState);
sk_sp<GrTexture> onCreateTexture(SkISize,
const GrBackendFormat&,
diff --git a/tests/BackendSurfaceMutableStateTest.cpp b/tests/BackendSurfaceMutableStateTest.cpp
index df8f1496..8e822e2 100644
--- a/tests/BackendSurfaceMutableStateTest.cpp
+++ b/tests/BackendSurfaceMutableStateTest.cpp
@@ -107,41 +107,65 @@
// real transitions to the image so we need to be careful about doing actual valid transitions.
GrVkGpu* gpu = static_cast<GrVkGpu*>(dContext->priv().getGpu());
- dContext->setBackendTextureState(backendTex, newState);
+ GrBackendSurfaceMutableState previousState;
+
+ dContext->setBackendTextureState(backendTex, newState, &previousState);
REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == info.fImageLayout);
REPORTER_ASSERT(reporter, gpu->queueIndex() == info.fCurrentQueueFamily);
+ REPORTER_ASSERT(reporter, previousState.isValid());
+ REPORTER_ASSERT(reporter, previousState.backend() == GrBackendApi::kVulkan);
+ REPORTER_ASSERT(reporter, previousState.getVkImageLayout() == initLayout);
+ REPORTER_ASSERT(reporter, previousState.getQueueFamilyIndex() == initQueue);
+
// Make sure passing in VK_IMAGE_LAYOUT_UNDEFINED does not change the layout
GrBackendSurfaceMutableState noopState(VK_IMAGE_LAYOUT_UNDEFINED, VK_QUEUE_FAMILY_IGNORED);
- dContext->setBackendTextureState(backendTex, noopState);
+ dContext->setBackendTextureState(backendTex, noopState, &previousState);
REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == info.fImageLayout);
REPORTER_ASSERT(reporter, gpu->queueIndex() == info.fCurrentQueueFamily);
+ REPORTER_ASSERT(reporter, previousState.isValid());
+ REPORTER_ASSERT(reporter, previousState.backend() == GrBackendApi::kVulkan);
+ REPORTER_ASSERT(reporter,
+ previousState.getVkImageLayout() == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ REPORTER_ASSERT(reporter, previousState.getQueueFamilyIndex() == gpu->queueIndex());
+
// To test queue transitions, we don't have any other valid queue available so instead we try
// to transition to external queue.
if (gpu->vkCaps().supportsExternalMemory()) {
GrBackendSurfaceMutableState externalState(VK_IMAGE_LAYOUT_GENERAL,
VK_QUEUE_FAMILY_EXTERNAL);
- dContext->setBackendTextureState(backendTex, externalState);
+ dContext->setBackendTextureState(backendTex, externalState, &previousState);
REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_GENERAL == info.fImageLayout);
REPORTER_ASSERT(reporter, VK_QUEUE_FAMILY_EXTERNAL == info.fCurrentQueueFamily);
+ REPORTER_ASSERT(reporter, previousState.isValid());
+ REPORTER_ASSERT(reporter, previousState.backend() == GrBackendApi::kVulkan);
+ REPORTER_ASSERT(reporter,
+ previousState.getVkImageLayout() == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
+ REPORTER_ASSERT(reporter, previousState.getQueueFamilyIndex() == gpu->queueIndex());
+
dContext->submit();
// Go back to the initial queue. Also we should stay in VK_IMAGE_LAYOUT_GENERAL since we
// are passing in VK_IMAGE_LAYOUT_UNDEFINED
GrBackendSurfaceMutableState externalState2(VK_IMAGE_LAYOUT_UNDEFINED, initQueue);
- dContext->setBackendTextureState(backendTex, externalState2);
+ dContext->setBackendTextureState(backendTex, externalState2, &previousState);
REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_GENERAL == info.fImageLayout);
REPORTER_ASSERT(reporter, gpu->queueIndex() == info.fCurrentQueueFamily);
+
+ REPORTER_ASSERT(reporter, previousState.isValid());
+ REPORTER_ASSERT(reporter, previousState.backend() == GrBackendApi::kVulkan);
+ REPORTER_ASSERT(reporter, previousState.getVkImageLayout() == VK_IMAGE_LAYOUT_GENERAL);
+ REPORTER_ASSERT(reporter, previousState.getQueueFamilyIndex() == VK_QUEUE_FAMILY_EXTERNAL);
}
// We must submit this work before we try to delete the backend texture.