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 "GrRenderTargetPriv.h" 11 #include "GrGLGpu.h" 12 #include "GrGLUtil.h" 13 #include "SkTraceMemoryDump.h" 14 15 #define GPUGL static_cast<GrGLGpu*>(this->getGpu()) 16 #define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X) 17 18 // Because this class is virtually derived from GrSurface we must explicitly call its constructor. 19 GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, 20 const GrSurfaceDesc& desc, 21 const IDDesc& idDesc, 22 GrGLStencilAttachment* stencil) 23 : GrSurface(gpu, idDesc.fLifeCycle, desc) 24 , INHERITED(gpu, idDesc.fLifeCycle, desc, idDesc.fSampleConfig, stencil) { 25 this->init(desc, idDesc); 26 this->registerWithCache(); 27 } 28 29 GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc, 30 Derived) 31 : GrSurface(gpu, idDesc.fLifeCycle, desc) 32 , INHERITED(gpu, idDesc.fLifeCycle, desc, idDesc.fSampleConfig) { 33 this->init(desc, idDesc); 34 } 35 36 void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) { 37 fRTFBOID = idDesc.fRTFBOID; 38 fTexFBOID = idDesc.fTexFBOID; 39 fMSColorRenderbufferID = idDesc.fMSColorRenderbufferID; 40 fRTLifecycle = idDesc.fLifeCycle; 41 42 fViewport.fLeft = 0; 43 fViewport.fBottom = 0; 44 fViewport.fWidth = desc.fWidth; 45 fViewport.fHeight = desc.fHeight; 46 47 fGpuMemorySize = this->totalSamples() * this->totalBytesPerSample(); 48 49 SkASSERT(fGpuMemorySize <= WorseCaseSize(desc)); 50 } 51 52 GrGLRenderTarget* GrGLRenderTarget::CreateWrapped(GrGLGpu* gpu, 53 const GrSurfaceDesc& desc, 54 const IDDesc& idDesc, 55 int stencilBits) { 56 GrGLStencilAttachment* sb = nullptr; 57 if (stencilBits) { 58 GrGLStencilAttachment::IDDesc sbDesc; 59 GrGLStencilAttachment::Format format; 60 format.fInternalFormat = GrGLStencilAttachment::kUnknownInternalFormat; 61 format.fPacked = false; 62 format.fStencilBits = stencilBits; 63 format.fTotalBits = stencilBits; 64 // Owndership of sb is passed to the GrRenderTarget so doesn't need to be deleted 65 sb = new GrGLStencilAttachment(gpu, sbDesc, desc.fWidth, desc.fHeight, 66 desc.fSampleCnt, format); 67 } 68 return (new GrGLRenderTarget(gpu, desc, idDesc, sb)); 69 } 70 71 size_t GrGLRenderTarget::onGpuMemorySize() const { 72 return fGpuMemorySize; 73 } 74 75 bool GrGLRenderTarget::completeStencilAttachment() { 76 GrGLGpu* gpu = this->getGLGpu(); 77 const GrGLInterface* interface = gpu->glInterface(); 78 GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment(); 79 if (nullptr == stencil) { 80 GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, 81 GR_GL_STENCIL_ATTACHMENT, 82 GR_GL_RENDERBUFFER, 0)); 83 GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, 84 GR_GL_DEPTH_ATTACHMENT, 85 GR_GL_RENDERBUFFER, 0)); 86 #ifdef SK_DEBUG 87 GrGLenum status; 88 GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); 89 SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status); 90 #endif 91 return true; 92 } else { 93 const GrGLStencilAttachment* glStencil = static_cast<const GrGLStencilAttachment*>(stencil); 94 GrGLuint rb = glStencil->renderbufferID(); 95 96 gpu->invalidateBoundRenderTarget(); 97 gpu->stats()->incRenderTargetBinds(); 98 GR_GL_CALL(interface, BindFramebuffer(GR_GL_FRAMEBUFFER, this->renderFBOID())); 99 GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, 100 GR_GL_STENCIL_ATTACHMENT, 101 GR_GL_RENDERBUFFER, rb)); 102 if (glStencil->format().fPacked) { 103 GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, 104 GR_GL_DEPTH_ATTACHMENT, 105 GR_GL_RENDERBUFFER, rb)); 106 } else { 107 GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, 108 GR_GL_DEPTH_ATTACHMENT, 109 GR_GL_RENDERBUFFER, 0)); 110 } 111 112 #ifdef SK_DEBUG 113 GrGLenum status; 114 GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); 115 SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status); 116 #endif 117 return true; 118 } 119 } 120 121 void GrGLRenderTarget::onRelease() { 122 if (kBorrowed_LifeCycle != fRTLifecycle) { 123 if (fTexFBOID) { 124 GL_CALL(DeleteFramebuffers(1, &fTexFBOID)); 125 } 126 if (fRTFBOID && fRTFBOID != fTexFBOID) { 127 GL_CALL(DeleteFramebuffers(1, &fRTFBOID)); 128 } 129 if (fMSColorRenderbufferID) { 130 GL_CALL(DeleteRenderbuffers(1, &fMSColorRenderbufferID)); 131 } 132 } 133 fRTFBOID = 0; 134 fTexFBOID = 0; 135 fMSColorRenderbufferID = 0; 136 INHERITED::onRelease(); 137 } 138 139 void GrGLRenderTarget::onAbandon() { 140 fRTFBOID = 0; 141 fTexFBOID = 0; 142 fMSColorRenderbufferID = 0; 143 INHERITED::onAbandon(); 144 } 145 146 GrGLGpu* GrGLRenderTarget::getGLGpu() const { 147 SkASSERT(!this->wasDestroyed()); 148 return static_cast<GrGLGpu*>(this->getGpu()); 149 } 150 151 void GrGLRenderTarget::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const { 152 // Don't log the backing texture's contribution to the memory size. This will be handled by the 153 // texture object. 154 155 // Log any renderbuffer's contribution to memory. We only do this if we own the renderbuffer 156 // (have a fMSColorRenderbufferID). 157 if (fMSColorRenderbufferID) { 158 size_t size = this->msaaSamples() * this->totalBytesPerSample(); 159 160 // Due to this resource having both a texture and a renderbuffer component, dump as 161 // skia/gpu_resources/resource_#/renderbuffer 162 SkString dumpName("skia/gpu_resources/resource_"); 163 dumpName.appendS32(this->getUniqueID()); 164 dumpName.append("/renderbuffer"); 165 166 traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", size); 167 168 if (this->isPurgeable()) { 169 traceMemoryDump->dumpNumericValue(dumpName.c_str(), "purgeable_size", "bytes", size); 170 } 171 172 SkString renderbuffer_id; 173 renderbuffer_id.appendU32(fMSColorRenderbufferID); 174 traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_renderbuffer", 175 renderbuffer_id.c_str()); 176 } 177 } 178 179 size_t GrGLRenderTarget::totalBytesPerSample() const { 180 SkASSERT(kUnknown_GrPixelConfig != fDesc.fConfig); 181 SkASSERT(!GrPixelConfigIsCompressed(fDesc.fConfig)); 182 size_t colorBytes = GrBytesPerPixel(fDesc.fConfig); 183 SkASSERT(colorBytes > 0); 184 185 return fDesc.fWidth * fDesc.fHeight * colorBytes; 186 } 187 188 int GrGLRenderTarget::msaaSamples() const { 189 if (fTexFBOID == kUnresolvableFBOID || fTexFBOID != fRTFBOID) { 190 // If the render target's FBO is external (fTexFBOID == kUnresolvableFBOID), or if we own 191 // the render target's FBO (fTexFBOID == fRTFBOID) then we use the provided sample count. 192 return SkTMax(1, fDesc.fSampleCnt); 193 } 194 195 // When fTexFBOID == fRTFBOID, we either are not using MSAA, or MSAA is auto resolving, so use 196 // 0 for the sample count. 197 return 0; 198 } 199 200 int GrGLRenderTarget::totalSamples() const { 201 int total_samples = this->msaaSamples(); 202 203 if (fTexFBOID != kUnresolvableFBOID) { 204 // If we own the resolve buffer then that is one more sample per pixel. 205 total_samples += 1; 206 } 207 208 return total_samples; 209 } 210