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
This commit is contained in:
parent
4a6e40d9d2
commit
9a1ed5d81d
@ -120,12 +120,16 @@ public:
|
||||
/**
|
||||
* Return a new surface whose contents will be drawn to an offscreen
|
||||
* render target, allocated by the surface.
|
||||
*
|
||||
* The GrTextureStorageAllocator will be reused if SkImage snapshots create
|
||||
* additional textures.
|
||||
*/
|
||||
static SkSurface* NewRenderTarget(GrContext*, Budgeted, const SkImageInfo&, int sampleCount,
|
||||
const SkSurfaceProps* = NULL);
|
||||
static SkSurface* NewRenderTarget(
|
||||
GrContext*, Budgeted, const SkImageInfo&, int sampleCount, const SkSurfaceProps* = NULL,
|
||||
GrTextureStorageAllocator = GrTextureStorageAllocator());
|
||||
|
||||
static SkSurface* NewRenderTarget(GrContext* gr, Budgeted b, const SkImageInfo& info) {
|
||||
return NewRenderTarget(gr, b, info, 0, NULL);
|
||||
return NewRenderTarget(gr, b, info, 0);
|
||||
}
|
||||
|
||||
int width() const { return fWidth; }
|
||||
|
@ -409,6 +409,9 @@ enum GrSurfaceFlags {
|
||||
|
||||
GR_MAKE_BITFIELD_OPS(GrSurfaceFlags)
|
||||
|
||||
// opaque type for 3D API object handles
|
||||
typedef intptr_t GrBackendObject;
|
||||
|
||||
/**
|
||||
* Some textures will be stored such that the upper and left edges of the content meet at the
|
||||
* the origin (in texture coord space) and for other textures the lower and left edges meet at
|
||||
@ -422,6 +425,58 @@ enum GrSurfaceOrigin {
|
||||
kBottomLeft_GrSurfaceOrigin,
|
||||
};
|
||||
|
||||
/**
|
||||
* An container of function pointers which consumers of Skia can fill in and
|
||||
* pass to Skia. Skia will use these function pointers in place of its backend
|
||||
* API texture creation function. Either all of the function pointers should be
|
||||
* filled in, or they should all be nullptr.
|
||||
*/
|
||||
struct GrTextureStorageAllocator {
|
||||
GrTextureStorageAllocator()
|
||||
: fAllocateTextureStorage(nullptr)
|
||||
, fDeallocateTextureStorage(nullptr) {
|
||||
}
|
||||
|
||||
enum class Result {
|
||||
kSucceededAndUploaded,
|
||||
kSucceededWithoutUpload,
|
||||
kFailed
|
||||
};
|
||||
typedef Result (*AllocateTextureStorageProc)(
|
||||
void* ctx, GrBackendObject texture, unsigned width,
|
||||
unsigned height, GrPixelConfig config, const void* srcData, GrSurfaceOrigin);
|
||||
typedef void (*DeallocateTextureStorageProc)(void* ctx, GrBackendObject texture);
|
||||
|
||||
/*
|
||||
* Generates and binds a texture to |textureStorageTarget()|. Allocates
|
||||
* storage for the texture.
|
||||
*
|
||||
* In OpenGL, the MIN and MAX filters for the created texture must be
|
||||
* GL_LINEAR. The WRAP_S and WRAP_T must be GL_CLAMP_TO_EDGE.
|
||||
*
|
||||
* If |srcData| is not nullptr, then the implementation of this function
|
||||
* may attempt to upload the data into the texture. On successful upload,
|
||||
* or if |srcData| is nullptr, returns kSucceededAndUploaded.
|
||||
*/
|
||||
AllocateTextureStorageProc fAllocateTextureStorage;
|
||||
|
||||
/*
|
||||
* Deallocate the storage for the given texture.
|
||||
*
|
||||
* Skia does not always destroy its outstanding textures. See
|
||||
* GrContext::abandonContext() for more details. The consumer of Skia is
|
||||
* responsible for making sure that all textures are destroyed, even if this
|
||||
* callback is not invoked.
|
||||
*/
|
||||
DeallocateTextureStorageProc fDeallocateTextureStorage;
|
||||
|
||||
/*
|
||||
* The context to use when invoking fAllocateTextureStorage and
|
||||
* fDeallocateTextureStorage.
|
||||
*/
|
||||
void* fCtx;
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes a surface to be created.
|
||||
*/
|
||||
@ -454,6 +509,12 @@ struct GrSurfaceDesc {
|
||||
* max supported count.
|
||||
*/
|
||||
int fSampleCnt;
|
||||
|
||||
/**
|
||||
* A custom platform-specific allocator to use in place of the backend APIs
|
||||
* usual texture creation method (e.g. TexImage2D in OpenGL).
|
||||
*/
|
||||
GrTextureStorageAllocator fTextureStorageAllocator;
|
||||
};
|
||||
|
||||
// Legacy alias
|
||||
@ -469,9 +530,6 @@ enum GrClipType {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// opaque type for 3D API object handles
|
||||
typedef intptr_t GrBackendObject;
|
||||
|
||||
|
||||
/** Ownership rules for external GPU resources imported into Skia. */
|
||||
enum GrWrapOwnership {
|
||||
|
@ -85,7 +85,8 @@ GrTexture::GrTexture(GrGpu* gpu, LifeCycle lifeCycle, const GrSurfaceDesc& desc)
|
||||
: INHERITED(gpu, lifeCycle, desc)
|
||||
, fMipMapsStatus(kNotAllocated_MipMapsStatus) {
|
||||
|
||||
if (!this->isExternal() && !GrPixelConfigIsCompressed(desc.fConfig)) {
|
||||
if (!this->isExternal() && !GrPixelConfigIsCompressed(desc.fConfig) &&
|
||||
!desc.fTextureStorageAllocator.fAllocateTextureStorage) {
|
||||
GrScratchKey key;
|
||||
GrTexturePriv::ComputeScratchKey(desc, &key);
|
||||
this->setScratchKey(key);
|
||||
|
@ -39,7 +39,8 @@ GrTexture* GrTextureProvider::createTexture(const GrSurfaceDesc& desc, bool budg
|
||||
!fGpu->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!GrPixelConfigIsCompressed(desc.fConfig)) {
|
||||
if (!GrPixelConfigIsCompressed(desc.fConfig) &&
|
||||
!desc.fTextureStorageAllocator.fAllocateTextureStorage) {
|
||||
static const uint32_t kFlags = kExact_ScratchTextureFlag |
|
||||
kNoCreate_ScratchTextureFlag;
|
||||
if (GrTexture* texture = this->refScratchTexture(desc, kFlags)) {
|
||||
|
@ -149,13 +149,15 @@ SkGpuDevice* SkGpuDevice::Create(GrRenderTarget* rt, int width, int height,
|
||||
|
||||
SkGpuDevice* SkGpuDevice::Create(GrContext* context, SkSurface::Budgeted budgeted,
|
||||
const SkImageInfo& info, int sampleCount,
|
||||
const SkSurfaceProps* props, InitContents init) {
|
||||
const SkSurfaceProps* props, InitContents init,
|
||||
GrTextureStorageAllocator customAllocator) {
|
||||
unsigned flags;
|
||||
if (!CheckAlphaTypeAndGetFlags(&info, init, &flags)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkAutoTUnref<GrRenderTarget> rt(CreateRenderTarget(context, budgeted, info, sampleCount));
|
||||
SkAutoTUnref<GrRenderTarget> rt(CreateRenderTarget(
|
||||
context, budgeted, info, sampleCount, customAllocator));
|
||||
if (nullptr == rt) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -182,8 +184,9 @@ SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, int width, int height,
|
||||
}
|
||||
}
|
||||
|
||||
GrRenderTarget* SkGpuDevice::CreateRenderTarget(GrContext* context, SkSurface::Budgeted budgeted,
|
||||
const SkImageInfo& origInfo, int sampleCount) {
|
||||
GrRenderTarget* SkGpuDevice::CreateRenderTarget(
|
||||
GrContext* context, SkSurface::Budgeted budgeted, const SkImageInfo& origInfo,
|
||||
int sampleCount, GrTextureStorageAllocator textureStorageAllocator) {
|
||||
if (kUnknown_SkColorType == origInfo.colorType() ||
|
||||
origInfo.width() < 0 || origInfo.height() < 0) {
|
||||
return nullptr;
|
||||
@ -212,6 +215,7 @@ GrRenderTarget* SkGpuDevice::CreateRenderTarget(GrContext* context, SkSurface::B
|
||||
desc.fHeight = info.height();
|
||||
desc.fConfig = SkImageInfo2GrPixelConfig(info);
|
||||
desc.fSampleCnt = sampleCount;
|
||||
desc.fTextureStorageAllocator = textureStorageAllocator;
|
||||
GrTexture* texture = context->textureProvider()->createTexture(
|
||||
desc, SkToBool(budgeted), nullptr, 0);
|
||||
if (nullptr == texture) {
|
||||
@ -322,7 +326,8 @@ void SkGpuDevice::replaceRenderTarget(bool shouldRetainContent) {
|
||||
: SkSurface::kNo_Budgeted;
|
||||
|
||||
SkAutoTUnref<GrRenderTarget> newRT(CreateRenderTarget(
|
||||
this->context(), budgeted, this->imageInfo(), fRenderTarget->desc().fSampleCnt));
|
||||
this->context(), budgeted, this->imageInfo(), fRenderTarget->desc().fSampleCnt,
|
||||
fRenderTarget->desc().fTextureStorageAllocator));
|
||||
|
||||
if (nullptr == newRT) {
|
||||
return;
|
||||
@ -1474,7 +1479,7 @@ void SkGpuDevice::drawProducerNine(const SkDraw& draw, GrTextureProducer* produc
|
||||
|
||||
SkRect srcR, dstR;
|
||||
while (iter.next(&srcR, &dstR)) {
|
||||
this->drawTextureProducer(producer, &srcR, &dstR, SkCanvas::kStrict_SrcRectConstraint,
|
||||
this->drawTextureProducer(producer, &srcR, &dstR, SkCanvas::kStrict_SrcRectConstraint,
|
||||
*draw.fMatrix, fClip, paint);
|
||||
}
|
||||
return;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "GrDrawContext.h"
|
||||
#include "GrContext.h"
|
||||
#include "GrSurfacePriv.h"
|
||||
#include "GrTypes.h"
|
||||
|
||||
class GrAccelData;
|
||||
class GrTextureProducer;
|
||||
@ -52,7 +53,8 @@ public:
|
||||
* the resource cache budget. On failure, returns nullptr.
|
||||
*/
|
||||
static SkGpuDevice* Create(GrContext*, SkSurface::Budgeted, const SkImageInfo&,
|
||||
int sampleCount, const SkSurfaceProps*, InitContents);
|
||||
int sampleCount, const SkSurfaceProps*,
|
||||
InitContents, GrTextureStorageAllocator = GrTextureStorageAllocator());
|
||||
|
||||
~SkGpuDevice() override {}
|
||||
|
||||
@ -255,7 +257,7 @@ private:
|
||||
bool drawDashLine(const SkPoint pts[2], const SkPaint& paint);
|
||||
|
||||
static GrRenderTarget* CreateRenderTarget(GrContext*, SkSurface::Budgeted, const SkImageInfo&,
|
||||
int sampleCount);
|
||||
int sampleCount, GrTextureStorageAllocator);
|
||||
|
||||
friend class GrAtlasTextContext;
|
||||
friend class SkSurface_Gpu; // for access to surfaceProps
|
||||
|
@ -76,6 +76,7 @@ static SkGrPixelRef* copy_to_new_texture_pixelref(GrTexture* texture, SkColorTyp
|
||||
}
|
||||
desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
||||
desc.fConfig = SkImageInfo2GrPixelConfig(dstCT, kPremul_SkAlphaType, dstPT);
|
||||
desc.fTextureStorageAllocator = texture->desc().fTextureStorageAllocator;
|
||||
|
||||
GrTexture* dst = context->textureProvider()->createTexture(desc, false, nullptr, 0);
|
||||
if (nullptr == dst) {
|
||||
|
@ -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<GrBackendObject>(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<GrBackendObject>(info));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
|
||||
int width,
|
||||
int height) {
|
||||
|
@ -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;
|
||||
|
@ -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<GrBackendObject>(&fInfo));
|
||||
} else {
|
||||
GL_CALL(DeleteTextures(1, &fInfo.fID));
|
||||
}
|
||||
}
|
||||
fInfo.fID = 0;
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ SkSurface* SkSurface::NewRenderTargetDirect(GrRenderTarget*, const SkSurfaceProp
|
||||
}
|
||||
|
||||
SkSurface* SkSurface::NewRenderTarget(GrContext*, Budgeted, const SkImageInfo&, int,
|
||||
const SkSurfaceProps*) {
|
||||
const SkSurfaceProps*, GrTextureStorageAllocator) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -120,9 +120,11 @@ SkSurface* SkSurface::NewRenderTargetDirect(GrRenderTarget* target, const SkSurf
|
||||
}
|
||||
|
||||
SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, Budgeted budgeted, const SkImageInfo& info,
|
||||
int sampleCount, const SkSurfaceProps* props) {
|
||||
SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(ctx, budgeted, info, sampleCount, props,
|
||||
SkGpuDevice::kClear_InitContents));
|
||||
int sampleCount, const SkSurfaceProps* props,
|
||||
GrTextureStorageAllocator customAllocator) {
|
||||
SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(
|
||||
ctx, budgeted, info, sampleCount, props, SkGpuDevice::kClear_InitContents,
|
||||
customAllocator));
|
||||
if (!device) {
|
||||
return nullptr;
|
||||
}
|
||||
|
109
tests/TextureStorageAllocator.cpp
Normal file
109
tests/TextureStorageAllocator.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "Test.h"
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "gl/GrGLGpu.h"
|
||||
#include "GrContext.h"
|
||||
#include "SkSurface_Gpu.h"
|
||||
#include "../include/gpu/gl/SkGLContext.h"
|
||||
#include "../include/gpu/GrTypes.h"
|
||||
#include "../include/private/SkTemplates.h"
|
||||
|
||||
class TestStorageAllocator {
|
||||
public:
|
||||
static GrTextureStorageAllocator::Result allocateTextureStorage(void* ctx,
|
||||
GrBackendObject texture, unsigned width, unsigned height, GrPixelConfig config,
|
||||
const void* srcData, GrSurfaceOrigin) {
|
||||
TestStorageAllocator* allocator = static_cast<TestStorageAllocator*>(ctx);
|
||||
if (!allocator->m_allowAllocation)
|
||||
return GrTextureStorageAllocator::Result::kFailed;
|
||||
SkAutoTMalloc<uint8_t> pixels(width * height * 4);
|
||||
memset(pixels.get(), 0, width * height * 4);
|
||||
|
||||
GrGLuint id;
|
||||
GrGLenum target = GR_GL_TEXTURE_2D;
|
||||
GR_GL_CALL(allocator->m_gl, GenTextures(1, &id));
|
||||
GR_GL_CALL(allocator->m_gl, BindTexture(target, id));
|
||||
GR_GL_CALL(allocator->m_gl, TexParameteri(target, GR_GL_TEXTURE_MAG_FILTER, GR_GL_NEAREST));
|
||||
GR_GL_CALL(allocator->m_gl, TexParameteri(target, GR_GL_TEXTURE_MIN_FILTER, GR_GL_NEAREST));
|
||||
GR_GL_CALL(allocator->m_gl, TexParameteri(target, GR_GL_TEXTURE_WRAP_S, GR_GL_CLAMP_TO_EDGE));
|
||||
GR_GL_CALL(allocator->m_gl, TexParameteri(target, GR_GL_TEXTURE_WRAP_T, GR_GL_CLAMP_TO_EDGE));
|
||||
GR_GL_CALL(allocator->m_gl, TexImage2D(target, 0, GR_GL_RGBA, width, height, 0, GR_GL_RGBA,
|
||||
GR_GL_UNSIGNED_BYTE, pixels.get()));
|
||||
|
||||
GrGLTextureInfo* info = reinterpret_cast<GrGLTextureInfo*>(texture);
|
||||
info->fID = id;
|
||||
info->fTarget = target;
|
||||
allocator->m_mostRecentlyAllocatedStorage = id;
|
||||
return GrTextureStorageAllocator::Result::kSucceededWithoutUpload;
|
||||
}
|
||||
static void deallocateTextureStorage(void* ctx, GrBackendObject texture) {
|
||||
TestStorageAllocator* allocator = static_cast<TestStorageAllocator*>(ctx);
|
||||
GrGLTextureInfo* info = reinterpret_cast<GrGLTextureInfo*>(texture);
|
||||
GR_GL_CALL(allocator->m_gl, DeleteTextures(1, &(info->fID)));
|
||||
}
|
||||
|
||||
GrGLuint m_mostRecentlyAllocatedStorage;
|
||||
const GrGLInterface* m_gl;
|
||||
bool m_allowAllocation;
|
||||
};
|
||||
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(CustomTexture, reporter, context, glContext) {
|
||||
static const int kWidth = 13;
|
||||
static const int kHeight = 13;
|
||||
|
||||
const GrGLInterface* gl = glContext->gl();
|
||||
TestStorageAllocator allocator;
|
||||
allocator.m_allowAllocation = true;
|
||||
allocator.m_gl = gl;
|
||||
GrTextureStorageAllocator grAllocator;
|
||||
grAllocator.fAllocateTextureStorage = &TestStorageAllocator::allocateTextureStorage;
|
||||
grAllocator.fDeallocateTextureStorage= &TestStorageAllocator::deallocateTextureStorage;
|
||||
grAllocator.fCtx = &allocator;
|
||||
|
||||
SkAutoTUnref<SkSurface> surface(SkSurface_Gpu::NewRenderTarget(
|
||||
context, SkSurface_Gpu::kNo_Budgeted, SkImageInfo::MakeN32Premul(kWidth, kHeight), 0,
|
||||
NULL, grAllocator));
|
||||
REPORTER_ASSERT(reporter, surface);
|
||||
GrGLuint id = allocator.m_mostRecentlyAllocatedStorage;
|
||||
|
||||
SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
|
||||
REPORTER_ASSERT(reporter, image->isTextureBacked());
|
||||
SkImageInfo imageInfo = SkImageInfo::MakeN32Premul(1,1);
|
||||
GrColor dest = 0x11223344;
|
||||
REPORTER_ASSERT(reporter, image->readPixels(imageInfo, &dest, 4 * kWidth, 0, 0));
|
||||
REPORTER_ASSERT(reporter, GrColorUnpackG(dest) == 0);
|
||||
|
||||
surface->getCanvas()->clear(SK_ColorGREEN);
|
||||
SkAutoTUnref<SkImage> image2(surface->newImageSnapshot());
|
||||
REPORTER_ASSERT(reporter, image2->isTextureBacked());
|
||||
REPORTER_ASSERT(reporter, allocator.m_mostRecentlyAllocatedStorage != id);
|
||||
|
||||
REPORTER_ASSERT(reporter, image2->readPixels(imageInfo, &dest, 4 * kWidth, 0, 0));
|
||||
REPORTER_ASSERT(reporter, GrColorUnpackG(dest) == 255);
|
||||
}
|
||||
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(CustomTextureFailure, reporter, context, glContext) {
|
||||
static const int kWidth = 13;
|
||||
static const int kHeight = 13;
|
||||
|
||||
const GrGLInterface* gl = glContext->gl();
|
||||
TestStorageAllocator allocator;
|
||||
allocator.m_allowAllocation = false;
|
||||
allocator.m_gl = gl;
|
||||
GrTextureStorageAllocator grAllocator;
|
||||
grAllocator.fAllocateTextureStorage = &TestStorageAllocator::allocateTextureStorage;
|
||||
grAllocator.fDeallocateTextureStorage= &TestStorageAllocator::deallocateTextureStorage;
|
||||
grAllocator.fCtx = &allocator;
|
||||
SkAutoTUnref<SkSurface> surface(SkSurface_Gpu::NewRenderTarget(
|
||||
context, SkSurface_Gpu::kNo_Budgeted, SkImageInfo::MakeN32Premul(kWidth, kHeight), 0,
|
||||
NULL, grAllocator));
|
||||
REPORTER_ASSERT(reporter, !surface);
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user