YUV planes cache
- Added new classes to contain YUV planes of memory, along with the associated data. - Used these classes in load_yuv_texture() to enable YUV planes caching - Added a unit test for the new cache BUG=450021 Review URL: https://codereview.chromium.org/851273003
This commit is contained in:
parent
89499d76b9
commit
692135f968
@ -218,6 +218,8 @@
|
||||
'<(skia_src_path)/core/SkWriteBuffer.cpp',
|
||||
'<(skia_src_path)/core/SkWriter32.cpp',
|
||||
'<(skia_src_path)/core/SkXfermode.cpp',
|
||||
'<(skia_src_path)/core/SkYUVPlanesCache.cpp',
|
||||
'<(skia_src_path)/core/SkYUVPlanesCache.h',
|
||||
|
||||
'<(skia_src_path)/doc/SkDocument.cpp',
|
||||
|
||||
|
@ -218,6 +218,7 @@
|
||||
'../tests/WritePixelsTest.cpp',
|
||||
'../tests/Writer32Test.cpp',
|
||||
'../tests/XfermodeTest.cpp',
|
||||
'../tests/YUVCacheTest.cpp',
|
||||
|
||||
'../tests/MatrixClipCollapseTest.cpp',
|
||||
'../src/utils/debugger/SkDrawCommand.h',
|
||||
|
@ -147,7 +147,7 @@ struct RectsBlurRec : public SkResourceCache::Rec {
|
||||
|
||||
static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextData) {
|
||||
const RectsBlurRec& rec = static_cast<const RectsBlurRec&>(baseRec);
|
||||
MaskValue* result = (MaskValue*)contextData;
|
||||
MaskValue* result = static_cast<MaskValue*>(contextData);
|
||||
|
||||
SkCachedData* tmpData = rec.fValue.fData;
|
||||
tmpData->ref();
|
||||
|
83
src/core/SkYUVPlanesCache.cpp
Normal file
83
src/core/SkYUVPlanesCache.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkYUVPlanesCache.h"
|
||||
#include "SkResourceCache.h"
|
||||
|
||||
#define CHECK_LOCAL(localCache, localName, globalName, ...) \
|
||||
((localCache) ? localCache->localName(__VA_ARGS__) : SkResourceCache::globalName(__VA_ARGS__))
|
||||
|
||||
namespace {
|
||||
static unsigned gYUVPlanesKeyNamespaceLabel;
|
||||
|
||||
struct YUVValue {
|
||||
SkYUVPlanesCache::Info fInfo;
|
||||
SkCachedData* fData;
|
||||
};
|
||||
|
||||
struct YUVPlanesKey : public SkResourceCache::Key {
|
||||
YUVPlanesKey(uint32_t genID)
|
||||
: fGenID(genID)
|
||||
{
|
||||
this->init(&gYUVPlanesKeyNamespaceLabel, sizeof(genID));
|
||||
}
|
||||
|
||||
uint32_t fGenID;
|
||||
};
|
||||
|
||||
struct YUVPlanesRec : public SkResourceCache::Rec {
|
||||
YUVPlanesRec(YUVPlanesKey key, SkCachedData* data, SkYUVPlanesCache::Info* info)
|
||||
: fKey(key)
|
||||
{
|
||||
fValue.fData = data;
|
||||
fValue.fInfo = *info;
|
||||
fValue.fData->attachToCacheAndRef();
|
||||
}
|
||||
~YUVPlanesRec() {
|
||||
fValue.fData->detachFromCacheAndUnref();
|
||||
}
|
||||
|
||||
YUVPlanesKey fKey;
|
||||
YUVValue fValue;
|
||||
|
||||
const Key& getKey() const SK_OVERRIDE { return fKey; }
|
||||
size_t bytesUsed() const SK_OVERRIDE { return sizeof(*this) + fValue.fData->size(); }
|
||||
|
||||
static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextData) {
|
||||
const YUVPlanesRec& rec = static_cast<const YUVPlanesRec&>(baseRec);
|
||||
YUVValue* result = static_cast<YUVValue*>(contextData);
|
||||
|
||||
SkCachedData* tmpData = rec.fValue.fData;
|
||||
tmpData->ref();
|
||||
if (NULL == tmpData->data()) {
|
||||
tmpData->unref();
|
||||
return false;
|
||||
}
|
||||
result->fData = tmpData;
|
||||
result->fInfo = rec.fValue.fInfo;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
SkCachedData* SkYUVPlanesCache::FindAndRef(uint32_t genID, Info* info,
|
||||
SkResourceCache* localCache) {
|
||||
YUVValue result;
|
||||
YUVPlanesKey key(genID);
|
||||
if (!CHECK_LOCAL(localCache, find, Find, key, YUVPlanesRec::Visitor, &result)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*info = result.fInfo;
|
||||
return result.fData;
|
||||
}
|
||||
|
||||
void SkYUVPlanesCache::Add(uint32_t genID, SkCachedData* data, Info* info,
|
||||
SkResourceCache* localCache) {
|
||||
YUVPlanesKey key(genID);
|
||||
return CHECK_LOCAL(localCache, add, Add, SkNEW_ARGS(YUVPlanesRec, (key, data, info)));
|
||||
}
|
50
src/core/SkYUVPlanesCache.h
Normal file
50
src/core/SkYUVPlanesCache.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SkYUVPlanesCache_DEFINED
|
||||
#define SkYUVPlanesCache_DEFINED
|
||||
|
||||
#include "SkCachedData.h"
|
||||
#include "SkImageInfo.h"
|
||||
|
||||
class SkResourceCache;
|
||||
|
||||
class SkYUVPlanesCache {
|
||||
public:
|
||||
/**
|
||||
* The Info struct contains data about the 3 Y, U and V planes of memory stored
|
||||
* contiguously, in that order, as a single block of memory within SkYUVPlanesCache.
|
||||
*
|
||||
* fSize: Width and height of each of the 3 planes (in pixels).
|
||||
* fSizeInMemory: Amount of memory allocated for each plane (may be different from
|
||||
"height * rowBytes", depending on the jpeg decoder's block size).
|
||||
* The sum of these is the total size stored within SkYUVPlanesCache.
|
||||
* fRowBytes: rowBytes for each of the 3 planes (in bytes).
|
||||
* fColorSpace: color space that will be used for the YUV -> RGB conversion.
|
||||
*/
|
||||
struct Info {
|
||||
SkISize fSize[3];
|
||||
size_t fSizeInMemory[3];
|
||||
size_t fRowBytes[3];
|
||||
SkYUVColorSpace fColorSpace;
|
||||
};
|
||||
/**
|
||||
* On success, return a ref to the SkCachedData that holds the pixels.
|
||||
*
|
||||
* On failure, return NULL.
|
||||
*/
|
||||
static SkCachedData* FindAndRef(uint32_t genID, Info* info,
|
||||
SkResourceCache* localCache = NULL);
|
||||
|
||||
/**
|
||||
* Add a pixelRef ID and its YUV planes data to the cache.
|
||||
*/
|
||||
static void Add(uint32_t genID, SkCachedData* data, Info* info,
|
||||
SkResourceCache* localCache = NULL);
|
||||
};
|
||||
|
||||
#endif
|
@ -15,7 +15,9 @@
|
||||
#include "SkData.h"
|
||||
#include "SkMessageBus.h"
|
||||
#include "SkPixelRef.h"
|
||||
#include "SkResourceCache.h"
|
||||
#include "SkTextureCompressor.h"
|
||||
#include "SkYUVPlanesCache.h"
|
||||
#include "effects/GrDitherEffect.h"
|
||||
#include "effects/GrPorterDuffXferProcessor.h"
|
||||
#include "effects/GrYUVtoRGBEffect.h"
|
||||
@ -221,48 +223,62 @@ static GrTexture *load_etc1_texture(GrContext* ctx, bool cache,
|
||||
static GrTexture *load_yuv_texture(GrContext* ctx, bool cache, const GrTextureParams* params,
|
||||
const SkBitmap& bm, const GrSurfaceDesc& desc) {
|
||||
// Subsets are not supported, the whole pixelRef is loaded when using YUV decoding
|
||||
if ((bm.pixelRef()->info().width() != bm.info().width()) ||
|
||||
(bm.pixelRef()->info().height() != bm.info().height())) {
|
||||
SkPixelRef* pixelRef = bm.pixelRef();
|
||||
if ((NULL == pixelRef) ||
|
||||
(pixelRef->info().width() != bm.info().width()) ||
|
||||
(pixelRef->info().height() != bm.info().height())) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SkPixelRef* pixelRef = bm.pixelRef();
|
||||
SkISize yuvSizes[3];
|
||||
if ((NULL == pixelRef) || !pixelRef->getYUV8Planes(yuvSizes, NULL, NULL, NULL)) {
|
||||
SkYUVPlanesCache::Info yuvInfo;
|
||||
SkAutoTUnref<SkCachedData> cachedData(
|
||||
SkYUVPlanesCache::FindAndRef(pixelRef->getGenerationID(), &yuvInfo));
|
||||
|
||||
void* planes[3];
|
||||
if (cachedData->data()) {
|
||||
planes[0] = (void*)cachedData->data();
|
||||
planes[1] = (uint8_t*)planes[0] + yuvInfo.fSizeInMemory[0];
|
||||
planes[2] = (uint8_t*)planes[1] + yuvInfo.fSizeInMemory[1];
|
||||
} else {
|
||||
// Fetch yuv plane sizes for memory allocation. Here, width and height can be
|
||||
// rounded up to JPEG block size and be larger than the image's width and height.
|
||||
if (!pixelRef->getYUV8Planes(yuvInfo.fSize, NULL, 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;
|
||||
yuvInfo.fRowBytes[i] = yuvInfo.fSize[i].fWidth;
|
||||
yuvInfo.fSizeInMemory[i] = yuvInfo.fRowBytes[i] * yuvInfo.fSize[i].fHeight;
|
||||
totalSize += yuvInfo.fSizeInMemory[i];
|
||||
}
|
||||
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];
|
||||
cachedData.reset(SkResourceCache::NewCachedData(totalSize));
|
||||
planes[0] = cachedData->writable_data();
|
||||
planes[1] = (uint8_t*)planes[0] + yuvInfo.fSizeInMemory[0];
|
||||
planes[2] = (uint8_t*)planes[1] + yuvInfo.fSizeInMemory[1];
|
||||
|
||||
SkYUVColorSpace colorSpace;
|
||||
|
||||
// Get the YUV planes
|
||||
if (!pixelRef->getYUV8Planes(yuvSizes, planes, rowBytes, &colorSpace)) {
|
||||
// Get the YUV planes and update plane sizes to actual image size
|
||||
if (!pixelRef->getYUV8Planes(yuvInfo.fSize, planes, yuvInfo.fRowBytes,
|
||||
&yuvInfo.fColorSpace)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Decoding is done, cache the resulting YUV planes
|
||||
SkYUVPlanesCache::Add(pixelRef->getGenerationID(), cachedData, &yuvInfo);
|
||||
}
|
||||
|
||||
GrSurfaceDesc yuvDesc;
|
||||
yuvDesc.fConfig = kAlpha_8_GrPixelConfig;
|
||||
SkAutoTUnref<GrTexture> yuvTextures[3];
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
yuvDesc.fWidth = yuvSizes[i].fWidth;
|
||||
yuvDesc.fHeight = yuvSizes[i].fHeight;
|
||||
yuvDesc.fWidth = yuvInfo.fSize[i].fWidth;
|
||||
yuvDesc.fHeight = yuvInfo.fSize[i].fHeight;
|
||||
yuvTextures[i].reset(
|
||||
ctx->refScratchTexture(yuvDesc, GrContext::kApprox_ScratchTexMatch));
|
||||
if (!yuvTextures[i] ||
|
||||
!yuvTextures[i]->writePixels(0, 0, yuvDesc.fWidth, yuvDesc.fHeight,
|
||||
yuvDesc.fConfig, planes[i], rowBytes[i])) {
|
||||
yuvDesc.fConfig, planes[i], yuvInfo.fRowBytes[i])) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@ -276,12 +292,12 @@ static GrTexture *load_yuv_texture(GrContext* ctx, bool cache, const GrTexturePa
|
||||
|
||||
GrRenderTarget* renderTarget = result ? result->asRenderTarget() : NULL;
|
||||
if (renderTarget) {
|
||||
SkAutoTUnref<GrFragmentProcessor> yuvToRgbProcessor(
|
||||
GrYUVtoRGBEffect::Create(yuvTextures[0], yuvTextures[1], yuvTextures[2], colorSpace));
|
||||
SkAutoTUnref<GrFragmentProcessor> yuvToRgbProcessor(GrYUVtoRGBEffect::Create(
|
||||
yuvTextures[0], yuvTextures[1], yuvTextures[2], yuvInfo.fColorSpace));
|
||||
GrPaint paint;
|
||||
paint.addColorProcessor(yuvToRgbProcessor);
|
||||
SkRect r = SkRect::MakeWH(SkIntToScalar(yuvSizes[0].fWidth),
|
||||
SkIntToScalar(yuvSizes[0].fHeight));
|
||||
SkRect r = SkRect::MakeWH(SkIntToScalar(yuvInfo.fSize[0].fWidth),
|
||||
SkIntToScalar(yuvInfo.fSize[0].fHeight));
|
||||
GrContext::AutoRenderTarget autoRT(ctx, renderTarget);
|
||||
GrContext::AutoClip ac(ctx, GrContext::AutoClip::kWideOpen_InitialClip);
|
||||
ctx->drawRect(paint, SkMatrix::I(), r);
|
||||
|
76
tests/YUVCacheTest.cpp
Normal file
76
tests/YUVCacheTest.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 "SkCachedData.h"
|
||||
#include "SkYUVPlanesCache.h"
|
||||
#include "SkResourceCache.h"
|
||||
#include "Test.h"
|
||||
|
||||
enum LockedState {
|
||||
kUnlocked,
|
||||
kLocked,
|
||||
};
|
||||
|
||||
enum CachedState {
|
||||
kNotInCache,
|
||||
kInCache,
|
||||
};
|
||||
|
||||
static void check_data(skiatest::Reporter* reporter, SkCachedData* data,
|
||||
int refcnt, CachedState cacheState, LockedState lockedState) {
|
||||
REPORTER_ASSERT(reporter, data->testing_only_getRefCnt() == refcnt);
|
||||
REPORTER_ASSERT(reporter, data->testing_only_isInCache() == (kInCache == cacheState));
|
||||
bool isLocked = (data->data() != NULL);
|
||||
REPORTER_ASSERT(reporter, isLocked == (lockedState == kLocked));
|
||||
}
|
||||
|
||||
DEF_TEST(YUVPlanesCache, reporter) {
|
||||
SkResourceCache cache(1024);
|
||||
|
||||
SkYUVPlanesCache::Info yuvInfo;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
yuvInfo.fSize[i].fWidth = 20 * i;
|
||||
yuvInfo.fSize[i].fHeight = 10 * i;
|
||||
yuvInfo.fSizeInMemory[i] = 800 * i;
|
||||
yuvInfo.fRowBytes[i] = 80 * i;
|
||||
}
|
||||
yuvInfo.fColorSpace = kRec601_SkYUVColorSpace;
|
||||
|
||||
const uint32_t genID = 12345678;
|
||||
|
||||
SkCachedData* data = SkYUVPlanesCache::FindAndRef(genID, &yuvInfo, &cache);
|
||||
REPORTER_ASSERT(reporter, NULL == data);
|
||||
|
||||
size_t size = 256;
|
||||
data = cache.newCachedData(size);
|
||||
memset(data->writable_data(), 0xff, size);
|
||||
|
||||
SkYUVPlanesCache::Add(genID, data, &yuvInfo, &cache);
|
||||
check_data(reporter, data, 2, kInCache, kLocked);
|
||||
|
||||
data->unref();
|
||||
check_data(reporter, data, 1, kInCache, kUnlocked);
|
||||
|
||||
SkYUVPlanesCache::Info yuvInfoRead;
|
||||
data = SkYUVPlanesCache::FindAndRef(genID, &yuvInfoRead, &cache);
|
||||
|
||||
REPORTER_ASSERT(reporter, data);
|
||||
REPORTER_ASSERT(reporter, data->size() == size);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
REPORTER_ASSERT(reporter, yuvInfo.fSize[i].fWidth == yuvInfoRead.fSize[i].fWidth);
|
||||
REPORTER_ASSERT(reporter, yuvInfo.fSize[i].fHeight == yuvInfoRead.fSize[i].fHeight);
|
||||
REPORTER_ASSERT(reporter, yuvInfo.fSizeInMemory[i] == yuvInfoRead.fSizeInMemory[i]);
|
||||
REPORTER_ASSERT(reporter, yuvInfo.fRowBytes[i] == yuvInfoRead.fRowBytes[i]);
|
||||
}
|
||||
REPORTER_ASSERT(reporter, yuvInfo.fColorSpace == yuvInfoRead.fColorSpace);
|
||||
|
||||
check_data(reporter, data, 2, kInCache, kLocked);
|
||||
|
||||
cache.purgeAll();
|
||||
check_data(reporter, data, 1, kNotInCache, kLocked);
|
||||
data->unref();
|
||||
}
|
Loading…
Reference in New Issue
Block a user