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 "SkSurface_Gpu.h"
      9 
     10 #include "GrBackendSurface.h"
     11 #include "GrContextPriv.h"
     12 #include "GrRenderTargetContextPriv.h"
     13 #include "GrTexture.h"
     14 
     15 #include "SkCanvas.h"
     16 #include "SkColorSpace_Base.h"
     17 #include "SkGpuDevice.h"
     18 #include "SkImage_Base.h"
     19 #include "SkImage_Gpu.h"
     20 #include "SkImagePriv.h"
     21 #include "SkSurface_Base.h"
     22 
     23 #if SK_SUPPORT_GPU
     24 
     25 SkSurface_Gpu::SkSurface_Gpu(sk_sp<SkGpuDevice> device)
     26     : INHERITED(device->width(), device->height(), &device->surfaceProps())
     27     , fDevice(std::move(device)) {
     28     SkASSERT(fDevice->accessRenderTargetContext()->asSurfaceProxy()->priv().isExact());
     29 }
     30 
     31 SkSurface_Gpu::~SkSurface_Gpu() {
     32 }
     33 
     34 static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
     35                                                       SkSurface::BackendHandleAccess access) {
     36     switch (access) {
     37         case SkSurface::kFlushRead_BackendHandleAccess:
     38             break;
     39         case SkSurface::kFlushWrite_BackendHandleAccess:
     40         case SkSurface::kDiscardWrite_BackendHandleAccess:
     41             // for now we don't special-case on Discard, but we may in the future.
     42             surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
     43             break;
     44     }
     45 
     46     // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in.
     47     surface->getDevice()->flush();
     48     GrRenderTargetContext* rtc = surface->getDevice()->accessRenderTargetContext();
     49     return rtc->accessRenderTarget();
     50 }
     51 
     52 GrBackendObject SkSurface_Gpu::onGetTextureHandle(BackendHandleAccess access) {
     53     GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
     54     if (!rt) {
     55         return 0;
     56     }
     57     GrTexture* texture = rt->asTexture();
     58     if (texture) {
     59         return texture->getTextureHandle();
     60     }
     61     return 0;
     62 }
     63 
     64 bool SkSurface_Gpu::onGetRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess access) {
     65     GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
     66     if (!rt) {
     67         return false;
     68     }
     69     *obj = rt->getRenderTargetHandle();
     70     return true;
     71 }
     72 
     73 SkCanvas* SkSurface_Gpu::onNewCanvas() {
     74     SkCanvas::InitFlags flags = SkCanvas::kDefault_InitFlags;
     75     flags = static_cast<SkCanvas::InitFlags>(flags | SkCanvas::kConservativeRasterClip_InitFlag);
     76 
     77     return new SkCanvas(fDevice.get(), flags);
     78 }
     79 
     80 sk_sp<SkSurface> SkSurface_Gpu::onNewSurface(const SkImageInfo& info) {
     81     int sampleCount = fDevice->accessRenderTargetContext()->numColorSamples();
     82     GrSurfaceOrigin origin = fDevice->accessRenderTargetContext()->origin();
     83     // TODO: Make caller specify this (change virtual signature of onNewSurface).
     84     static const SkBudgeted kBudgeted = SkBudgeted::kNo;
     85     return SkSurface::MakeRenderTarget(fDevice->context(), kBudgeted, info, sampleCount,
     86                                        origin, &this->props());
     87 }
     88 
     89 sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot() {
     90     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
     91     if (!rtc) {
     92         return nullptr;
     93     }
     94 
     95     GrContext* ctx = fDevice->context();
     96 
     97     if (!rtc->asSurfaceProxy()) {
     98         return nullptr;
     99     }
    100 
    101     SkBudgeted budgeted = rtc->asSurfaceProxy()->isBudgeted();
    102 
    103     sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
    104     // If the original render target is a buffer originally created by the client, then we don't
    105     // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid
    106     // copy-on-write.
    107     if (!srcProxy || rtc->priv().refsWrappedObjects()) {
    108         SkASSERT(rtc->origin() == rtc->asSurfaceProxy()->origin());
    109 
    110         srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), budgeted);
    111     }
    112 
    113     const SkImageInfo info = fDevice->imageInfo();
    114     sk_sp<SkImage> image;
    115     if (srcProxy) {
    116         // The renderTargetContext coming out of SkGpuDevice should always be exact and the
    117         // above copy creates a kExact surfaceContext.
    118         SkASSERT(srcProxy->priv().isExact());
    119         image = sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
    120                                         info.alphaType(), std::move(srcProxy),
    121                                         info.refColorSpace(), budgeted);
    122     }
    123     return image;
    124 }
    125 
    126 // Create a new render target and, if necessary, copy the contents of the old
    127 // render target into it. Note that this flushes the SkGpuDevice but
    128 // doesn't force an OpenGL flush.
    129 void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
    130     GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
    131 
    132     // are we sharing our backing proxy with the image? Note this call should never create a new
    133     // image because onCopyOnWrite is only called when there is a cached image.
    134     sk_sp<SkImage> image(this->refCachedImage());
    135     SkASSERT(image);
    136 
    137     GrSurfaceProxy* imageProxy = ((SkImage_Base*) image.get())->peekProxy();
    138     SkASSERT(imageProxy);
    139 
    140     if (rtc->asSurfaceProxy()->underlyingUniqueID() == imageProxy->underlyingUniqueID()) {
    141         fDevice->replaceRenderTargetContext(SkSurface::kRetain_ContentChangeMode == mode);
    142     } else if (kDiscard_ContentChangeMode == mode) {
    143         this->SkSurface_Gpu::onDiscard();
    144     }
    145 }
    146 
    147 void SkSurface_Gpu::onDiscard() {
    148     fDevice->accessRenderTargetContext()->discard();
    149 }
    150 
    151 bool SkSurface_Gpu::onFlush(int numSemaphores, GrBackendSemaphore* signalSemaphores) {
    152     return fDevice->flushAndSignalSemaphores(numSemaphores, signalSemaphores);
    153 }
    154 
    155 bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
    156     return fDevice->wait(numSemaphores, waitSemaphores);
    157 }
    158 
    159 ///////////////////////////////////////////////////////////////////////////////
    160 
    161 bool SkSurface_Gpu::Valid(const SkImageInfo& info) {
    162     switch (info.colorType()) {
    163         case kRGBA_F16_SkColorType:
    164             return info.colorSpace() && info.colorSpace()->gammaIsLinear();
    165         case kRGBA_8888_SkColorType:
    166         case kBGRA_8888_SkColorType:
    167             return !info.colorSpace() || info.colorSpace()->gammaCloseToSRGB();
    168         default:
    169             return !info.colorSpace();
    170     }
    171 }
    172 
    173 bool SkSurface_Gpu::Valid(GrContext* context, GrPixelConfig config, SkColorSpace* colorSpace) {
    174     switch (config) {
    175         case kRGBA_half_GrPixelConfig:
    176             return colorSpace && colorSpace->gammaIsLinear();
    177         case kSRGBA_8888_GrPixelConfig:
    178         case kSBGRA_8888_GrPixelConfig:
    179             return context->caps()->srgbSupport() && colorSpace && colorSpace->gammaCloseToSRGB();
    180         case kRGBA_8888_GrPixelConfig:
    181         case kBGRA_8888_GrPixelConfig:
    182             // If we don't have sRGB support, we may get here with a color space. It still needs
    183             // to be sRGB-like (so that the application will work correctly on sRGB devices.)
    184             return !colorSpace ||
    185                 (colorSpace->gammaCloseToSRGB() && !context->caps()->srgbSupport());
    186         default:
    187             return !colorSpace;
    188     }
    189 }
    190 
    191 sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted,
    192                                              const SkImageInfo& info, int sampleCount,
    193                                              GrSurfaceOrigin origin, const SkSurfaceProps* props) {
    194     if (!SkSurface_Gpu::Valid(info)) {
    195         return nullptr;
    196     }
    197 
    198     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(
    199             ctx, budgeted, info, sampleCount, origin, props, SkGpuDevice::kClear_InitContents));
    200     if (!device) {
    201         return nullptr;
    202     }
    203     return sk_make_sp<SkSurface_Gpu>(std::move(device));
    204 }
    205 
    206 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context,
    207                                                    const GrBackendTextureDesc& desc,
    208                                                    sk_sp<SkColorSpace> colorSpace,
    209                                                    const SkSurfaceProps* props) {
    210     if (!context) {
    211         return nullptr;
    212     }
    213     GrBackendTexture tex(desc, context->contextPriv().getBackend());
    214     return MakeFromBackendTexture(context, tex, desc.fOrigin, desc.fSampleCnt, colorSpace, props);
    215 }
    216 
    217 sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex,
    218                                                    GrSurfaceOrigin origin, int sampleCnt,
    219                                                    sk_sp<SkColorSpace> colorSpace,
    220                                                    const SkSurfaceProps* props) {
    221     if (!context) {
    222         return nullptr;
    223     }
    224     if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) {
    225         return nullptr;
    226     }
    227 
    228     sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeBackendTextureRenderTargetContext(
    229                                                                     tex,
    230                                                                     origin,
    231                                                                     sampleCnt,
    232                                                                     std::move(colorSpace),
    233                                                                     props));
    234     if (!rtc) {
    235         return nullptr;
    236     }
    237 
    238     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
    239                                                 SkGpuDevice::kUninit_InitContents));
    240     if (!device) {
    241         return nullptr;
    242     }
    243     return sk_make_sp<SkSurface_Gpu>(std::move(device));
    244 }
    245 
    246 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
    247                                                         const GrBackendRenderTargetDesc& desc,
    248                                                         sk_sp<SkColorSpace> colorSpace,
    249                                                         const SkSurfaceProps* props) {
    250     if (!context) {
    251         return nullptr;
    252     }
    253 
    254     GrBackendRenderTarget backendRT(desc, context->contextPriv().getBackend());
    255     return MakeFromBackendRenderTarget(context, backendRT, desc.fOrigin,
    256                                        std::move(colorSpace), props);
    257 
    258 }
    259 
    260 sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
    261                                                         const GrBackendRenderTarget& backendRT,
    262                                                         GrSurfaceOrigin origin,
    263                                                         sk_sp<SkColorSpace> colorSpace,
    264                                                         const SkSurfaceProps* props) {
    265     if (!context) {
    266         return nullptr;
    267     }
    268     if (!SkSurface_Gpu::Valid(context, backendRT.config(), colorSpace.get())) {
    269         return nullptr;
    270     }
    271 
    272     sk_sp<GrRenderTargetContext> rtc(
    273         context->contextPriv().makeBackendRenderTargetRenderTargetContext(backendRT,
    274                                                                           origin,
    275                                                                           std::move(colorSpace),
    276                                                                           props));
    277     if (!rtc) {
    278         return nullptr;
    279     }
    280 
    281     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc),
    282                                                 backendRT.width(), backendRT.height(),
    283                                                 SkGpuDevice::kUninit_InitContents));
    284     if (!device) {
    285         return nullptr;
    286     }
    287 
    288     return sk_make_sp<SkSurface_Gpu>(std::move(device));
    289 }
    290 
    291 sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
    292                                                                  const GrBackendTextureDesc& desc,
    293                                                                  sk_sp<SkColorSpace> colorSpace,
    294                                                                  const SkSurfaceProps* props) {
    295     if (!context) {
    296         return nullptr;
    297     }
    298     GrBackendTexture tex(desc, context->contextPriv().getBackend());
    299     return MakeFromBackendTextureAsRenderTarget(context, tex, desc.fOrigin, desc.fSampleCnt,
    300                                                 std::move(colorSpace), props);
    301 }
    302 
    303 sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
    304                                                                  const GrBackendTexture& tex,
    305                                                                  GrSurfaceOrigin origin,
    306                                                                  int sampleCnt,
    307                                                                  sk_sp<SkColorSpace> colorSpace,
    308                                                                  const SkSurfaceProps* props) {
    309     if (!context) {
    310         return nullptr;
    311     }
    312     if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) {
    313         return nullptr;
    314     }
    315 
    316     sk_sp<GrRenderTargetContext> rtc(
    317         context->contextPriv().makeBackendTextureAsRenderTargetRenderTargetContext(
    318                                                                               tex,
    319                                                                               origin,
    320                                                                               sampleCnt,
    321                                                                               std::move(colorSpace),
    322                                                                               props));
    323     if (!rtc) {
    324         return nullptr;
    325     }
    326 
    327     sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
    328                                                 SkGpuDevice::kUninit_InitContents));
    329     if (!device) {
    330         return nullptr;
    331     }
    332     return sk_make_sp<SkSurface_Gpu>(std::move(device));
    333 }
    334 
    335 #endif
    336