Home | History | Annotate | Download | only in gl
      1 /*
      2  * Copyright 2011 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 "GrGLRenderTarget.h"
      9 
     10 #include "GrContext.h"
     11 #include "GrGLGpu.h"
     12 #include "GrGLUtil.h"
     13 #include "GrGpuResourcePriv.h"
     14 #include "GrRenderTargetPriv.h"
     15 #include "SkTraceMemoryDump.h"
     16 
     17 #define GPUGL static_cast<GrGLGpu*>(this->getGpu())
     18 #define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
     19 
     20 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
     21 // Constructor for wrapped render targets.
     22 GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu,
     23                                    const GrSurfaceDesc& desc,
     24                                    const IDDesc& idDesc,
     25                                    GrGLStencilAttachment* stencil)
     26     : GrSurface(gpu, desc)
     27     , INHERITED(gpu, desc, ComputeFlags(gpu->glCaps(), idDesc), stencil) {
     28     this->init(desc, idDesc);
     29     this->registerWithCacheWrapped();
     30 }
     31 
     32 GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, const GrSurfaceDesc& desc,
     33                                    const IDDesc& idDesc)
     34     : GrSurface(gpu, desc)
     35     , INHERITED(gpu, desc, ComputeFlags(gpu->glCaps(), idDesc)) {
     36     this->init(desc, idDesc);
     37 }
     38 
     39 inline GrRenderTargetFlags GrGLRenderTarget::ComputeFlags(const GrGLCaps& glCaps,
     40                                                           const IDDesc& idDesc) {
     41     GrRenderTargetFlags flags = GrRenderTargetFlags::kNone;
     42     if (idDesc.fIsMixedSampled) {
     43         SkASSERT(glCaps.usesMixedSamples() && idDesc.fRTFBOID); // FBO 0 can't be mixed sampled.
     44         flags |= GrRenderTargetFlags::kMixedSampled;
     45     }
     46     if (glCaps.maxWindowRectangles() > 0 && idDesc.fRTFBOID) {
     47         flags |= GrRenderTargetFlags::kWindowRectsSupport;
     48     }
     49     return flags;
     50 }
     51 
     52 void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) {
     53     fRTFBOID                = idDesc.fRTFBOID;
     54     fTexFBOID               = idDesc.fTexFBOID;
     55     fMSColorRenderbufferID  = idDesc.fMSColorRenderbufferID;
     56     fRTFBOOwnership         = idDesc.fRTFBOOwnership;
     57 
     58     fViewport.fLeft   = 0;
     59     fViewport.fBottom = 0;
     60     fViewport.fWidth  = desc.fWidth;
     61     fViewport.fHeight = desc.fHeight;
     62 
     63     fNumSamplesOwnedPerPixel = this->totalSamples();
     64 }
     65 
     66 sk_sp<GrGLRenderTarget> GrGLRenderTarget::MakeWrapped(GrGLGpu* gpu,
     67                                                       const GrSurfaceDesc& desc,
     68                                                       const IDDesc& idDesc,
     69                                                       int stencilBits) {
     70     GrGLStencilAttachment* sb = nullptr;
     71     if (stencilBits) {
     72         GrGLStencilAttachment::IDDesc sbDesc;
     73         GrGLStencilAttachment::Format format;
     74         format.fInternalFormat = GrGLStencilAttachment::kUnknownInternalFormat;
     75         format.fPacked = false;
     76         format.fStencilBits = stencilBits;
     77         format.fTotalBits = stencilBits;
     78         // Ownership of sb is passed to the GrRenderTarget so doesn't need to be deleted
     79         sb = new GrGLStencilAttachment(gpu, sbDesc, desc.fWidth, desc.fHeight,
     80                                        desc.fSampleCnt, format);
     81     }
     82     return sk_sp<GrGLRenderTarget>(new GrGLRenderTarget(gpu, desc, idDesc, sb));
     83 }
     84 
     85 GrBackendRenderTarget GrGLRenderTarget::getBackendRenderTarget() const {
     86     GrGLFramebufferInfo fbi;
     87     fbi.fFBOID = fRTFBOID;
     88     fbi.fFormat = this->getGLGpu()->glCaps().configSizedInternalFormat(this->config());
     89 
     90     return GrBackendRenderTarget(this->width(), this->height(), this->numColorSamples(),
     91                                  this->numStencilSamples(), fbi);
     92 }
     93 
     94 size_t GrGLRenderTarget::onGpuMemorySize() const {
     95     return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
     96                                   fNumSamplesOwnedPerPixel, GrMipMapped::kNo);
     97 }
     98 
     99 bool GrGLRenderTarget::completeStencilAttachment() {
    100     GrGLGpu* gpu = this->getGLGpu();
    101     const GrGLInterface* interface = gpu->glInterface();
    102     GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
    103     if (nullptr == stencil) {
    104         GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
    105                                                       GR_GL_STENCIL_ATTACHMENT,
    106                                                       GR_GL_RENDERBUFFER, 0));
    107         GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
    108                                                       GR_GL_DEPTH_ATTACHMENT,
    109                                                       GR_GL_RENDERBUFFER, 0));
    110 #ifdef SK_DEBUG
    111         if (kChromium_GrGLDriver != gpu->glContext().driver()) {
    112             // This check can cause problems in Chromium if the context has been asynchronously
    113             // abandoned (see skbug.com/5200)
    114             GrGLenum status;
    115             GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
    116             SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status);
    117         }
    118 #endif
    119         return true;
    120     } else {
    121         const GrGLStencilAttachment* glStencil = static_cast<const GrGLStencilAttachment*>(stencil);
    122         GrGLuint rb = glStencil->renderbufferID();
    123 
    124         gpu->invalidateBoundRenderTarget();
    125         gpu->stats()->incRenderTargetBinds();
    126         GR_GL_CALL(interface, BindFramebuffer(GR_GL_FRAMEBUFFER, this->renderFBOID()));
    127         GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
    128                                                       GR_GL_STENCIL_ATTACHMENT,
    129                                                       GR_GL_RENDERBUFFER, rb));
    130         if (glStencil->format().fPacked) {
    131             GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
    132                                                           GR_GL_DEPTH_ATTACHMENT,
    133                                                           GR_GL_RENDERBUFFER, rb));
    134         } else {
    135             GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
    136                                                           GR_GL_DEPTH_ATTACHMENT,
    137                                                           GR_GL_RENDERBUFFER, 0));
    138         }
    139 
    140 #ifdef SK_DEBUG
    141         if (kChromium_GrGLDriver != gpu->glContext().driver()) {
    142             // This check can cause problems in Chromium if the context has been asynchronously
    143             // abandoned (see skbug.com/5200)
    144             GrGLenum status;
    145             GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
    146             SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status);
    147         }
    148 #endif
    149         return true;
    150     }
    151 }
    152 
    153 void GrGLRenderTarget::onRelease() {
    154     if (GrBackendObjectOwnership::kBorrowed != fRTFBOOwnership) {
    155         if (fTexFBOID) {
    156             GL_CALL(DeleteFramebuffers(1, &fTexFBOID));
    157         }
    158         if (fRTFBOID && fRTFBOID != fTexFBOID) {
    159             GL_CALL(DeleteFramebuffers(1, &fRTFBOID));
    160         }
    161         if (fMSColorRenderbufferID) {
    162             GL_CALL(DeleteRenderbuffers(1, &fMSColorRenderbufferID));
    163         }
    164     }
    165     fRTFBOID                = 0;
    166     fTexFBOID               = 0;
    167     fMSColorRenderbufferID  = 0;
    168     INHERITED::onRelease();
    169 }
    170 
    171 void GrGLRenderTarget::onAbandon() {
    172     fRTFBOID                = 0;
    173     fTexFBOID               = 0;
    174     fMSColorRenderbufferID  = 0;
    175     INHERITED::onAbandon();
    176 }
    177 
    178 GrGLGpu* GrGLRenderTarget::getGLGpu() const {
    179     SkASSERT(!this->wasDestroyed());
    180     return static_cast<GrGLGpu*>(this->getGpu());
    181 }
    182 
    183 bool GrGLRenderTarget::canAttemptStencilAttachment() const {
    184     if (this->getGpu()->getContext()->caps()->avoidStencilBuffers()) {
    185         return false;
    186     }
    187 
    188     // Only modify the FBO's attachments if we have created the FBO. Public APIs do not currently
    189     // allow for borrowed FBO ownership, so we can safely assume that if an object is owned,
    190     // Skia created it.
    191     return this->fRTFBOOwnership == GrBackendObjectOwnership::kOwned;
    192 }
    193 
    194 void GrGLRenderTarget::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
    195     // Don't log the backing texture's contribution to the memory size. This will be handled by the
    196     // texture object.
    197 
    198     // Log any renderbuffer's contribution to memory. We only do this if we own the renderbuffer
    199     // (have a fMSColorRenderbufferID).
    200     if (fMSColorRenderbufferID) {
    201         size_t size = GrSurface::ComputeSize(this->config(), this->width(), this->height(),
    202                                              this->msaaSamples(), GrMipMapped::kNo);
    203 
    204         // Due to this resource having both a texture and a renderbuffer component, dump as
    205         // skia/gpu_resources/resource_#/renderbuffer
    206         SkString dumpName("skia/gpu_resources/resource_");
    207         dumpName.appendU32(this->uniqueID().asUInt());
    208         dumpName.append("/renderbuffer");
    209 
    210         traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", size);
    211 
    212         if (this->isPurgeable()) {
    213             traceMemoryDump->dumpNumericValue(dumpName.c_str(), "purgeable_size", "bytes", size);
    214         }
    215 
    216         SkString renderbuffer_id;
    217         renderbuffer_id.appendU32(fMSColorRenderbufferID);
    218         traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_renderbuffer",
    219                                           renderbuffer_id.c_str());
    220     }
    221 }
    222 
    223 int GrGLRenderTarget::msaaSamples() const {
    224     if (fTexFBOID == kUnresolvableFBOID || fTexFBOID != fRTFBOID) {
    225         // If the render target's FBO is external (fTexFBOID == kUnresolvableFBOID), or if we own
    226         // the render target's FBO (fTexFBOID == fRTFBOID) then we use the provided sample count.
    227         return this->numStencilSamples();
    228     }
    229 
    230     // When fTexFBOID == fRTFBOID, we either are not using MSAA, or MSAA is auto resolving, so use
    231     // 0 for the sample count.
    232     return 0;
    233 }
    234 
    235 int GrGLRenderTarget::totalSamples() const {
    236   int total_samples = this->msaaSamples();
    237 
    238   if (fTexFBOID != kUnresolvableFBOID) {
    239       // If we own the resolve buffer then that is one more sample per pixel.
    240       total_samples += 1;
    241   }
    242 
    243   return total_samples;
    244 }
    245