/src/skia/src/gpu/gl/GrGLRenderTarget.cpp
Line | Count | Source (jump to first uncovered line) |
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 "src/gpu/gl/GrGLRenderTarget.h" |
9 | | |
10 | | #include "include/core/SkTraceMemoryDump.h" |
11 | | #include "include/gpu/GrDirectContext.h" |
12 | | #include "src/gpu/GrBackendUtils.h" |
13 | | #include "src/gpu/GrDirectContextPriv.h" |
14 | | #include "src/gpu/GrGpuResourcePriv.h" |
15 | | #include "src/gpu/GrResourceProvider.h" |
16 | | #include "src/gpu/gl/GrGLGpu.h" |
17 | | #include "src/gpu/gl/GrGLUtil.h" |
18 | | |
19 | | #define GPUGL static_cast<GrGLGpu*>(this->getGpu()) |
20 | 0 | #define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X) |
21 | | |
22 | | // Because this class is virtually derived from GrSurface we must explicitly call its constructor. |
23 | | // Constructor for wrapped render targets. |
24 | | GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, |
25 | | const SkISize& dimensions, |
26 | | GrGLFormat format, |
27 | | int sampleCount, |
28 | | const IDs& ids, |
29 | | sk_sp<GrGLAttachment> stencil) |
30 | | : GrSurface(gpu, dimensions, GrProtected::kNo) |
31 | 0 | , INHERITED(gpu, dimensions, sampleCount, GrProtected::kNo, std::move(stencil)) { |
32 | 0 | this->init(format, ids); |
33 | 0 | this->setFlags(gpu->glCaps(), ids); |
34 | 0 | this->registerWithCacheWrapped(GrWrapCacheable::kNo); |
35 | 0 | } Unexecuted instantiation: GrGLRenderTarget::GrGLRenderTarget(GrGLGpu*, SkISize const&, GrGLFormat, int, GrGLRenderTarget::IDs const&, sk_sp<GrGLAttachment>) Unexecuted instantiation: GrGLRenderTarget::GrGLRenderTarget(GrGLGpu*, SkISize const&, GrGLFormat, int, GrGLRenderTarget::IDs const&, sk_sp<GrGLAttachment>) |
36 | | |
37 | | GrGLRenderTarget::GrGLRenderTarget(GrGLGpu* gpu, |
38 | | const SkISize& dimensions, |
39 | | GrGLFormat format, |
40 | | int sampleCount, |
41 | | const IDs& ids) |
42 | | : GrSurface(gpu, dimensions, GrProtected::kNo) |
43 | 0 | , INHERITED(gpu, dimensions, sampleCount, GrProtected::kNo) { |
44 | 0 | this->init(format, ids); |
45 | 0 | this->setFlags(gpu->glCaps(), ids); |
46 | 0 | } Unexecuted instantiation: GrGLRenderTarget::GrGLRenderTarget(GrGLGpu*, SkISize const&, GrGLFormat, int, GrGLRenderTarget::IDs const&) Unexecuted instantiation: GrGLRenderTarget::GrGLRenderTarget(GrGLGpu*, SkISize const&, GrGLFormat, int, GrGLRenderTarget::IDs const&) |
47 | | |
48 | 0 | inline void GrGLRenderTarget::setFlags(const GrGLCaps& glCaps, const IDs& idDesc) { |
49 | 0 | if ((fMultisampleFBOID | fSingleSampleFBOID) == 0) { |
50 | 0 | this->setGLRTFBOIDIs0(); |
51 | 0 | } |
52 | 0 | } |
53 | | |
54 | 0 | void GrGLRenderTarget::init(GrGLFormat format, const IDs& idDesc) { |
55 | 0 | fMultisampleFBOID = idDesc.fMultisampleFBOID; |
56 | 0 | fSingleSampleFBOID = idDesc.fSingleSampleFBOID; |
57 | 0 | fMSColorRenderbufferID = idDesc.fMSColorRenderbufferID; |
58 | 0 | fRTFBOOwnership = idDesc.fRTFBOOwnership; |
59 | 0 | fRTFormat = format; |
60 | 0 | fTotalMemorySamplesPerPixel = idDesc.fTotalMemorySamplesPerPixel; |
61 | 0 | } |
62 | | |
63 | 0 | GrGLFormat stencil_bits_to_format(int stencilBits) { |
64 | 0 | SkASSERT(stencilBits); |
65 | 0 | switch (stencilBits) { |
66 | 0 | case 8: |
67 | | // We pick the packed format here so when we query total size we are at least not |
68 | | // underestimating the total size of the stencil buffer. However, in reality this |
69 | | // rarely matters since we usually don't care about the size of wrapped objects. |
70 | 0 | return GrGLFormat::kDEPTH24_STENCIL8; |
71 | 0 | case 16: |
72 | 0 | return GrGLFormat::kSTENCIL_INDEX16; |
73 | 0 | default: |
74 | 0 | SkASSERT(false); |
75 | 0 | return GrGLFormat::kUnknown; |
76 | 0 | } |
77 | 0 | } Unexecuted instantiation: stencil_bits_to_format(int) Unexecuted instantiation: stencil_bits_to_format(int) |
78 | | |
79 | | sk_sp<GrGLRenderTarget> GrGLRenderTarget::MakeWrapped(GrGLGpu* gpu, |
80 | | const SkISize& dimensions, |
81 | | GrGLFormat format, |
82 | | int sampleCount, |
83 | | const IDs& idDesc, |
84 | 0 | int stencilBits) { |
85 | 0 | sk_sp<GrGLAttachment> sb; |
86 | 0 | if (stencilBits) { |
87 | | // We pick a "fake" actual format that matches the number of stencil bits. When wrapping |
88 | | // an FBO with some number of stencil bits all we care about in the future is that we have |
89 | | // a format with the same number of stencil bits. We don't even directly use the format or |
90 | | // any other properties. Thus it is fine for us to just assign an arbitrary format that |
91 | | // matches the stencil bit count. |
92 | 0 | GrGLFormat sFmt = stencil_bits_to_format(stencilBits); |
93 | | |
94 | | // We don't have the actual renderbufferID but we need to make an attachment for the stencil |
95 | | // so we just set it to an invalid value of 0 to make sure we don't explicitly use it or try |
96 | | // and delete it. |
97 | 0 | sb = GrGLAttachment::MakeWrappedRenderBuffer(gpu, |
98 | 0 | /*renderbufferID=*/0, |
99 | 0 | dimensions, |
100 | 0 | GrAttachment::UsageFlags::kStencilAttachment, |
101 | 0 | sampleCount, |
102 | 0 | sFmt); |
103 | 0 | } |
104 | 0 | return sk_sp<GrGLRenderTarget>( |
105 | 0 | new GrGLRenderTarget(gpu, dimensions, format, sampleCount, idDesc, std::move(sb))); |
106 | 0 | } |
107 | | |
108 | 0 | GrBackendRenderTarget GrGLRenderTarget::getBackendRenderTarget() const { |
109 | 0 | bool useMultisampleFBO = (this->numSamples() > 1); |
110 | 0 | GrGLFramebufferInfo fbi; |
111 | 0 | fbi.fFBOID = (useMultisampleFBO) ? fMultisampleFBOID : fSingleSampleFBOID; |
112 | 0 | fbi.fFormat = GrGLFormatToEnum(this->format()); |
113 | 0 | int numStencilBits = 0; |
114 | 0 | if (GrAttachment* stencil = this->getStencilAttachment(useMultisampleFBO)) { |
115 | 0 | numStencilBits = GrBackendFormatStencilBits(stencil->backendFormat()); |
116 | 0 | } |
117 | |
|
118 | 0 | return GrBackendRenderTarget( |
119 | 0 | this->width(), this->height(), this->numSamples(), numStencilBits, fbi); |
120 | 0 | } |
121 | | |
122 | 0 | GrBackendFormat GrGLRenderTarget::backendFormat() const { |
123 | | // We should never have a GrGLRenderTarget (even a textureable one with a target that is not |
124 | | // texture 2D. |
125 | 0 | return GrBackendFormat::MakeGL(GrGLFormatToEnum(fRTFormat), GR_GL_TEXTURE_2D); |
126 | 0 | } |
127 | | |
128 | 0 | size_t GrGLRenderTarget::onGpuMemorySize() const { |
129 | 0 | return GrSurface::ComputeSize(this->backendFormat(), this->dimensions(), |
130 | 0 | fTotalMemorySamplesPerPixel, GrMipmapped::kNo); |
131 | 0 | } |
132 | | |
133 | 0 | bool GrGLRenderTarget::completeStencilAttachment(GrAttachment* stencil, bool useMultisampleFBO) { |
134 | 0 | GrGLGpu* gpu = this->getGLGpu(); |
135 | 0 | const GrGLInterface* interface = gpu->glInterface(); |
136 | |
|
137 | 0 | if (this->numSamples() == 1 && useMultisampleFBO) { |
138 | | // We will be rendering to the dynamic msaa fbo. Make sure to initialize it first. |
139 | 0 | if (!this->ensureDynamicMSAAAttachment()) { |
140 | 0 | return false; |
141 | 0 | } |
142 | 0 | } |
143 | | |
144 | 0 | GrGLuint stencilFBOID = (useMultisampleFBO) ? fMultisampleFBOID : fSingleSampleFBOID; |
145 | 0 | gpu->bindFramebuffer(GR_GL_FRAMEBUFFER, stencilFBOID); |
146 | |
|
147 | 0 | if (nullptr == stencil) { |
148 | 0 | GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, |
149 | 0 | GR_GL_STENCIL_ATTACHMENT, |
150 | 0 | GR_GL_RENDERBUFFER, 0)); |
151 | 0 | GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, |
152 | 0 | GR_GL_DEPTH_ATTACHMENT, |
153 | 0 | GR_GL_RENDERBUFFER, 0)); |
154 | 0 | } else { |
155 | 0 | const GrGLAttachment* glStencil = static_cast<const GrGLAttachment*>(stencil); |
156 | 0 | GrGLuint rb = glStencil->renderbufferID(); |
157 | 0 | GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, |
158 | 0 | GR_GL_STENCIL_ATTACHMENT, |
159 | 0 | GR_GL_RENDERBUFFER, rb)); |
160 | 0 | if (GrGLFormatIsPackedDepthStencil(glStencil->format())) { |
161 | 0 | GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, |
162 | 0 | GR_GL_DEPTH_ATTACHMENT, |
163 | 0 | GR_GL_RENDERBUFFER, rb)); |
164 | 0 | } else { |
165 | 0 | GR_GL_CALL(interface, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, |
166 | 0 | GR_GL_DEPTH_ATTACHMENT, |
167 | 0 | GR_GL_RENDERBUFFER, 0)); |
168 | 0 | } |
169 | 0 | } |
170 | |
|
171 | | #ifdef SK_DEBUG |
172 | 0 | if (!gpu->glCaps().skipErrorChecks()) { |
173 | 0 | GrGLenum status; |
174 | 0 | GR_GL_CALL_RET(interface, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); |
175 | 0 | if (status != GR_GL_FRAMEBUFFER_COMPLETE) { |
176 | | // This can fail if the context has been asynchronously abandoned (see skbug.com/5200). |
177 | 0 | return false; |
178 | 0 | } |
179 | 0 | } |
180 | | #endif |
181 | | |
182 | 0 | return true; |
183 | 0 | } Unexecuted instantiation: GrGLRenderTarget::completeStencilAttachment(GrAttachment*, bool) Unexecuted instantiation: GrGLRenderTarget::completeStencilAttachment(GrAttachment*, bool) |
184 | | |
185 | 0 | bool GrGLRenderTarget::ensureDynamicMSAAAttachment() { |
186 | 0 | SkASSERT(this->numSamples() == 1); |
187 | 0 | if (fMultisampleFBOID) { |
188 | 0 | return true; |
189 | 0 | } |
190 | 0 | SkASSERT(!fDynamicMSAAAttachment); |
191 | |
|
192 | 0 | GrResourceProvider* resourceProvider = this->getContext()->priv().resourceProvider(); |
193 | 0 | const GrCaps& caps = *this->getGpu()->caps(); |
194 | |
|
195 | 0 | int internalSampleCount = caps.internalMultisampleCount(this->backendFormat()); |
196 | 0 | if (internalSampleCount <= 1) { |
197 | 0 | return false; |
198 | 0 | } |
199 | | |
200 | 0 | GL_CALL(GenFramebuffers(1, &fMultisampleFBOID)); |
201 | 0 | if (!fMultisampleFBOID) { |
202 | 0 | return false; |
203 | 0 | } |
204 | | |
205 | 0 | this->getGLGpu()->bindFramebuffer(GR_GL_FRAMEBUFFER, fMultisampleFBOID); |
206 | |
|
207 | 0 | if (resourceProvider->caps()->msaaResolvesAutomatically()) { |
208 | 0 | if (GrGLTexture* glTex = static_cast<GrGLTexture*>(this->asTexture())) { |
209 | 0 | GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, |
210 | 0 | glTex->target(), glTex->textureID(), |
211 | 0 | 0 /*mipMapLevel*/, internalSampleCount)); |
212 | 0 | return true; |
213 | 0 | } |
214 | 0 | } |
215 | | |
216 | 0 | fDynamicMSAAAttachment.reset( |
217 | 0 | static_cast<GrGLAttachment*>(resourceProvider->getDiscardableMSAAAttachment( |
218 | 0 | this->dimensions(), this->backendFormat(), internalSampleCount, |
219 | 0 | GrProtected(this->isProtected())).release())); |
220 | 0 | if (!fDynamicMSAAAttachment) { |
221 | 0 | return false; |
222 | 0 | } |
223 | | |
224 | 0 | GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_RENDERBUFFER, |
225 | 0 | fDynamicMSAAAttachment->renderbufferID())); |
226 | 0 | return true; |
227 | 0 | } Unexecuted instantiation: GrGLRenderTarget::ensureDynamicMSAAAttachment() Unexecuted instantiation: GrGLRenderTarget::ensureDynamicMSAAAttachment() |
228 | | |
229 | 0 | void GrGLRenderTarget::onRelease() { |
230 | 0 | if (GrBackendObjectOwnership::kBorrowed != fRTFBOOwnership) { |
231 | 0 | GrGLGpu* gpu = this->getGLGpu(); |
232 | 0 | if (fSingleSampleFBOID) { |
233 | 0 | SkASSERT(fSingleSampleFBOID != fMultisampleFBOID); |
234 | 0 | gpu->deleteFramebuffer(fSingleSampleFBOID); |
235 | 0 | } |
236 | 0 | if (fMultisampleFBOID) { |
237 | 0 | SkASSERT(fMultisampleFBOID != fSingleSampleFBOID); |
238 | 0 | gpu->deleteFramebuffer(fMultisampleFBOID); |
239 | 0 | } |
240 | 0 | if (fMSColorRenderbufferID) { |
241 | 0 | GL_CALL(DeleteRenderbuffers(1, &fMSColorRenderbufferID)); |
242 | 0 | } |
243 | 0 | } |
244 | 0 | fMultisampleFBOID = 0; |
245 | 0 | fSingleSampleFBOID = 0; |
246 | 0 | fMSColorRenderbufferID = 0; |
247 | 0 | INHERITED::onRelease(); |
248 | 0 | } Unexecuted instantiation: GrGLRenderTarget::onRelease() Unexecuted instantiation: GrGLRenderTarget::onRelease() |
249 | | |
250 | 0 | void GrGLRenderTarget::onAbandon() { |
251 | 0 | fMultisampleFBOID = 0; |
252 | 0 | fSingleSampleFBOID = 0; |
253 | 0 | fMSColorRenderbufferID = 0; |
254 | 0 | INHERITED::onAbandon(); |
255 | 0 | } |
256 | | |
257 | 0 | GrGLGpu* GrGLRenderTarget::getGLGpu() const { |
258 | 0 | SkASSERT(!this->wasDestroyed()); |
259 | 0 | return static_cast<GrGLGpu*>(this->getGpu()); |
260 | 0 | } Unexecuted instantiation: GrGLRenderTarget::getGLGpu() const Unexecuted instantiation: GrGLRenderTarget::getGLGpu() const |
261 | | |
262 | 0 | bool GrGLRenderTarget::canAttemptStencilAttachment(bool useMultisampleFBO) const { |
263 | | // This cap should have been handled at a higher level. |
264 | 0 | SkASSERT(!this->getGpu()->getContext()->priv().caps()->avoidStencilBuffers()); |
265 | | // Only modify the FBO's attachments if we have created the FBO. Public APIs do not currently |
266 | | // allow for borrowed FBO ownership, so we can safely assume that if an object is owned, |
267 | | // Skia created it. |
268 | 0 | return this->fRTFBOOwnership == GrBackendObjectOwnership::kOwned || |
269 | | // The dmsaa attachment is always owned and always supports adding stencil. |
270 | 0 | (this->numSamples() == 1 && useMultisampleFBO); |
271 | 0 | } Unexecuted instantiation: GrGLRenderTarget::canAttemptStencilAttachment(bool) const Unexecuted instantiation: GrGLRenderTarget::canAttemptStencilAttachment(bool) const |
272 | | |
273 | 0 | void GrGLRenderTarget::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const { |
274 | | // Don't check this->fRefsWrappedObjects, as we might be the base of a GrGLTextureRenderTarget |
275 | | // which is multiply inherited from both ourselves and a texture. In these cases, one part |
276 | | // (texture, rt) may be wrapped, while the other is owned by Skia. |
277 | 0 | bool refsWrappedRenderTargetObjects = |
278 | 0 | this->fRTFBOOwnership == GrBackendObjectOwnership::kBorrowed; |
279 | 0 | if (refsWrappedRenderTargetObjects && !traceMemoryDump->shouldDumpWrappedObjects()) { |
280 | 0 | return; |
281 | 0 | } |
282 | | |
283 | 0 | int numSamplesNotInTexture = fTotalMemorySamplesPerPixel; |
284 | 0 | if (this->asTexture()) { |
285 | 0 | --numSamplesNotInTexture; // GrGLTexture::dumpMemoryStatistics accounts for 1 sample. |
286 | 0 | } |
287 | 0 | if (numSamplesNotInTexture >= 1) { |
288 | 0 | size_t size = GrSurface::ComputeSize(this->backendFormat(), this->dimensions(), |
289 | 0 | numSamplesNotInTexture, GrMipmapped::kNo); |
290 | | |
291 | | // Due to this resource having both a texture and a renderbuffer component, dump as |
292 | | // skia/gpu_resources/resource_#/renderbuffer |
293 | 0 | SkString resourceName = this->getResourceName(); |
294 | 0 | resourceName.append("/renderbuffer"); |
295 | |
|
296 | 0 | this->dumpMemoryStatisticsPriv(traceMemoryDump, resourceName, "RenderTarget", size); |
297 | |
|
298 | 0 | SkString renderbuffer_id; |
299 | 0 | renderbuffer_id.appendU32(fMSColorRenderbufferID); |
300 | 0 | traceMemoryDump->setMemoryBacking(resourceName.c_str(), "gl_renderbuffer", |
301 | 0 | renderbuffer_id.c_str()); |
302 | 0 | } |
303 | 0 | } |