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, Retrieves the back-end API handle of texture. If flushPendingGrContextIO is true,
complete deferred I/O operations. 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 flushPendingGrContextIO flag to flush outstanding requests ##
#Param origin storage for one of: kTopLeft_GrSurfaceOrigin, #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 #Enum CachingHint
#Code #Code

View File

@ -533,7 +533,7 @@ public:
/** Retrieves the back-end API handle of texture. If flushPendingGrContextIO is true, /** Retrieves the back-end API handle of texture. If flushPendingGrContextIO is true,
complete deferred I/O operations. 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 flushPendingGrContextIO flag to flush outstanding requests
@param origin storage for one of: kTopLeft_GrSurfaceOrigin, @param origin storage for one of: kTopLeft_GrSurfaceOrigin,
@ -543,6 +543,21 @@ public:
GrBackendObject getTextureHandle(bool flushPendingGrContextIO, GrBackendObject getTextureHandle(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin = nullptr) const; 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 /** \enum SkImage::CachingHint
CachingHint selects whether Skia may internally cache SkBitmap generated by CachingHint selects whether Skia may internally cache SkBitmap generated by
decoding SkImage, or by copying SkImage from GPU to CPU. The default behavior decoding SkImage, or by copying SkImage from GPU to CPU. The default behavior

View File

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

View File

@ -113,6 +113,10 @@ struct GrGLTextureInfo {
GrGLenum fTarget; GrGLenum fTarget;
GrGLuint fID; GrGLuint fID;
GrGLenum fFormat = 0; 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*)); GR_STATIC_ASSERT(sizeof(GrBackendObject) >= sizeof(const GrGLTextureInfo*));

View File

@ -14,11 +14,19 @@
struct GrMockTextureInfo { struct GrMockTextureInfo {
GrPixelConfig fConfig; GrPixelConfig fConfig;
int fID; int fID;
bool operator==(const GrMockTextureInfo& that) const {
return fConfig == that.fConfig && fID == that.fID;
}
}; };
struct GrMockRenderTargetInfo { struct GrMockRenderTargetInfo {
GrPixelConfig fConfig; GrPixelConfig fConfig;
int fID; 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 { enum Flag {
kNoncoherent_Flag = 0x1, // memory must be flushed to device after mapping 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: private:
friend class GrVkHeap; // For access to usesSystemHeap friend class GrVkHeap; // For access to usesSystemHeap
bool fUsesSystemHeap; 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 // 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. // to our internal GrVkImageInfo by calling getTextureHandle on a GrVkTexture.
void updateImageLayout(VkImageLayout layout) { fImageLayout = layout; } 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*)); 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 #ifdef SK_VULKAN

View File

@ -167,6 +167,13 @@ GrBackendObject SkImage::getTextureHandle(bool flushPendingGrContextIO,
return as_IB(this)->onGetTextureHandle(flushPendingGrContextIO, origin); 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 { bool SkImage::isValid(GrContext* context) const {
if (context && context->contextPriv().abandoned()) { if (context && context->contextPriv().abandoned()) {
return false; return false;
@ -182,6 +189,11 @@ bool SkImage::isTextureBacked() const { return false; }
GrBackendObject SkImage::getTextureHandle(bool, GrSurfaceOrigin*) const { return 0; } 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 { bool SkImage::isValid(GrContext* context) const {
if (context) { if (context) {
return false; return false;

View File

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

View File

@ -198,6 +198,28 @@ GrBackendObject SkImage_Gpu::onGetTextureHandle(bool flushPendingGrContextIO,
return 0; 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 { GrTexture* SkImage_Gpu::onGetTexture() const {
GrTextureProxy* proxy = this->peekProxy(); GrTextureProxy* proxy = this->peekProxy();
if (!proxy) { if (!proxy) {

View File

@ -51,6 +51,9 @@ public:
} }
GrBackendObject onGetTextureHandle(bool flushPendingGrContextIO, GrBackendObject onGetTextureHandle(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const override; GrSurfaceOrigin* origin) const override;
GrBackendTexture onGetBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const override;
GrTexture* onGetTexture() const override; GrTexture* onGetTexture() const override;
bool onReadPixels(const SkImageInfo&, void* dstPixels, size_t dstRowBytes, 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; GrSurfaceOrigin readBackOrigin;
GrBackendObject readBackHandle = srcImage->getTextureHandle(false, &readBackOrigin); GrBackendTexture readBackBackendTex = srcImage->getBackendTexture(false, &readBackOrigin);
// TODO: Make it so we can check this (see skbug.com/5019) if (!GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex)) {
#if 0 ERRORF(reporter, "backend mismatch\n");
if (readBackHandle != tex->getTextureHandle()) {
ERRORF(reporter, "backend mismatch %d %d\n",
(int)readBackHandle, (int)tex->getTextureHandle());
} }
REPORTER_ASSERT(reporter, readBackHandle == tex->getTextureHandle()); REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex));
#else
REPORTER_ASSERT(reporter, SkToBool(readBackHandle));
#endif
if (readBackOrigin != texOrigin) { if (readBackOrigin != texOrigin) {
ERRORF(reporter, "origin mismatch %d %d\n", 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)); TextureReleaseChecker::Release, &releaseChecker));
GrSurfaceOrigin readBackOrigin; GrSurfaceOrigin readBackOrigin;
GrBackendObject readBackHandle = refImg->getTextureHandle(false, &readBackOrigin); GrBackendTexture readBackBackendTex = refImg->getBackendTexture(false, &readBackOrigin);
// TODO: Make it so we can check this (see skbug.com/5019) if (!GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex)) {
#if 0 ERRORF(reporter, "backend mismatch\n");
if (*readBackHandle != *(backendTexHandle)) {
ERRORF(reporter, "backend mismatch %d %d\n",
(int)readBackHandle, (int)backendTexHandle);
} }
REPORTER_ASSERT(reporter, readBackHandle == backendTexHandle); REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex));
#else
REPORTER_ASSERT(reporter, SkToBool(readBackHandle));
#endif
if (readBackOrigin != texOrigin) { if (readBackOrigin != texOrigin) {
ERRORF(reporter, "origin mismatch %d %d\n", 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()); sk_sp<SkImage> image(surface->makeImageSnapshot());
REPORTER_ASSERT(reporter, as_IB(image)->isTextureBacked()); REPORTER_ASSERT(reporter, as_IB(image)->isTextureBacked());
GrBackendObject textureHandle = image->getTextureHandle(false); GrBackendTexture backendTex = image->getBackendTexture(false);
REPORTER_ASSERT(reporter, 0 != textureHandle); REPORTER_ASSERT(reporter, backendTex.isValid());
surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode); surface->notifyContentWillChange(SkSurface::kDiscard_ContentChangeMode);
REPORTER_ASSERT(reporter, as_IB(image)->isTextureBacked()); 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 #endif