diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 7a5ccbf559..2b64f0fe76 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -9,6 +9,10 @@ Milestone 87 * + * 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 0690900fb0..2c9123621b 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -38,6 +38,7 @@ skia_gpu_sources = [ "$_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 6425cb5226..b3d3f793fb 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 @@ private: #endif }; - GrBackend fBackend; + GrBackend fBackend = GrBackendApi::kMock; + bool fIsValid = false; }; #endif diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h index 5f4b2a8f2c..0a96abc8a6 100644 --- a/include/gpu/GrContext.h +++ b/include/gpu/GrContext.h @@ -687,18 +687,23 @@ public: * 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 0000000000..dec31d715c --- /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 + +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 e6100c8b26..96edd6fba2 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -754,6 +754,7 @@ GrBackendTexture GrContext::createCompressedBackendTexture(int width, int height bool GrContext::setBackendTextureState(const GrBackendTexture& backendTexture, const GrBackendSurfaceMutableState& state, + GrBackendSurfaceMutableState* previousState, GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) { sk_sp callback; @@ -769,7 +770,7 @@ bool GrContext::setBackendTextureState(const GrBackendTexture& backendTexture, 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::updateCompressedBackendTexture(const GrBackendTexture& backendTe bool GrContext::setBackendRenderTargetState(const GrBackendRenderTarget& backendRenderTarget, const GrBackendSurfaceMutableState& state, + GrBackendSurfaceMutableState* previousState, GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) { sk_sp callback; @@ -839,7 +841,8 @@ bool GrContext::setBackendRenderTargetState(const GrBackendRenderTarget& backend 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 5cacf8aca6..a5f5e8c75b 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -635,12 +635,14 @@ public: virtual bool setBackendTextureState(const GrBackendTexture&, const GrBackendSurfaceMutableState&, + GrBackendSurfaceMutableState* previousState, sk_sp finishedCallback) { return false; } virtual bool setBackendRenderTargetState(const GrBackendRenderTarget&, const GrBackendSurfaceMutableState&, + GrBackendSurfaceMutableState* previousState, sk_sp finishedCallback) { return false; } diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp index 701fd8abc7..307210cac9 100644 --- a/src/gpu/vk/GrVkGpu.cpp +++ b/src/gpu/vk/GrVkGpu.cpp @@ -1816,7 +1816,8 @@ void set_layout_and_queue_from_mutable_state(GrVkGpu* gpu, GrVkImage* image, bool GrVkGpu::setBackendSurfaceState(GrVkImageInfo info, sk_sp currentState, SkISize dimensions, - const GrVkSharedImageInfo& newInfo) { + const GrVkSharedImageInfo& newInfo, + GrBackendSurfaceMutableState* previousState) { sk_sp texture = GrVkTexture::MakeWrappedTexture( this, dimensions, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType, info, std::move(currentState)); @@ -1824,32 +1825,39 @@ bool GrVkGpu::setBackendSurfaceState(GrVkImageInfo info, 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 finishedCallback) { GrVkImageInfo info; SkAssertResult(backendTeture.getVkImageInfo(&info)); sk_sp 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 finishedCallback) { + GrBackendSurfaceMutableState* previousState, + sk_sp finishedCallback) { GrVkImageInfo info; SkAssertResult(backendRenderTarget.getVkImageInfo(&info)); sk_sp 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 bd27d93e8a..63abc61110 100644 --- a/src/gpu/vk/GrVkGpu.h +++ b/src/gpu/vk/GrVkGpu.h @@ -79,10 +79,12 @@ public: bool setBackendTextureState(const GrBackendTexture&, const GrBackendSurfaceMutableState&, + GrBackendSurfaceMutableState* previousState, sk_sp finishedCallback) override; bool setBackendRenderTargetState(const GrBackendRenderTarget&, const GrBackendSurfaceMutableState&, + GrBackendSurfaceMutableState* previousState, sk_sp finishedCallback) override; void deleteBackendTexture(const GrBackendTexture&) override; @@ -215,7 +217,8 @@ private: bool setBackendSurfaceState(GrVkImageInfo info, sk_sp currentState, SkISize dimensions, - const GrVkSharedImageInfo& newInfo); + const GrVkSharedImageInfo& newInfo, + GrBackendSurfaceMutableState* previousState); sk_sp onCreateTexture(SkISize, const GrBackendFormat&, diff --git a/tests/BackendSurfaceMutableStateTest.cpp b/tests/BackendSurfaceMutableStateTest.cpp index df8f14964b..8e822e25c9 100644 --- a/tests/BackendSurfaceMutableStateTest.cpp +++ b/tests/BackendSurfaceMutableStateTest.cpp @@ -107,41 +107,65 @@ DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkBackendSurfaceMutableStateTest, reporter, ctxIn // real transitions to the image so we need to be careful about doing actual valid transitions. GrVkGpu* gpu = static_cast(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.