aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gyp/tests.gypi1
-rw-r--r--include/core/SkImageGenerator.h14
-rw-r--r--include/core/SkPixelRef.h16
-rw-r--r--src/core/SkImageGenerator.cpp39
-rw-r--r--src/core/SkPixelRef.cpp4
-rw-r--r--src/gpu/SkGr.cpp82
-rw-r--r--src/lazy/SkDiscardablePixelRef.h6
-rw-r--r--tests/ImageGeneratorTest.cpp31
8 files changed, 193 insertions, 0 deletions
diff --git a/gyp/tests.gypi b/gyp/tests.gypi
index 6a6447963f..34e8f540e0 100644
--- a/gyp/tests.gypi
+++ b/gyp/tests.gypi
@@ -103,6 +103,7 @@
'../tests/ImageCacheTest.cpp',
'../tests/ImageDecodingTest.cpp',
'../tests/ImageFilterTest.cpp',
+ '../tests/ImageGeneratorTest.cpp',
'../tests/ImageNewShaderTest.cpp',
'../tests/InfRectTest.cpp',
'../tests/InterpolatorTest.cpp',
diff --git a/include/core/SkImageGenerator.h b/include/core/SkImageGenerator.h
index 157bfdb001..17477e37b3 100644
--- a/include/core/SkImageGenerator.h
+++ b/include/core/SkImageGenerator.h
@@ -116,12 +116,26 @@ public:
bool getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes);
#endif
+ /**
+ * If planes or rowBytes is NULL or if any entry in planes is NULL or if any entry in rowBytes
+ * is 0, this imagegenerator should output the sizes and return true if it can efficiently
+ * return YUV planar data. If it cannot, it should return false. Note that either planes and
+ * rowBytes are both fully defined and non NULL/non 0 or they are both NULL or have NULL or 0
+ * entries only. Having only partial planes/rowBytes information is not supported.
+ *
+ * If all planes and rowBytes entries are non NULL or non 0, then it should copy the
+ * associated YUV data into those planes of memory supplied by the caller. It should validate
+ * that the sizes match what it expected. If the sizes do not match, it should return false.
+ */
+ bool getYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]);
+
protected:
virtual SkData* onRefEncodedData();
virtual bool onGetInfo(SkImageInfo* info);
virtual bool onGetPixels(const SkImageInfo& info,
void* pixels, size_t rowBytes,
SkPMColor ctable[], int* ctableCount);
+ virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]);
};
#endif // SkImageGenerator_DEFINED
diff --git a/include/core/SkPixelRef.h b/include/core/SkPixelRef.h
index a24ef8e231..afab7fad9e 100644
--- a/include/core/SkPixelRef.h
+++ b/include/core/SkPixelRef.h
@@ -13,6 +13,7 @@
#include "SkRefCnt.h"
#include "SkString.h"
#include "SkImageInfo.h"
+#include "SkSize.h"
#include "SkTDArray.h"
//#define xed
@@ -219,6 +220,18 @@ public:
*/
virtual GrTexture* getTexture() { return NULL; }
+ /**
+ * If any planes or rowBytes is NULL, this should output the sizes and return true
+ * if it can efficiently return YUV planar data. If it cannot, it should return false.
+ *
+ * If all planes and rowBytes are not NULL, then it should copy the associated Y,U,V data
+ * into those planes of memory supplied by the caller. It should validate that the sizes
+ * match what it expected. If the sizes do not match, it should return false.
+ */
+ bool getYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]) {
+ return this->onGetYUV8Planes(sizes, planes, rowBytes);
+ }
+
bool readPixels(SkBitmap* dst, const SkIRect* subset = NULL);
/**
@@ -305,6 +318,9 @@ protected:
// default impl returns NULL.
virtual SkData* onRefEncodedData();
+ // default impl returns false.
+ virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]);
+
/**
* Returns the size (in bytes) of the internally allocated memory.
* This should be implemented in all serializable SkPixelRef derived classes.
diff --git a/src/core/SkImageGenerator.cpp b/src/core/SkImageGenerator.cpp
index daa55a3a4d..551d8f78dc 100644
--- a/src/core/SkImageGenerator.cpp
+++ b/src/core/SkImageGenerator.cpp
@@ -57,6 +57,45 @@ bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t r
}
#endif
+bool SkImageGenerator::getYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]) {
+#ifdef SK_DEBUG
+ // In all cases, we need the sizes array
+ SkASSERT(NULL != sizes);
+
+ bool isValidWithPlanes = (NULL != planes) && (NULL != rowBytes) &&
+ ((NULL != planes[0]) && (NULL != planes[1]) && (NULL != planes[2]) &&
+ (0 != rowBytes[0]) && (0 != rowBytes[1]) && (0 != rowBytes[2]));
+ bool isValidWithoutPlanes =
+ ((NULL == planes) ||
+ ((NULL == planes[0]) && (NULL == planes[1]) && (NULL == planes[2]))) &&
+ ((NULL == rowBytes) ||
+ ((0 == rowBytes[0]) && (0 == rowBytes[1]) && (0 == rowBytes[2])));
+
+ // Either we have all planes and rowBytes information or we have none of it
+ // Having only partial information is not supported
+ SkASSERT(isValidWithPlanes || isValidWithoutPlanes);
+
+ // If we do have planes information, make sure all sizes are non 0
+ // and all rowBytes are valid
+ SkASSERT(!isValidWithPlanes ||
+ ((sizes[0].fWidth >= 0) &&
+ (sizes[0].fHeight >= 0) &&
+ (sizes[1].fWidth >= 0) &&
+ (sizes[1].fHeight >= 0) &&
+ (sizes[2].fWidth >= 0) &&
+ (sizes[2].fHeight >= 0) &&
+ (rowBytes[0] >= (size_t)sizes[0].fWidth) &&
+ (rowBytes[1] >= (size_t)sizes[1].fWidth) &&
+ (rowBytes[2] >= (size_t)sizes[2].fWidth)));
+#endif
+
+ return this->onGetYUV8Planes(sizes, planes, rowBytes);
+}
+
+bool SkImageGenerator::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]) {
+ return false;
+}
+
/////////////////////////////////////////////////////////////////////////////////////////////
SkData* SkImageGenerator::onRefEncodedData() {
diff --git a/src/core/SkPixelRef.cpp b/src/core/SkPixelRef.cpp
index 651b26eefe..1064070192 100644
--- a/src/core/SkPixelRef.cpp
+++ b/src/core/SkPixelRef.cpp
@@ -253,6 +253,10 @@ SkData* SkPixelRef::onRefEncodedData() {
return NULL;
}
+bool SkPixelRef::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]) {
+ return false;
+}
+
size_t SkPixelRef::getAllocatedSizeInBytes() const {
return 0;
}
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index c4e2c1f93f..5c0464da20 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -15,6 +15,7 @@
#include "GrGpu.h"
#include "effects/GrDitherEffect.h"
#include "GrDrawTargetCaps.h"
+#include "effects/GrYUVtoRGBEffect.h"
#ifndef SK_IGNORE_ETC1_SUPPORT
# include "ktx.h"
@@ -193,6 +194,81 @@ static GrTexture *load_etc1_texture(GrContext* ctx,
}
#endif // SK_IGNORE_ETC1_SUPPORT
+static GrTexture *load_yuv_texture(GrContext* ctx, const GrTextureParams* params,
+ const SkBitmap& bm, const GrTextureDesc& desc) {
+ GrTexture* result = NULL;
+
+ SkPixelRef* pixelRef = bm.pixelRef();
+ SkISize yuvSizes[3];
+ if ((NULL == pixelRef) || !pixelRef->getYUV8Planes(yuvSizes, NULL, NULL)) {
+ return NULL;
+ }
+
+ // Allocate the memory for YUV
+ size_t totalSize(0);
+ size_t sizes[3], rowBytes[3];
+ for (int i = 0; i < 3; ++i) {
+ rowBytes[i] = yuvSizes[i].fWidth;
+ totalSize += sizes[i] = rowBytes[i] * yuvSizes[i].fHeight;
+ }
+ SkAutoMalloc storage(totalSize);
+ void* planes[3];
+ planes[0] = storage.get();
+ planes[1] = (uint8_t*)planes[0] + sizes[0];
+ planes[2] = (uint8_t*)planes[1] + sizes[1];
+
+ // Get the YUV planes
+ if (!pixelRef->getYUV8Planes(yuvSizes, planes, rowBytes)) {
+ return NULL;
+ }
+
+ GrTextureDesc yuvDesc;
+ yuvDesc.fConfig = kAlpha_8_GrPixelConfig;
+ GrAutoScratchTexture yuvTextures[3];
+ for (int i = 0; i < 3; ++i) {
+ yuvDesc.fWidth = yuvSizes[i].fWidth;
+ yuvDesc.fHeight = yuvSizes[i].fHeight;
+ yuvTextures[i].set(ctx, yuvDesc);
+ if ((NULL == yuvTextures[i].texture()) ||
+ !ctx->writeTexturePixels(yuvTextures[i].texture(),
+ 0, 0, yuvDesc.fWidth, yuvDesc.fHeight,
+ yuvDesc.fConfig, planes[i], rowBytes[i])) {
+ return NULL;
+ }
+ }
+
+ GrTextureDesc rtDesc = desc;
+ rtDesc.fFlags = rtDesc.fFlags |
+ kRenderTarget_GrTextureFlagBit |
+ kNoStencil_GrTextureFlagBit;
+
+ // This texture is likely to be used again so leave it in the cache
+ GrCacheID cacheID;
+ generate_bitmap_cache_id(bm, &cacheID);
+
+ GrResourceKey key;
+ result = ctx->createTexture(params, rtDesc, cacheID, NULL, 0, &key);
+ GrRenderTarget* renderTarget = result ? result->asRenderTarget() : NULL;
+ if (NULL != renderTarget) {
+ add_genID_listener(key, bm.pixelRef());
+ SkAutoTUnref<GrEffect> yuvToRgbEffect(GrYUVtoRGBEffect::Create(
+ yuvTextures[0].texture(), yuvTextures[1].texture(), yuvTextures[2].texture()));
+ GrPaint paint;
+ paint.addColorEffect(yuvToRgbEffect);
+ SkRect r = SkRect::MakeWH(SkIntToScalar(yuvSizes[0].fWidth),
+ SkIntToScalar(yuvSizes[0].fHeight));
+ GrContext::AutoRenderTarget autoRT(ctx, renderTarget);
+ GrContext::AutoMatrix am;
+ am.setIdentity(ctx);
+ GrContext::AutoClip ac(ctx, GrContext::AutoClip::kWideOpen_InitialClip);
+ ctx->drawRect(paint, r);
+ } else {
+ SkSafeSetNull(result);
+ }
+
+ return result;
+}
+
static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
bool cache,
const GrTextureParams* params,
@@ -264,6 +340,12 @@ static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
}
#endif // SK_IGNORE_ETC1_SUPPORT
+ else {
+ GrTexture *texture = load_yuv_texture(ctx, params, *bitmap, desc);
+ if (NULL != texture) {
+ return texture;
+ }
+ }
SkAutoLockPixels alp(*bitmap);
if (!bitmap->readyToDraw()) {
return NULL;
diff --git a/src/lazy/SkDiscardablePixelRef.h b/src/lazy/SkDiscardablePixelRef.h
index 2edef80128..d31a040164 100644
--- a/src/lazy/SkDiscardablePixelRef.h
+++ b/src/lazy/SkDiscardablePixelRef.h
@@ -48,6 +48,12 @@ private:
size_t rowBytes,
SkDiscardableMemory::Factory* factory);
+ virtual bool onGetYUV8Planes(SkISize sizes[3],
+ void* planes[3],
+ size_t rowBytes[3]) SK_OVERRIDE {
+ return fGenerator->getYUV8Planes(sizes, planes, rowBytes);
+ }
+
friend bool SkInstallDiscardablePixelRef(SkImageGenerator*, SkBitmap*,
SkDiscardableMemory::Factory*);
diff --git a/tests/ImageGeneratorTest.cpp b/tests/ImageGeneratorTest.cpp
new file mode 100644
index 0000000000..aaf149b37c
--- /dev/null
+++ b/tests/ImageGeneratorTest.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkImageGenerator.h"
+#include "Test.h"
+
+DEF_TEST(ImageGenerator, reporter) {
+ SkImageGenerator ig;
+ SkISize sizes[3];
+ sizes[0] = SkISize::Make(200, 200);
+ sizes[1] = SkISize::Make(100, 100);
+ sizes[2] = SkISize::Make( 50, 50);
+ void* planes[3] = { NULL };
+ size_t rowBytes[3] = { 0 };
+
+ // Check that the YUV decoding API does not cause any crashes
+ ig.getYUV8Planes(sizes, NULL, NULL);
+ ig.getYUV8Planes(sizes, planes, NULL);
+ ig.getYUV8Planes(sizes, NULL, rowBytes);
+ ig.getYUV8Planes(sizes, planes, rowBytes);
+
+ int dummy;
+ planes[0] = planes[1] = planes[2] = &dummy;
+ rowBytes[0] = rowBytes[1] = rowBytes[2] = 250;
+
+ ig.getYUV8Planes(sizes, planes, rowBytes);
+}