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 "include/core/SkTraceMemoryDump.h"
9 #include "include/gpu/GrContext.h"
10 #include "src/gpu/GrContextPriv.h"
11 #include "src/gpu/GrGpuResourcePriv.h"
12 #include "src/gpu/GrRenderTargetPriv.h"
13 #include "src/gpu/gl/GrGLGpu.h"
14 #include "src/gpu/gl/GrGLRenderTarget.h"
15 #include "src/gpu/gl/GrGLUtil.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.
GrGLRenderTarget(GrGLGpu * gpu,const SkISize & size,GrGLFormat format,GrPixelConfig config,int sampleCount,const IDs & ids,GrGLStencilAttachment * stencil)22 GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu,
23 const SkISize& size,
24 GrGLFormat format,
25 GrPixelConfig config,
26 int sampleCount,
27 const IDs& ids,
28 GrGLStencilAttachment* stencil)
29 : GrSurface(gpu, size, config, GrProtected::kNo)
30 , INHERITED(gpu, size, config, sampleCount, GrProtected::kNo, stencil) {
31 this->setFlags(gpu->glCaps(), ids);
32 this->init(format, ids);
33 this->registerWithCacheWrapped(GrWrapCacheable::kNo);
34 }
35
GrGLRenderTarget(GrGLGpu * gpu,const SkISize & size,GrGLFormat format,GrPixelConfig config,int sampleCount,const IDs & ids)36 GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu,
37 const SkISize& size,
38 GrGLFormat format,
39 GrPixelConfig config,
40 int sampleCount,
41 const IDs& ids)
42 : GrSurface(gpu, size, config, GrProtected::kNo)
43 , INHERITED(gpu, size, config, sampleCount, GrProtected::kNo) {
44 this->setFlags(gpu->glCaps(), ids);
45 this->init(format, ids);
46 }
47
setFlags(const GrGLCaps & glCaps,const IDs & idDesc)48 inline void GrGLRenderTarget::setFlags(const GrGLCaps& glCaps, const IDs& idDesc) {
49 if (!idDesc.fRTFBOID) {
50 this->setGLRTFBOIDIs0();
51 }
52 }
53
init(GrGLFormat format,const IDs & idDesc)54 void GrGLRenderTarget::init(GrGLFormat format, const IDs& idDesc) {
55 fRTFBOID = idDesc.fRTFBOID;
56 fTexFBOID = idDesc.fTexFBOID;
57 fMSColorRenderbufferID = idDesc.fMSColorRenderbufferID;
58 fRTFBOOwnership = idDesc.fRTFBOOwnership;
59 fRTFormat = format;
60 fNumSamplesOwnedPerPixel = this->totalSamples();
61 }
62
MakeWrapped(GrGLGpu * gpu,const SkISize & size,GrGLFormat format,GrPixelConfig config,int sampleCount,const IDs & idDesc,int stencilBits)63 sk_sp<GrGLRenderTarget> GrGLRenderTarget::MakeWrapped(GrGLGpu* gpu,
64 const SkISize& size,
65 GrGLFormat format,
66 GrPixelConfig config,
67 int sampleCount,
68 const IDs& 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, size.width(), size.height(), sampleCount,
80 format);
81 }
82 return sk_sp<GrGLRenderTarget>(
83 new GrGLRenderTarget(gpu, size, format, config, sampleCount, idDesc, sb));
84 }
85
getBackendRenderTarget() const86 GrBackendRenderTarget GrGLRenderTarget::getBackendRenderTarget() const {
87 GrGLFramebufferInfo fbi;
88 fbi.fFBOID = fRTFBOID;
89 fbi.fFormat = GrGLFormatToEnum(this->format());
90 int numStencilBits = 0;
91 if (GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment()) {
92 numStencilBits = stencil->bits();
93 }
94
95 return GrBackendRenderTarget(
96 this->width(), this->height(), this->numSamples(), numStencilBits, fbi);
97 }
98
backendFormat() const99 GrBackendFormat GrGLRenderTarget::backendFormat() const {
100 // We should never have a GrGLRenderTarget (even a textureable one with a target that is not
101 // texture 2D.
102 return GrBackendFormat::MakeGL(GrGLFormatToEnum(fRTFormat), GR_GL_TEXTURE_2D);
103 }
104
onGpuMemorySize() const105 size_t GrGLRenderTarget::onGpuMemorySize() const {
106 const GrCaps& caps = *this->getGpu()->caps();
107 return GrSurface::ComputeSize(caps, this->backendFormat(), this->width(), this->height(),
108 fNumSamplesOwnedPerPixel, GrMipMapped::kNo);
109 }
110
completeStencilAttachment()111 bool GrGLRenderTarget::completeStencilAttachment() {
112 GrGLGpu* gpu = this->getGLGpu();
113 const GrGLInterface* interface = gpu->glInterface();
114 GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment();
115 if (nullptr == stencil) {
116 GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
117 GR_GL_STENCIL_ATTACHMENT,
118 GR_GL_RENDERBUFFER, 0));
119 GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
120 GR_GL_DEPTH_ATTACHMENT,
121 GR_GL_RENDERBUFFER, 0));
122 #ifdef SK_DEBUG
123 if (kChromium_GrGLDriver != gpu->glContext().driver()) {
124 // This check can cause problems in Chromium if the context has been asynchronously
125 // abandoned (see skbug.com/5200)
126 GrGLenum status;
127 GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
128 SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status);
129 }
130 #endif
131 return true;
132 } else {
133 const GrGLStencilAttachment* glStencil = static_cast<const GrGLStencilAttachment*>(stencil);
134 GrGLuint rb = glStencil->renderbufferID();
135
136 gpu->invalidateBoundRenderTarget();
137 gpu->bindFramebuffer(GR_GL_FRAMEBUFFER, this->renderFBOID());
138 GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
139 GR_GL_STENCIL_ATTACHMENT,
140 GR_GL_RENDERBUFFER, rb));
141 if (glStencil->format().fPacked) {
142 GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
143 GR_GL_DEPTH_ATTACHMENT,
144 GR_GL_RENDERBUFFER, rb));
145 } else {
146 GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
147 GR_GL_DEPTH_ATTACHMENT,
148 GR_GL_RENDERBUFFER, 0));
149 }
150
151
152 #ifdef SK_DEBUG
153 if (kChromium_GrGLDriver != gpu->glContext().driver()) {
154 // This check can cause problems in Chromium if the context has been asynchronously
155 // abandoned (see skbug.com/5200)
156 GrGLenum status;
157 GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
158 SkASSERT(GR_GL_FRAMEBUFFER_COMPLETE == status);
159 }
160 #endif
161 return true;
162 }
163 }
164
onRelease()165 void GrGLRenderTarget::onRelease() {
166 if (GrBackendObjectOwnership::kBorrowed != fRTFBOOwnership) {
167 GrGLGpu* gpu = this->getGLGpu();
168 if (fTexFBOID) {
169 gpu->deleteFramebuffer(fTexFBOID);
170 }
171 if (fRTFBOID && fRTFBOID != fTexFBOID) {
172 gpu->deleteFramebuffer(fRTFBOID);
173 }
174 if (fMSColorRenderbufferID) {
175 GL_CALL(DeleteRenderbuffers(1, &fMSColorRenderbufferID));
176 }
177 }
178 fRTFBOID = 0;
179 fTexFBOID = 0;
180 fMSColorRenderbufferID = 0;
181 INHERITED::onRelease();
182 }
183
onAbandon()184 void GrGLRenderTarget::onAbandon() {
185 fRTFBOID = 0;
186 fTexFBOID = 0;
187 fMSColorRenderbufferID = 0;
188 INHERITED::onAbandon();
189 }
190
getGLGpu() const191 GrGLGpu* GrGLRenderTarget::getGLGpu() const {
192 SkASSERT(!this->wasDestroyed());
193 return static_cast<GrGLGpu*>(this->getGpu());
194 }
195
canAttemptStencilAttachment() const196 bool GrGLRenderTarget::canAttemptStencilAttachment() const {
197 if (this->getGpu()->getContext()->priv().caps()->avoidStencilBuffers()) {
198 return false;
199 }
200
201 // Only modify the FBO's attachments if we have created the FBO. Public APIs do not currently
202 // allow for borrowed FBO ownership, so we can safely assume that if an object is owned,
203 // Skia created it.
204 return this->fRTFBOOwnership == GrBackendObjectOwnership::kOwned;
205 }
206
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const207 void GrGLRenderTarget::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
208 // Don't check this->fRefsWrappedObjects, as we might be the base of a GrGLTextureRenderTarget
209 // which is multiply inherited from both ourselves and a texture. In these cases, one part
210 // (texture, rt) may be wrapped, while the other is owned by Skia.
211 bool refsWrappedRenderTargetObjects =
212 this->fRTFBOOwnership == GrBackendObjectOwnership::kBorrowed;
213 if (refsWrappedRenderTargetObjects && !traceMemoryDump->shouldDumpWrappedObjects()) {
214 return;
215 }
216
217 // Don't log the framebuffer, as the framebuffer itself doesn't contribute to meaningful
218 // memory usage. It is always a wrapper around either:
219 // - a texture, which is owned elsewhere, and will be dumped there
220 // - a renderbuffer, which will be dumped below.
221
222 // Log any renderbuffer's contribution to memory.
223 if (fMSColorRenderbufferID) {
224 const GrCaps& caps = *this->getGpu()->caps();
225 size_t size = GrSurface::ComputeSize(caps, this->backendFormat(), this->width(),
226 this->height(), this->msaaSamples(), GrMipMapped::kNo);
227
228 // Due to this resource having both a texture and a renderbuffer component, dump as
229 // skia/gpu_resources/resource_#/renderbuffer
230 SkString resourceName = this->getResourceName();
231 resourceName.append("/renderbuffer");
232
233 this->dumpMemoryStatisticsPriv(traceMemoryDump, resourceName, "RenderTarget", size);
234
235 SkString renderbuffer_id;
236 renderbuffer_id.appendU32(fMSColorRenderbufferID);
237 traceMemoryDump->setMemoryBacking(resourceName.c_str(), "gl_renderbuffer",
238 renderbuffer_id.c_str());
239 }
240 }
241
msaaSamples() const242 int GrGLRenderTarget::msaaSamples() const {
243 if (fTexFBOID == kUnresolvableFBOID || fTexFBOID != fRTFBOID) {
244 // If the render target's FBO is external (fTexFBOID == kUnresolvableFBOID), or if we own
245 // the render target's FBO (fTexFBOID == fRTFBOID) then we use the provided sample count.
246 return this->numSamples();
247 }
248
249 // When fTexFBOID == fRTFBOID, we either are not using MSAA, or MSAA is auto resolving, so use
250 // 0 for the sample count.
251 return 0;
252 }
253
totalSamples() const254 int GrGLRenderTarget::totalSamples() const {
255 int total_samples = this->msaaSamples();
256
257 if (fTexFBOID != kUnresolvableFBOID) {
258 // If we own the resolve buffer then that is one more sample per pixel.
259 total_samples += 1;
260 }
261
262 return total_samples;
263 }
264