зеркало из https://github.com/mozilla/moz-skia.git
Fleshed out GPU portion of image/surface feature
https://codereview.appspot.com/6813055/ git-svn-id: http://skia.googlecode.com/svn/trunk@6214 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
d3eb336d56
Коммит
97b6b0730d
44
gm/image.cpp
44
gm/image.cpp
|
@ -11,7 +11,13 @@
|
|||
#include "SkStream.h"
|
||||
#include "SkData.h"
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrContext.h"
|
||||
|
||||
namespace skiagm {
|
||||
extern GrContext* GetGr();
|
||||
};
|
||||
#endif
|
||||
|
||||
static SkData* fileToData(const char path[]) {
|
||||
SkFILEStream stream(path);
|
||||
|
@ -109,19 +115,40 @@ public:
|
|||
|
||||
protected:
|
||||
virtual SkString onShortName() {
|
||||
return SkString("image");
|
||||
return SkString("image-surface");
|
||||
}
|
||||
|
||||
virtual SkISize onISize() {
|
||||
return SkISize::Make(640, 480);
|
||||
return SkISize::Make(800, 500);
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
drawJpeg(canvas, this->getISize());
|
||||
|
||||
canvas->translate(10, 10);
|
||||
canvas->scale(2, 2);
|
||||
|
||||
static const char* kLabel1 = "Original Img";
|
||||
static const char* kLabel2 = "Modified Img";
|
||||
static const char* kLabel3 = "Cur Surface";
|
||||
|
||||
static const char* kLabel4 = "Pre-Alloc Img";
|
||||
static const char* kLabel5 = "New Alloc Img";
|
||||
static const char* kLabel6 = "SkPicture";
|
||||
static const char* kLabel7 = "GPU";
|
||||
|
||||
SkPaint textPaint;
|
||||
|
||||
canvas->drawText(kLabel1, strlen(kLabel1), 10, 60, textPaint);
|
||||
canvas->drawText(kLabel2, strlen(kLabel2), 10, 140, textPaint);
|
||||
canvas->drawText(kLabel3, strlen(kLabel3), 10, 220, textPaint);
|
||||
|
||||
canvas->drawText(kLabel4, strlen(kLabel4), 80, 10, textPaint);
|
||||
canvas->drawText(kLabel5, strlen(kLabel5), 160, 10, textPaint);
|
||||
canvas->drawText(kLabel6, strlen(kLabel6), 250, 10, textPaint);
|
||||
canvas->drawText(kLabel7, strlen(kLabel7), 340, 10, textPaint);
|
||||
|
||||
canvas->translate(80, 20);
|
||||
|
||||
// since we draw into this directly, we need to start fresh
|
||||
sk_bzero(fBuffer, fBufferSize);
|
||||
|
||||
|
@ -134,12 +161,23 @@ protected:
|
|||
SkAutoTUnref<SkSurface> surf0(SkSurface::NewRasterDirect(info, NULL, fBuffer, RB));
|
||||
SkAutoTUnref<SkSurface> surf1(SkSurface::NewRaster(info, NULL));
|
||||
SkAutoTUnref<SkSurface> surf2(SkSurface::NewPicture(info.fWidth, info.fHeight));
|
||||
#if SK_SUPPORT_GPU
|
||||
GrContext* ctx = skiagm::GetGr();
|
||||
|
||||
SkAutoTUnref<SkSurface> surf3(SkSurface::NewRenderTarget(ctx, info, NULL, 0));
|
||||
#endif
|
||||
|
||||
test_surface(canvas, surf0);
|
||||
canvas->translate(80, 0);
|
||||
test_surface(canvas, surf1);
|
||||
canvas->translate(80, 0);
|
||||
test_surface(canvas, surf2);
|
||||
#if SK_SUPPORT_GPU
|
||||
if (NULL != ctx) {
|
||||
canvas->translate(80, 0);
|
||||
test_surface(canvas, surf3);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual uint32_t onGetFlags() const SK_OVERRIDE {
|
||||
|
|
|
@ -229,6 +229,9 @@
|
|||
'<(skia_src_path)/gpu/SkGrPixelRef.cpp',
|
||||
'<(skia_src_path)/gpu/SkGrTexturePixelRef.cpp',
|
||||
|
||||
'<(skia_src_path)/image/SkImage_Gpu.cpp',
|
||||
'<(skia_src_path)/image/SkSurface_Gpu.cpp',
|
||||
|
||||
'<(skia_src_path)/gpu/gl/SkGLContext.cpp'
|
||||
],
|
||||
'skgr_native_gl_sources': [
|
||||
|
|
|
@ -16,7 +16,6 @@ class SkCanvas;
|
|||
class SkPaint;
|
||||
class SkShader;
|
||||
class GrContext;
|
||||
struct GrPlatformTextureDesc;
|
||||
|
||||
// need for TileMode
|
||||
#include "SkShader.h"
|
||||
|
@ -63,13 +62,12 @@ public:
|
|||
int fHeight;
|
||||
ColorType fColorType;
|
||||
AlphaType fAlphaType;
|
||||
|
||||
};
|
||||
|
||||
static SkImage* NewRasterCopy(const Info&, SkColorSpace*, const void* pixels, size_t rowBytes);
|
||||
static SkImage* NewRasterData(const Info&, SkColorSpace*, SkData* pixels, size_t rowBytes);
|
||||
static SkImage* NewEncodedData(SkData*);
|
||||
static SkImage* NewTexture(GrContext*, const GrPlatformTextureDesc&);
|
||||
static SkImage* NewTexture(GrTexture*);
|
||||
|
||||
int width() const { return fWidth; }
|
||||
int height() const { return fHeight; }
|
||||
|
|
|
@ -55,4 +55,14 @@ static inline size_t SkImageMinRowBytes(const SkImage::Info& info) {
|
|||
// in which case the surface may need to perform a copy-on-write.
|
||||
extern SkPixelRef* SkBitmapImageGetPixelRef(SkImage* rasterImage);
|
||||
|
||||
// Given an image created with NewTexture, return its GrTexture. This
|
||||
// may be called to see if the surface and the image share the same GrTexture,
|
||||
// in which case the surface may need to perform a copy-on-write.
|
||||
extern GrTexture* SkTextureImageGetTexture(SkImage* rasterImage);
|
||||
|
||||
// Update the texture wrapped by an image created with NewTexture. This
|
||||
// is called when a surface and image share the same GrTexture and the
|
||||
// surface needs to perform a copy-on-write
|
||||
extern void SkTextureImageSetTexture(SkImage* image, GrTexture* texture);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,7 +14,7 @@ class SkImage_Base : public SkImage {
|
|||
public:
|
||||
SkImage_Base(int width, int height) : INHERITED(width, height) {}
|
||||
|
||||
virtual void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) = 0;
|
||||
virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) = 0;
|
||||
|
||||
private:
|
||||
typedef SkImage INHERITED;
|
||||
|
|
|
@ -9,65 +9,77 @@
|
|||
#include "SkImagePriv.h"
|
||||
#include "SkBitmap.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkData.h"
|
||||
#include "SkDataPixelRef.h"
|
||||
#include "GrContext.h"
|
||||
#include "GrTexture.h"
|
||||
#include "SkGrPixelRef.h"
|
||||
|
||||
class SkImage_Gpu : public SkImage_Base {
|
||||
public:
|
||||
static bool ValidArgs(GrContext* context,
|
||||
const GrPlatformTextureDesc& desc) {
|
||||
if (0 == desc.fTextureHandle) {
|
||||
return false;
|
||||
}
|
||||
if (desc.fWidth < 0 || desc.fHeight < 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
SK_DECLARE_INST_COUNT(SkImage_Gpu)
|
||||
|
||||
SkImage_Gpu(GrContext* context, const GrPlatformTextureDesc& desc);
|
||||
SkImage_Gpu(GrTexture*);
|
||||
virtual ~SkImage_Gpu();
|
||||
|
||||
virtual void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) SK_OVERRIDE;
|
||||
virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) SK_OVERRIDE;
|
||||
|
||||
GrTexture* getTexture() { return fTexture; }
|
||||
|
||||
void setTexture(GrTexture* texture);
|
||||
|
||||
private:
|
||||
GrTexture* fTexture;
|
||||
SkBitmap fBitmap;
|
||||
|
||||
typedef SkImage_Base INHERITED;
|
||||
};
|
||||
|
||||
SK_DEFINE_INST_COUNT(SkImage_Gpu)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkImage_Gpu::SkImage_Gpu(GrContext* context, const GrPlatformTextureDesc& desc)
|
||||
: INHERITED(desc.fWidth, desc.fHeight) {
|
||||
#if 0
|
||||
bool isOpaque;
|
||||
SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
|
||||
SkImage_Gpu::SkImage_Gpu(GrTexture* texture)
|
||||
: INHERITED(texture->width(), texture->height())
|
||||
, fTexture(texture) {
|
||||
|
||||
fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes);
|
||||
fBitmap.setPixelRef(SkNEW_ARGS(SkDataPixelRef, (data)))->unref();
|
||||
fBitmap.setIsOpaque(isOpaque);
|
||||
fBitmap.setImmutable();
|
||||
#endif
|
||||
SkASSERT(NULL != fTexture);
|
||||
fTexture->ref();
|
||||
fBitmap.setConfig(SkBitmap::kARGB_8888_Config, fTexture->width(), fTexture->height());
|
||||
fBitmap.setPixelRef(new SkGrPixelRef(fTexture))->unref();
|
||||
}
|
||||
|
||||
SkImage_Gpu::~SkImage_Gpu() {}
|
||||
SkImage_Gpu::~SkImage_Gpu() {
|
||||
SkSafeUnref(fTexture);
|
||||
}
|
||||
|
||||
void SkImage_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
|
||||
void SkImage_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
|
||||
const SkPaint* paint) {
|
||||
canvas->drawBitmap(fBitmap, x, y, paint);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void SkImage_Gpu::setTexture(GrTexture* texture) {
|
||||
|
||||
SkImage* SkImage::NewRasterCopy(NewTexture(GrContext* context,
|
||||
const GrPlatformTextureDesc& desc) {
|
||||
if (NULL == context) {
|
||||
return NULL;
|
||||
}
|
||||
if (!SkImage_Gpu::ValidArgs(context, desc)) {
|
||||
return NULL;
|
||||
if (texture == fTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
return SkNEW_ARGS(SkImage_Gpu, (context, desc));
|
||||
SkRefCnt_SafeAssign(fTexture, texture);
|
||||
fBitmap.setPixelRef(new SkGrPixelRef(texture))->unref();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkImage* SkImage::NewTexture(GrTexture* texture) {
|
||||
if (NULL == texture) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return SkNEW_ARGS(SkImage_Gpu, (texture));
|
||||
}
|
||||
|
||||
GrTexture* SkTextureImageGetTexture(SkImage* image) {
|
||||
return ((SkImage_Gpu*)image)->getTexture();
|
||||
}
|
||||
|
||||
void SkTextureImageSetTexture(SkImage* image, GrTexture* texture) {
|
||||
((SkImage_Gpu*)image)->setTexture(texture);
|
||||
}
|
||||
|
|
|
@ -43,8 +43,6 @@ void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
|
|||
}
|
||||
}
|
||||
|
||||
void SkSurface_Base::onCopyOnWrite(SkImage*, SkCanvas*) {}
|
||||
|
||||
SkCanvas* SkSurface_Base::getCachedCanvas() {
|
||||
if (NULL == fCachedCanvas) {
|
||||
fCachedCanvas = this->onNewCanvas();
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
*
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
virtual void onCopyOnWrite(SkImage* cachedImage, SkCanvas*);
|
||||
virtual void onCopyOnWrite(SkImage* cachedImage, SkCanvas*) = 0;
|
||||
|
||||
inline SkCanvas* getCachedCanvas();
|
||||
inline SkImage* getCachedImage();
|
||||
|
|
|
@ -8,125 +8,100 @@
|
|||
#include "SkSurface_Base.h"
|
||||
#include "SkImagePriv.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkMallocPixelRef.h"
|
||||
|
||||
static const size_t kIgnoreRowBytesValue = (size_t)~0;
|
||||
#include "SkGpuDevice.h"
|
||||
|
||||
class SkSurface_Gpu : public SkSurface_Base {
|
||||
public:
|
||||
static bool Valid(const SkImage::Info&, SkColorSpace*, size_t rb = kIgnoreRowBytesValue);
|
||||
SK_DECLARE_INST_COUNT(SkSurface_Gpu)
|
||||
|
||||
SkSurface_Gpu(const SkImage::Info&, SkColorSpace*, void*, size_t rb);
|
||||
SkSurface_Gpu(const SkImage::Info&, SkColorSpace*, SkPixelRef*, size_t rb);
|
||||
SkSurface_Gpu(GrContext*, const SkImage::Info&, int sampleCount);
|
||||
SkSurface_Gpu(GrContext*, GrRenderTarget*);
|
||||
virtual ~SkSurface_Gpu();
|
||||
|
||||
virtual SkCanvas* onNewCanvas() SK_OVERRIDE;
|
||||
virtual SkSurface* onNewSurface(const SkImage::Info&, SkColorSpace*) SK_OVERRIDE;
|
||||
virtual SkImage* onNewImageShapshot() SK_OVERRIDE;
|
||||
virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y,
|
||||
const SkPaint*) SK_OVERRIDE;
|
||||
virtual void onCopyOnWrite(SkImage*, SkCanvas*) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkBitmap fBitmap;
|
||||
bool fWeOwnThePixels;
|
||||
SkGpuDevice* fDevice;
|
||||
|
||||
typedef SkSurface_Base INHERITED;
|
||||
};
|
||||
|
||||
SK_DEFINE_INST_COUNT(SkSurface_Gpu)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkSurface_Gpu::Valid(const SkImage::Info& info, SkColorSpace* cs,
|
||||
size_t rowBytes) {
|
||||
static const size_t kMaxTotalSize = SK_MaxS32;
|
||||
|
||||
bool isOpaque;
|
||||
SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
|
||||
|
||||
int shift = 0;
|
||||
switch (config) {
|
||||
case SkBitmap::kA8_Config:
|
||||
shift = 0;
|
||||
break;
|
||||
case SkBitmap::kRGB_565_Config:
|
||||
shift = 1;
|
||||
break;
|
||||
case SkBitmap::kARGB_8888_Config:
|
||||
shift = 2;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: examine colorspace
|
||||
|
||||
if (kIgnoreRowBytesValue == rowBytes) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t minRB = (uint64_t)info.fWidth << shift;
|
||||
if (minRB > rowBytes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t alignedRowBytes = rowBytes >> shift << shift;
|
||||
if (alignedRowBytes != rowBytes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t size = (uint64_t)info.fHeight * rowBytes;
|
||||
if (size > kMaxTotalSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SkSurface_Gpu::SkSurface_Gpu(const SkImage::Info& info, SkColorSpace* cs,
|
||||
void* pixels, size_t rb)
|
||||
SkSurface_Gpu::SkSurface_Gpu(GrContext* ctx, const SkImage::Info& info,
|
||||
int sampleCount)
|
||||
: INHERITED(info.fWidth, info.fHeight) {
|
||||
bool isOpaque;
|
||||
SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
|
||||
|
||||
fBitmap.setConfig(config, info.fWidth, info.fHeight, rb);
|
||||
fBitmap.setPixels(pixels);
|
||||
fBitmap.setIsOpaque(isOpaque);
|
||||
fWeOwnThePixels = false;
|
||||
fDevice = SkNEW_ARGS(SkGpuDevice, (ctx, config, info.fWidth, info.fHeight, sampleCount));
|
||||
}
|
||||
|
||||
SkSurface_Gpu::SkSurface_Gpu(const SkImage::Info& info, SkColorSpace* cs,
|
||||
SkPixelRef* pr, size_t rb)
|
||||
: INHERITED(info.fWidth, info.fHeight) {
|
||||
bool isOpaque;
|
||||
SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
|
||||
SkSurface_Gpu::SkSurface_Gpu(GrContext* ctx, GrRenderTarget* renderTarget)
|
||||
: INHERITED(renderTarget->width(), renderTarget->height()) {
|
||||
fDevice = SkNEW_ARGS(SkGpuDevice, (ctx, renderTarget));
|
||||
}
|
||||
|
||||
fBitmap.setConfig(config, info.fWidth, info.fHeight, rb);
|
||||
fBitmap.setPixelRef(pr);
|
||||
fBitmap.setIsOpaque(isOpaque);
|
||||
fWeOwnThePixels = true;
|
||||
|
||||
if (!isOpaque) {
|
||||
fBitmap.eraseColor(0);
|
||||
}
|
||||
SkSurface_Gpu::~SkSurface_Gpu() {
|
||||
SkSafeUnref(fDevice);
|
||||
}
|
||||
|
||||
SkCanvas* SkSurface_Gpu::onNewCanvas() {
|
||||
return SkNEW_ARGS(SkCanvas, (fBitmap));
|
||||
return SkNEW_ARGS(SkCanvas, (fDevice));
|
||||
}
|
||||
|
||||
SkSurface* SkSurface_Gpu::onNewSurface(const SkImage::Info& info,
|
||||
SkColorSpace* cs) {
|
||||
return SkSurface::NewRaster(info, cs);
|
||||
SkColorSpace* cs) {
|
||||
GrRenderTarget* rt = (GrRenderTarget*) fDevice->accessRenderTarget();
|
||||
int sampleCount = rt->numSamples();
|
||||
return SkSurface::NewRenderTarget(fDevice->context(), info, NULL, sampleCount);
|
||||
}
|
||||
|
||||
SkImage* SkSurface_Gpu::onNewImageShapshot() {
|
||||
// if we don't own the pixels, we need to make a deep-copy
|
||||
// if we do, we need to perform a copy-on-write the next time
|
||||
// we draw to this bitmap from our canvas...
|
||||
return SkNewImageFromBitmap(fBitmap);
|
||||
|
||||
GrRenderTarget* rt = (GrRenderTarget*) fDevice->accessRenderTarget();
|
||||
|
||||
return SkImage::NewTexture(rt->asTexture());
|
||||
}
|
||||
|
||||
void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
|
||||
const SkPaint* paint) {
|
||||
canvas->drawBitmap(fBitmap, x, y, paint);
|
||||
canvas->drawBitmap(fDevice->accessBitmap(false), x, y, paint);
|
||||
}
|
||||
|
||||
// Copy the contents of the SkGpuDevice into a new texture and give that
|
||||
// texture to the SkImage. Note that this flushes the SkGpuDevice but
|
||||
// doesn't force an OpenGL flush.
|
||||
void SkSurface_Gpu::onCopyOnWrite(SkImage* image, SkCanvas* canvas) {
|
||||
GrRenderTarget* rt = (GrRenderTarget*) fDevice->accessRenderTarget();
|
||||
|
||||
// are we sharing our render target with the image?
|
||||
if (rt->asTexture() == SkTextureImageGetTexture(image)) {
|
||||
GrTextureDesc desc;
|
||||
// copyTexture requires a render target as the destination
|
||||
desc.fFlags = kRenderTarget_GrTextureFlagBit;
|
||||
desc.fWidth = fDevice->width();
|
||||
desc.fHeight = fDevice->height();
|
||||
desc.fConfig = SkBitmapConfig2GrPixelConfig(fDevice->config());
|
||||
desc.fSampleCnt = 0;
|
||||
|
||||
GrTexture* tex = fDevice->context()->createUncachedTexture(desc, NULL, 0);
|
||||
if (NULL == tex) {
|
||||
SkTextureImageSetTexture(image, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
fDevice->context()->copyTexture(rt->asTexture(), tex->asRenderTarget());
|
||||
|
||||
SkTextureImageSetTexture(image, tex);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -145,10 +120,22 @@ SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, const SkImage::Info& info,
|
|||
if (NULL == ctx) {
|
||||
return NULL;
|
||||
}
|
||||
if (!SkSurface_Gpu::Valid(info, cs, sampleCount)) {
|
||||
|
||||
bool isOpaque;
|
||||
SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
|
||||
|
||||
GrTextureDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrTextureFlagBit;
|
||||
desc.fWidth = info.fWidth;
|
||||
desc.fHeight = info.fHeight;
|
||||
desc.fConfig = SkBitmapConfig2GrPixelConfig(config);
|
||||
desc.fSampleCnt = sampleCount;
|
||||
|
||||
GrTexture* tex = ctx->createUncachedTexture(desc, NULL, 0);
|
||||
if (NULL == tex) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// return SkNEW_ARGS(SkSurface_Gpu, (info, cs, pr, rowBytes));
|
||||
|
||||
return SkNEW_ARGS(SkSurface_Gpu, (ctx, tex->asRenderTarget()));
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ public:
|
|||
virtual SkImage* onNewImageShapshot() SK_OVERRIDE;
|
||||
virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y,
|
||||
const SkPaint*) SK_OVERRIDE;
|
||||
virtual void onCopyOnWrite(SkImage*, SkCanvas*) SK_OVERRIDE;
|
||||
|
||||
private:
|
||||
SkPicture* fPicture;
|
||||
|
@ -75,6 +76,11 @@ void SkSurface_Picture::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
|
|||
SkImagePrivDrawPicture(canvas, fPicture, x, y, paint);
|
||||
}
|
||||
|
||||
void SkSurface_Picture::onCopyOnWrite(SkImage* cachedImage, SkCanvas*) {
|
||||
// We always spawn a copy of the recording picture when we
|
||||
// are asked for a snapshot, so we never need to do anything here.
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче