Add GrBackendTexture accessor to SkImage (take 2)

This makes accessing the GPU resource behind an SkImage a lot more typesafe. Additionally, the GrBackendObject is being deprecated so this is the path forward.

I split the controversial stuff off into https://skia-review.googlesource.com/c/skia/+/118575 (Add SkImage::setLayout call).

Change-Id: I297e72770e8fb360fac7c7cd74f050ae759ae133
Reviewed-on: https://skia-review.googlesource.com/118571
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Robert Phillips 2018-04-04 15:54:55 -04:00 committed by Skia Commit-Bot
parent 1fda0247a7
commit c5509955b9
14 changed files with 169 additions and 25 deletions

View File

@ -1326,7 +1326,7 @@ drawImage(textureImage, "backEndTexture");
Retrieves the back-end API handle of texture. If flushPendingGrContextIO is true,
complete deferred I/O operations.
If origin in not nullptr, copies location of content drawn into Image.
If origin is not nullptr, copies location of content drawn into Image.
#Param flushPendingGrContextIO flag to flush outstanding requests ##
#Param origin storage for one of: kTopLeft_GrSurfaceOrigin,
@ -1390,6 +1390,32 @@ for (auto origin : { kTopLeft_GrSurfaceOrigin, kBottomLeft_GrSurfaceOrigin } ) {
# ------------------------------------------------------------------------------
#Method GrBackendTexture getBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin = nullptr) const
#In Property
#Line # returns GPU reference to Image as texture ##
Retrieves the backend texture. If there is none an invalid object will be returned.
If flushPendingGrContextIO is true, complete deferred I/O operations.
If origin in not nullptr, copies location of content drawn into Image.
#Param flushPendingGrContextIO flag to flush outstanding requests ##
#Param origin storage for one of: kTopLeft_GrSurfaceOrigin,
kBottomLeft_GrSurfaceOrigin; or nullptr
##
#Return back-end API texture handle. Invalid on failure. ##
#NoExample
##
#SeeAlso MakeFromTexture isTextureBacked
#Method ##
# ------------------------------------------------------------------------------
#Enum CachingHint
#Code

View File

@ -533,7 +533,7 @@ public:
/** Retrieves the back-end API handle of texture. If flushPendingGrContextIO is true,
complete deferred I/O operations.
If origin in not nullptr, copies location of content drawn into SkImage.
If origin is not nullptr, copies location of content drawn into SkImage.
@param flushPendingGrContextIO flag to flush outstanding requests
@param origin storage for one of: kTopLeft_GrSurfaceOrigin,
@ -543,6 +543,21 @@ public:
GrBackendObject getTextureHandle(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin = nullptr) const;
#if GR_TEST_UTILS
/** Retrieves the backend texture. If there is none an invalid object will be returned.
If flushPendingGrContextIO is true, complete deferred I/O operations.
If origin is not nullptr, copies location of content drawn into SkImage.
@param flushPendingGrContextIO flag to flush outstanding requests
@param origin storage for one of: kTopLeft_GrSurfaceOrigin,
kBottomLeft_GrSurfaceOrigin; or nullptr
@return back-end API texture handle. Invalid on failure.
*/
GrBackendTexture getBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin = nullptr) const;
#endif
/** \enum SkImage::CachingHint
CachingHint selects whether Skia may internally cache SkBitmap generated by
decoding SkImage, or by copying SkImage from GPU to CPU. The default behavior

View File

@ -145,7 +145,10 @@ public:
*/
GrBackendFormat format() const;
#if GR_TEST_UTILS
GrPixelConfig testingOnly_getPixelConfig() const;
static bool TestingOnly_Equals(const GrBackendTexture& , const GrBackendTexture&);
#endif
private:
// Friending for access to the GrPixelConfig
@ -158,6 +161,7 @@ private:
friend class GrGLGpu;
friend class GrVkGpu;
friend class PromiseImageHelper;
GrPixelConfig config() const { return fConfig; }
int fWidth; //<! width in pixels

View File

@ -113,6 +113,10 @@ struct GrGLTextureInfo {
GrGLenum fTarget;
GrGLuint fID;
GrGLenum fFormat = 0;
bool operator==(const GrGLTextureInfo& that) const {
return fTarget == that.fTarget && fID == that.fID && fFormat == that.fFormat;
}
};
GR_STATIC_ASSERT(sizeof(GrBackendObject) >= sizeof(const GrGLTextureInfo*));

View File

@ -14,11 +14,19 @@
struct GrMockTextureInfo {
GrPixelConfig fConfig;
int fID;
bool operator==(const GrMockTextureInfo& that) const {
return fConfig == that.fConfig && fID == that.fID;
}
};
struct GrMockRenderTargetInfo {
GrPixelConfig fConfig;
int fID;
bool operator==(const GrMockRenderTargetInfo& that) const {
return fConfig == that.fConfig && fID == that.fID;
}
};
/**

View File

@ -53,6 +53,12 @@ struct GrVkAlloc {
enum Flag {
kNoncoherent_Flag = 0x1, // memory must be flushed to device after mapping
};
bool operator==(const GrVkAlloc& that) const {
return fMemory == that.fMemory && fOffset == that.fOffset && fSize == that.fSize &&
fFlags == that.fFlags && fUsesSystemHeap == that.fUsesSystemHeap;
}
private:
friend class GrVkHeap; // For access to usesSystemHeap
bool fUsesSystemHeap;
@ -73,6 +79,12 @@ struct GrVkImageInfo {
// while we're still holding onto the wrapped texture. They will first need to get a handle
// to our internal GrVkImageInfo by calling getTextureHandle on a GrVkTexture.
void updateImageLayout(VkImageLayout layout) { fImageLayout = layout; }
bool operator==(const GrVkImageInfo& that) const {
return fImage == that.fImage && fAlloc == that.fAlloc &&
fImageTiling == that.fImageTiling && fImageLayout == that.fImageLayout &&
fFormat == that.fFormat && fLevelCount == that.fLevelCount;
}
};
GR_STATIC_ASSERT(sizeof(GrBackendObject) >= sizeof(const GrVkImageInfo*));

View File

@ -165,6 +165,41 @@ GrBackendFormat GrBackendTexture::format() const {
}
}
#if GR_TEST_UTILS
bool GrBackendTexture::TestingOnly_Equals(const GrBackendTexture& t0, const GrBackendTexture& t1) {
if (!t0.isValid() || !t1.isValid()) {
return false; // two invalid backend textures are not considered equal
}
if (t0.fWidth != t1.fWidth ||
t0.fHeight != t1.fHeight ||
t0.fConfig != t1.fConfig ||
t0.fMipMapped != t1.fMipMapped ||
t0.fBackend != t1.fBackend) {
return false;
}
switch (t0.fBackend) {
case kOpenGL_GrBackend:
return t0.fGLInfo == t1.fGLInfo;
case kMock_GrBackend:
return t0.fMockInfo == t1.fMockInfo;
case kVulkan_GrBackend:
#ifdef SK_VULKAN
return t0.fVkInfo == t1.fVkInfo;
#else
// fall through
#endif
case kMetal_GrBackend: // fall through
default:
return false;
}
SkASSERT(0);
return false;
}
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef SK_VULKAN

View File

@ -167,6 +167,13 @@ GrBackendObject SkImage::getTextureHandle(bool flushPendingGrContextIO,
return as_IB(this)->onGetTextureHandle(flushPendingGrContextIO, origin);
}
#if GR_TEST_UTILS
GrBackendTexture SkImage::getBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const {
return as_IB(this)->onGetBackendTexture(flushPendingGrContextIO, origin);
}
#endif
bool SkImage::isValid(GrContext* context) const {
if (context && context->contextPriv().abandoned()) {
return false;
@ -182,6 +189,11 @@ bool SkImage::isTextureBacked() const { return false; }
GrBackendObject SkImage::getTextureHandle(bool, GrSurfaceOrigin*) const { return 0; }
GrBackendTexture SkImage::getBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const {
return GrBackendTexture(); // invalid
}
bool SkImage::isValid(GrContext* context) const {
if (context) {
return false;

View File

@ -13,9 +13,17 @@
#include "SkSurface.h"
#if SK_SUPPORT_GPU
#include "GrBackendSurface.h"
#include "GrTextureProxy.h"
class GrTexture;
#else
class SK_API GrBackendTexture {
public:
GrBackendTexture() {}
bool isValid() const { return false; }
};
#endif
#include <new>
@ -59,6 +67,11 @@ public:
GrSurfaceOrigin* origin) const {
return 0;
}
virtual GrBackendTexture onGetBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const {
return GrBackendTexture(); // invalid
}
virtual GrTexture* onGetTexture() const { return nullptr; }
#endif
virtual SkImageCacherator* peekCacherator() const { return nullptr; }

View File

@ -198,6 +198,28 @@ GrBackendObject SkImage_Gpu::onGetTextureHandle(bool flushPendingGrContextIO,
return 0;
}
GrBackendTexture SkImage_Gpu::onGetBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const {
SkASSERT(fProxy);
if (!fProxy->instantiate(fContext->contextPriv().resourceProvider())) {
return GrBackendTexture(); // invalid
}
GrTexture* texture = fProxy->priv().peekTexture();
if (texture) {
if (flushPendingGrContextIO) {
fContext->contextPriv().prepareSurfaceForExternalIO(fProxy.get());
}
if (origin) {
*origin = fProxy->origin();
}
return texture->getBackendTexture();
}
return GrBackendTexture(); // invalid
}
GrTexture* SkImage_Gpu::onGetTexture() const {
GrTextureProxy* proxy = this->peekProxy();
if (!proxy) {

View File

@ -51,6 +51,9 @@ public:
}
GrBackendObject onGetTextureHandle(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const override;
GrBackendTexture onGetBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const override;
GrTexture* onGetTexture() const override;
bool onReadPixels(const SkImageInfo&, void* dstPixels, size_t dstRowBytes,

View File

@ -227,17 +227,12 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_ImageBackedGPU, reporter, ct
}
GrSurfaceOrigin readBackOrigin;
GrBackendObject readBackHandle = srcImage->getTextureHandle(false, &readBackOrigin);
// TODO: Make it so we can check this (see skbug.com/5019)
#if 0
if (readBackHandle != tex->getTextureHandle()) {
ERRORF(reporter, "backend mismatch %d %d\n",
(int)readBackHandle, (int)tex->getTextureHandle());
GrBackendTexture readBackBackendTex = srcImage->getBackendTexture(false, &readBackOrigin);
if (!GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex)) {
ERRORF(reporter, "backend mismatch\n");
}
REPORTER_ASSERT(reporter, readBackHandle == tex->getTextureHandle());
#else
REPORTER_ASSERT(reporter, SkToBool(readBackHandle));
#endif
REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex));
if (readBackOrigin != texOrigin) {
ERRORF(reporter, "origin mismatch %d %d\n", readBackOrigin, texOrigin);
}

View File

@ -817,17 +817,11 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(SkImage_NewFromTextureRelease, reporter, c
TextureReleaseChecker::Release, &releaseChecker));
GrSurfaceOrigin readBackOrigin;
GrBackendObject readBackHandle = refImg->getTextureHandle(false, &readBackOrigin);
// TODO: Make it so we can check this (see skbug.com/5019)
#if 0
if (*readBackHandle != *(backendTexHandle)) {
ERRORF(reporter, "backend mismatch %d %d\n",
(int)readBackHandle, (int)backendTexHandle);
GrBackendTexture readBackBackendTex = refImg->getBackendTexture(false, &readBackOrigin);
if (!GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex)) {
ERRORF(reporter, "backend mismatch\n");
}
REPORTER_ASSERT(reporter, readBackHandle == backendTexHandle);
#else
REPORTER_ASSERT(reporter, SkToBool(readBackHandle));
#endif
REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex));
if (readBackOrigin != texOrigin) {
ERRORF(reporter, "origin mismatch %d %d\n", readBackOrigin, texOrigin);
}

View File

@ -551,11 +551,12 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfacepeekTexture_Gpu, reporter, ctxInfo) {
sk_sp<SkImage> image(surface->makeImageSnapshot());
REPORTER_ASSERT(reporter, as_IB(image)->isTextureBacked());
GrBackendObject textureHandle = image->getTextureHandle(false);
REPORTER_ASSERT(reporter, 0 != textureHandle);
GrBackendTexture backendTex = image->getBackendTexture(false);
REPORTER_ASSERT(reporter, backendTex.isValid());
surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
REPORTER_ASSERT(reporter, as_IB(image)->isTextureBacked());
REPORTER_ASSERT(reporter, textureHandle == image->getTextureHandle(false));
GrBackendTexture backendTex2 = image->getBackendTexture(false);
REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(backendTex, backendTex2));
}
}
#endif