Add SkCanvas::writePixels that takes info+pixels directly

add corresponding methods to device (w/ diff name to avoid colliding with exising virtuals)

BUG=skia:
R=bsalomon@google.com, robertphillips@google.com, junov@google.com, junov@chromium.org

Author: reed@google.com

Review URL: https://codereview.chromium.org/180113010

git-svn-id: http://skia.googlecode.com/svn/trunk@13697 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
commit-bot@chromium.org 2014-03-07 03:25:16 +00:00
parent a5572e5bb2
commit 4cd9e2169e
23 changed files with 501 additions and 101 deletions

View File

@ -1,4 +1,3 @@
/*
* Copyright 2013 Google Inc.
*
@ -10,6 +9,7 @@
#include "SkCanvas.h"
#include "SkConfig8888.h"
#include "SkString.h"
#include "sk_tool_utils.h"
class PremulAndUnpremulAlphaOpsBench : public SkBenchmark {
public:
@ -45,9 +45,16 @@ protected:
bmp2.setConfig(SkBitmap::kARGB_8888_Config, size.width(),
size.height());
SkColorType ct;
SkAlphaType at;
sk_tool_utils::config8888_to_imagetypes(fUnPremulConfig, &ct, &at);
if (bmp1.isOpaque()) {
at = kOpaque_SkAlphaType;
}
for (int loop = 0; loop < loops; ++loop) {
// Unpremul -> Premul
canvas->writePixels(bmp1, 0, 0, fUnPremulConfig);
sk_tool_utils::write_pixels(canvas, bmp1, 0, 0, ct, at);
// Premul -> Unpremul
canvas->readPixels(&bmp2, 0, 0, fUnPremulConfig);
}

View File

@ -1,4 +1,3 @@
/*
* Copyright 2013 Google Inc.
*
@ -8,35 +7,35 @@
#include "SkBenchmark.h"
#include "SkCanvas.h"
#include "SkConfig8888.h"
#include "SkString.h"
class WritePixelsBench : public SkBenchmark {
public:
WritePixelsBench(SkCanvas::Config8888 config)
: fConfig(config)
, fName("writepix") {
switch (config) {
case SkCanvas::kNative_Premul_Config8888:
fName.append("_native_PM");
WritePixelsBench(SkColorType ct, SkAlphaType at)
: fColorType(ct)
, fAlphaType(at)
, fName("writepix")
{
switch (ct) {
case kRGBA_8888_SkColorType:
fName.append("_RGBA");
break;
case SkCanvas::kNative_Unpremul_Config8888:
fName.append("_native_UPM");
break;
case SkCanvas::kBGRA_Premul_Config8888:
fName.append("_bgra_PM");
break;
case SkCanvas::kBGRA_Unpremul_Config8888:
fName.append("_bgra_UPM");
break;
case SkCanvas::kRGBA_Premul_Config8888:
fName.append("_rgba_PM");
break;
case SkCanvas::kRGBA_Unpremul_Config8888:
fName.append("_rgba_UPM");
case kBGRA_8888_SkColorType:
fName.append("_BGRA");
break;
default:
SK_CRASH();
SkASSERT(0);
break;
}
switch (at) {
case kPremul_SkAlphaType:
fName.append("_PM");
break;
case kUnpremul_SkAlphaType:
fName.append("_UPM");
break;
default:
SkASSERT(0);
break;
}
}
@ -52,22 +51,27 @@ protected:
canvas->clear(0xFFFF0000);
SkBitmap bmp;
bmp.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
bmp.allocN32Pixels(size.width(), size.height());
canvas->readPixels(&bmp, 0, 0);
SkImageInfo info = bmp.info();
info.fColorType = fColorType;
info.fAlphaType = fAlphaType;
for (int loop = 0; loop < loops; ++loop) {
canvas->writePixels(bmp, 0, 0, fConfig);
canvas->writePixels(info, bmp.getPixels(), bmp.rowBytes(), 0, 0);
}
}
private:
SkCanvas::Config8888 fConfig;
SkString fName;
SkColorType fColorType;
SkAlphaType fAlphaType;
SkString fName;
typedef SkBenchmark INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_BENCH( return SkNEW_ARGS(WritePixelsBench, (SkCanvas::kRGBA_Premul_Config8888)); )
DEF_BENCH( return SkNEW_ARGS(WritePixelsBench, (SkCanvas::kRGBA_Unpremul_Config8888)); )
DEF_BENCH( return SkNEW_ARGS(WritePixelsBench, (kRGBA_8888_SkColorType, kPremul_SkAlphaType)); )
DEF_BENCH( return SkNEW_ARGS(WritePixelsBench, (kRGBA_8888_SkColorType, kUnpremul_SkAlphaType)); )

View File

@ -20,6 +20,7 @@
'../bench/SkGMBench.cpp',
'../bench/SkGMBench.h',
'../bench/benchmain.cpp',
'../tools/sk_tool_utils.cpp',
],
'conditions': [
['skia_gpu == 1',
@ -54,6 +55,7 @@
'include_dirs': [
'../src/core',
'../src/gpu',
'../tools',
],
'dependencies': [
'skia_lib.gyp:skia_lib',

View File

@ -3,6 +3,7 @@
'../src/core',
'../src/effects',
'../src/utils',
'../tools',
],
'dependencies': [
'skia_lib.gyp:skia_lib',

View File

@ -16,6 +16,7 @@
'SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG=1',
'SK_SUPPORT_LEGACY_PUBLICEFFECTCONSTRUCTORS=1',
'SK_SUPPORT_LEGACY_COPYTO_CONFIG',
'SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG',
],
},
}

View File

@ -179,5 +179,7 @@
'../tests/TDStackNesterTest.cpp',
'../experimental/PdfViewer/src/SkTDStackNester.h',
'../tools/sk_tool_utils.cpp',
],
}

View File

@ -86,6 +86,7 @@ public:
virtual SkImageInfo imageInfo() const SK_OVERRIDE;
#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
/**
* DEPRECATED: This will be made protected once WebKit stops using it.
* Instead use Canvas' writePixels method.
@ -103,7 +104,7 @@ public:
*/
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE;
#endif
/**
* Return the device's associated gpu render target, or NULL.
*/
@ -215,9 +216,8 @@ protected:
* 3. The rectangle (x, y, x + bitmap->width(), y + bitmap->height()) is
* contained in the device bounds.
*/
virtual bool onReadPixels(const SkBitmap& bitmap,
int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE;
virtual bool onReadPixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) SK_OVERRIDE;
virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int, int) SK_OVERRIDE;
/** Called when this device is installed into a Canvas. Balanced by a call
to unlockPixels() when the device is removed from a Canvas.

View File

@ -18,6 +18,8 @@
#include "SkRegion.h"
#include "SkXfermode.h"
//#define SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
class SkBounder;
class SkBaseDevice;
class SkDraw;
@ -264,7 +266,9 @@ public:
*/
bool readPixels(const SkIRect& srcRect, SkBitmap* bitmap);
#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
/**
* DEPRECATED
* Similar to draw sprite, this method will copy the pixels in bitmap onto
* the canvas, with the top/left corner specified by (x, y). The canvas'
* pixel values are completely replaced: there is no blending.
@ -279,9 +283,34 @@ public:
* Note: If you are recording drawing commands on this canvas to
* SkPicture, writePixels() is ignored!
*/
void writePixels(const SkBitmap& bitmap,
int x, int y,
Config8888 config8888 = kNative_Premul_Config8888);
void writePixels(const SkBitmap& bitmap, int x, int y, Config8888 config8888);
#endif
/**
* This method affects the pixels in the base-layer, and operates in pixel coordinates,
* ignoring the matrix and clip.
*
* The specified ImageInfo and (x,y) offset specifies a rectangle: target.
*
* target.setXYWH(x, y, info.width(), info.height());
*
* Target is intersected with the bounds of the base-layer. If this intersection is not empty,
* then we have two sets of pixels (of equal size), the "src" specified by info+pixels+rowBytes
* and the "dst" by the canvas' backend. Replace the dst pixels with the corresponding src
* pixels, performing any colortype/alphatype transformations needed (in the case where the
* src and dst have different colortypes or alphatypes).
*
* This call can fail, returning false, for several reasons:
* - If the src colortype/alphatype cannot be converted to the canvas' types
* - If this canvas is not backed by pixels (e.g. picture or PDF)
*/
bool writePixels(const SkImageInfo&, const void* pixels, size_t rowBytes, int x, int y);
/**
* Helper for calling writePixels(info, ...) by passing its pixels and rowbytes. If the bitmap
* is just wrapping a texture, returns false and does nothing.
*/
bool writePixels(const SkBitmap& bitmap, int x, int y);
///////////////////////////////////////////////////////////////////////////

