GrGLRenderTarget.cpp revision 94c0468b2b4255e3beed81efdcfbf6d9d39e11e4
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.
22GrGLRenderTarget::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
32GrGLRenderTarget::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
39inline 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 (GrCaps::WindowRectsSupport::kNone != glCaps.windowRectsSupport() && idDesc.fRTFBOID) {
47        flags |= GrRenderTargetFlags::kWindowRectsSupport;
48    }
49    return flags;
50}
51
52void 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
66sk_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
85size_t GrGLRenderTarget::onGpuMemorySize() const {
86    return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
87                                  fNumSamplesOwnedPerPixel, GrMipMapped::kNo);
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    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
185void 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(), GrMipMapped::kNo);
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
214int 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
226int 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