зеркало из https://github.com/mozilla/moz-skia.git
Adding a new SkSurface factory for generating surfaces from the scratch texture pool.
TEST=Surface unit test BUG=crbug.com/351798 R=bsalomon@google.com, robertphillips@google.com, reed@google.com Author: junov@chromium.org Review URL: https://codereview.chromium.org/201153023 git-svn-id: http://skia.googlecode.com/svn/trunk@13864 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
b9c95978c6
Коммит
d8a57af725
|
@ -73,6 +73,20 @@ public:
|
|||
*/
|
||||
static SkSurface* NewRenderTarget(GrContext*, const SkImageInfo&, int sampleCount = 0);
|
||||
|
||||
/**
|
||||
* Return a new surface whose contents will be drawn to an offscreen
|
||||
* render target, allocated by the surface from the scratch texture pool
|
||||
* managed by the GrContext. The scratch texture pool serves the purpose
|
||||
* of retaining textures after they are no longer in use in order to
|
||||
* re-use them later without having to re-allocate. Scratch textures
|
||||
* should be used in cases where high turnover is expected. This allows,
|
||||
* for example, the copy on write to recycle a texture from a recently
|
||||
* released SkImage snapshot of the surface.
|
||||
* Note: Scratch textures count against the GrContext's cached resource
|
||||
* budget.
|
||||
*/
|
||||
static SkSurface* NewScratchRenderTarget(GrContext*, const SkImageInfo&, int sampleCount = 0);
|
||||
|
||||
int width() const { return fWidth; }
|
||||
int height() const { return fHeight; }
|
||||
|
||||
|
|
|
@ -111,6 +111,11 @@ public:
|
|||
*/
|
||||
size_t getGpuTextureCacheBytes() const;
|
||||
|
||||
/**
|
||||
* Returns the number of resources hosted by the texture cache.
|
||||
*/
|
||||
int getGpuTextureCacheResourceCount() const;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Textures
|
||||
|
||||
|
|
|
@ -29,12 +29,18 @@ class GrTextContext;
|
|||
*/
|
||||
class SK_API SkGpuDevice : public SkBitmapDevice {
|
||||
public:
|
||||
enum Flags {
|
||||
kNeedClear_Flag = 1 << 0, //!< Surface requires an initial clear
|
||||
kCached_Flag = 1 << 1, //!< Surface is cached and needs to be unlocked when released
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an SkGpuDevice from a GrSurface. This will fail if the surface is not a render
|
||||
* target. The caller owns a ref on the returned device.
|
||||
* target. The caller owns a ref on the returned device. If the surface is cached,
|
||||
* the kCached_Flag should be specified to make the device responsible for unlocking
|
||||
* the surface when it is released.
|
||||
*/
|
||||
static SkGpuDevice* Create(GrSurface* surface);
|
||||
static SkGpuDevice* Create(GrSurface* surface, unsigned flags = 0);
|
||||
|
||||
/**
|
||||
* New device that will create an offscreen renderTarget based on the
|
||||
|
@ -58,7 +64,7 @@ public:
|
|||
* DEPRECATED -- need to make this private, call Create(surface)
|
||||
* New device that will render to the specified renderTarget.
|
||||
*/
|
||||
SkGpuDevice(GrContext*, GrRenderTarget*);
|
||||
SkGpuDevice(GrContext*, GrRenderTarget*, unsigned flags = 0);
|
||||
|
||||
/**
|
||||
* DEPRECATED -- need to make this private, call Create(surface)
|
||||
|
@ -66,7 +72,7 @@ public:
|
|||
* The GrTexture's asRenderTarget() must be non-NULL or device will not
|
||||
* function.
|
||||
*/
|
||||
SkGpuDevice(GrContext*, GrTexture*);
|
||||
SkGpuDevice(GrContext*, GrTexture*, unsigned flags = 0);
|
||||
|
||||
virtual ~SkGpuDevice();
|
||||
|
||||
|
@ -173,10 +179,7 @@ private:
|
|||
bool fNeedClear;
|
||||
|
||||
// called from rt and tex cons
|
||||
void initFromRenderTarget(GrContext*, GrRenderTarget*, bool cached);
|
||||
|
||||
// used by createCompatibleDevice
|
||||
SkGpuDevice(GrContext*, GrTexture* texture, bool needClear);
|
||||
void initFromRenderTarget(GrContext*, GrRenderTarget*, unsigned flags);
|
||||
|
||||
virtual SkBaseDevice* onCreateDevice(const SkImageInfo&, Usage) SK_OVERRIDE;
|
||||
|
||||
|
|
|
@ -220,6 +220,10 @@ size_t GrContext::getGpuTextureCacheBytes() const {
|
|||
return fTextureCache->getCachedResourceBytes();
|
||||
}
|
||||
|
||||
int GrContext::getGpuTextureCacheResourceCount() const {
|
||||
return fTextureCache->getCachedResourceCount();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrTexture* GrContext::findAndRefTexture(const GrTextureDesc& desc,
|
||||
|
|
|
@ -213,6 +213,11 @@ public:
|
|||
*/
|
||||
size_t getCachedResourceBytes() const { return fEntryBytes; }
|
||||
|
||||
/**
|
||||
* Returns the number of cached resources.
|
||||
*/
|
||||
int getCachedResourceCount() const { return fEntryCount; }
|
||||
|
||||
// For a found or added resource to be completely exclusive to the caller
|
||||
// both the kNoOtherOwners and kHide flags need to be specified
|
||||
enum OwnershipFlags {
|
||||
|
|
|
@ -158,31 +158,31 @@ static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) {
|
|||
return bitmap;
|
||||
}
|
||||
|
||||
SkGpuDevice* SkGpuDevice::Create(GrSurface* surface) {
|
||||
SkGpuDevice* SkGpuDevice::Create(GrSurface* surface, unsigned flags) {
|
||||
SkASSERT(NULL != surface);
|
||||
if (NULL == surface->asRenderTarget() || NULL == surface->getContext()) {
|
||||
return NULL;
|
||||
}
|
||||
if (surface->asTexture()) {
|
||||
return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asTexture()));
|
||||
return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asTexture(), flags));
|
||||
} else {
|
||||
return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asRenderTarget()));
|
||||
return SkNEW_ARGS(SkGpuDevice, (surface->getContext(), surface->asRenderTarget(), flags));
|
||||
}
|
||||
}
|
||||
|
||||
SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture)
|
||||
SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture, unsigned flags)
|
||||
: SkBitmapDevice(make_bitmap(context, texture->asRenderTarget())) {
|
||||
this->initFromRenderTarget(context, texture->asRenderTarget(), false);
|
||||
this->initFromRenderTarget(context, texture->asRenderTarget(), flags);
|
||||
}
|
||||
|
||||
SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget)
|
||||
SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget, unsigned flags)
|
||||
: SkBitmapDevice(make_bitmap(context, renderTarget)) {
|
||||
this->initFromRenderTarget(context, renderTarget, false);
|
||||
this->initFromRenderTarget(context, renderTarget, flags);
|
||||
}
|
||||
|
||||
void SkGpuDevice::initFromRenderTarget(GrContext* context,
|
||||
GrRenderTarget* renderTarget,
|
||||
bool cached) {
|
||||
unsigned flags) {
|
||||
fDrawProcs = NULL;
|
||||
|
||||
fContext = context;
|
||||
|
@ -192,7 +192,7 @@ void SkGpuDevice::initFromRenderTarget(GrContext* context,
|
|||
fFallbackTextContext = SkNEW_ARGS(GrBitmapTextContext, (fContext, fLeakyProperties));
|
||||
|
||||
fRenderTarget = NULL;
|
||||
fNeedClear = false;
|
||||
fNeedClear = flags & kNeedClear_Flag;
|
||||
|
||||
SkASSERT(NULL != renderTarget);
|
||||
fRenderTarget = renderTarget;
|
||||
|
@ -209,7 +209,7 @@ void SkGpuDevice::initFromRenderTarget(GrContext* context,
|
|||
|
||||
SkImageInfo info;
|
||||
surface->asImageInfo(&info);
|
||||
SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, surface, cached));
|
||||
SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, surface, flags & kCached_Flag));
|
||||
|
||||
this->setPixelRef(pr)->unref();
|
||||
}
|
||||
|
@ -1971,11 +1971,12 @@ SkBaseDevice* SkGpuDevice::onCreateDevice(const SkImageInfo& info, Usage usage)
|
|||
|
||||
SkAutoTUnref<GrTexture> texture;
|
||||
// Skia's convention is to only clear a device if it is non-opaque.
|
||||
bool needClear = !info.isOpaque();
|
||||
unsigned flags = info.isOpaque() ? 0 : kNeedClear_Flag;
|
||||
|
||||
#if CACHE_COMPATIBLE_DEVICE_TEXTURES
|
||||
// layers are never draw in repeat modes, so we can request an approx
|
||||
// match and ignore any padding.
|
||||
flags |= kCached_Flag;
|
||||
const GrContext::ScratchTexMatch match = (kSaveLayer_Usage == usage) ?
|
||||
GrContext::kApprox_ScratchTexMatch :
|
||||
GrContext::kExact_ScratchTexMatch;
|
||||
|
@ -1984,7 +1985,7 @@ SkBaseDevice* SkGpuDevice::onCreateDevice(const SkImageInfo& info, Usage usage)
|
|||
texture.reset(fContext->createUncachedTexture(desc, NULL, 0));
|
||||
#endif
|
||||
if (NULL != texture.get()) {
|
||||
return SkNEW_ARGS(SkGpuDevice,(fContext, texture, needClear));
|
||||
return SkGpuDevice::Create(texture, flags);
|
||||
} else {
|
||||
GrPrintf("---- failed to create compatible device texture [%d %d]\n",
|
||||
info.width(), info.height());
|
||||
|
@ -1996,18 +1997,6 @@ SkSurface* SkGpuDevice::newSurface(const SkImageInfo& info) {
|
|||
return SkSurface::NewRenderTarget(fContext, info, fRenderTarget->numSamples());
|
||||
}
|
||||
|
||||
SkGpuDevice::SkGpuDevice(GrContext* context,
|
||||
GrTexture* texture,
|
||||
bool needClear)
|
||||
: SkBitmapDevice(make_bitmap(context, texture->asRenderTarget())) {
|
||||
|
||||
SkASSERT(texture && texture->asRenderTarget());
|
||||
// This constructor is called from onCreateDevice. It has locked the RT in the texture
|
||||
// cache. We pass true for the third argument so that it will get unlocked.
|
||||
this->initFromRenderTarget(context, texture->asRenderTarget(), true);
|
||||
fNeedClear = needClear;
|
||||
}
|
||||
|
||||
class GPUAccelData : public SkPicture::AccelData {
|
||||
public:
|
||||
GPUAccelData(Key key) : INHERITED(key) { }
|
||||
|
|
|
@ -14,7 +14,7 @@ class SkSurface_Gpu : public SkSurface_Base {
|
|||
public:
|
||||
SK_DECLARE_INST_COUNT(SkSurface_Gpu)
|
||||
|
||||
SkSurface_Gpu(GrRenderTarget*);
|
||||
SkSurface_Gpu(GrRenderTarget*, bool cached);
|
||||
virtual ~SkSurface_Gpu();
|
||||
|
||||
virtual SkCanvas* onNewCanvas() SK_OVERRIDE;
|
||||
|
@ -32,9 +32,9 @@ private:
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkSurface_Gpu::SkSurface_Gpu(GrRenderTarget* renderTarget)
|
||||
SkSurface_Gpu::SkSurface_Gpu(GrRenderTarget* renderTarget, bool cached)
|
||||
: INHERITED(renderTarget->width(), renderTarget->height()) {
|
||||
fDevice = SkNEW_ARGS(SkGpuDevice, (renderTarget->getContext(), renderTarget));
|
||||
fDevice = SkGpuDevice::Create(renderTarget, cached ? SkGpuDevice::kCached_Flag : 0);
|
||||
|
||||
if (kRGB_565_GrPixelConfig != renderTarget->config()) {
|
||||
fDevice->clear(0x0);
|
||||
|
@ -95,7 +95,7 @@ SkSurface* SkSurface::NewRenderTargetDirect(GrRenderTarget* target) {
|
|||
if (NULL == target) {
|
||||
return NULL;
|
||||
}
|
||||
return SkNEW_ARGS(SkSurface_Gpu, (target));
|
||||
return SkNEW_ARGS(SkSurface_Gpu, (target, false));
|
||||
}
|
||||
|
||||
SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, const SkImageInfo& info, int sampleCount) {
|
||||
|
@ -117,5 +117,28 @@ SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, const SkImageInfo& info, i
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return SkNEW_ARGS(SkSurface_Gpu, (tex->asRenderTarget()));
|
||||
return SkNEW_ARGS(SkSurface_Gpu, (tex->asRenderTarget(), false));
|
||||
}
|
||||
|
||||
SkSurface* SkSurface::NewScratchRenderTarget(GrContext* ctx, const SkImageInfo& info, int sampleCount) {
|
||||
if (NULL == ctx) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SkBitmap::Config config = SkImageInfoToBitmapConfig(info);
|
||||
|
||||
GrTextureDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrTextureFlagBit | kCheckAllocation_GrTextureFlagBit;
|
||||
desc.fWidth = info.fWidth;
|
||||
desc.fHeight = info.fHeight;
|
||||
desc.fConfig = SkBitmapConfig2GrPixelConfig(config);
|
||||
desc.fSampleCnt = sampleCount;
|
||||
|
||||
SkAutoTUnref<GrTexture> tex(ctx->lockAndRefScratchTexture(desc, GrContext::kExact_ScratchTexMatch));
|
||||
|
||||
if (NULL == tex) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return SkNEW_ARGS(SkSurface_Gpu, (tex->asRenderTarget(), true));
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ enum SurfaceType {
|
|||
kRaster_SurfaceType,
|
||||
kRasterDirect_SurfaceType,
|
||||
kGpu_SurfaceType,
|
||||
kGpuScratch_SurfaceType,
|
||||
kPicture_SurfaceType
|
||||
};
|
||||
|
||||
|
@ -48,6 +49,11 @@ static SkSurface* createSurface(SurfaceType surfaceType, GrContext* context,
|
|||
case kGpu_SurfaceType:
|
||||
#if SK_SUPPORT_GPU
|
||||
return context ? SkSurface::NewRenderTarget(context, info) : NULL;
|
||||
#endif
|
||||
break;
|
||||
case kGpuScratch_SurfaceType:
|
||||
#if SK_SUPPORT_GPU
|
||||
return context ? SkSurface::NewScratchRenderTarget(context, info) : NULL;
|
||||
#endif
|
||||
break;
|
||||
case kPicture_SurfaceType:
|
||||
|
@ -123,7 +129,7 @@ static void test_imagepeek(skiatest::Reporter* reporter) {
|
|||
} gRec[] = {
|
||||
{ kRasterCopy_ImageType, true },
|
||||
{ kRasterData_ImageType, true },
|
||||
{ kGpu_ImageType, false },
|
||||
{ kGpu_ImageType, false },
|
||||
{ kPicture_ImageType, false },
|
||||
{ kCodec_ImageType, false },
|
||||
};
|
||||
|
@ -164,6 +170,7 @@ static void test_canvaspeek(skiatest::Reporter* reporter,
|
|||
{ kRasterDirect_SurfaceType, true },
|
||||
#if SK_SUPPORT_GPU
|
||||
{ kGpu_SurfaceType, false },
|
||||
{ kGpuScratch_SurfaceType, false },
|
||||
#endif
|
||||
{ kPicture_SurfaceType, false },
|
||||
};
|
||||
|
@ -305,14 +312,36 @@ static void TestSurfaceWritableAfterSnapshotRelease(skiatest::Reporter* reporter
|
|||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
static void TestSurfaceInCache(skiatest::Reporter* reporter,
|
||||
SurfaceType surfaceType,
|
||||
GrContext* context) {
|
||||
context->freeGpuResources();
|
||||
REPORTER_ASSERT(reporter, 0 == context->getGpuTextureCacheResourceCount());
|
||||
SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context));
|
||||
// Note: the stencil buffer is always cached, so kGpu_SurfaceType uses
|
||||
// one cached resource, and kGpuScratch_SurfaceType uses two.
|
||||
int expectedCachedResources = surfaceType == kGpuScratch_SurfaceType ? 2 : 1;
|
||||
REPORTER_ASSERT(reporter, expectedCachedResources == context->getGpuTextureCacheResourceCount());
|
||||
|
||||
// Verify that all the cached resources are locked in cache.
|
||||
context->freeGpuResources();
|
||||
REPORTER_ASSERT(reporter, expectedCachedResources == context->getGpuTextureCacheResourceCount());
|
||||
|
||||
// Verify that all the cached resources are unlocked upon surface release
|
||||
surface.reset(0);
|
||||
context->freeGpuResources();
|
||||
REPORTER_ASSERT(reporter, 0 == context->getGpuTextureCacheResourceCount());
|
||||
}
|
||||
|
||||
static void Test_crbug263329(skiatest::Reporter* reporter,
|
||||
SurfaceType surfaceType,
|
||||
GrContext* context) {
|
||||
// This is a regression test for crbug.com/263329
|
||||
// Bug was caused by onCopyOnWrite releasing the old surface texture
|
||||
// back to the scratch texture pool even though the texture is used
|
||||
// by and active SkImage_Gpu.
|
||||
SkAutoTUnref<SkSurface> surface1(createSurface(kGpu_SurfaceType, context));
|
||||
SkAutoTUnref<SkSurface> surface2(createSurface(kGpu_SurfaceType, context));
|
||||
SkAutoTUnref<SkSurface> surface1(createSurface(surfaceType, context));
|
||||
SkAutoTUnref<SkSurface> surface2(createSurface(surfaceType, context));
|
||||
SkCanvas* canvas1 = surface1->getCanvas();
|
||||
SkCanvas* canvas2 = surface2->getCanvas();
|
||||
canvas1->clear(1);
|
||||
|
@ -345,7 +374,7 @@ static void TestGetTexture(skiatest::Reporter* reporter,
|
|||
SkAutoTUnref<SkSurface> surface(createSurface(surfaceType, context));
|
||||
SkAutoTUnref<SkImage> image(surface->newImageSnapshot());
|
||||
GrTexture* texture = image->getTexture();
|
||||
if (surfaceType == kGpu_SurfaceType) {
|
||||
if (surfaceType == kGpu_SurfaceType || surfaceType == kGpuScratch_SurfaceType) {
|
||||
REPORTER_ASSERT(reporter, NULL != texture);
|
||||
REPORTER_ASSERT(reporter, 0 != texture->getTextureHandle());
|
||||
} else {
|
||||
|
@ -407,12 +436,20 @@ DEF_GPUTEST(Surface, reporter, factory) {
|
|||
if (NULL != factory) {
|
||||
GrContext* context = factory->get(GrContextFactory::kNative_GLContextType);
|
||||
if (NULL != context) {
|
||||
Test_crbug263329(reporter, context);
|
||||
TestSurfaceInCache(reporter, kGpu_SurfaceType, context);
|
||||
TestSurfaceInCache(reporter, kGpuScratch_SurfaceType, context);
|
||||
Test_crbug263329(reporter, kGpu_SurfaceType, context);
|
||||
Test_crbug263329(reporter, kGpuScratch_SurfaceType, context);
|
||||
TestSurfaceCopyOnWrite(reporter, kGpu_SurfaceType, context);
|
||||
TestSurfaceCopyOnWrite(reporter, kGpuScratch_SurfaceType, context);
|
||||
TestSurfaceWritableAfterSnapshotRelease(reporter, kGpu_SurfaceType, context);
|
||||
TestSurfaceWritableAfterSnapshotRelease(reporter, kGpuScratch_SurfaceType, context);
|
||||
TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
|
||||
TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kDiscard_ContentChangeMode);
|
||||
TestSurfaceNoCanvas(reporter, kGpu_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
|
||||
TestSurfaceNoCanvas(reporter, kGpuScratch_SurfaceType, context, SkSurface::kRetain_ContentChangeMode);
|
||||
TestGetTexture(reporter, kGpu_SurfaceType, context);
|
||||
TestGetTexture(reporter, kGpuScratch_SurfaceType, context);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче