aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Brian Osman <brianosman@google.com>2017-02-23 17:06:10 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-02-24 16:09:33 +0000
commit9ad1f92e2fceea33215c0f13cee42a679fb88d44 (patch)
treef44afa1066b401ae5e3cf189078ff6fceaccca78 /src
parent20de615e3d02ff52c9a3c319ce35bcaace97be25 (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.cpp7
-rw-r--r--src/gpu/GrGpu.h4
-rw-r--r--src/gpu/GrGpuResource.cpp11
-rw-r--r--src/gpu/GrTexturePriv.h10
-rw-r--r--src/gpu/gl/GrGLGpu.cpp4
-rw-r--r--src/gpu/gl/GrGLGpu.h2
-rw-r--r--src/gpu/gl/GrGLTexture.cpp19
-rw-r--r--src/gpu/gl/GrGLTexture.h1
-rw-r--r--src/gpu/vk/GrVkGpu.cpp3
-rw-r--r--src/gpu/vk/GrVkGpu.h2
-rw-r--r--src/gpu/vk/GrVkTexture.cpp6
-rw-r--r--src/gpu/vk/GrVkTexture.h1
-rw-r--r--src/image/SkImage.cpp16
-rw-r--r--src/image/SkImage_Gpu.cpp68
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));