From 9a1ed5d81dbfc7d5b67b568dfe12b4033a9af154 Mon Sep 17 00:00:00 2001 From: erikchen Date: Wed, 10 Feb 2016 16:32:34 -0800 Subject: skia: Add support for CHROMIUM_image backed textures. I created a new abstract base class TextureStorageAllocator that consumers of Skia can subclass and pass back to Skia. When a surface is created with a pointer to a TextureStorageAllocator, any textures it creates, or that are derived from the original surface, will allocate and deallocate storage using the methods on TextureStorageAllocator. BUG=https://code.google.com/p/chromium/issues/detail?id=579664 GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1623653002 Committed: https://skia.googlesource.com/skia/+/92098e691f10a010e7421125ba4d44c02506bb55 Committed: https://skia.googlesource.com/skia/+/7fec91ce6660190f8d7c5eb6f3061e4550cc672b Committed: https://skia.googlesource.com/skia/+/b8d6e088590160f1198110c2371b802c1d541a36 Review URL: https://codereview.chromium.org/1623653002 --- src/gpu/gl/GrGLGpu.cpp | 152 +++++++++++++++++++++++++++++---------------- src/gpu/gl/GrGLGpu.h | 12 ++++ src/gpu/gl/GrGLTexture.cpp | 8 ++- 3 files changed, 119 insertions(+), 53 deletions(-) (limited to 'src/gpu/gl') diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index cd28ecaab5..e29a7f81f3 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -929,14 +929,24 @@ bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc, !(0 == left && 0 == top && desc.fWidth == width && desc.fHeight == height)) { succeeded = false; } else { - CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); - GL_ALLOC_CALL(this->glInterface(), TexImage2D(target, 0, internalFormat, desc.fWidth, - desc.fHeight, 0, externalFormat, - externalType, dataOrOffset)); - GrGLenum error = check_alloc_error(desc, this->glInterface()); - if (error != GR_GL_NO_ERROR) { - succeeded = false; - } + if (desc.fTextureStorageAllocator.fAllocateTextureStorage) { + if (dataOrOffset) { + GL_CALL(TexSubImage2D(target, + 0, // level + left, top, + width, height, + externalFormat, externalType, dataOrOffset)); + } + } else { + CLEAR_ERROR_BEFORE_ALLOC(this->glInterface()); + GL_ALLOC_CALL(this->glInterface(), TexImage2D( + target, 0, internalFormat, desc.fWidth, desc.fHeight, 0, externalFormat, + externalType, dataOrOffset)); + GrGLenum error = check_alloc_error(desc, this->glInterface()); + if (error != GR_GL_NO_ERROR) { + succeeded = false; + } + } } } else { if (swFlipY || glFlipY) { @@ -1205,52 +1215,10 @@ GrTexture* GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc, bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag); GrGLTexture::IDDesc idDesc; - idDesc.fInfo.fID = 0; - GL_CALL(GenTextures(1, &idDesc.fInfo.fID)); idDesc.fLifeCycle = lifeCycle; - // We only support GL_TEXTURE_2D at the moment. - idDesc.fInfo.fTarget = GR_GL_TEXTURE_2D; - - if (!idDesc.fInfo.fID) { - return return_null_texture(); - } - - this->setScratchTextureUnit(); - GL_CALL(BindTexture(idDesc.fInfo.fTarget, idDesc.fInfo.fID)); - - if (renderTarget && this->glCaps().textureUsageSupport()) { - // provides a hint about how this texture will be used - GL_CALL(TexParameteri(idDesc.fInfo.fTarget, - GR_GL_TEXTURE_USAGE, - GR_GL_FRAMEBUFFER_ATTACHMENT)); - } - - // Some drivers like to know filter/wrap before seeing glTexImage2D. Some - // drivers have a bug where an FBO won't be complete if it includes a - // texture that is not mipmap complete (considering the filter in use). GrGLTexture::TexParams initialTexParams; - // we only set a subset here so invalidate first - initialTexParams.invalidate(); - initialTexParams.fMinFilter = GR_GL_NEAREST; - initialTexParams.fMagFilter = GR_GL_NEAREST; - initialTexParams.fWrapS = GR_GL_CLAMP_TO_EDGE; - initialTexParams.fWrapT = GR_GL_CLAMP_TO_EDGE; - GL_CALL(TexParameteri(idDesc.fInfo.fTarget, - GR_GL_TEXTURE_MAG_FILTER, - initialTexParams.fMagFilter)); - GL_CALL(TexParameteri(idDesc.fInfo.fTarget, - GR_GL_TEXTURE_MIN_FILTER, - initialTexParams.fMinFilter)); - GL_CALL(TexParameteri(idDesc.fInfo.fTarget, - GR_GL_TEXTURE_WRAP_S, - initialTexParams.fWrapS)); - GL_CALL(TexParameteri(idDesc.fInfo.fTarget, - GR_GL_TEXTURE_WRAP_T, - initialTexParams.fWrapT)); - if (!this->uploadTexData(desc, idDesc.fInfo.fTarget, kNewTexture_UploadType, 0, 0, - desc.fWidth, desc.fHeight, - desc.fConfig, srcData, rowBytes)) { - GL_CALL(DeleteTextures(1, &idDesc.fInfo.fID)); + if (!this->createTextureImpl(desc, &idDesc.fInfo, renderTarget, srcData, + &initialTexParams, rowBytes)) { return return_null_texture(); } @@ -1473,6 +1441,86 @@ int GrGLGpu::getCompatibleStencilIndex(GrPixelConfig config) { return this->glCaps().getStencilFormatIndexForConfig(config); } +bool GrGLGpu::createTextureImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info, + bool renderTarget, const void* srcData, + GrGLTexture::TexParams* initialTexParams, size_t rowBytes) { + // Some drivers like to know filter/wrap before seeing glTexImage2D. Some + // drivers have a bug where an FBO won't be complete if it includes a + // texture that is not mipmap complete (considering the filter in use). + + // we only set a subset here so invalidate first + initialTexParams->invalidate(); + initialTexParams->fMinFilter = GR_GL_NEAREST; + initialTexParams->fMagFilter = GR_GL_NEAREST; + initialTexParams->fWrapS = GR_GL_CLAMP_TO_EDGE; + initialTexParams->fWrapT = GR_GL_CLAMP_TO_EDGE; + + if (desc.fTextureStorageAllocator.fAllocateTextureStorage) { + return this->createTextureExternalAllocatorImpl(desc, info, srcData, rowBytes); + } + + info->fID = 0; + info->fTarget = GR_GL_TEXTURE_2D; + GL_CALL(GenTextures(1, &(info->fID))); + + if (!info->fID) { + return false; + } + + this->setScratchTextureUnit(); + GL_CALL(BindTexture(info->fTarget, info->fID)); + + if (renderTarget && this->glCaps().textureUsageSupport()) { + // provides a hint about how this texture will be used + GL_CALL(TexParameteri(info->fTarget, + GR_GL_TEXTURE_USAGE, + GR_GL_FRAMEBUFFER_ATTACHMENT)); + } + + GL_CALL(TexParameteri(info->fTarget, + GR_GL_TEXTURE_MAG_FILTER, + initialTexParams->fMagFilter)); + GL_CALL(TexParameteri(info->fTarget, + GR_GL_TEXTURE_MIN_FILTER, + initialTexParams->fMinFilter)); + GL_CALL(TexParameteri(info->fTarget, + GR_GL_TEXTURE_WRAP_S, + initialTexParams->fWrapS)); + GL_CALL(TexParameteri(info->fTarget, + GR_GL_TEXTURE_WRAP_T, + initialTexParams->fWrapT)); + if (!this->uploadTexData(desc, info->fTarget, kNewTexture_UploadType, 0, 0, + desc.fWidth, desc.fHeight, + desc.fConfig, srcData, rowBytes)) { + GL_CALL(DeleteTextures(1, &(info->fID))); + return false; + } + return true; +} + +bool GrGLGpu::createTextureExternalAllocatorImpl( + const GrSurfaceDesc& desc, GrGLTextureInfo* info, const void* srcData, size_t rowBytes) { + switch (desc.fTextureStorageAllocator.fAllocateTextureStorage( + desc.fTextureStorageAllocator.fCtx, reinterpret_cast(info), + desc.fWidth, desc.fHeight, desc.fConfig, srcData, desc.fOrigin)) { + case GrTextureStorageAllocator::Result::kSucceededAndUploaded: + return true; + case GrTextureStorageAllocator::Result::kFailed: + return false; + case GrTextureStorageAllocator::Result::kSucceededWithoutUpload: + break; + } + + if (!this->uploadTexData(desc, info->fTarget, kNewTexture_UploadType, 0, 0, + desc.fWidth, desc.fHeight, + desc.fConfig, srcData, rowBytes)) { + desc.fTextureStorageAllocator.fDeallocateTextureStorage( + desc.fTextureStorageAllocator.fCtx, reinterpret_cast(info)); + return false; + } + return true; +} + GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt, int width, int height) { diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index ec93bbfe21..ce2f95ef30 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -159,6 +159,18 @@ private: // compatible stencil format, or negative if there is no compatible stencil format. int getCompatibleStencilIndex(GrPixelConfig config); + // If |desc.fTextureStorageAllocator| exists, use that to create the + // texture. Otherwise, create the texture directly. + // Returns whether the texture is successfully created. On success, the + // result is stored in |info|. + // The texture is populated with |srcData|, if it exists. + // The texture parameters are cached in |initialTexParams|. + bool createTextureImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info, + bool renderTarget, const void* srcData, + GrGLTexture::TexParams* initialTexParams, size_t rowBytes); + bool createTextureExternalAllocatorImpl(const GrSurfaceDesc& desc, GrGLTextureInfo* info, + const void* srcData, size_t rowBytes); + void onClear(GrRenderTarget*, const SkIRect& rect, GrColor color) override; void onClearStencilClip(GrRenderTarget*, const SkIRect& rect, bool insideClip) override; diff --git a/src/gpu/gl/GrGLTexture.cpp b/src/gpu/gl/GrGLTexture.cpp index 39a8d9279f..864547ae26 100644 --- a/src/gpu/gl/GrGLTexture.cpp +++ b/src/gpu/gl/GrGLTexture.cpp @@ -37,7 +37,13 @@ void GrGLTexture::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) { void GrGLTexture::onRelease() { if (fInfo.fID) { if (GrGpuResource::kBorrowed_LifeCycle != fTextureIDLifecycle) { - GL_CALL(DeleteTextures(1, &fInfo.fID)); + if (this->desc().fTextureStorageAllocator.fDeallocateTextureStorage) { + this->desc().fTextureStorageAllocator.fDeallocateTextureStorage( + this->desc().fTextureStorageAllocator.fCtx, + reinterpret_cast(&fInfo)); + } else { + GL_CALL(DeleteTextures(1, &fInfo.fID)); + } } fInfo.fID = 0; } -- cgit v1.2.3