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