diff options
author | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-03-07 03:25:16 +0000 |
---|---|---|
committer | commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-03-07 03:25:16 +0000 |
commit | 4cd9e2169e35cd67ee7358acea6541245e1d1744 (patch) | |
tree | 6e78d84ef91181b41f5c45a73bab003c63780f10 | |
parent | a5572e5bb2a2bbeeb59de0741c2527869d365a0c (diff) |
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
-rw-r--r-- | bench/PremulAndUnpremulAlphaOpsBench.cpp | 11 | ||||
-rw-r--r-- | bench/WritePixelsBench.cpp | 56 | ||||
-rw-r--r-- | gyp/bench.gyp | 2 | ||||
-rw-r--r-- | gyp/bench.gypi | 1 | ||||
-rw-r--r-- | gyp/skia_for_chromium_defines.gypi | 1 | ||||
-rw-r--r-- | gyp/tests.gypi | 2 | ||||
-rw-r--r-- | include/core/SkBitmapDevice.h | 8 | ||||
-rw-r--r-- | include/core/SkCanvas.h | 35 | ||||
-rw-r--r-- | include/core/SkDevice.h | 14 | ||||
-rw-r--r-- | include/gpu/SkGpuDevice.h | 9 | ||||
-rw-r--r-- | src/core/SkBitmapDevice.cpp | 91 | ||||
-rw-r--r-- | src/core/SkCanvas.cpp | 57 | ||||
-rw-r--r-- | src/core/SkConfig8888.h | 5 | ||||
-rw-r--r-- | src/core/SkDevice.cpp | 24 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 21 | ||||
-rw-r--r-- | src/utils/SkDeferredCanvas.cpp | 31 | ||||
-rw-r--r-- | src/utils/SkGatherPixelRefsAndRects.h | 2 | ||||
-rw-r--r-- | src/utils/SkPictureUtils.cpp | 3 | ||||
-rw-r--r-- | tests/DeferredCanvasTest.cpp | 37 | ||||
-rw-r--r-- | tests/PremulAlphaRoundTripTest.cpp | 85 | ||||
-rw-r--r-- | tests/WritePixelsTest.cpp | 15 | ||||
-rw-r--r-- | tools/sk_tool_utils.cpp | 48 | ||||
-rw-r--r-- | tools/sk_tool_utils.h | 28 |
23 files changed, 493 insertions, 93 deletions
diff --git a/bench/PremulAndUnpremulAlphaOpsBench.cpp b/bench/PremulAndUnpremulAlphaOpsBench.cpp index 93c84c9095..4afa43fe6e 100644 --- a/bench/PremulAndUnpremulAlphaOpsBench.cpp +++ b/bench/PremulAndUnpremulAlphaOpsBench.cpp @@ -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); } diff --git a/bench/WritePixelsBench.cpp b/bench/WritePixelsBench.cpp index 0313846a3b..27c3f5a45b 100644 --- a/bench/WritePixelsBench.cpp +++ b/bench/WritePixelsBench.cpp @@ -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"); - break; - case SkCanvas::kNative_Unpremul_Config8888: - fName.append("_native_UPM"); + WritePixelsBench(SkColorType ct, SkAlphaType at) + : fColorType(ct) + , fAlphaType(at) + , fName("writepix") + { + switch (ct) { + case kRGBA_8888_SkColorType: + fName.append("_RGBA"); break; - case SkCanvas::kBGRA_Premul_Config8888: - fName.append("_bgra_PM"); + case kBGRA_8888_SkColorType: + fName.append("_BGRA"); break; - case SkCanvas::kBGRA_Unpremul_Config8888: - fName.append("_bgra_UPM"); + default: + SkASSERT(0); break; - case SkCanvas::kRGBA_Premul_Config8888: - fName.append("_rgba_PM"); + } + switch (at) { + case kPremul_SkAlphaType: + fName.append("_PM"); break; - case SkCanvas::kRGBA_Unpremul_Config8888: - fName.append("_rgba_UPM"); + case kUnpremul_SkAlphaType: + fName.append("_UPM"); break; default: - SK_CRASH(); + 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)); ) diff --git a/gyp/bench.gyp b/gyp/bench.gyp index c2337f6bba..43924ab30a 100644 --- a/gyp/bench.gyp +++ b/gyp/bench.gyp @@ -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', diff --git a/gyp/bench.gypi b/gyp/bench.gypi index 8170d81fc3..6680e75289 100644 --- a/gyp/bench.gypi +++ b/gyp/bench.gypi @@ -3,6 +3,7 @@ '../src/core', '../src/effects', '../src/utils', + '../tools', ], 'dependencies': [ 'skia_lib.gyp:skia_lib', diff --git a/gyp/skia_for_chromium_defines.gypi b/gyp/skia_for_chromium_defines.gypi index de026ae4f2..35877431b0 100644 --- a/gyp/skia_for_chromium_defines.gypi +++ b/gyp/skia_for_chromium_defines.gypi @@ -16,6 +16,7 @@ 'SK_SUPPORT_LEGACY_COMPATIBLEDEVICE_CONFIG=1', 'SK_SUPPORT_LEGACY_PUBLICEFFECTCONSTRUCTORS=1', 'SK_SUPPORT_LEGACY_COPYTO_CONFIG', + 'SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG', ], }, } diff --git a/gyp/tests.gypi b/gyp/tests.gypi index 6990464279..80bd380886 100644 --- a/gyp/tests.gypi +++ b/gyp/tests.gypi @@ -179,5 +179,7 @@ '../tests/TDStackNesterTest.cpp', '../experimental/PdfViewer/src/SkTDStackNester.h', + + '../tools/sk_tool_utils.cpp', ], } diff --git a/include/core/SkBitmapDevice.h b/include/core/SkBitmapDevice.h index 1d181555e0..a34507134d 100644 --- a/include/core/SkBitmapDevice.h +++ b/include/core/SkBitmapDevice.h @@ -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. diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index b646ba4024..a987708c42 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -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); /////////////////////////////////////////////////////////////////////////// diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h index 899c5d3754..b78dfbff90 100644 --- a/include/core/SkDevice.h +++ b/include/core/SkDevice.h @@ -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. @@ -388,6 +392,14 @@ protected: 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. * If the device does handle a property, that property should be set to the identity value diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h index 3ccab51831..64bd33f439 100644 --- a/include/gpu/SkGpuDevice.h +++ b/include/gpu/SkGpuDevice.h @@ -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; diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp index 7ed8058c6a..098f0fc96c 100644 --- a/src/core/SkBitmapDevice.cpp +++ b/src/core/SkBitmapDevice.cpp @@ -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; +} /////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 2ffd3e4916..58ec8fd4c5 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -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; diff --git a/src/core/SkConfig8888.h b/src/core/SkConfig8888.h index 96eaef2447..041773e6df 100644 --- a/src/core/SkConfig8888.h +++ b/src/core/SkConfig8888.h @@ -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 diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 23cf8f0ea2..6087cd2a14 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -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 + diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index cf1464a598..7cecf25bb2 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -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); diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp index 09494c9aaa..b81d64c57d 100644 --- a/src/utils/SkDeferredCanvas.cpp +++ b/src/utils/SkDeferredCanvas.cpp @@ -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); diff --git a/src/utils/SkGatherPixelRefsAndRects.h b/src/utils/SkGatherPixelRefsAndRects.h index 90ab0f6cff..4b5bb6f9e5 100644 --- a/src/utils/SkGatherPixelRefsAndRects.h +++ b/src/utils/SkGatherPixelRefsAndRects.h @@ -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: diff --git a/src/utils/SkPictureUtils.cpp b/src/utils/SkPictureUtils.cpp index cda64052c3..e41bfecfb4 100644 --- a/src/utils/SkPictureUtils.cpp +++ b/src/utils/SkPictureUtils.cpp @@ -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); diff --git a/tests/DeferredCanvasTest.cpp b/tests/DeferredCanvasTest.cpp index 62b1b17ffe..367300f9f2 100644 --- a/tests/DeferredCanvasTest.cpp +++ b/tests/DeferredCanvasTest.cpp @@ -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); diff --git a/tests/PremulAlphaRoundTripTest.cpp b/tests/PremulAlphaRoundTripTest.cpp index 488d93e19d..68fbec80bd 100644 --- a/tests/PremulAlphaRoundTripTest.cpp +++ b/tests/PremulAlphaRoundTripTest.cpp @@ -9,31 +9,61 @@ #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) { +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 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); - SkAutoLockPixels alp(bmp); - uint32_t* pixels = reinterpret_cast<uint32_t*>(bmp.getPixels()); for (int a = 0; a < 256; ++a) { + uint32_t* pixels = bmp.getAddr32(0, a); for (int r = 0; r < 256; ++r) { - pixels[a * 256 + r] = SkPackConfig8888(unpremulConfig, a, r, 0, 0); + pixels[r] = proc(SkColorSetARGB(a, r, 0, 0)); } } - canvas->writePixels(bmp, 0, 0, unpremulConfig); -} -static const SkCanvas::Config8888 gUnpremulConfigs[] = { - SkCanvas::kNative_Unpremul_Config8888, - SkCanvas::kBGRA_Unpremul_Config8888, - SkCanvas::kRGBA_Unpremul_Config8888, -}; + 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]); } } } diff --git a/tests/WritePixelsTest.cpp b/tests/WritePixelsTest.cpp index e2e4a0c802..7adcf0295d 100644 --- a/tests/WritePixelsTest.cpp +++ b/tests/WritePixelsTest.cpp @@ -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)); diff --git a/tools/sk_tool_utils.cpp b/tools/sk_tool_utils.cpp new file mode 100644 index 0000000000..f5b8b9f93d --- /dev/null +++ b/tools/sk_tool_utils.cpp @@ -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); +} + +} diff --git a/tools/sk_tool_utils.h b/tools/sk_tool_utils.h new file mode 100644 index 0000000000..7747a12096 --- /dev/null +++ b/tools/sk_tool_utils.h @@ -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 |