Home | History | Annotate | Download | only in image
      1 /*
      2  * Copyright 2012 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 "SkImage_Gpu.h"
      9 #include "SkCanvas.h"
     10 #include "GrContext.h"
     11 #include "SkGpuDevice.h"
     12 
     13 SkImage_Gpu::SkImage_Gpu(int w, int h, SkAlphaType at, GrTexture* tex,
     14                          int sampleCountForNewSurfaces, SkSurface::Budgeted budgeted)
     15     : INHERITED(w, h, NULL)
     16     , fTexture(SkRef(tex))
     17     , fSampleCountForNewSurfaces(sampleCountForNewSurfaces)
     18     , fAlphaType(at)
     19     , fBudgeted(budgeted)
     20     {}
     21 
     22 SkSurface* SkImage_Gpu::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) const {
     23     GrTexture* tex = this->getTexture();
     24     SkASSERT(tex);
     25     GrContext* ctx = tex->getContext();
     26     if (!ctx) {
     27         // the texture may have been abandoned, so we have to check
     28         return NULL;
     29     }
     30     // TODO: Change signature of onNewSurface to take a budgeted param.
     31     const SkSurface::Budgeted budgeted = SkSurface::kNo_Budgeted;
     32     return SkSurface::NewRenderTarget(ctx, budgeted, info, fSampleCountForNewSurfaces, &props);
     33 }
     34 
     35 extern void SkTextureImageApplyBudgetedDecision(SkImage* image) {
     36     if (image->getTexture()) {
     37         ((SkImage_Gpu*)image)->applyBudgetDecision();
     38     }
     39 }
     40 
     41 SkShader* SkImage_Gpu::onNewShader(SkShader::TileMode tileX, SkShader::TileMode tileY,
     42                                    const SkMatrix* localMatrix) const {
     43     SkBitmap bm;
     44     GrWrapTextureInBitmap(fTexture, this->width(), this->height(), this->isOpaque(), &bm);
     45     return SkShader::CreateBitmapShader(bm, tileX, tileY, localMatrix);
     46 }
     47 
     48 bool SkImage_Gpu::getROPixels(SkBitmap* dst) const {
     49     SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
     50     if (!dst->tryAllocPixels(SkImageInfo::MakeN32(this->width(), this->height(), at))) {
     51         return false;
     52     }
     53     if (!fTexture->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig,
     54                               dst->getPixels(), dst->rowBytes())) {
     55         return false;
     56     }
     57     return true;
     58 }
     59 
     60 bool SkImage_Gpu::isOpaque() const {
     61     return GrPixelConfigIsOpaque(fTexture->config());
     62 }
     63 
     64 static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
     65     switch (info.colorType()) {
     66         case kRGBA_8888_SkColorType:
     67         case kBGRA_8888_SkColorType:
     68             break;
     69         default:
     70             return; // nothing to do
     71     }
     72 
     73     // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian,
     74     // and in either case, the alpha-byte is always in the same place, so we can safely call
     75     // SkPreMultiplyColor()
     76     //
     77     SkColor* row = (SkColor*)pixels;
     78     for (int y = 0; y < info.height(); ++y) {
     79         for (int x = 0; x < info.width(); ++x) {
     80             row[x] = SkPreMultiplyColor(row[x]);
     81         }
     82     }
     83 }
     84 
     85 bool SkImage_Gpu::onReadPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
     86                                int srcX, int srcY) const {
     87     GrPixelConfig config = SkImageInfo2GrPixelConfig(info.colorType(), info.alphaType(),
     88                                                      info.profileType());
     89     uint32_t flags = 0;
     90     if (kUnpremul_SkAlphaType == info.alphaType() && kPremul_SkAlphaType == fAlphaType) {
     91         // let the GPU perform this transformation for us
     92         flags = GrContext::kUnpremul_PixelOpsFlag;
     93     }
     94     if (!fTexture->readPixels(srcX, srcY, info.width(), info.height(), config,
     95                               pixels, rowBytes, flags)) {
     96         return false;
     97     }
     98     // do we have to manually fix-up the alpha channel?
     99     //      src         dst
    100     //      unpremul    premul      fix manually
    101     //      premul      unpremul    done by kUnpremul_PixelOpsFlag
    102     // all other combos need to change.
    103     //
    104     // Should this be handled by Ganesh? todo:?
    105     //
    106     if (kPremul_SkAlphaType == info.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
    107         apply_premul(info, pixels, rowBytes);
    108     }
    109     return true;
    110 }
    111 
    112 ///////////////////////////////////////////////////////////////////////////////////////////////////
    113 
    114 SkImage* SkImage::NewFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc, SkAlphaType at) {
    115     if (desc.fWidth <= 0 || desc.fHeight <= 0) {
    116         return NULL;
    117     }
    118     SkAutoTUnref<GrTexture> tex(ctx->textureProvider()->wrapBackendTexture(desc));
    119     if (!tex) {
    120         return NULL;
    121     }
    122     const SkSurface::Budgeted budgeted = SkSurface::kNo_Budgeted;
    123     return SkNEW_ARGS(SkImage_Gpu, (desc.fWidth, desc.fHeight, at, tex, 0, budgeted));
    124 }
    125 
    126 SkImage* SkImage::NewFromTextureCopy(GrContext* ctx, const GrBackendTextureDesc& srcDesc,
    127                                      SkAlphaType at) {
    128     const bool isBudgeted = true;
    129     const SkSurface::Budgeted budgeted = SkSurface::kYes_Budgeted;
    130 
    131     if (srcDesc.fWidth <= 0 || srcDesc.fHeight <= 0) {
    132         return NULL;
    133     }
    134     SkAutoTUnref<GrTexture> src(ctx->textureProvider()->wrapBackendTexture(srcDesc));
    135     if (!src) {
    136         return NULL;
    137     }
    138 
    139     GrSurfaceDesc dstDesc;
    140     // need to be a rendertarget for readpixels to work, instead of kNone_GrSurfaceFlags
    141     dstDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    142     dstDesc.fOrigin = srcDesc.fOrigin;
    143     dstDesc.fWidth = srcDesc.fWidth;
    144     dstDesc.fHeight = srcDesc.fHeight;
    145     dstDesc.fConfig = srcDesc.fConfig;
    146     dstDesc.fSampleCnt = srcDesc.fSampleCnt;
    147 
    148     SkAutoTUnref<GrTexture> dst(ctx->textureProvider()->createTexture(
    149                                                                   dstDesc, isBudgeted, NULL, 0));
    150     if (!dst) {
    151         return NULL;
    152     }
    153 
    154     const SkIRect srcR = SkIRect::MakeWH(dstDesc.fWidth, dstDesc.fHeight);
    155     const SkIPoint dstP = SkIPoint::Make(0, 0);
    156     ctx->copySurface(dst, src, srcR, dstP, GrContext::kFlushWrites_PixelOp);
    157 
    158     const int sampleCount = 0;  // todo: make this an explicit parameter to newSurface()?
    159     return SkNEW_ARGS(SkImage_Gpu, (dstDesc.fWidth, dstDesc.fHeight, at, dst, sampleCount,
    160                                     budgeted));
    161 }
    162