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         // Owndership 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 size_t GrGLRenderTarget::onGpuMemorySize() const {
     86     return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
     87                                   fNumSamplesOwnedPerPixel, false);
     88 }
     89 
     90 bool GrGLRenderTarget::completeStencilAttachment() {
     91     GrGLGpu* gpu = this->getGLGpu();
     92     const GrGLInterface* interface = gpu->glInterface();
     93     GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
     94     if (nullptr == stencil) {
     95         GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
     96                                                       GR_GL_STENCIL_ATTACHMENT,
     97                                                       GR_GL_RENDERBUFFER, 0));
     98         GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
     99                                                       GR_GL_DEPTH_ATTACHMENT,
    100                                                       GR_GL_RENDERBUFFER, 0));
    101 #ifdef SK_DEBUG
    102         if (kChromium_GrGLDriver != gpu->glContext().driver()) {
    103             // This check can cause problems in Chromium if the context has been asynchronously
    104             // abandoned (see skbug.com/5200)
    105             GrGLenum status;
    106             GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
    107             SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status);
    108         }
    109 #endif
    110         return true;
    111     } else {
    112         const GrGLStencilAttachment* glStencil = static_cast<const GrGLStencilAttachment*>(stencil);
    113         GrGLuint rb = glStencil->renderbufferID();
    114 
    115         gpu->invalidateBoundRenderTarget();
    116         gpu->stats()->incRenderTargetBinds();
    117         GR_GL_CALL(interface, BindFramebuffer(GR_GL_FRAMEBUFFER, this->renderFBOID()));
    118         GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
    119                                                       GR_GL_STENCIL_ATTACHMENT,
    120                                                       GR_GL_RENDERBUFFER, rb));
    121         if (glStencil->format().fPacked) {
    122             GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
    123                                                           GR_GL_DEPTH_ATTACHMENT,
    124                                                           GR_GL_RENDERBUFFER, rb));
    125         } else {
    126             GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
    127                                                           GR_GL_DEPTH_ATTACHMENT,
    128                                                           GR_GL_RENDERBUFFER, 0));
    129         }
    130 
    131 #ifdef SK_DEBUG
    132         if (kChromium_GrGLDriver != gpu->glContext().driver()) {
    133             // This check can cause problems in Chromium if the context has been asynchronously
    134             // abandoned (see skbug.com/5200)
    135             GrGLenum status;
    136             GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
    137             SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status);
    138         }
    139 #endif
    140         return true;
    141     }
    142 }
    143 
    144 void GrGLRenderTarget::onRelease() {
    145     if (GrBackendObjectOwnership::kBorrowed != fRTFBOOwnership) {
    146         if (fTexFBOID) {
    147             GL_CALL(DeleteFramebuffers(1, &fTexFBOID));
    148         }
    149         if (fRTFBOID && fRTFBOID != fTexFBOID) {
    150             GL_CALL(DeleteFramebuffers(1, &fRTFBOID));
    151         }
    152         if (fMSColorRenderbufferID) {
    153             GL_CALL(DeleteRenderbuffers(1, &fMSColorRenderbufferID));
    154         }
    155     }
    156     fRTFBOID                = 0;
    157     fTexFBOID               = 0;
    158     fMSColorRenderbufferID  = 0;
    159     INHERITED::onRelease();
    160 }
    161 
    162 void GrGLRenderTarget::onAbandon() {
    163     fRTFBOID                = 0;
    164     fTexFBOID               = 0;
    165     fMSColorRenderbufferID  = 0;
    166     INHERITED::onAbandon();
    167 }
    168 
    169 GrGLGpu* GrGLRenderTarget::getGLGpu() const {
    170     SkASSERT(!this->wasDestroyed());
    171     return static_cast<GrGLGpu*>(this->getGpu());
    172 }
    173 
    174 bool GrGLRenderTarget::canAttemptStencilAttachment() const {
    175     if (this->getGpu()->getContext()->caps()->avoidStencilBuffers()) {
    176         return false;
    177     }
    178 
    179     // Only modify the FBO's attachments if we have created the FBO. Public APIs do not currently
    180     // allow for borrowed FBO ownership, so we can safely assume that if an object is owned,
    181     // Skia created it.
    182     return this->fRTFBOOwnership == GrBackendObjectOwnership::kOwned;
    183 }
    184 
    185 void GrGLRenderTarget::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
    186     // Don't log the backing texture's contribution to the memory size. This will be handled by the
    187     // texture object.
    188 
    189     // Log any renderbuffer's contribution to memory. We only do this if we own the renderbuffer
    190     // (have a fMSColorRenderbufferID).
    191     if (fMSColorRenderbufferID) {
    192         size_t size = GrSurface::ComputeSize(this->config(), this->width(), this->height(),
    193                                              this->msaaSamples(), false);
    194 
    195         // Due to this resource having both a texture and a renderbuffer component, dump as
    196         // skia/gpu_resources/resource_#/renderbuffer
    197         SkString dumpName("skia/gpu_resources/resource_");
    198         dumpName.appendU32(this->uniqueID().asUInt());
    199         dumpName.append("/renderbuffer");
    200 
    201         traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", size);
    202 
    203         if (this->isPurgeable()) {
    204             traceMemoryDump->dumpNumericValue(dumpName.c_str(), "purgeable_size", "bytes", size);
    205         }
    206 
    207         SkString renderbuffer_id;
    208         renderbuffer_id.appendU32(fMSColorRenderbufferID);
    209         traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_renderbuffer",
    210                                           renderbuffer_id.c_str());
    211     }
    212 }
    213 
    214 int GrGLRenderTarget::msaaSamples() const {
    215     if (fTexFBOID == kUnresolvableFBOID || fTexFBOID != fRTFBOID) {
    216         // If the render target's FBO is external (fTexFBOID == kUnresolvableFBOID), or if we own
    217         // the render target's FBO (fTexFBOID == fRTFBOID) then we use the provided sample count.
    218         return SkTMax(1, this->numStencilSamples());
    219     }
    220 
    221     // When fTexFBOID == fRTFBOID, we either are not using MSAA, or MSAA is auto resolving, so use
    222     // 0 for the sample count.
    223     return 0;
    224 }
    225 
    226 int GrGLRenderTarget::totalSamples() const {
    227   int total_samples = this->msaaSamples();
    228 
    229   if (fTexFBOID != kUnresolvableFBOID) {
    230       // If we own the resolve buffer then that is one more sample per pixel.
    231       total_samples += 1;
    232   }
    233 
    234   return total_samples;
    235 }
    236