Skia side RGB to YUV gpu conversion
This code is the one that's currently working in my local chromium build. A few things still need to be addressed and I'll highlight these directly in the code. BUG=skia: R=reed@google.com, bsalomon@google.com, senorblanco@google.com, senorblanco@chromium.org, robertphillips@google.com, scroggo@google.com, halcanary@google.com Author: sugoi@chromium.org Review URL: https://codereview.chromium.org/374743003
This commit is contained in:
parent
02cafcc1bf
commit
518d83dbc1
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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*);
|
||||
|
||||
|
31
tests/ImageGeneratorTest.cpp
Normal file
31
tests/ImageGeneratorTest.cpp
Normal file
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user