View File

@ -116,6 +116,7 @@ public:
*/
const SkBitmap& accessBitmap(bool changePixels);
#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
/**
* DEPRECATED: This will be made protected once WebKit stops using it.
* Instead use Canvas' writePixels method.
@ -132,7 +133,10 @@ public:
* not kARGB_8888_Config then this parameter is ignored.
*/
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888 = SkCanvas::kNative_Premul_Config8888) = 0;
SkCanvas::Config8888 config8888 = SkCanvas::kNative_Premul_Config8888);
#endif
bool writePixelsDirect(const SkImageInfo&, const void*, size_t rowBytes, int x, int y);
/**
* Return the device's associated gpu render target, or NULL.
@ -387,6 +391,14 @@ protected:
// default impl returns NULL
virtual const void* peekPixels(SkImageInfo*, size_t* rowBytes);
/**
* The caller is responsible for "pre-clipping" the src. The impl can assume that the src
* image at the specified x,y offset will fit within the device's bounds.
*
* This is explicitly asserted in writePixelsDirect(), the public way to call this.
*/
virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int x, int y);
/**
* Leaky properties are those which the device should be applying but it isn't.
* These properties will be applied by the draw, when and as it can.

View File

@ -90,9 +90,10 @@ public:
virtual SkBitmap::Config config() const SK_OVERRIDE;
virtual void clear(SkColor color) SK_OVERRIDE;
#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE;
#endif
virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE;
virtual void drawPoints(const SkDraw&, SkCanvas::PointMode mode, size_t count,
const SkPoint[], const SkPaint& paint) SK_OVERRIDE;
@ -148,10 +149,8 @@ public:
class SkAutoCachedTexture; // used internally
protected:
// overrides from SkBaseDevice
virtual bool onReadPixels(const SkBitmap& bitmap,
int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE;
virtual bool onReadPixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) SK_OVERRIDE;
virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int, int) SK_OVERRIDE;
private:
GrContext* fContext;

View File

@ -199,6 +199,7 @@ bool SkBitmapDevice::onReadPixels(const SkBitmap& bitmap,
return true;
}
#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
void SkBitmapDevice::writePixels(const SkBitmap& bitmap,
int x, int y,
SkCanvas::Config8888 config8888) {
@ -265,6 +266,96 @@ void SkBitmapDevice::writePixels(const SkBitmap& bitmap,
draw.fMatrix = &SkMatrix::I();
this->drawSprite(draw, *sprite, x, y, paint);
}
#endif
static void rect_memcpy(void* dst, size_t dstRB, const void* src, size_t srcRB, size_t bytesPerRow,
int rowCount) {
SkASSERT(bytesPerRow <= srcRB);
SkASSERT(bytesPerRow <= dstRB);
for (int i = 0; i < rowCount; ++i) {
memcpy(dst, src, bytesPerRow);
dst = (char*)dst + dstRB;
src = (const char*)src + srcRB;
}
}
static bool info2config8888(const SkImageInfo& info, SkCanvas::Config8888* config) {
bool pre;
switch (info.alphaType()) {
case kPremul_SkAlphaType:
case kOpaque_SkAlphaType:
pre = true;
break;
case kUnpremul_SkAlphaType:
pre = false;
break;
default:
return false;
}
switch (info.colorType()) {
case kRGBA_8888_SkColorType:
*config = pre ? SkCanvas::kRGBA_Premul_Config8888 : SkCanvas::kRGBA_Unpremul_Config8888;
return true;
case kBGRA_8888_SkColorType:
*config = pre ? SkCanvas::kBGRA_Premul_Config8888 : SkCanvas::kBGRA_Unpremul_Config8888;
return true;
default:
return false;
}
}
// TODO: make this guy real, and not rely on legacy config8888 utility
#include "SkConfig8888.h"
static bool write_pixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes) {
if (srcInfo.dimensions() != dstInfo.dimensions()) {
return false;
}
if (4 == srcInfo.bytesPerPixel() && 4 == dstInfo.bytesPerPixel()) {
SkCanvas::Config8888 srcConfig, dstConfig;
if (!info2config8888(srcInfo, &srcConfig) || !info2config8888(dstInfo, &dstConfig)) {
return false;
}
SkConvertConfig8888Pixels((uint32_t*)dstPixels, dstRowBytes, dstConfig,
(const uint32_t*)srcPixels, srcRowBytes, srcConfig,
srcInfo.width(), srcInfo.height());
return true;
}
if (srcInfo.colorType() == dstInfo.colorType()) {
switch (srcInfo.colorType()) {
case kRGB_565_SkColorType:
case kAlpha_8_SkColorType:
break;
case kARGB_4444_SkColorType:
if (srcInfo.alphaType() != dstInfo.alphaType()) {
return false;
}
break;
default:
return false;
}
rect_memcpy(dstPixels, dstRowBytes, srcPixels, srcRowBytes,
srcInfo.width() * srcInfo.bytesPerPixel(), srcInfo.height());
}
// TODO: add support for more conversions as needed
return false;
}
bool SkBitmapDevice::onWritePixels(const SkImageInfo& srcInfo, const void* srcPixels,
size_t srcRowBytes, int x, int y) {
SkImageInfo dstInfo = fBitmap.info();
dstInfo.fWidth = srcInfo.width();
dstInfo.fHeight = srcInfo.height();
void* dstPixels = fBitmap.getAddr(x, y);
size_t dstRowBytes = fBitmap.rowBytes();
if (write_pixels(dstInfo, dstPixels, dstRowBytes, srcInfo, srcPixels, srcRowBytes)) {
fBitmap.notifyPixelsChanged();
return true;
}
return false;
}
///////////////////////////////////////////////////////////////////////////////

View File

@ -696,6 +696,7 @@ bool SkCanvas::readPixels(const SkIRect& srcRect, SkBitmap* bitmap) {
}
}
#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y,
Config8888 config8888) {
SkBaseDevice* device = this->getDevice();
@ -707,6 +708,62 @@ void SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y,
}
}
}
#endif
bool SkCanvas::writePixels(const SkBitmap& bitmap, int x, int y) {
if (bitmap.getTexture()) {
return false;
}
SkBitmap bm(bitmap);
bm.lockPixels();
if (bm.getPixels()) {
return this->writePixels(bm.info(), bm.getPixels(), bm.rowBytes(), x, y);
}
return false;
}
bool SkCanvas::writePixels(const SkImageInfo& origInfo, const void* pixels, size_t rowBytes,
int x, int y) {
switch (origInfo.colorType()) {
case kUnknown_SkColorType:
case kIndex_8_SkColorType:
return false;
default:
break;
}
if (NULL == pixels || rowBytes < origInfo.minRowBytes()) {
return false;
}
const SkISize size = this->getBaseLayerSize();
SkIRect target = SkIRect::MakeXYWH(x, y, origInfo.width(), origInfo.height());
if (!target.intersect(0, 0, size.width(), size.height())) {
return false;
}
SkBaseDevice* device = this->getDevice();
if (!device) {
return false;
}
SkImageInfo info = origInfo;
// the intersect may have shrunk info's logical size
info.fWidth = target.width();
info.fHeight = target.height();
// if x or y are negative, then we have to adjust pixels
if (x > 0) {
x = 0;
}
if (y > 0) {
y = 0;
}
// here x,y are either 0 or negative
pixels = ((const char*)pixels - y * rowBytes - x * info.bytesPerPixel());
// The device can assert that the requested area is always contained in its bounds
return device->writePixelsDirect(info, pixels, rowBytes, target.x(), target.y());
}
SkCanvas* SkCanvas::canvasForDrawIter() {
return this;

View File

@ -1,4 +1,3 @@
/*
* Copyright 2011 Google Inc.
*
@ -6,6 +5,8 @@
* found in the LICENSE file.
*/
#ifndef SkConfig8888_DEFINED
#define SkConfig8888_DEFINED
#include "SkCanvas.h"
#include "SkColorPriv.h"
@ -74,3 +75,5 @@ static inline void SkCopyConfig8888ToBitmap(const SkBitmap& dstBmp,
}
}
#endif

