Add GrContext API to allow updating GrBackendSurfaceMutableState.

This is currently only supported for the Vulkan backend

Bug: skia:10254
Change-Id: I9274799098dc00dec5abcbcec95ce7cc23fec537
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/293844
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Greg Daniel 2020-06-09 17:29:32 -04:00 committed by Skia Commit-Bot
parent 4442bfa50b
commit 1db8e7990a
9 changed files with 181 additions and 5 deletions

View File

@ -8,9 +8,13 @@ Milestone 85
------------
* <insert new release notes here>
* Add GrContext function to set mutable state on a backend surface. Currently this
is only used for setting vulkan VkImage layout and queue family.
https://review.skia.org/293844
* SkSurface factores that take GrBackendTexture or GrBackendRenderTarget now always
call the release proc (if provided) on failure. SkSurface::replaceBackendTexture
call the release proc (if provided) on failure. SkSurface::replaceBackendTexture
also calls the release proc on failure.
https://review.skia.org/293762

View File

@ -51,6 +51,7 @@ public:
private:
friend class GrBackendSurfaceMutableStateImpl;
friend class GrVkGpu;
union {
char fDummy;

View File

@ -665,6 +665,26 @@ public:
GrGpuFinishedProc finishedProc = nullptr,
GrGpuFinishedContext finishedContext = nullptr);
/**
* Updates the state of the GrBackendTexture/RenderTarget to have the passed in
* GrBackendSurfaceMutableState. All objects that wrap the backend surface (i.e. SkSurfaces and
* SkImages) will also be aware of this state change. This call does not submit the state change
* to the gpu, but requires the client to call GrContext::submit to send it to the GPU. The work
* for this call is ordered linearly with all other calls that require GrContext::submit to be
* 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.
*/
bool setBackendTextureState(const GrBackendTexture&,
const GrBackendSurfaceMutableState&,
GrGpuFinishedProc finishedProc = nullptr,
GrGpuFinishedContext finishedContext = nullptr);
bool setBackendRenderTargetState(const GrBackendRenderTarget&,
const GrBackendSurfaceMutableState&,
GrGpuFinishedProc finishedProc = nullptr,
GrGpuFinishedContext finishedContext = nullptr);
void deleteBackendTexture(GrBackendTexture);
// This interface allows clients to pre-compile shaders and populate the runtime program cache.

View File

