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