Add SkSpecialImage & SkSpecialSurface classes
Initial classes. GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1579323002 Review URL: https://codereview.chromium.org/1579323002
This commit is contained in:
parent
7471c780d4
commit
b6c65e9995
@ -249,6 +249,10 @@
|
||||
'<(skia_src_path)/core/SkSharedMutex.cpp',
|
||||
'<(skia_src_path)/core/SkSharedMutex.h',
|
||||
'<(skia_src_path)/core/SkSmallAllocator.h',
|
||||
'<(skia_src_path)/core/SkSpecialImage.cpp',
|
||||
'<(skia_src_path)/core/SkSpecialImage.h',
|
||||
'<(skia_src_path)/core/SkSpecialSurface.cpp',
|
||||
'<(skia_src_path)/core/SkSpecialSurface.h',
|
||||
'<(skia_src_path)/core/SkSpinlock.cpp',
|
||||
'<(skia_src_path)/core/SkSpriteBlitter_ARGB32.cpp',
|
||||
'<(skia_src_path)/core/SkSpriteBlitter_RGB16.cpp',
|
||||
|
@ -381,6 +381,7 @@ private:
|
||||
|
||||
bool isPreLocked() const { return fPreLocked; }
|
||||
friend class SkImage_Raster;
|
||||
friend class SkSpecialImage_Raster;
|
||||
|
||||
// When copying a bitmap to another with the same shape and config, we can safely
|
||||
// clone the pixelref generation ID too, which makes them equivalent under caching.
|
||||
|
224
src/core/SkSpecialImage.cpp
Normal file
224
src/core/SkSpecialImage.cpp
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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 "SkCanvas.h"
|
||||
#include "SkSpecialImage.h"
|
||||
#include "SkSpecialSurface.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class SkSpecialImage_Base : public SkSpecialImage {
|
||||
public:
|
||||
SkSpecialImage_Base(const SkIRect& subset) : INHERITED(subset) { }
|
||||
virtual ~SkSpecialImage_Base() { }
|
||||
|
||||
virtual void onDraw(SkCanvas*, int x, int y, const SkPaint*) const = 0;
|
||||
|
||||
virtual bool onPeekPixels(SkPixmap*) const { return false; }
|
||||
|
||||
virtual GrTexture* onPeekTexture() const { return nullptr; }
|
||||
|
||||
virtual SkSpecialSurface* onNewSurface(const SkImageInfo& info) const { return nullptr; }
|
||||
|
||||
private:
|
||||
typedef SkSpecialImage INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
static inline const SkSpecialImage_Base* as_IB(const SkSpecialImage* image) {
|
||||
return static_cast<const SkSpecialImage_Base*>(image);
|
||||
}
|
||||
|
||||
void SkSpecialImage::draw(SkCanvas* canvas, int x, int y, const SkPaint* paint) const {
|
||||
return as_IB(this)->onDraw(canvas, x, y, paint);
|
||||
}
|
||||
|
||||
bool SkSpecialImage::peekPixels(SkPixmap* pixmap) const {
|
||||
return as_IB(this)->onPeekPixels(pixmap);
|
||||
}
|
||||
|
||||
GrTexture* SkSpecialImage::peekTexture() const {
|
||||
return as_IB(this)->onPeekTexture();
|
||||
}
|
||||
|
||||
SkSpecialSurface* SkSpecialImage::newSurface(const SkImageInfo& info) const {
|
||||
return as_IB(this)->onNewSurface(info);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "SkImage.h"
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "SkGr.h"
|
||||
#include "SkGrPriv.h"
|
||||
#endif
|
||||
|
||||
class SkSpecialImage_Image : public SkSpecialImage_Base {
|
||||
public:
|
||||
SkSpecialImage_Image(const SkIRect& subset, const SkImage* image)
|
||||
: INHERITED(subset)
|
||||
, fImage(SkRef(image)) {
|
||||
}
|
||||
|
||||
~SkSpecialImage_Image() override { }
|
||||
|
||||
void onDraw(SkCanvas* canvas, int x, int y, const SkPaint* paint) const override {
|
||||
SkRect dst = SkRect::MakeXYWH(x, y, this->subset().width(), this->subset().height());
|
||||
|
||||
canvas->drawImageRect(fImage, this->subset(),
|
||||
dst, paint, SkCanvas::kStrict_SrcRectConstraint);
|
||||
}
|
||||
|
||||
bool onPeekPixels(SkPixmap* pixmap) const override {
|
||||
return fImage->peekPixels(pixmap);
|
||||
}
|
||||
|
||||
GrTexture* onPeekTexture() const override { return fImage->getTexture(); }
|
||||
|
||||
SkSpecialSurface* onNewSurface(const SkImageInfo& info) const override {
|
||||
#if SK_SUPPORT_GPU
|
||||
GrTexture* texture = fImage->getTexture();
|
||||
if (texture) {
|
||||
GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(info);
|
||||
desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
||||
|
||||
return SkSpecialSurface::NewRenderTarget(texture->getContext(), desc);
|
||||
}
|
||||
#endif
|
||||
return SkSpecialSurface::NewRaster(info, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
SkAutoTUnref<const SkImage> fImage;
|
||||
|
||||
typedef SkSpecialImage_Base INHERITED;
|
||||
};
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
static bool rect_fits(const SkIRect& rect, int width, int height) {
|
||||
return rect.fLeft >= 0 && rect.fLeft < width && rect.fLeft < rect.fRight &&
|
||||
rect.fRight >= 0 && rect.fRight <= width &&
|
||||
rect.fTop >= 0 && rect.fTop < height && rect.fTop < rect.fBottom &&
|
||||
rect.fBottom >= 0 && rect.fBottom <= height;
|
||||
}
|
||||
#endif
|
||||
|
||||
SkSpecialImage* SkSpecialImage::NewFromImage(const SkIRect& subset, const SkImage* image) {
|
||||
SkASSERT(rect_fits(subset, image->width(), image->height()));
|
||||
return new SkSpecialImage_Image(subset, image);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "SkBitmap.h"
|
||||
#include "SkImageInfo.h"
|
||||
#include "SkPixelRef.h"
|
||||
|
||||
class SkSpecialImage_Raster : public SkSpecialImage_Base {
|
||||
public:
|
||||
SkSpecialImage_Raster(const SkIRect& subset, const SkBitmap& bm)
|
||||
: INHERITED(subset)
|
||||
, fBitmap(bm) {
|
||||
if (bm.pixelRef()->isPreLocked()) {
|
||||
// we only preemptively lock if there is no chance of triggering something expensive
|
||||
// like a lazy decode or imagegenerator. PreLocked means it is flat pixels already.
|
||||
fBitmap.lockPixels();
|
||||
}
|
||||
}
|
||||
|
||||
~SkSpecialImage_Raster() override { }
|
||||
|
||||
void onDraw(SkCanvas* canvas, int x, int y, const SkPaint* paint) const override {
|
||||
SkRect dst = SkRect::MakeXYWH(x, y,
|
||||
this->subset().width(), this->subset().height());
|
||||
|
||||
canvas->drawBitmapRect(fBitmap, this->subset(),
|
||||
dst, paint, SkCanvas::kStrict_SrcRectConstraint);
|
||||
}
|
||||
|
||||
bool onPeekPixels(SkPixmap* pixmap) const override {
|
||||
const SkImageInfo info = fBitmap.info();
|
||||
if ((kUnknown_SkColorType == info.colorType()) || !fBitmap.getPixels()) {
|
||||
return false;
|
||||
}
|
||||
const void* pixels = fBitmap.getPixels();
|
||||
if (pixels) {
|
||||
if (pixmap) {
|
||||
pixmap->reset(info, pixels, fBitmap.rowBytes());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SkSpecialSurface* onNewSurface(const SkImageInfo& info) const override {
|
||||
return SkSpecialSurface::NewRaster(info, nullptr);
|
||||
}
|
||||
|
||||
private:
|
||||
SkBitmap fBitmap;
|
||||
|
||||
typedef SkSpecialImage_Base INHERITED;
|
||||
};
|
||||
|
||||
SkSpecialImage* SkSpecialImage::NewFromRaster(const SkIRect& subset, const SkBitmap& bm) {
|
||||
SkASSERT(nullptr == bm.getTexture());
|
||||
SkASSERT(rect_fits(subset, bm.width(), bm.height()));
|
||||
return new SkSpecialImage_Raster(subset, bm);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "GrTexture.h"
|
||||
|
||||
class SkSpecialImage_Gpu : public SkSpecialImage_Base {
|
||||
public:
|
||||
SkSpecialImage_Gpu(const SkIRect& subset, GrTexture* tex)
|
||||
: INHERITED(subset)
|
||||
, fTexture(SkRef(tex)) {
|
||||
}
|
||||
|
||||
~SkSpecialImage_Gpu() override { }
|
||||
|
||||
void onDraw(SkCanvas* canvas, int x, int y, const SkPaint* paint) const override {
|
||||
SkRect dst = SkRect::MakeXYWH(x, y,
|
||||
this->subset().width(), this->subset().height());
|
||||
|
||||
SkBitmap bm;
|
||||
|
||||
static const bool kUnknownOpacity = false;
|
||||
GrWrapTextureInBitmap(fTexture,
|
||||
fTexture->width(), fTexture->height(), kUnknownOpacity, &bm);
|
||||
|
||||
canvas->drawBitmapRect(bm, this->subset(),
|
||||
dst, paint, SkCanvas::kStrict_SrcRectConstraint);
|
||||
}
|
||||
|
||||
GrTexture* onPeekTexture() const override { return fTexture; }
|
||||
|
||||
SkSpecialSurface* onNewSurface(const SkImageInfo& info) const override {
|
||||
GrSurfaceDesc desc = GrImageInfoToSurfaceDesc(info);
|
||||
desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
||||
|
||||
return SkSpecialSurface::NewRenderTarget(fTexture->getContext(), desc);
|
||||
}
|
||||
|
||||
private:
|
||||
SkAutoTUnref<GrTexture> fTexture;
|
||||
|
||||
typedef SkSpecialImage_Base INHERITED;
|
||||
};
|
||||
|
||||
SkSpecialImage* SkSpecialImage::NewFromGpu(const SkIRect& subset, GrTexture* tex) {
|
||||
SkASSERT(rect_fits(subset, tex->width(), tex->height()));
|
||||
return new SkSpecialImage_Gpu(subset, tex);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
SkSpecialImage* SkSpecialImage::NewFromGpu(const SkIRect& subset, GrTexture* tex) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
84
src/core/SkSpecialImage.h
Normal file
84
src/core/SkSpecialImage.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file
|
||||
*/
|
||||
|
||||
#ifndef SkSpecialImage_DEFINED
|
||||
#define SkSpecialImage_DEFINED
|
||||
|
||||
#include "SkRefCnt.h"
|
||||
|
||||
class GrTexture;
|
||||
class SkBitmap;
|
||||
class SkCanvas;
|
||||
class SkImage;
|
||||
struct SkImageInfo;
|
||||
class SkPaint;
|
||||
class SkSpecialSurface;
|
||||
|
||||
/**
|
||||
* This is a restricted form of SkImage solely intended for internal use. It
|
||||
* differs from SkImage in that:
|
||||
* - it can only be backed by raster or gpu (no generators)
|
||||
* - it can be backed by a GrTexture larger than its nominal bounds
|
||||
* - it can't be drawn tiled
|
||||
* - it can't be drawn with MIPMAPs
|
||||
* It is similar to SkImage in that it abstracts how the pixels are stored/represented.
|
||||
*
|
||||
* Note: the contents of the backing storage outside of the subset rect are undefined.
|
||||
*/
|
||||
class SkSpecialImage : public SkRefCnt {
|
||||
public:
|
||||
int width() const { return fSubset.width(); }
|
||||
int height() const { return fSubset.height(); }
|
||||
|
||||
/**
|
||||
* Draw this SpecialImage into the canvas.
|
||||
*/
|
||||
void draw(SkCanvas*, int x, int y, const SkPaint*) const;
|
||||
|
||||
static SkSpecialImage* NewFromImage(const SkIRect& subset, const SkImage*);
|
||||
static SkSpecialImage* NewFromRaster(const SkIRect& subset, const SkBitmap&);
|
||||
static SkSpecialImage* NewFromGpu(const SkIRect& subset, GrTexture*);
|
||||
|
||||
/**
|
||||
* Create a new surface with a backend that is compatible with this image.
|
||||
*/
|
||||
SkSpecialSurface* newSurface(const SkImageInfo&) const;
|
||||
|
||||
protected:
|
||||
SkSpecialImage(const SkIRect& subset) : fSubset(subset) { }
|
||||
|
||||
// The following 3 are for testing and shouldn't be used.
|
||||
friend class TestingSpecialImageAccess;
|
||||
friend class TestingSpecialSurfaceAccess;
|
||||
const SkIRect& subset() const { return fSubset; }
|
||||
|
||||
/**
|
||||
* If the SpecialImage is backed by cpu pixels, return the const address
|
||||
* of those pixels and, if not null, return the ImageInfo and rowBytes.
|
||||
* The returned address is only valid while the image object is in scope.
|
||||
*
|
||||
* The returned ImageInfo represents the backing memory. Use 'subset'
|
||||
* to get the active portion's dimensions.
|
||||
*
|
||||
* On failure, return false and ignore the pixmap parameter.
|
||||
*/
|
||||
bool peekPixels(SkPixmap*) const;
|
||||
|
||||
/**
|
||||
* If the SpecialImage is backed by a gpu texture, return that texture.
|
||||
* The active portion of the texture can be retrieved via 'subset'.
|
||||
*/
|
||||
GrTexture* peekTexture() const;
|
||||
|
||||
private:
|
||||
const SkIRect fSubset;
|
||||
|
||||
typedef SkRefCnt INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
177
src/core/SkSpecialSurface.cpp
Normal file
177
src/core/SkSpecialSurface.cpp
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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 "SkCanvas.h"
|
||||
#include "SkSpecialImage.h"
|
||||
#include "SkSpecialSurface.h"
|
||||
#include "SkSurfacePriv.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class SkSpecialSurface_Base : public SkSpecialSurface {
|
||||
public:
|
||||
SkSpecialSurface_Base(const SkIRect& subset, const SkSurfaceProps* props)
|
||||
: INHERITED(subset, props)
|
||||
, fCanvas(nullptr) {
|
||||
}
|
||||
|
||||
virtual ~SkSpecialSurface_Base() { }
|
||||
|
||||
// reset is called after an SkSpecialImage has been snapped
|
||||
void reset() { fCanvas.reset(); }
|
||||
|
||||
// This can return nullptr if reset has already been called or something when wrong in the ctor
|
||||
SkCanvas* onGetCanvas() { return fCanvas; }
|
||||
|
||||
virtual SkSpecialImage* onNewImageSnapshot() = 0;
|
||||
|
||||
protected:
|
||||
SkAutoTUnref<SkCanvas> fCanvas; // initialized by derived classes in ctors
|
||||
|
||||
private:
|
||||
typedef SkSpecialSurface INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
static SkSpecialSurface_Base* as_SB(SkSpecialSurface* surface) {
|
||||
return static_cast<SkSpecialSurface_Base*>(surface);
|
||||
}
|
||||
|
||||
SkSpecialSurface::SkSpecialSurface(const SkIRect& subset, const SkSurfaceProps* props)
|
||||
: fProps(SkSurfacePropsCopyOrDefault(props))
|
||||
, fSubset(subset) {
|
||||
SkASSERT(fSubset.width() > 0);
|
||||
SkASSERT(fSubset.height() > 0);
|
||||
}
|
||||
|
||||
SkCanvas* SkSpecialSurface::getCanvas() {
|
||||
return as_SB(this)->onGetCanvas();
|
||||
}
|
||||
|
||||
SkSpecialImage* SkSpecialSurface::newImageSnapshot() {
|
||||
SkSpecialImage* image = as_SB(this)->onNewImageSnapshot();
|
||||
as_SB(this)->reset();
|
||||
return SkSafeRef(image); // the caller will call unref() to balance this
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "SkMallocPixelRef.h"
|
||||
|
||||
class SkSpecialSurface_Raster : public SkSpecialSurface_Base {
|
||||
public:
|
||||
SkSpecialSurface_Raster(SkPixelRef* pr, const SkIRect& subset, const SkSurfaceProps* props)
|
||||
: INHERITED(subset, props) {
|
||||
const SkImageInfo& info = pr->info();
|
||||
|
||||
fBitmap.setInfo(info, info.minRowBytes());
|
||||
fBitmap.setPixelRef(pr);
|
||||
|
||||
fCanvas.reset(new SkCanvas(fBitmap));
|
||||
}
|
||||
|
||||
~SkSpecialSurface_Raster() override { }
|
||||
|
||||
SkSpecialImage* onNewImageSnapshot() override {
|
||||
return SkSpecialImage::NewFromRaster(this->subset(), fBitmap);
|
||||
}
|
||||
|
||||
private:
|
||||
SkBitmap fBitmap;
|
||||
|
||||
typedef SkSpecialSurface_Base INHERITED;
|
||||
};
|
||||
|
||||
SkSpecialSurface* SkSpecialSurface::NewFromBitmap(const SkIRect& subset, SkBitmap& bm,
|
||||
const SkSurfaceProps* props) {
|
||||
return new SkSpecialSurface_Raster(bm.pixelRef(), subset, props);
|
||||
}
|
||||
|
||||
SkSpecialSurface* SkSpecialSurface::NewRaster(const SkImageInfo& info,
|
||||
const SkSurfaceProps* props) {
|
||||
SkAutoTUnref<SkPixelRef> pr(SkMallocPixelRef::NewZeroed(info, 0, nullptr));
|
||||
if (nullptr == pr.get()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const SkIRect subset = SkIRect::MakeWH(pr->info().width(), pr->info().height());
|
||||
|
||||
return new SkSpecialSurface_Raster(pr, subset, props);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "GrContext.h"
|
||||
#include "SkGpuDevice.h"
|
||||
|
||||
class SkSpecialSurface_Gpu : public SkSpecialSurface_Base {
|
||||
public:
|
||||
SkSpecialSurface_Gpu(GrTexture* texture, const SkIRect& subset, const SkSurfaceProps* props)
|
||||
: INHERITED(subset, props)
|
||||
, fTexture(texture) {
|
||||
|
||||
SkASSERT(fTexture->asRenderTarget());
|
||||
|
||||
SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(fTexture->asRenderTarget(), props,
|
||||
SkGpuDevice::kUninit_InitContents));
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
|
||||
fCanvas.reset(new SkCanvas(device));
|
||||
}
|
||||
|
||||
~SkSpecialSurface_Gpu() override { }
|
||||
|
||||
SkSpecialImage* onNewImageSnapshot() override {
|
||||
return SkSpecialImage::NewFromGpu(this->subset(), fTexture);
|
||||
}
|
||||
|
||||
private:
|
||||
SkAutoTUnref<GrTexture> fTexture;
|
||||
|
||||
typedef SkSpecialSurface_Base INHERITED;
|
||||
};
|
||||
|
||||
SkSpecialSurface* SkSpecialSurface::NewFromTexture(const SkIRect& subset, GrTexture* texture,
|
||||
const SkSurfaceProps* props) {
|
||||
if (!texture->asRenderTarget()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new SkSpecialSurface_Gpu(texture, subset, props);
|
||||
}
|
||||
|
||||
SkSpecialSurface* SkSpecialSurface::NewRenderTarget(GrContext* context,
|
||||
const GrSurfaceDesc& desc,
|
||||
const SkSurfaceProps* props) {
|
||||
if (!context || !SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GrTexture* temp = context->textureProvider()->createApproxTexture(desc);
|
||||
if (!temp) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const SkIRect subset = SkIRect::MakeWH(desc.fWidth, desc.fHeight);
|
||||
|
||||
return new SkSpecialSurface_Gpu(temp, subset, props);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
SkSpecialSurface* SkSpecialSurface::NewFromTexture(const SkIRect& subset, GrTexture*,
|
||||
const SkSurfaceProps*) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkSpecialSurface* SkSpecialSurface::NewRenderTarget(GrContext* context,
|
||||
const GrSurfaceDesc& desc,
|
||||
const SkSurfaceProps* props) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
93
src/core/SkSpecialSurface.h
Normal file
93
src/core/SkSpecialSurface.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file
|
||||
*/
|
||||
|
||||
#ifndef SkSpecialSurface_DEFINED
|
||||
#define SkSpecialSurface_DEFINED
|
||||
|
||||
#include "SkRefCnt.h"
|
||||
#include "SkSurfaceProps.h"
|
||||
|
||||
class GrContext;
|
||||
struct GrSurfaceDesc;
|
||||
class SkCanvas;
|
||||
struct SkImageInfo;
|
||||
class SkSpecialImage;
|
||||
|
||||
/**
|
||||
* SkSpecialSurface is a restricted form of SkSurface solely for internal use. It differs
|
||||
* from SkSurface in that:
|
||||
* - it can be backed by GrTextures larger than [ fWidth, fHeight ]
|
||||
* - it can't be used for tiling
|
||||
* - it becomes inactive once a snapshot of it is taken (i.e., no copy-on-write)
|
||||
* - it has no generation ID
|
||||
*/
|
||||
class SkSpecialSurface : public SkRefCnt {
|
||||
public:
|
||||
const SkSurfaceProps& props() const { return fProps; }
|
||||
|
||||
int width() const { return fSubset.width(); }
|
||||
int height() const { return fSubset.height(); }
|
||||
|
||||
/**
|
||||
* Return a canvas that will draw into this surface. This will always
|
||||
* return the same canvas for a given surface, and is managed/owned by the
|
||||
* surface.
|
||||
*
|
||||
* The canvas will be invalid after 'newImageSnapshot' is called.
|
||||
*/
|
||||
SkCanvas* getCanvas();
|
||||
|
||||
/**
|
||||
* Returns an image of the current state of the surface pixels up to this
|
||||
* point. The canvas returned by 'getCanvas' becomes invalidated by this
|
||||
* call and no more drawing to this surface is allowed.
|
||||
*/
|
||||
SkSpecialImage* newImageSnapshot();
|
||||
|
||||
/**
|
||||
* Use an existing (renderTarget-capable) GrTexture as the backing store.
|
||||
*/
|
||||
static SkSpecialSurface* NewFromTexture(const SkIRect& subset, GrTexture*,
|
||||
const SkSurfaceProps* = nullptr);
|
||||
|
||||
/**
|
||||
* Allocate a new GPU-backed SkSpecialSurface. If the requested surface cannot
|
||||
* be created, nullptr will be returned.
|
||||
*/
|
||||
static SkSpecialSurface* NewRenderTarget(GrContext*, const GrSurfaceDesc&,
|
||||
const SkSurfaceProps* = nullptr);
|
||||
|
||||
/**
|
||||
* Use and existing SkBitmap as the backing store.
|
||||
*/
|
||||
static SkSpecialSurface* NewFromBitmap(const SkIRect& subset, SkBitmap& bm,
|
||||
const SkSurfaceProps* = nullptr);
|
||||
|
||||
/**
|
||||
* Return a new CPU-backed surface, with the memory for the pixels automatically
|
||||
* allocated.
|
||||
*
|
||||
* If the requested surface cannot be created, or the request is not a
|
||||
* supported configuration, nullptr will be returned.
|
||||
*/
|
||||
static SkSpecialSurface* NewRaster(const SkImageInfo&, const SkSurfaceProps* = nullptr);
|
||||
|
||||
protected:
|
||||
SkSpecialSurface(const SkIRect& subset, const SkSurfaceProps*);
|
||||
|
||||
// For testing only
|
||||
friend class TestingSpecialSurfaceAccess;
|
||||
const SkIRect& subset() const { return fSubset; }
|
||||
|
||||
private:
|
||||
const SkSurfaceProps fProps;
|
||||
const SkIRect fSubset;
|
||||
|
||||
typedef SkRefCnt INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
150
tests/SpecialImageTest.cpp
Normal file
150
tests/SpecialImageTest.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* 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 "SkBitmap.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkImage.h"
|
||||
#include "SkSpecialImage.h"
|
||||
#include "SkSpecialSurface.h"
|
||||
#include "Test.h"
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrContext.h"
|
||||
#endif
|
||||
|
||||
class TestingSpecialImageAccess {
|
||||
public:
|
||||
static const SkIRect& Subset(const SkSpecialImage* img) {
|
||||
return img->subset();
|
||||
}
|
||||
|
||||
static bool PeekPixels(const SkSpecialImage* img, SkPixmap* pixmap) {
|
||||
return img->peekPixels(pixmap);
|
||||
}
|
||||
|
||||
static GrTexture* PeekTexture(const SkSpecialImage* img) {
|
||||
return img->peekTexture();
|
||||
}
|
||||
};
|
||||
|
||||
// This test creates backing resources exactly sized to [kFullSize x kFullSize].
|
||||
// It then wraps them in an SkSpecialImage with only the center (red) region being active.
|
||||
// It then draws the SkSpecialImage to a full sized (all blue) canvas and checks that none
|
||||
// of the inactive (green) region leaked out.
|
||||
|
||||
static const int kSmallerSize = 10;
|
||||
static const int kPad = 3;
|
||||
static const int kFullSize = kSmallerSize + 2 * kPad;
|
||||
|
||||
// Create a bitmap with red in the center and green around it
|
||||
static SkBitmap create_bm() {
|
||||
SkBitmap bm;
|
||||
bm.allocN32Pixels(kFullSize, kFullSize, true);
|
||||
|
||||
SkCanvas temp(bm);
|
||||
|
||||
temp.clear(SK_ColorGREEN);
|
||||
SkPaint p;
|
||||
p.setColor(SK_ColorRED);
|
||||
p.setAntiAlias(false);
|
||||
|
||||
temp.drawRect(SkRect::MakeXYWH(SkIntToScalar(kPad), SkIntToScalar(kPad),
|
||||
SkIntToScalar(kSmallerSize), SkIntToScalar(kSmallerSize)),
|
||||
p);
|
||||
|
||||
return bm;
|
||||
}
|
||||
|
||||
// Basic test of the SkSpecialImage public API (e.g., peekTexture, peekPixels & draw)
|
||||
static void test_image(SkSpecialImage* img, skiatest::Reporter* reporter,
|
||||
bool peekPixelsSucceeds, bool peekTextureSucceeds) {
|
||||
const SkIRect subset = TestingSpecialImageAccess::Subset(img);
|
||||
REPORTER_ASSERT(reporter, kPad == subset.left());
|
||||
REPORTER_ASSERT(reporter, kPad == subset.top());
|
||||
REPORTER_ASSERT(reporter, kSmallerSize == subset.width());
|
||||
REPORTER_ASSERT(reporter, kSmallerSize == subset.height());
|
||||
|
||||
//--------------
|
||||
REPORTER_ASSERT(reporter, peekTextureSucceeds == !!TestingSpecialImageAccess::PeekTexture(img));
|
||||
|
||||
//--------------
|
||||
SkPixmap pixmap;
|
||||
REPORTER_ASSERT(reporter, peekPixelsSucceeds ==
|
||||
!!TestingSpecialImageAccess::PeekPixels(img, &pixmap));
|
||||
if (peekPixelsSucceeds) {
|
||||
REPORTER_ASSERT(reporter, kFullSize == pixmap.width());
|
||||
REPORTER_ASSERT(reporter, kFullSize == pixmap.height());
|
||||
}
|
||||
|
||||
//--------------
|
||||
SkImageInfo info = SkImageInfo::MakeN32(kFullSize, kFullSize, kOpaque_SkAlphaType);
|
||||
|
||||
SkAutoTUnref<SkSpecialSurface> surf(img->newSurface(info));
|
||||
|
||||
SkCanvas* canvas = surf->getCanvas();
|
||||
|
||||
canvas->clear(SK_ColorBLUE);
|
||||
img->draw(canvas, kPad, kPad, nullptr);
|
||||
|
||||
SkBitmap bm;
|
||||
bm.allocN32Pixels(kFullSize, kFullSize, true);
|
||||
|
||||
bool result = canvas->readPixels(bm.info(), bm.getPixels(), bm.rowBytes(), 0, 0);
|
||||
SkASSERT_RELEASE(result);
|
||||
|
||||
// Only the center (red) portion should've been drawn into the canvas
|
||||
REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kPad-1, kPad-1));
|
||||
REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kPad, kPad));
|
||||
REPORTER_ASSERT(reporter, SK_ColorRED == bm.getColor(kSmallerSize+kPad-1,
|
||||
kSmallerSize+kPad-1));
|
||||
REPORTER_ASSERT(reporter, SK_ColorBLUE == bm.getColor(kSmallerSize+kPad,
|
||||
kSmallerSize+kPad));
|
||||
}
|
||||
|
||||
DEF_TEST(SpecialImage_Raster, reporter) {
|
||||
SkBitmap bm = create_bm();
|
||||
|
||||
const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
|
||||
|
||||
SkAutoTUnref<SkSpecialImage> img(SkSpecialImage::NewFromRaster(subset, bm));
|
||||
test_image(img, reporter, true, false);
|
||||
}
|
||||
|
||||
DEF_TEST(SpecialImage_Image, reporter) {
|
||||
SkBitmap bm = create_bm();
|
||||
|
||||
SkAutoTUnref<SkImage> fullImage(SkImage::NewFromBitmap(bm));
|
||||
|
||||
const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
|
||||
|
||||
SkAutoTUnref<SkSpecialImage> img(SkSpecialImage::NewFromImage(subset, fullImage));
|
||||
test_image(img, reporter, true, false);
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialImage_Gpu, reporter, context) {
|
||||
SkBitmap bm = create_bm();
|
||||
|
||||
GrSurfaceDesc desc;
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
desc.fFlags = kNone_GrSurfaceFlags;
|
||||
desc.fWidth = kFullSize;
|
||||
desc.fHeight = kFullSize;
|
||||
|
||||
SkAutoTUnref<GrTexture> texture(context->textureProvider()->createTexture(desc, false,
|
||||
bm.getPixels(), 0));
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
|
||||
|
||||
SkAutoTUnref<SkSpecialImage> img(SkSpecialImage::NewFromGpu(subset, texture));
|
||||
test_image(img, reporter, false, true);
|
||||
}
|
||||
|
||||
#endif
|
115
tests/SpecialSurfaceTest.cpp
Normal file
115
tests/SpecialSurfaceTest.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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 "SkCanvas.h"
|
||||
#include "SkSpecialImage.h"
|
||||
#include "SkSpecialSurface.h"
|
||||
#include "Test.h"
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
#include "GrContext.h"
|
||||
#include "SkGr.h"
|
||||
#endif
|
||||
|
||||
class TestingSpecialSurfaceAccess {
|
||||
public:
|
||||
static const SkIRect& Subset(const SkSpecialSurface* surf) {
|
||||
return surf->subset();
|
||||
}
|
||||
|
||||
static const SkIRect& Subset(const SkSpecialImage* img) {
|
||||
return img->subset();
|
||||
}
|
||||
};
|
||||
|
||||
// Both 'kSmallerSize' and 'kFullSize' need to be a non-power-of-2 to exercise
|
||||
// the gpu's loose fit behavior
|
||||
static const int kSmallerSize = 10;
|
||||
static const int kPad = 5;
|
||||
static const int kFullSize = kSmallerSize + 2 * kPad;
|
||||
|
||||
// Exercise the public API of SkSpecialSurface (e.g., getCanvas, newImageSnapshot)
|
||||
static void test_surface(SkSpecialSurface* surf, skiatest::Reporter* reporter, int offset) {
|
||||
|
||||
const SkIRect surfSubset = TestingSpecialSurfaceAccess::Subset(surf);
|
||||
REPORTER_ASSERT(reporter, offset == surfSubset.fLeft);
|
||||
REPORTER_ASSERT(reporter, offset == surfSubset.fTop);
|
||||
REPORTER_ASSERT(reporter, kSmallerSize == surfSubset.width());
|
||||
REPORTER_ASSERT(reporter, kSmallerSize == surfSubset.height());
|
||||
|
||||
SkCanvas* canvas = surf->getCanvas();
|
||||
SkASSERT_RELEASE(canvas);
|
||||
|
||||
canvas->clear(SK_ColorRED);
|
||||
|
||||
SkAutoTUnref<SkSpecialImage> img(surf->newImageSnapshot());
|
||||
REPORTER_ASSERT(reporter, img);
|
||||
|
||||
const SkIRect imgSubset = TestingSpecialSurfaceAccess::Subset(img);
|
||||
REPORTER_ASSERT(reporter, surfSubset == imgSubset);
|
||||
|
||||
// the canvas was invalidated by the newImageSnapshot call
|
||||
REPORTER_ASSERT(reporter, !surf->getCanvas());
|
||||
}
|
||||
|
||||
DEF_TEST(SpecialSurface_Raster, reporter) {
|
||||
|
||||
SkImageInfo info = SkImageInfo::MakeN32(kSmallerSize, kSmallerSize, kOpaque_SkAlphaType);
|
||||
SkAutoTUnref<SkSpecialSurface> surf(SkSpecialSurface::NewRaster(info));
|
||||
|
||||
test_surface(surf, reporter, 0);
|
||||
}
|
||||
|
||||
DEF_TEST(SpecialSurface_Raster2, reporter) {
|
||||
|
||||
SkBitmap bm;
|
||||
bm.allocN32Pixels(kFullSize, kFullSize, true);
|
||||
|
||||
const SkIRect subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
|
||||
|
||||
SkAutoTUnref<SkSpecialSurface> surf(SkSpecialSurface::NewFromBitmap(subset, bm));
|
||||
|
||||
test_surface(surf, reporter, kPad);
|
||||
|
||||
// TODO: check that the clear didn't escape the active region
|
||||
}
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialSurface_Gpu1, reporter, context) {
|
||||
GrSurfaceDesc desc;
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
||||
desc.fWidth = kSmallerSize;
|
||||
desc.fHeight = kSmallerSize;
|
||||
|
||||
SkAutoTUnref<SkSpecialSurface> surf(SkSpecialSurface::NewRenderTarget(context, desc));
|
||||
|
||||
test_surface(surf, reporter, 0);
|
||||
}
|
||||
|
||||
// test the more flexible factory
|
||||
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SpecialSurface_Gpu2, reporter, context) {
|
||||
GrSurfaceDesc desc;
|
||||
desc.fConfig = kSkia8888_GrPixelConfig;
|
||||
desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
||||
desc.fWidth = kFullSize;
|
||||
desc.fHeight = kFullSize;
|
||||
|
||||
SkAutoTUnref<GrTexture> temp(context->textureProvider()->createApproxTexture(desc));
|
||||
SkASSERT_RELEASE(temp);
|
||||
|
||||
const SkIRect subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
|
||||
|
||||
SkAutoTUnref<SkSpecialSurface> surf(SkSpecialSurface::NewFromTexture(subset, temp));
|
||||
|
||||
test_surface(surf, reporter, kPad);
|
||||
|
||||
// TODO: check that the clear didn't escape the active region
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user