@ -53,7 +53,6 @@ public:
return *this;
}
void setImageLayout(VkImageLayout layout) {
// Defaulting to use std::memory_order_seq_cst
fLayout.store(layout);

View File

@ -785,6 +785,48 @@ GrBackendTexture GrContext::createCompressedBackendTexture(int width, int height
finishedContext);
}
bool GrContext::setBackendTextureState(const GrBackendTexture& backendTexture,
const GrBackendSurfaceMutableState& state,
GrGpuFinishedProc finishedProc,
GrGpuFinishedContext finishedContext) {
if (!this->asDirectContext()) {
finishedProc(finishedContext);
return false;
}
if (this->abandoned()) {
finishedProc(finishedContext);
return false;
}
sk_sp<GrRefCntedCallback> callback;
if (finishedProc) {
callback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
}
return fGpu->setBackendTextureState(backendTexture, state, std::move(callback));
}
bool GrContext::setBackendRenderTargetState(const GrBackendRenderTarget& backendRenderTarget,
const GrBackendSurfaceMutableState& state,
GrGpuFinishedProc finishedProc,
GrGpuFinishedContext finishedContext) {
if (!this->asDirectContext()) {
finishedProc(finishedContext);
return false;
}
if (this->abandoned()) {
finishedProc(finishedContext);
return false;
}
sk_sp<GrRefCntedCallback> callback;
if (finishedProc) {
callback.reset(new GrRefCntedCallback(finishedProc, finishedContext));
}
return fGpu->setBackendRenderTargetState(backendRenderTarget, state, std::move(callback));
}
void GrContext::deleteBackendTexture(GrBackendTexture backendTex) {
TRACE_EVENT0("skia.gpu", TRACE_FUNC);
// For the Vulkan backend we still must destroy the backend texture when the context is
@ -796,6 +838,8 @@ void GrContext::deleteBackendTexture(GrBackendTexture backendTex) {
fGpu->deleteBackendTexture(backendTex);
}
//////////////////////////////////////////////////////////////////////////////
bool GrContext::precompileShader(const SkData& key, const SkData& data) {
return fGpu->precompileShader(key, data);
}

View File

@ -622,6 +622,18 @@ public:
GrGpuFinishedContext finishedContext,
const BackendTextureData*);
virtual bool setBackendTextureState(const GrBackendTexture&,
const GrBackendSurfaceMutableState&,
sk_sp<GrRefCntedCallback> finishedCallback) {
return false;
}
virtual bool setBackendRenderTargetState(const GrBackendRenderTarget&,
const GrBackendSurfaceMutableState&,
sk_sp<GrRefCntedCallback> finishedCallback) {
return false;
}
/**
* Frees a texture created by createBackendTexture(). If ownership of the backend
* texture has been transferred to a GrContext using adopt semantics this should not be called.

View File

@ -1778,6 +1778,51 @@ GrBackendTexture GrVkGpu::onCreateCompressedBackendTexture(
return beTex;
}
bool GrVkGpu::setBackendSurfaceState(GrVkImageInfo info,
sk_sp<GrBackendSurfaceMutableStateImpl> currentState,
SkISize dimensions,
const GrVkSharedImageInfo& newInfo) {
sk_sp<GrVkTexture> texture = GrVkTexture::MakeWrappedTexture(
this, dimensions, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType, info,
std::move(currentState));
SkASSERT(texture);
if (!texture) {
return false;
}
// Even though internally we use this helper for getting src access flags and stages they
// can also be used for general dst flags since we don't know exactly what the client
// plans on using the image for.
VkImageLayout newLayout = newInfo.getImageLayout();
VkPipelineStageFlags dstStage = GrVkImage::LayoutToPipelineSrcStageFlags(newLayout);
VkAccessFlags dstAccess = GrVkImage::LayoutToSrcAccessMask(newLayout);
texture->setImageLayoutAndQueueIndex(this, newLayout, dstAccess, dstStage, false,
newInfo.getQueueFamilyIndex());
return true;
}
bool GrVkGpu::setBackendTextureState(const GrBackendTexture& backendTeture,
const GrBackendSurfaceMutableState& newState,
sk_sp<GrRefCntedCallback> finishedCallback) {
GrVkImageInfo info;
SkAssertResult(backendTeture.getVkImageInfo(&info));
sk_sp<GrBackendSurfaceMutableStateImpl> currentState = backendTeture.getMutableState();
SkASSERT(currentState);
SkASSERT(newState.fBackend == GrBackend::kVulkan);
return this->setBackendSurfaceState(info, std::move(currentState), backendTeture.dimensions(),
newState.fVkState);
}
bool GrVkGpu::setBackendRenderTargetState(const GrBackendRenderTarget& backendRenderTarget,
const GrBackendSurfaceMutableState& newState,
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);
}
void GrVkGpu::querySampleLocations(GrRenderTarget* renderTarget,
SkTArray<SkPoint>* sampleLocations) {
@ -1944,7 +1989,9 @@ void GrVkGpu::addImageMemoryBarrier(const GrManagedResource* resource,
}
void GrVkGpu::prepareSurfacesForBackendAccessAndExternalIO(
GrSurfaceProxy* proxies[], int numProxies, SkSurface::BackendSurfaceAccess access,
GrSurfaceProxy* proxies[],
int numProxies,
SkSurface::BackendSurfaceAccess access,
const GrPrepareForExternalIORequests& externalRequests) {
SkASSERT(numProxies >= 0);
SkASSERT(!numProxies || proxies);

View File

@ -73,6 +73,14 @@ public:
void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {}
bool setBackendTextureState(const GrBackendTexture&,
const GrBackendSurfaceMutableState&,
sk_sp<GrRefCntedCallback> finishedCallback) override;
bool setBackendRenderTargetState(const GrBackendRenderTarget&,
const GrBackendSurfaceMutableState&,
sk_sp<GrRefCntedCallback> finishedCallback) override;
void deleteBackendTexture(const GrBackendTexture&) override;
bool compile(const GrProgramDesc&, const GrProgramInfo&) override;
@ -193,6 +201,11 @@ private:
sk_sp<GrRefCntedCallback> finishedCallback,
const BackendTextureData*) override;
bool setBackendSurfaceState(GrVkImageInfo info,
sk_sp<GrBackendSurfaceMutableStateImpl> currentState,
SkISize dimensions,
const GrVkSharedImageInfo& newInfo);
sk_sp<GrTexture> onCreateTexture(SkISize,
const GrBackendFormat&,
GrRenderable,

View File

@ -9,13 +9,14 @@
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrContext.h"
#include "include/gpu/vk/GrVkTypes.h"
#include "src/gpu/GrContextPriv.h"
#include "src/gpu/GrTexture.h"
#include "src/gpu/GrTextureProxy.h"
#include "src/image/SkImage_Base.h"
#include "tests/Test.h"
#ifdef SK_VULKAN
#include "src/gpu/vk/GrVkGpu.h"
#include "src/gpu/vk/GrVkTexture.h"
DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkBackendSurfaceMutableStateTest, reporter, ctxInfo) {
@ -102,6 +103,41 @@ DEF_GPUTEST_FOR_VULKAN_CONTEXT(VkBackendSurfaceMutableStateTest, reporter, ctxIn
REPORTER_ASSERT(reporter, initLayout == info.fImageLayout);
REPORTER_ASSERT(reporter, initQueue == info.fCurrentQueueFamily);
// Test using the setBackendTextureStateAPI. Unlike the previous test this will actually add
// real transitions to the image so we need to be careful about doing actual valid transitions.
GrVkGpu* gpu = static_cast<GrVkGpu*>(context->priv().getGpu());
context->setBackendTextureState(backendTex, newState);
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);
// 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);
context->setBackendTextureState(backendTex, externalState);
REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_GENERAL == info.fImageLayout);
REPORTER_ASSERT(reporter, VK_QUEUE_FAMILY_EXTERNAL == info.fCurrentQueueFamily);
context->submit();
GrBackendSurfaceMutableState externalState2(VK_IMAGE_LAYOUT_GENERAL, initQueue);
context->setBackendTextureState(backendTex, externalState2);
REPORTER_ASSERT(reporter, backendTex.getVkImageInfo(&info));
REPORTER_ASSERT(reporter, VK_IMAGE_LAYOUT_GENERAL == info.fImageLayout);
REPORTER_ASSERT(reporter, gpu->queueIndex() == info.fCurrentQueueFamily);
}
// We must submit this work before we try to delete the backend texture.
context->submit(true);
context->deleteBackendTexture(backendTex);
}