From c5509955b98daa0643da7fcd7ad356a9aa5a42da Mon Sep 17 00:00:00 2001 From: Robert Phillips Date: Wed, 4 Apr 2018 15:54:55 -0400 Subject: [PATCH] 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 Reviewed-by: Brian Salomon --- docs/SkImage_Reference.bmh | 28 ++++++++++++++++++++++++++- include/core/SkImage.h | 17 ++++++++++++++++- include/gpu/GrBackendSurface.h | 4 ++++ include/gpu/gl/GrGLTypes.h | 4 ++++ include/gpu/mock/GrMockTypes.h | 8 ++++++++ include/gpu/vk/GrVkTypes.h | 12 ++++++++++++ src/gpu/GrBackendSurface.cpp | 35 ++++++++++++++++++++++++++++++++++ src/image/SkImage.cpp | 12 ++++++++++++ src/image/SkImage_Base.h | 13 +++++++++++++ src/image/SkImage_Gpu.cpp | 22 +++++++++++++++++++++ src/image/SkImage_Gpu.h | 3 +++ tests/ImageFilterCacheTest.cpp | 15 +++++---------- tests/ImageTest.cpp | 14 ++++---------- tests/SurfaceTest.cpp | 7 ++++--- 14 files changed, 169 insertions(+), 25 deletions(-) diff --git a/docs/SkImage_Reference.bmh b/docs/SkImage_Reference.bmh index 781ad71c1d..7aad9ae893 100644 --- a/docs/SkImage_Reference.bmh +++ b/docs/SkImage_Reference.bmh @@ -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 diff --git a/include/core/SkImage.h b/include/core/SkImage.h index aed0843e06..216844bc7c 100644 --- a/include/core/SkImage.h +++ b/include/core/SkImage.h @@ -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 diff --git a/include/gpu/GrBackendSurface.h b/include/gpu/GrBackendSurface.h index 02fd1621ca..106edb751e 100644 --- a/include/gpu/GrBackendSurface.h +++ b/include/gpu/GrBackendSurface.h @@ -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; //= sizeof(const GrGLTextureInfo*)); diff --git a/include/gpu/mock/GrMockTypes.h b/include/gpu/mock/GrMockTypes.h index 6e38175838..5ca0730956 100644 --- a/include/gpu/mock/GrMockTypes.h +++ b/include/gpu/mock/GrMockTypes.h @@ -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; + } }; /** diff --git a/include/gpu/vk/GrVkTypes.h b/include/gpu/vk/GrVkTypes.h index 70571981b6..bfc3d5ac3e 100644 --- a/include/gpu/vk/GrVkTypes.h +++ b/include/gpu/vk/GrVkTypes.h @@ -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*)); diff --git a/src/gpu/GrBackendSurface.cpp b/src/gpu/GrBackendSurface.cpp index 6f48a758a8..978e66db0b 100644 --- a/src/gpu/GrBackendSurface.cpp +++ b/src/gpu/GrBackendSurface.cpp @@ -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 diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp index 40daa6fbc3..4f8fe74d30 100644 --- a/src/image/SkImage.cpp +++ b/src/image/SkImage.cpp @@ -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; diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h index b3bbbc4080..950163a079 100644 --- a/src/image/SkImage_Base.h +++ b/src/image/SkImage_Base.h @@ -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 @@ -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; } diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp index 3c05f1d219..0dd7e95843 100644 --- a/src/image/SkImage_Gpu.cpp +++ b/src/image/SkImage_Gpu.cpp @@ -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) { diff --git a/src/image/SkImage_Gpu.h b/src/image/SkImage_Gpu.h index 7a4fa9751a..af7c1fac6a 100644 --- a/src/image/SkImage_Gpu.h +++ b/src/image/SkImage_Gpu.h @@ -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, diff --git a/tests/ImageFilterCacheTest.cpp b/tests/ImageFilterCacheTest.cpp index a541c1c546..e9c9f0b14e 100644 --- a/tests/ImageFilterCacheTest.cpp +++ b/tests/ImageFilterCacheTest.cpp @@ -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); } diff --git a/tests/ImageTest.cpp b/tests/ImageTest.cpp index 98c2f03c2e..fd9baecd4b 100644 --- a/tests/ImageTest.cpp +++ b/tests/ImageTest.cpp @@ -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); } diff --git a/tests/SurfaceTest.cpp b/tests/SurfaceTest.cpp index e74dcc915c..744dd63a42 100644 --- a/tests/SurfaceTest.cpp +++ b/tests/SurfaceTest.cpp @@ -551,11 +551,12 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SurfacepeekTexture_Gpu, reporter, ctxInfo) { sk_sp 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