aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar sugoi <sugoi@chromium.org>2015-01-19 10:10:27 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-01-19 10:10:27 -0800
commit692135f9689d4dcb5ba91ff8f4899e268c0bfe11 (patch)
tree73d0911ff57b27e75df7c5a1da554b959a2e6ca1
parent89499d76b9616a455dfe8257cef9e4489938ea22 (diff)
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
-rw-r--r--gyp/core.gypi2
-rw-r--r--gyp/tests.gypi1
-rw-r--r--src/core/SkMaskCache.cpp2
-rw-r--r--src/core/SkYUVPlanesCache.cpp83
-rw-r--r--src/core/SkYUVPlanesCache.h50
-rw-r--r--src/gpu/SkGr.cpp74
-rw-r--r--tests/YUVCacheTest.cpp76
7 files changed, 258 insertions, 30 deletions
diff --git a/gyp/core.gypi b/gyp/core.gypi
index c5cecb666e..e7738af8bb 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -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',
diff --git a/gyp/tests.gypi b/gyp/tests.gypi
index d59b26204a..ac71d36169 100644
--- a/gyp/tests.gypi
+++ b/gyp/tests.gypi
@@ -218,6 +218,7 @@
'../tests/WritePixelsTest.cpp',
'../tests/Writer32Test.cpp',
'../tests/XfermodeTest.cpp',
+ '../tests/YUVCacheTest.cpp',
'../tests/MatrixClipCollapseTest.cpp',
'../src/utils/debugger/SkDrawCommand.h',
diff --git a/src/core/SkMaskCache.cpp b/src/core/SkMaskCache.cpp
index a360fc56d7..02d355d4f1 100644
--- a/src/core/SkMaskCache.cpp
+++ b/src/core/SkMaskCache.cpp
@@ -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();
diff --git a/src/core/SkYUVPlanesCache.cpp b/src/core/SkYUVPlanesCache.cpp
new file mode 100644
index 0000000000..69885fe46a
--- /dev/null
+++ b/src/core/SkYUVPlanesCache.cpp
@@ -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)));
+}
diff --git a/src/core/SkYUVPlanesCache.h b/src/core/SkYUVPlanesCache.h
new file mode 100644
index 0000000000..aa9b89e2a5
--- /dev/null
+++ b/src/core/SkYUVPlanesCache.h
@@ -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
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 49d3c6bb48..18b27534bc 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -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())) {
- return NULL;
- }
-
SkPixelRef* pixelRef = bm.pixelRef();
- SkISize yuvSizes[3];
- if ((NULL == pixelRef) || !pixelRef->getYUV8Planes(yuvSizes, NULL, NULL, NULL)) {
+ if ((NULL == pixelRef) ||
+ (pixelRef->info().width() != bm.info().width()) ||
+ (pixelRef->info().height() != bm.info().height())) {
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);
+ SkYUVPlanesCache::Info yuvInfo;
+ SkAutoTUnref<SkCachedData> cachedData(
+ SkYUVPlanesCache::FindAndRef(pixelRef->getGenerationID(), &yuvInfo));
+
void* planes[3];
- planes[0] = storage.get();
- planes[1] = (uint8_t*)planes[0] + sizes[0];
- planes[2] = (uint8_t*)planes[1] + sizes[1];
+ 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;
+ }
- SkYUVColorSpace colorSpace;
+ // Allocate the memory for YUV
+ size_t totalSize(0);
+ for (int i = 0; i < 3; ++i) {
+ yuvInfo.fRowBytes[i] = yuvInfo.fSize[i].fWidth;
+ yuvInfo.fSizeInMemory[i] = yuvInfo.fRowBytes[i] * yuvInfo.fSize[i].fHeight;
+ totalSize += yuvInfo.fSizeInMemory[i];
+ }
+ 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];
+
+ // Get the YUV planes and update plane sizes to actual image size
+ if (!pixelRef->getYUV8Planes(yuvInfo.fSize, planes, yuvInfo.fRowBytes,
+ &yuvInfo.fColorSpace)) {
+ return NULL;
+ }
- // Get the YUV planes
- if (!pixelRef->getYUV8Planes(yuvSizes, planes, rowBytes, &colorSpace)) {
- 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);
diff --git a/tests/YUVCacheTest.cpp b/tests/YUVCacheTest.cpp
new file mode 100644
index 0000000000..f5b5897334
--- /dev/null
+++ b/tests/YUVCacheTest.cpp
@@ -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();
+}