Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2015 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "GrContext.h"
      9 #include "GrDrawContext.h"
     10 #include "GrYUVProvider.h"
     11 #include "effects/GrYUVEffect.h"
     12 
     13 #include "SkCachedData.h"
     14 #include "SkRefCnt.h"
     15 #include "SkResourceCache.h"
     16 #include "SkYUVPlanesCache.h"
     17 
     18 namespace {
     19 /**
     20  *  Helper class to manage the resources used for storing the YUV planar data. Depending on the
     21  *  useCache option, we may find (and lock) the data in our ResourceCache, or we may have allocated
     22  *  it in scratch storage.
     23  */
     24 class YUVScoper {
     25 public:
     26     bool init(GrYUVProvider*, SkYUVPlanesCache::Info*, void* planes[3], bool useCache);
     27 
     28 private:
     29     // we only use one or the other of these
     30     SkAutoTUnref<SkCachedData>  fCachedData;
     31     SkAutoMalloc                fStorage;
     32 };
     33 }
     34 
     35 bool YUVScoper::init(GrYUVProvider* provider, SkYUVPlanesCache::Info* yuvInfo, void* planes[3],
     36                      bool useCache) {
     37     if (useCache) {
     38         fCachedData.reset(SkYUVPlanesCache::FindAndRef(provider->onGetID(), yuvInfo));
     39     }
     40 
     41     if (fCachedData.get()) {
     42         planes[0] = (void*)fCachedData->data();
     43         planes[1] = (uint8_t*)planes[0] + yuvInfo->fSizeInMemory[0];
     44         planes[2] = (uint8_t*)planes[1] + yuvInfo->fSizeInMemory[1];
     45     } else {
     46         // Fetch yuv plane sizes for memory allocation. Here, width and height can be
     47         // rounded up to JPEG block size and be larger than the image's width and height.
     48         if (!provider->onGetYUVSizes(yuvInfo->fSize)) {
     49             return false;
     50         }
     51 
     52         // Allocate the memory for YUV
     53         size_t totalSize(0);
     54         for (int i = 0; i < GrYUVProvider::kPlaneCount; ++i) {
     55             yuvInfo->fRowBytes[i] = yuvInfo->fSize[i].fWidth; // we assume snug fit: rb == width
     56             yuvInfo->fSizeInMemory[i] = yuvInfo->fRowBytes[i] * yuvInfo->fSize[i].fHeight;
     57             totalSize += yuvInfo->fSizeInMemory[i];
     58         }
     59         if (useCache) {
     60             fCachedData.reset(SkResourceCache::NewCachedData(totalSize));
     61             planes[0] = fCachedData->writable_data();
     62         } else {
     63             fStorage.reset(totalSize);
     64             planes[0] = fStorage.get();
     65         }
     66         planes[1] = (uint8_t*)planes[0] + yuvInfo->fSizeInMemory[0];
     67         planes[2] = (uint8_t*)planes[1] + yuvInfo->fSizeInMemory[1];
     68 
     69         // Get the YUV planes and update plane sizes to actual image size
     70         if (!provider->onGetYUVPlanes(yuvInfo->fSize, planes, yuvInfo->fRowBytes,
     71                                       &yuvInfo->fColorSpace)) {
     72             return false;
     73         }
     74 
     75         if (useCache) {
     76             // Decoding is done, cache the resulting YUV planes
     77             SkYUVPlanesCache::Add(provider->onGetID(), fCachedData, yuvInfo);
     78         }
     79     }
     80     return true;
     81 }
     82 
     83 GrTexture* GrYUVProvider::refAsTexture(GrContext* ctx, const GrSurfaceDesc& desc, bool useCache) {
     84     SkYUVPlanesCache::Info yuvInfo;
     85     void* planes[3];
     86     YUVScoper scoper;
     87     if (!scoper.init(this, &yuvInfo, planes, useCache)) {
     88         return nullptr;
     89     }
     90 
     91     GrSurfaceDesc yuvDesc;
     92     yuvDesc.fConfig = kAlpha_8_GrPixelConfig;
     93     SkAutoTUnref<GrTexture> yuvTextures[3];
     94     for (int i = 0; i < 3; ++i) {
     95         yuvDesc.fWidth  = yuvInfo.fSize[i].fWidth;
     96         yuvDesc.fHeight = yuvInfo.fSize[i].fHeight;
     97         // TODO: why do we need this check?
     98         bool needsExactTexture = (yuvDesc.fWidth  != yuvInfo.fSize[0].fWidth) ||
     99                                  (yuvDesc.fHeight != yuvInfo.fSize[0].fHeight);
    100         if (needsExactTexture) {
    101             yuvTextures[i].reset(ctx->textureProvider()->createTexture(yuvDesc, SkBudgeted::kYes));
    102         } else {
    103             yuvTextures[i].reset(ctx->textureProvider()->createApproxTexture(yuvDesc));
    104         }
    105         if (!yuvTextures[i] ||
    106             !yuvTextures[i]->writePixels(0, 0, yuvDesc.fWidth, yuvDesc.fHeight,
    107                                          yuvDesc.fConfig, planes[i], yuvInfo.fRowBytes[i])) {
    108                 return nullptr;
    109             }
    110     }
    111 
    112     GrSurfaceDesc rtDesc = desc;
    113     rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
    114 
    115     SkAutoTUnref<GrTexture> result(ctx->textureProvider()->createTexture(rtDesc, SkBudgeted::kYes,
    116                                                                          nullptr, 0));
    117     if (!result) {
    118         return nullptr;
    119     }
    120 
    121     GrRenderTarget* renderTarget = result->asRenderTarget();
    122     SkASSERT(renderTarget);
    123 
    124     GrPaint paint;
    125     SkAutoTUnref<const GrFragmentProcessor> yuvToRgbProcessor(
    126                                         GrYUVEffect::CreateYUVToRGB(yuvTextures[0],
    127                                                                     yuvTextures[1],
    128                                                                     yuvTextures[2],
    129                                                                     yuvInfo.fSize,
    130                                                                     yuvInfo.fColorSpace));
    131     paint.addColorFragmentProcessor(yuvToRgbProcessor);
    132     paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
    133     const SkRect r = SkRect::MakeIWH(yuvInfo.fSize[0].fWidth, yuvInfo.fSize[0].fHeight);
    134 
    135     SkAutoTUnref<GrDrawContext> drawContext(ctx->drawContext(renderTarget));
    136     if (!drawContext) {
    137         return nullptr;
    138     }
    139 
    140     drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), r);
    141 
    142     return result.detach();
    143 }
    144 
    145