diff options
author | Brian Osman <brianosman@google.com> | 2017-02-23 17:06:10 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-02-24 16:09:33 +0000 |
commit | 9ad1f92e2fceea33215c0f13cee42a679fb88d44 (patch) | |
tree | f44afa1066b401ae5e3cf189078ff6fceaccca78 /src | |
parent | 20de615e3d02ff52c9a3c319ce35bcaace97be25 (diff) |
Add GrExternalTextureData and SkCrossContextImageData
GrExternalTextureData is an API for exporting the backend-specific
information about a texture in a type-safe way, and without pointing
into the GrTexture. The new detachBackendTexture API lets us release
ownership of a texture to the client.
SkCrossContextImageData is the public API that lets clients upload
textures on one thread/GrContext, then safely transfer ownership to
another thread and GrContext for rendering.
Only GL is implemented/supported right now. Vulkan support requires
that we add thread-safe memory pools, or otherwise transfer the
actual memory block containing the texture to the new context.
BUG=skia:
Change-Id: I784a3a74be69807df038c7d192eaed002c7e45ca
Reviewed-on: https://skia-review.googlesource.com/8529
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/GrContext.cpp | 7 | ||||
-rw-r--r-- | src/gpu/GrGpu.h | 4 | ||||
-rw-r--r-- | src/gpu/GrGpuResource.cpp | 11 | ||||
-rw-r--r-- | src/gpu/GrTexturePriv.h | 10 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.cpp | 4 | ||||
-rw-r--r-- | src/gpu/gl/GrGLGpu.h | 2 | ||||
-rw-r--r-- | src/gpu/gl/GrGLTexture.cpp | 19 | ||||
-rw-r--r-- | src/gpu/gl/GrGLTexture.h | 1 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpu.cpp | 3 | ||||
-rw-r--r-- | src/gpu/vk/GrVkGpu.h | 2 | ||||
-rw-r--r-- | src/gpu/vk/GrVkTexture.cpp | 6 | ||||
-rw-r--r-- | src/gpu/vk/GrVkTexture.h | 1 | ||||
-rw-r--r-- | src/image/SkImage.cpp | 16 | ||||
-rw-r--r-- | src/image/SkImage_Gpu.cpp | 68 |
14 files changed, 153 insertions, 1 deletions
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 4b1324e33e..e816687b0b 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -545,6 +545,13 @@ void GrContext::prepareSurfaceForExternalIO(GrSurface* surface) { fDrawingManager->prepareSurfaceForExternalIO(surface); } +GrFence GrContext::prepareSurfaceForExternalIOAndFlush(GrSurface* surface) { + this->prepareSurfaceForExternalIO(surface); + GrFence fence = fGpu->insertFence(); + fGpu->flush(); + return fence; +} + void GrContext::flushSurfaceWrites(GrSurface* surface) { ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index 0aed3d2c74..f710810650 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -382,6 +382,10 @@ public: virtual bool waitFence(GrFence, uint64_t timeout = 1000) const = 0; virtual void deleteFence(GrFence) const = 0; + // Ensures that all queued up driver-level commands have been sent to the GPU. For example, on + // OpenGL, this calls glFlush. + virtual void flush() = 0; + /////////////////////////////////////////////////////////////////////////// // Debugging and Stats diff --git a/src/gpu/GrGpuResource.cpp b/src/gpu/GrGpuResource.cpp index c3a9556588..dcc4e62282 100644 --- a/src/gpu/GrGpuResource.cpp +++ b/src/gpu/GrGpuResource.cpp @@ -43,6 +43,17 @@ void GrGpuResource::registerWithCacheWrapped() { get_resource_cache(fGpu)->resourceAccess().insertResource(this); } +void GrGpuResource::detachFromCache() { + if (this->wasDestroyed()) { + return; + } + if (fUniqueKey.isValid()) { + this->removeUniqueKey(); + } + this->removeScratchKey(); + this->makeUnbudgeted(); +} + GrGpuResource::~GrGpuResource() { // The cache should have released or destroyed this resource. SkASSERT(this->wasDestroyed()); diff --git a/src/gpu/GrTexturePriv.h b/src/gpu/GrTexturePriv.h index 042061129d..cc0a05edfd 100644 --- a/src/gpu/GrTexturePriv.h +++ b/src/gpu/GrTexturePriv.h @@ -8,6 +8,7 @@ #ifndef GrTexturePriv_DEFINED #define GrTexturePriv_DEFINED +#include "GrExternalTextureData.h" #include "GrTexture.h" /** Class that adds methods to GrTexture that are only intended for use internal to Skia. @@ -67,6 +68,15 @@ public: } SkDestinationSurfaceColorMode mipColorMode() const { return fTexture->fMipColorMode; } + /** + * Return the native bookkeeping data for this texture, and detach the backend object from + * this GrTexture. It's lifetime will no longer be managed by Ganesh, and this GrTexture will + * no longer refer to it. Leaves this GrTexture in an orphan state. + */ + std::unique_ptr<GrExternalTextureData> detachBackendTexture() { + return fTexture->detachBackendTexture(); + } + static void ComputeScratchKey(const GrSurfaceDesc&, GrScratchKey*); private: diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index ad00b0a90c..5dce7d1e2b 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -4741,3 +4741,7 @@ bool GrGLGpu::waitFence(GrFence fence, uint64_t timeout) const { void GrGLGpu::deleteFence(GrFence fence) const { GL_CALL(DeleteSync((GrGLsync)fence)); } + +void GrGLGpu::flush() { + GL_CALL(Flush()); +} diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index fdc2ebbfa9..b6ca4f6fd6 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -150,6 +150,8 @@ public: bool waitFence(GrFence, uint64_t timeout) const override; void deleteFence(GrFence) const override; + void flush() override; + private: GrGLGpu(GrGLContext* ctx, GrContext* context); diff --git a/src/gpu/gl/GrGLTexture.cpp b/src/gpu/gl/GrGLTexture.cpp index edce7b1f33..a5609887c0 100644 --- a/src/gpu/gl/GrGLTexture.cpp +++ b/src/gpu/gl/GrGLTexture.cpp @@ -5,9 +5,11 @@ * found in the LICENSE file. */ +#include "GrContext.h" #include "GrGLTexture.h" #include "GrGLGpu.h" #include "GrShaderCaps.h" +#include "SkMakeUnique.h" #include "SkTraceMemoryDump.h" #define GPUGL static_cast<GrGLGpu*>(this->getGpu()) @@ -111,6 +113,23 @@ GrBackendObject GrGLTexture::getTextureHandle() const { return reinterpret_cast<GrBackendObject>(&fInfo); } +std::unique_ptr<GrExternalTextureData> GrGLTexture::detachBackendTexture() { + // Flush any pending writes to this texture, as well GL itself + GrFence fence = this->getContext()->prepareSurfaceForExternalIOAndFlush(this); + + // Make a copy of our GL-specific information + auto data = skstd::make_unique<GrGLExternalTextureData>(fInfo, fence); + + // Ensure the cache can't reach this texture anymore + this->detachFromCache(); + + // Detach from the GL object, so we don't use it (or try to delete it when we're freed) + fInfo.fTarget = 0; + fInfo.fID = 0; + + return std::move(data); +} + void GrGLTexture::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump, const SkString& dumpName) const { SkString texture_id; diff --git a/src/gpu/gl/GrGLTexture.h b/src/gpu/gl/GrGLTexture.h index 029fd87a1a..16b47f1f07 100644 --- a/src/gpu/gl/GrGLTexture.h +++ b/src/gpu/gl/GrGLTexture.h @@ -71,6 +71,7 @@ protected: void onRelease() override; void setMemoryBacking(SkTraceMemoryDump* traceMemoryDump, const SkString& dumpName) const override; + std::unique_ptr<GrExternalTextureData> detachBackendTexture() override; private: TexParams fTexParams; diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp index 915ac9747e..8569c9367f 100644 --- a/src/gpu/vk/GrVkGpu.cpp +++ b/src/gpu/vk/GrVkGpu.cpp @@ -1860,3 +1860,6 @@ void GrVkGpu::deleteFence(GrFence fence) const { GR_VK_CALL(this->vkInterface(), DestroyFence(this->device(), (VkFence)fence, nullptr)); } +void GrVkGpu::flush() { + // We submit the command buffer to the queue whenever Ganesh is flushed, so nothing is needed +} diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h index 18059b9682..c935945bd1 100644 --- a/src/gpu/vk/GrVkGpu.h +++ b/src/gpu/vk/GrVkGpu.h @@ -133,6 +133,8 @@ public: bool waitFence(GrFence, uint64_t timeout) const override; void deleteFence(GrFence) const override; + void flush() override; + void generateMipmap(GrVkTexture* tex); bool updateBuffer(GrVkBuffer* buffer, const void* src, VkDeviceSize offset, VkDeviceSize size); diff --git a/src/gpu/vk/GrVkTexture.cpp b/src/gpu/vk/GrVkTexture.cpp index 7f0cf8d1d8..a8f1bf00dc 100644 --- a/src/gpu/vk/GrVkTexture.cpp +++ b/src/gpu/vk/GrVkTexture.cpp @@ -144,6 +144,12 @@ GrBackendObject GrVkTexture::getTextureHandle() const { return (GrBackendObject)&fInfo; } +std::unique_ptr<GrExternalTextureData> GrVkTexture::detachBackendTexture() { + // Not supported on Vulkan yet + // TODO: Add thread-safe memory pools, and implement this. + return nullptr; +} + GrVkGpu* GrVkTexture::getVkGpu() const { SkASSERT(!this->wasDestroyed()); return static_cast<GrVkGpu*>(this->getGpu()); diff --git a/src/gpu/vk/GrVkTexture.h b/src/gpu/vk/GrVkTexture.h index 70db54838d..db7124e2b8 100644 --- a/src/gpu/vk/GrVkTexture.h +++ b/src/gpu/vk/GrVkTexture.h @@ -42,6 +42,7 @@ protected: void onAbandon() override; void onRelease() override; + std::unique_ptr<GrExternalTextureData> detachBackendTexture() override; private: enum Wrapped { kWrapped }; diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp index 48d9ad32ba..638b0c2955 100644 --- a/src/image/SkImage.cpp +++ b/src/image/SkImage.cpp @@ -8,6 +8,7 @@ #include "SkBitmap.h" #include "SkBitmapCache.h" #include "SkCanvas.h" +#include "SkCrossContextImageData.h" #include "SkData.h" #include "SkImageEncoder.h" #include "SkImageFilter.h" @@ -357,6 +358,21 @@ sk_sp<SkImage> SkImage::makeTextureImage(GrContext*, SkColorSpace* dstColorSpace return nullptr; } +std::unique_ptr<SkCrossContextImageData> SkCrossContextImageData::MakeFromEncoded( + GrContext*, sk_sp<SkData> encoded, SkColorSpace* dstColorSpace) { + sk_sp<SkImage> image = SkImage::MakeFromEncoded(std::move(encoded)); + if (!image) { + return nullptr; + } + // TODO: Force decode to raster here? + return std::unique_ptr<SkCrossContextImageData>(new SkCrossContextImageData(std::move(image))); +} + +sk_sp<SkImage> SkImage::MakeFromCrossContextImageData( + GrContext*, std::unique_ptr<SkCrossContextImageData> ccid) { + return ccid->fImage; +} + sk_sp<SkImage> SkImage::makeNonTextureImage() const { return sk_ref_sp(const_cast<SkImage*>(this)); } diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp index 05caf867a3..ddb62d7a89 100644 --- a/src/image/SkImage_Gpu.cpp +++ b/src/image/SkImage_Gpu.cpp @@ -14,6 +14,7 @@ #include "GrCaps.h" #include "GrContext.h" #include "GrContextPriv.h" +#include "GrGpu.h" #include "GrImageTextureMaker.h" #include "GrRenderTargetContext.h" #include "GrTextureAdjuster.h" @@ -21,6 +22,7 @@ #include "GrTextureProxy.h" #include "effects/GrYUVEffect.h" #include "SkCanvas.h" +#include "SkCrossContextImageData.h" #include "SkBitmapCache.h" #include "SkGrPriv.h" #include "SkImage_Gpu.h" @@ -357,7 +359,7 @@ static sk_sp<SkImage> create_image_from_maker(GrTextureMaker* maker, SkAlphaType std::move(texColorSpace), SkBudgeted::kNo); } -sk_sp<SkImage> SkImage::makeTextureImage(GrContext *context, SkColorSpace* dstColorSpace) const { +sk_sp<SkImage> SkImage::makeTextureImage(GrContext* context, SkColorSpace* dstColorSpace) const { if (!context) { return nullptr; } @@ -377,6 +379,70 @@ sk_sp<SkImage> SkImage::makeTextureImage(GrContext *context, SkColorSpace* dstCo return nullptr; } +std::unique_ptr<SkCrossContextImageData> SkCrossContextImageData::MakeFromEncoded( + GrContext* context, sk_sp<SkData> encoded, SkColorSpace* dstColorSpace) { + sk_sp<SkImage> codecImage = SkImage::MakeFromEncoded(std::move(encoded)); + if (!codecImage) { + return nullptr; + } + + // If we don't have the ability to use fences, we can't safely transfer a texture between + // threads, so just hand off the codec image + if (!context->caps()->fenceSyncSupport()) { + return std::unique_ptr<SkCrossContextImageData>( + new SkCrossContextImageData(std::move(codecImage))); + } + + sk_sp<SkImage> textureImage = codecImage->makeTextureImage(context, dstColorSpace); + if (!textureImage) { + // TODO: Force decode to raster here? Do mip-mapping, like getDeferredTextureImageData? + return std::unique_ptr<SkCrossContextImageData>( + new SkCrossContextImageData(std::move(codecImage))); + } + + // Crack open the gpu image, extract the backend data, stick it in the SkCCID + GrTexture* texture = as_IB(textureImage)->peekTexture(); + SkASSERT(texture); + + GrBackendTextureDesc desc; + desc.fFlags = kNone_GrBackendTextureFlag; + desc.fOrigin = texture->origin(); + desc.fWidth = texture->width(); + desc.fHeight = texture->height(); + desc.fConfig = texture->config(); + desc.fSampleCnt = 0; + + auto textureData = texture->texturePriv().detachBackendTexture(); + if (!textureData) { + // Handles backends that don't support this feature (currently Vulkan). Do a raster decode + // here? + return std::unique_ptr<SkCrossContextImageData>( + new SkCrossContextImageData(std::move(codecImage))); + } + + SkImageInfo info = as_IB(textureImage)->onImageInfo(); + return std::unique_ptr<SkCrossContextImageData>(new SkCrossContextImageData( + desc, std::move(textureData), info.alphaType(), info.refColorSpace())); +} + +sk_sp<SkImage> SkImage::MakeFromCrossContextImageData( + GrContext* context, std::unique_ptr<SkCrossContextImageData> ccid) { + if (ccid->fImage) { + // No pre-existing GPU resource. We could upload it now (with makeTextureImage), + // but we'd need a dstColorSpace. + return ccid->fImage; + } + + if (ccid->fTextureData) { + GrFence fence = ccid->fTextureData->getFence(); + context->getGpu()->waitFence(fence); + context->getGpu()->deleteFence(fence); + } + + return MakeFromAdoptedTexture(context, ccid->fDesc, ccid->fAlphaType, + std::move(ccid->fColorSpace)); +} + sk_sp<SkImage> SkImage::makeNonTextureImage() const { if (!this->isTextureBacked()) { return sk_ref_sp(const_cast<SkImage*>(this)); |