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 check this->fRefsWrappedObjects, as we might be the base of a GrGLTextureRenderTarget 196 // which is multiply inherited from both ourselves and a texture. In these cases, one part 197 // (texture, rt) may be wrapped, while the other is owned by Skia. 198 bool refsWrappedRenderTargetObjects = 199 this->fRTFBOOwnership == GrBackendObjectOwnership::kBorrowed; 200 if (refsWrappedRenderTargetObjects && !traceMemoryDump->shouldDumpWrappedObjects()) { 201 return; 202 } 203 204 // Don't log the framebuffer, as the framebuffer itself doesn't contribute to meaningful 205 // memory usage. It is always a wrapper around either: 206 // - a texture, which is owned elsewhere, and will be dumped there 207 // - a renderbuffer, which will be dumped below. 208 209 // Log any renderbuffer's contribution to memory. 210 if (fMSColorRenderbufferID) { 211 size_t size = GrSurface::ComputeSize(this->config(), this->width(), this->height(), 212 this->msaaSamples(), GrMipMapped::kNo); 213 214 // Due to this resource having both a texture and a renderbuffer component, dump as 215 // skia/gpu_resources/resource_#/renderbuffer 216 SkString resourceName = this->getResourceName(); 217 resourceName.append("/renderbuffer"); 218 219 this->dumpMemoryStatisticsPriv(traceMemoryDump, resourceName, "RenderTarget", size); 220 221 SkString renderbuffer_id; 222 renderbuffer_id.appendU32(fMSColorRenderbufferID); 223 traceMemoryDump->setMemoryBacking(resourceName.c_str(), "gl_renderbuffer", 224 renderbuffer_id.c_str()); 225 } 226 } 227 228 int GrGLRenderTarget::msaaSamples() const { 229 if (fTexFBOID == kUnresolvableFBOID || fTexFBOID != fRTFBOID) { 230 // If the render target's FBO is external (fTexFBOID == kUnresolvableFBOID), or if we own 231 // the render target's FBO (fTexFBOID == fRTFBOID) then we use the provided sample count. 232 return this->numStencilSamples(); 233 } 234 235 // When fTexFBOID == fRTFBOID, we either are not using MSAA, or MSAA is auto resolving, so use 236 // 0 for the sample count. 237 return 0; 238 } 239 240 int GrGLRenderTarget::totalSamples() const { 241 int total_samples = this->msaaSamples(); 242 243 if (fTexFBOID != kUnresolvableFBOID) { 244 // If we own the resolve buffer then that is one more sample per pixel. 245 total_samples += 1; 246 } 247 248 return total_samples; 249 } 250