View File

@ -170,3 +170,27 @@ void SkBaseDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer,
const bool pathIsMutable = true;
this->drawPath(draw, path, paint, preMatrix, pathIsMutable);
}
bool SkBaseDevice::writePixelsDirect(const SkImageInfo& info, const void* pixels, size_t rowBytes,
int x, int y) {
#ifdef SK_DEBUG
SkASSERT(info.width() > 0 && info.height() > 0);
SkASSERT(pixels);
SkASSERT(rowBytes >= info.minRowBytes());
SkASSERT(x >= 0 && y >= 0);
const SkImageInfo& dstInfo = this->imageInfo();
SkASSERT(x + info.width() <= dstInfo.width());
SkASSERT(y + info.height() <= dstInfo.height());
#endif
return this->onWritePixels(info, pixels, rowBytes, x, y);
}
bool SkBaseDevice::onWritePixels(const SkImageInfo&, const void*, size_t, int, int) {
return false;
}
#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
void SkBaseDevice::writePixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) {}
#endif

View File

@ -403,6 +403,7 @@ bool SkGpuDevice::onReadPixels(const SkBitmap& bitmap,
flags);
}
#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888) {
SkAutoLockPixels alp(bitmap);
@ -422,6 +423,26 @@ void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y,
fRenderTarget->writePixels(x, y, bitmap.width(), bitmap.height(),
config, bitmap.getPixels(), bitmap.rowBytes(), flags);
}
#endif
bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
int x, int y) {
// TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
GrPixelConfig config = SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType());
if (kUnknown_GrPixelConfig == config) {
return false;
}
uint32_t flags = 0;
if (kUnpremul_SkAlphaType == info.alphaType()) {
flags = GrContext::kUnpremul_PixelOpsFlag;
}
fRenderTarget->writePixels(x, y, info.width(), info.height(), config, pixels, rowBytes, flags);
// need to bump our genID for compatibility with clients that "know" we have a bitmap
this->onAccessBitmap().notifyPixelsChanged();
return true;
}
void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) {
INHERITED::onAttachToCanvas(canvas);

View File

@ -30,8 +30,7 @@ enum PlaybackMode {
kSilent_PlaybackMode,
};
namespace {
bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint,
static bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint,
size_t bitmapSizeThreshold) {
if (bitmap && ((bitmap->getTexture() && !bitmap->isImmutable()) ||
(bitmap->getSize() > bitmapSizeThreshold))) {
@ -54,7 +53,6 @@ bool shouldDrawImmediately(const SkBitmap* bitmap, const SkPaint* paint,
}
return false;
}
}
//-----------------------------------------------------------------------------
// DeferredPipeController
@ -170,9 +168,10 @@ public:
virtual SkBaseDevice* onCreateDevice(const SkImageInfo&, Usage) SK_OVERRIDE;
#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE;
#endif
virtual SkSurface* newSurface(const SkImageInfo&) SK_OVERRIDE;
protected:
@ -180,6 +179,7 @@ protected:
virtual bool onReadPixels(const SkBitmap& bitmap,
int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE;
virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int x, int y) SK_OVERRIDE;
// The following methods are no-ops on a deferred device
virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
@ -478,8 +478,9 @@ void DeferredDevice::prepareForImmediatePixelWrite() {
fImmediateCanvas->flush();
}
void DeferredDevice::writePixels(const SkBitmap& bitmap,
int x, int y, SkCanvas::Config8888 config8888) {
#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
void DeferredDevice::writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888) {
if (x <= 0 && y <= 0 && (x + bitmap.width()) >= width() &&
(y + bitmap.height()) >= height()) {
@ -506,6 +507,24 @@ void DeferredDevice::writePixels(const SkBitmap& bitmap,
}
}
#endif
bool DeferredDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes,
int x, int y) {
SkASSERT(x >= 0 && y >= 0);
SkASSERT(x + info.width() <= width());
SkASSERT(y + info.height() <= height());
this->flushPendingCommands(kNormal_PlaybackMode);
const SkImageInfo deviceInfo = this->imageInfo();
if (info.width() == deviceInfo.width() && info.height() == deviceInfo.height()) {
this->skipPendingCommands();
}
this->prepareForImmediatePixelWrite();
return immediateDevice()->onWritePixels(info, pixels, rowBytes, x, y);
}
const SkBitmap& DeferredDevice::onAccessBitmap() {
this->flushPendingCommands(kNormal_PlaybackMode);

View File

@ -49,10 +49,12 @@ public:
return fEmptyBitmap.info();
}
#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE {
NotSupported();
}
#endif
virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
protected:

