GrGLRenderTarget.cpp revision f1c6cd7603bd8c3f55b5070c8faa666652e98cc2
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 "GrGLGpu.h" 11#include "GrGLUtil.h" 12#include "GrGpuResourcePriv.h" 13#include "GrRenderTargetPriv.h" 14#include "SkTraceMemoryDump.h" 15 16#define GPUGL static_cast<GrGLGpu*>(this->getGpu()) 17#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X) 18 19// Because this class is virtually derived from GrSurface we must explicitly call its constructor. 20// Constructor for wrapped render targets. 21GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, 22 const GrSurfaceDesc& desc, 23 const IDDesc& idDesc, 24 GrGLStencilAttachment* stencil) 25 : GrSurface(gpu, desc) 26 , INHERITED(gpu, desc, ComputeFlags(gpu->glCaps(), idDesc), stencil) { 27 this->init(desc, idDesc); 28 this->registerWithCacheWrapped(); 29} 30 31GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, const GrSurfaceDesc& desc, 32 const IDDesc& idDesc) 33 : GrSurface(gpu, desc) 34 , INHERITED(gpu, desc, ComputeFlags(gpu->glCaps(), idDesc)) { 35 this->init(desc, idDesc); 36} 37 38inline GrRenderTarget::Flags GrGLRenderTarget::ComputeFlags(const GrGLCaps& glCaps, 39 const IDDesc& idDesc) { 40 Flags flags = Flags::kNone; 41 if (idDesc.fIsMixedSampled) { 42 SkASSERT(glCaps.usesMixedSamples() && idDesc.fRTFBOID); // FBO 0 can't be mixed sampled. 43 flags |= Flags::kMixedSampled; 44 } 45 if (glCaps.maxWindowRectangles() > 0 && idDesc.fRTFBOID) { 46 flags |= Flags::kWindowRectsSupport; 47 } 48 return flags; 49} 50 51void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) { 52 fRTFBOID = idDesc.fRTFBOID; 53 fTexFBOID = idDesc.fTexFBOID; 54 fMSColorRenderbufferID = idDesc.fMSColorRenderbufferID; 55 fRTFBOOwnership = idDesc.fRTFBOOwnership; 56 57 fViewport.fLeft = 0; 58 fViewport.fBottom = 0; 59 fViewport.fWidth = desc.fWidth; 60 fViewport.fHeight = desc.fHeight; 61 62 fGpuMemorySize = this->totalSamples() * this->totalBytesPerSample(); 63 64 SkASSERT(fGpuMemorySize <= WorstCaseSize(desc)); 65} 66 67GrGLRenderTarget* GrGLRenderTarget::CreateWrapped(GrGLGpu* gpu, 68 const GrSurfaceDesc& desc, 69 const IDDesc& idDesc, 70 int stencilBits) { 71 GrGLStencilAttachment* sb = nullptr; 72 if (stencilBits) { 73 GrGLStencilAttachment::IDDesc sbDesc; 74 GrGLStencilAttachment::Format format; 75 format.fInternalFormat = GrGLStencilAttachment::kUnknownInternalFormat; 76 format.fPacked = false; 77 format.fStencilBits = stencilBits; 78 format.fTotalBits = stencilBits; 79 // Owndership of sb is passed to the GrRenderTarget so doesn't need to be deleted 80 sb = new GrGLStencilAttachment(gpu, sbDesc, desc.fWidth, desc.fHeight, 81 desc.fSampleCnt, format); 82 } 83 return (new GrGLRenderTarget(gpu, desc, idDesc, sb)); 84} 85 86size_t GrGLRenderTarget::onGpuMemorySize() const { 87 return fGpuMemorySize; 88} 89 90bool 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 144void 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 162void GrGLRenderTarget::onAbandon() { 163 fRTFBOID = 0; 164 fTexFBOID = 0; 165 fMSColorRenderbufferID = 0; 166 INHERITED::onAbandon(); 167} 168 169GrGLGpu* GrGLRenderTarget::getGLGpu() const { 170 SkASSERT(!this->wasDestroyed()); 171 return static_cast<GrGLGpu*>(this->getGpu()); 172} 173 174bool GrGLRenderTarget::canAttemptStencilAttachment() const { 175 // Only modify the FBO's attachments if we have created the FBO. Public APIs do not currently 176 // allow for borrowed FBO ownership, so we can safely assume that if an object is owned, 177 // Skia created it. 178 return this->fRTFBOOwnership == GrBackendObjectOwnership::kOwned; 179} 180 181void GrGLRenderTarget::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const { 182 // Don't log the backing texture's contribution to the memory size. This will be handled by the 183 // texture object. 184 185 // Log any renderbuffer's contribution to memory. We only do this if we own the renderbuffer 186 // (have a fMSColorRenderbufferID). 187 if (fMSColorRenderbufferID) { 188 size_t size = this->msaaSamples() * this->totalBytesPerSample(); 189 190 // Due to this resource having both a texture and a renderbuffer component, dump as 191 // skia/gpu_resources/resource_#/renderbuffer 192 SkString dumpName("skia/gpu_resources/resource_"); 193 dumpName.appendS32(this->getUniqueID()); 194 dumpName.append("/renderbuffer"); 195 196 traceMemoryDump->dumpNumericValue(dumpName.c_str(), "size", "bytes", size); 197 198 if (this->isPurgeable()) { 199 traceMemoryDump->dumpNumericValue(dumpName.c_str(), "purgeable_size", "bytes", size); 200 } 201 202 SkString renderbuffer_id; 203 renderbuffer_id.appendU32(fMSColorRenderbufferID); 204 traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_renderbuffer", 205 renderbuffer_id.c_str()); 206 } 207} 208 209size_t GrGLRenderTarget::totalBytesPerSample() const { 210 SkASSERT(kUnknown_GrPixelConfig != fDesc.fConfig); 211 SkASSERT(!GrPixelConfigIsCompressed(fDesc.fConfig)); 212 size_t colorBytes = GrBytesPerPixel(fDesc.fConfig); 213 SkASSERT(colorBytes > 0); 214 215 return fDesc.fWidth * fDesc.fHeight * colorBytes; 216} 217 218int GrGLRenderTarget::msaaSamples() const { 219 if (fTexFBOID == kUnresolvableFBOID || fTexFBOID != fRTFBOID) { 220 // If the render target's FBO is external (fTexFBOID == kUnresolvableFBOID), or if we own 221 // the render target's FBO (fTexFBOID == fRTFBOID) then we use the provided sample count. 222 return SkTMax(1, fDesc.fSampleCnt); 223 } 224 225 // When fTexFBOID == fRTFBOID, we either are not using MSAA, or MSAA is auto resolving, so use 226 // 0 for the sample count. 227 return 0; 228} 229 230int GrGLRenderTarget::totalSamples() const { 231 int total_samples = this->msaaSamples(); 232 233 if (fTexFBOID != kUnresolvableFBOID) { 234 // If we own the resolve buffer then that is one more sample per pixel. 235 total_samples += 1; 236 } 237 238 return total_samples; 239} 240