View File

@ -85,10 +85,13 @@ public:
virtual void clear(SkColor color) SK_OVERRIDE {
nothing_to_do();
}
#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
virtual void writePixels(const SkBitmap& bitmap, int x, int y,
SkCanvas::Config8888 config8888) SK_OVERRIDE {
not_supported();
}
#endif
virtual void drawPaint(const SkDraw&, const SkPaint& paint) SK_OVERRIDE {
this->addBitmapFromPaint(paint);

View File

@ -15,6 +15,8 @@
#include "SkShader.h"
#include "SkSurface.h"
#include "Test.h"
#include "sk_tool_utils.h"
#if SK_SUPPORT_GPU
#include "GrContextFactory.h"
#else
@ -24,6 +26,21 @@ class GrContextFactory;
static const int gWidth = 2;
static const int gHeight = 2;
static void callWritePixels(SkCanvas* canvas, const SkBitmap& src, int x, int y,
SkCanvas::Config8888 config) {
SkBitmap bm(src);
bm.lockPixels();
SkImageInfo info = bm.info();
sk_tool_utils::config8888_to_imagetypes(config, &info.fColorType, &info.fAlphaType);
if (src.isOpaque()) {
info.fAlphaType = kOpaque_SkAlphaType;
}
canvas->writePixels(info, bm.getPixels(), bm.rowBytes(), x, y);
}
static void create(SkBitmap* bm, SkColor color) {
bm->allocN32Pixels(gWidth, gHeight);
bm->eraseColor(color);
@ -145,13 +162,16 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
surface->clearCounts();
canvas->writePixels(srcBitmap, 0, 0);
#if 0
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
#endif
surface->clearCounts();
canvas->flush();
#if 0
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
#endif
// Case 3: writePixels that partially covers the canvas
surface->clearCounts();
@ -161,13 +181,16 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
surface->clearCounts();
canvas->writePixels(srcBitmap, 5, 0);
#if 0
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
#endif
surface->clearCounts();
canvas->flush();
#if 0
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
#endif
// Case 4: unpremultiplied opaque writePixels that entirely
// covers the canvas
@ -177,7 +200,7 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
surface->clearCounts();
canvas->writePixels(srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
callWritePixels(canvas, srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
@ -194,7 +217,7 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
surface->clearCounts();
canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
callWritePixels(canvas, srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);
@ -216,7 +239,7 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
surface->clearCounts();
canvas->writePixels(srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
callWritePixels(canvas, srcBitmap, 0, 0, SkCanvas::kRGBA_Unpremul_Config8888);
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
@ -238,7 +261,7 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
surface->clearCounts();
canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
callWritePixels(canvas, srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
REPORTER_ASSERT(reporter, 1 == surface->fDiscardCount); // because of the clear
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
@ -262,7 +285,7 @@ static void TestDeferredCanvasWritePixelsToSurface(skiatest::Reporter* reporter)
REPORTER_ASSERT(reporter, 0 == surface->fRetainCount);
surface->clearCounts();
canvas->writePixels(srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
callWritePixels(canvas, srcBitmap, 5, 0, SkCanvas::kRGBA_Unpremul_Config8888);
REPORTER_ASSERT(reporter, 0 == surface->fDiscardCount);
REPORTER_ASSERT(reporter, 1 == surface->fRetainCount);

View File

@ -9,32 +9,62 @@
#include "SkCanvas.h"
#include "SkConfig8888.h"
#include "Test.h"
#include "sk_tool_utils.h"
#if SK_SUPPORT_GPU
#include "GrContextFactory.h"
#include "SkGpuDevice.h"
#endif
static void fillCanvas(SkCanvas* canvas, SkCanvas::Config8888 unpremulConfig) {
SkBitmap bmp;
bmp.allocN32Pixels(256, 256);
SkAutoLockPixels alp(bmp);
uint32_t* pixels = reinterpret_cast<uint32_t*>(bmp.getPixels());
for (int a = 0; a < 256; ++a) {
for (int r = 0; r < 256; ++r) {
pixels[a * 256 + r] = SkPackConfig8888(unpremulConfig, a, r, 0, 0);
}
}
canvas->writePixels(bmp, 0, 0, unpremulConfig);
static uint32_t pack_unpremul_rgba(SkColor c) {
uint32_t packed;
uint8_t* byte = reinterpret_cast<uint8_t*>(&packed);
byte[0] = SkColorGetR(c);
byte[1] = SkColorGetG(c);
byte[2] = SkColorGetB(c);
byte[3] = SkColorGetA(c);
return packed;
}
static const SkCanvas::Config8888 gUnpremulConfigs[] = {
SkCanvas::kNative_Unpremul_Config8888,
SkCanvas::kBGRA_Unpremul_Config8888,
SkCanvas::kRGBA_Unpremul_Config8888,
static uint32_t pack_unpremul_bgra(SkColor c) {
uint32_t packed;
uint8_t* byte = reinterpret_cast<uint8_t*>(&packed);
byte[0] = SkColorGetB(c);
byte[1] = SkColorGetG(c);
byte[2] = SkColorGetR(c);
byte[3] = SkColorGetA(c);
return packed;
}
typedef uint32_t (*PackUnpremulProc)(SkColor);
const struct {
SkColorType fColorType;
PackUnpremulProc fPackProc;
SkCanvas::Config8888 fConfig8888;
} gUnpremul[] = {
{ kRGBA_8888_SkColorType, pack_unpremul_rgba, SkCanvas::kRGBA_Unpremul_Config8888 },
{ kBGRA_8888_SkColorType, pack_unpremul_bgra, SkCanvas::kBGRA_Unpremul_Config8888 },
};
static void fillCanvas(SkCanvas* canvas, SkColorType colorType, PackUnpremulProc proc) {
// Don't strictly need a bitmap, but its a handy way to allocate the pixels
SkBitmap bmp;
bmp.allocN32Pixels(256, 256);
for (int a = 0; a < 256; ++a) {
uint32_t* pixels = bmp.getAddr32(0, a);
for (int r = 0; r < 256; ++r) {
pixels[r] = proc(SkColorSetARGB(a, r, 0, 0));
}
}
SkImageInfo info = bmp.info();
info.fColorType = colorType;
info.fAlphaType = kUnpremul_SkAlphaType;
canvas->writePixels(info, bmp.getPixels(), bmp.rowBytes(), 0, 0);
}
DEF_GPUTEST(PremulAlphaRoundTrip, reporter, factory) {
const SkImageInfo info = SkImageInfo::MakeN32Premul(256, 256);
@ -74,32 +104,23 @@ DEF_GPUTEST(PremulAlphaRoundTrip, reporter, factory) {
SkBitmap readBmp2;
readBmp2.allocN32Pixels(256, 256);
for (size_t upmaIdx = 0;
upmaIdx < SK_ARRAY_COUNT(gUnpremulConfigs);
++upmaIdx) {
fillCanvas(&canvas, gUnpremulConfigs[upmaIdx]);
{
SkAutoLockPixels alp1(readBmp1);
SkAutoLockPixels alp2(readBmp2);
sk_bzero(readBmp1.getPixels(), readBmp1.getSafeSize());
sk_bzero(readBmp2.getPixels(), readBmp2.getSafeSize());
}
for (size_t upmaIdx = 0; upmaIdx < SK_ARRAY_COUNT(gUnpremul); ++upmaIdx) {
fillCanvas(&canvas, gUnpremul[upmaIdx].fColorType, gUnpremul[upmaIdx].fPackProc);
readBmp1.eraseColor(0);
readBmp2.eraseColor(0);
canvas.readPixels(&readBmp1, 0, 0, gUnpremulConfigs[upmaIdx]);
canvas.writePixels(readBmp1, 0, 0, gUnpremulConfigs[upmaIdx]);
canvas.readPixels(&readBmp2, 0, 0, gUnpremulConfigs[upmaIdx]);
canvas.readPixels(&readBmp1, 0, 0, gUnpremul[upmaIdx].fConfig8888);
sk_tool_utils::write_pixels(&canvas, readBmp1, 0, 0, gUnpremul[upmaIdx].fColorType,
kUnpremul_SkAlphaType);
canvas.readPixels(&readBmp2, 0, 0, gUnpremul[upmaIdx].fConfig8888);
SkAutoLockPixels alp1(readBmp1);
SkAutoLockPixels alp2(readBmp2);
uint32_t* pixels1 =
reinterpret_cast<uint32_t*>(readBmp1.getPixels());
uint32_t* pixels2 =
reinterpret_cast<uint32_t*>(readBmp2.getPixels());
bool success = true;
for (int y = 0; y < 256 && success; ++y) {
const uint32_t* pixels1 = readBmp1.getAddr32(0, y);
const uint32_t* pixels2 = readBmp2.getAddr32(0, y);
for (int x = 0; x < 256 && success; ++x) {
int i = y * 256 + x;
REPORTER_ASSERT(reporter, success = pixels1[i] == pixels2[i]);
REPORTER_ASSERT(reporter, success = pixels1[x] == pixels2[x]);
}
}
}

View File

@ -11,6 +11,7 @@
#include "SkMathPriv.h"
#include "SkRegion.h"
#include "Test.h"
#include "sk_tool_utils.h"
#if SK_SUPPORT_GPU
#include "GrContextFactory.h"
@ -134,16 +135,13 @@ static uint32_t getBitmapColor(int x, int y, int w, SkCanvas::Config8888 config8
}
static void fillCanvas(SkCanvas* canvas) {
static SkBitmap bmp;
SkBitmap bmp;
if (bmp.isNull()) {
SkDEBUGCODE(bool alloc = ) bmp.allocN32Pixels(DEV_W, DEV_H);
SkASSERT(alloc);
SkAutoLockPixels alp(bmp);
intptr_t pixels = reinterpret_cast<intptr_t>(bmp.getPixels());
for (int y = 0; y < DEV_H; ++y) {
for (int x = 0; x < DEV_W; ++x) {
SkPMColor* pixel = reinterpret_cast<SkPMColor*>(pixels + y * bmp.rowBytes() + x * bmp.bytesPerPixel());
*pixel = getCanvasColor(x, y);
*bmp.getAddr32(x, y) = getCanvasColor(x, y);
}
}
}
@ -468,7 +466,12 @@ DEF_GPUTEST(WritePixels, reporter, factory) {
SkBitmap bmp;
REPORTER_ASSERT(reporter, setupBitmap(&bmp, config8888, rect.width(), rect.height(), SkToBool(tightBmp)));
uint32_t idBefore = canvas.getDevice()->accessBitmap(false).getGenerationID();
canvas.writePixels(bmp, rect.fLeft, rect.fTop, config8888);
SkColorType ct;
SkAlphaType at;
sk_tool_utils::config8888_to_imagetypes(config8888, &ct, &at);
sk_tool_utils::write_pixels(&canvas, bmp, rect.fLeft, rect.fTop, ct, at);
uint32_t idAfter = canvas.getDevice()->accessBitmap(false).getGenerationID();
REPORTER_ASSERT(reporter, checkWrite(reporter, &canvas, bmp, rect.fLeft, rect.fTop, config8888));

48
tools/sk_tool_utils.cpp Normal file
View File

@ -0,0 +1,48 @@
#include "sk_tool_utils.h"
namespace sk_tool_utils {
void config8888_to_imagetypes(SkCanvas::Config8888 config, SkColorType* ct, SkAlphaType* at) {
switch (config) {
case SkCanvas::kNative_Premul_Config8888:
*ct = kPMColor_SkColorType;
*at = kPremul_SkAlphaType;
break;
case SkCanvas::kNative_Unpremul_Config8888:
*ct = kPMColor_SkColorType;
*at = kUnpremul_SkAlphaType;
break;
case SkCanvas::kBGRA_Premul_Config8888:
*ct = kBGRA_8888_SkColorType;
*at = kPremul_SkAlphaType;
break;
case SkCanvas::kBGRA_Unpremul_Config8888:
*ct = kBGRA_8888_SkColorType;
*at = kUnpremul_SkAlphaType;
break;
case SkCanvas::kRGBA_Premul_Config8888:
*ct = kRGBA_8888_SkColorType;
*at = kPremul_SkAlphaType;
break;
case SkCanvas::kRGBA_Unpremul_Config8888:
*ct = kRGBA_8888_SkColorType;
*at = kUnpremul_SkAlphaType;
break;
default:
SkASSERT(0);
}
}
void write_pixels(SkCanvas* canvas, const SkBitmap& bitmap, int x, int y,
SkColorType colorType, SkAlphaType alphaType) {
SkBitmap tmp(bitmap);
tmp.lockPixels();
SkImageInfo info = tmp.info();
info.fColorType = colorType;
info.fAlphaType = alphaType;
canvas->writePixels(info, tmp.getPixels(), tmp.rowBytes(), x, y);
}
}

28
tools/sk_tool_utils.h Normal file
View File

@ -0,0 +1,28 @@
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef sk_tool_utils_DEFINED
#define sk_tool_utils_DEFINED
#include "SkCanvas.h"
#include "SkBitmap.h"
namespace sk_tool_utils {
/**
* Return the colorType and alphaType that correspond to the specified Config8888
*/
void config8888_to_imagetypes(SkCanvas::Config8888, SkColorType*, SkAlphaType*);
/**
* Call canvas->writePixels() by using the pixels from bitmap, but with an info that claims
* the pixels are colorType + alphaType
*/
void write_pixels(SkCanvas*, const SkBitmap&, int x, int y, SkColorType, SkAlphaType);
}
#endif