Flutter Engine
The Flutter Engine
GrGLRenderTarget.cpp
Go to the documentation of this file.
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
9
19
20#define GPUGL static_cast<GrGLGpu*>(this->getGpu())
21#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
22#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(GPUGL->glInterface(), RET, X)
23
24// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
25// Constructor for wrapped render targets.
27 const SkISize& dimensions,
29 int sampleCount,
30 const IDs& ids,
32 skgpu::Protected isProtected,
33 std::string_view label)
34 : GrSurface(gpu, dimensions, isProtected, label)
35 , GrRenderTarget(gpu, dimensions, sampleCount, isProtected, label, std::move(stencil)) {
36 this->init(format, ids);
37 this->setFlags(gpu->glCaps(), ids);
38 this->registerWithCacheWrapped(GrWrapCacheable::kNo);
39}
40
42 const SkISize& dimensions,
44 int sampleCount,
45 const IDs& ids,
46 skgpu::Protected isProtected,
47 std::string_view label)
48 : GrSurface(gpu, dimensions, isProtected, label)
49 , GrRenderTarget(gpu, dimensions, sampleCount, isProtected, label) {
50 this->init(format, ids);
51 this->setFlags(gpu->glCaps(), ids);
52}
53
54inline void GrGLRenderTarget::setFlags(const GrGLCaps& glCaps, const IDs& idDesc) {
55 if ((fMultisampleFBOID | fSingleSampleFBOID) == 0) {
56 this->setGLRTFBOIDIs0();
57 }
58}
59
61 fMultisampleFBOID = idDesc.fMultisampleFBOID;
62 fSingleSampleFBOID = idDesc.fSingleSampleFBOID;
63 fMSColorRenderbufferID = idDesc.fMSColorRenderbufferID;
64 fRTFBOOwnership = idDesc.fRTFBOOwnership;
65 fRTFormat = format;
66 fTotalMemorySamplesPerPixel = idDesc.fTotalMemorySamplesPerPixel;
67}
68
70 SkASSERT(stencilBits);
71 switch (stencilBits) {
72 case 8:
73 // We pick the packed format here so when we query total size we are at least not
74 // underestimating the total size of the stencil buffer. However, in reality this
75 // rarely matters since we usually don't care about the size of wrapped objects.
77 case 16:
79 default:
80 SkASSERT(false);
82 }
83}
84
86 const SkISize& dimensions,
88 int sampleCount,
89 const IDs& idDesc,
90 int stencilBits,
91 skgpu::Protected isProtected,
92 std::string_view label) {
94 if (stencilBits) {
95 // We pick a "fake" actual format that matches the number of stencil bits. When wrapping
96 // an FBO with some number of stencil bits all we care about in the future is that we have
97 // a format with the same number of stencil bits. We don't even directly use the format or
98 // any other properties. Thus it is fine for us to just assign an arbitrary format that
99 // matches the stencil bit count.
100 GrGLFormat sFmt = stencil_bits_to_format(stencilBits);
101
102 // We don't have the actual renderbufferID but we need to make an attachment for the stencil
103 // so we just set it to an invalid value of 0 to make sure we don't explicitly use it or try
104 // and delete it.
106 /*renderbufferID=*/0,
109 sampleCount,
110 sFmt);
111 }
113 gpu, dimensions, format, sampleCount, idDesc, std::move(sb), isProtected, label));
114}
115
117 bool useMultisampleFBO = (this->numSamples() > 1);
119 fbi.fFBOID = (useMultisampleFBO) ? fMultisampleFBOID : fSingleSampleFBOID;
120 fbi.fFormat = GrGLFormatToEnum(this->format());
122 int numStencilBits = 0;
123 if (GrAttachment* stencil = this->getStencilAttachment(useMultisampleFBO)) {
124 numStencilBits = GrBackendFormatStencilBits(stencil->backendFormat());
125 }
126
128 this->width(), this->height(), this->numSamples(), numStencilBits, fbi);
129}
130
132 // We should never have a GrGLRenderTarget (even a textureable one with a target that is not
133 // texture 2D.
135}
136
137size_t GrGLRenderTarget::onGpuMemorySize() const {
139 this->dimensions(),
140 fTotalMemorySamplesPerPixel,
142}
143
144void GrGLRenderTarget::onSetLabel() {
145 SkASSERT(fMSColorRenderbufferID);
146 SkASSERT(fRTFBOOwnership == GrBackendObjectOwnership::kOwned);
147}
148
149bool GrGLRenderTarget::completeStencilAttachment(GrAttachment* stencil, bool useMultisampleFBO) {
150 // We defer attaching the new stencil buffer until the next time our framebuffer is bound.
151 if (this->getStencilAttachment(useMultisampleFBO) != stencil) {
152 fNeedsStencilAttachmentBind[useMultisampleFBO] = true;
153 }
154 return true;
155}
156
158 SkASSERT(this->numSamples() == 1);
159 if (fMultisampleFBOID) {
160 return true;
161 }
162 SkASSERT(!fDynamicMSAAAttachment);
163
164 GrResourceProvider* resourceProvider = this->getContext()->priv().resourceProvider();
165 const GrCaps& caps = *this->getGpu()->caps();
166
167 int internalSampleCount = caps.internalMultisampleCount(this->backendFormat());
168 if (internalSampleCount <= 1) {
169 return false;
170 }
171
172 if (resourceProvider->caps()->msaaResolvesAutomatically() && this->asTexture()) {
173 // We can use EXT_multisampled_render_to_texture for MSAA. We will configure the FBO as MSAA
174 // or not during bindFBO().
175 fMultisampleFBOID = fSingleSampleFBOID;
176 return true;
177 }
178
179 GL_CALL(GenFramebuffers(1, &fMultisampleFBOID));
180 if (!fMultisampleFBOID) {
181 return false;
182 }
183
184 this->getGLGpu()->bindFramebuffer(GR_GL_FRAMEBUFFER, fMultisampleFBOID);
185
186 fDynamicMSAAAttachment.reset(
187 static_cast<GrGLAttachment*>(resourceProvider->getDiscardableMSAAAttachment(
188 this->dimensions(), this->backendFormat(), internalSampleCount,
189 GrProtected(this->isProtected()), GrMemoryless::kNo).release()));
190 if (!fDynamicMSAAAttachment) {
191 return false;
192 }
193
195 fDynamicMSAAAttachment->renderbufferID()));
196 return true;
197}
198
199void GrGLRenderTarget::bindInternal(GrGLenum fboTarget, bool useMultisampleFBO) {
200 GrGLuint fboId = useMultisampleFBO ? fMultisampleFBOID : fSingleSampleFBOID;
201 this->getGLGpu()->bindFramebuffer(fboTarget, fboId);
202
203 if (fSingleSampleFBOID != 0 &&
204 fSingleSampleFBOID == fMultisampleFBOID &&
205 useMultisampleFBO != fDMSAARenderToTextureFBOIsMultisample) {
206 auto* glTex = static_cast<GrGLTexture*>(this->asTexture());
208 GL_CALL(FramebufferTexture2D(fboTarget,
211 0 /*texture*/,
212 0 /*mipMapLevel*/));
213 }
214 if (useMultisampleFBO) {
215 int sampleCount = this->numSamples() > 1 ?
216 this->numSamples() :
218 GL_CALL(FramebufferTexture2DMultisample(fboTarget,
220 glTex->target(),
221 glTex->textureID(),
222 0 /*mipMapLevel*/,
223 sampleCount));
224 } else {
225 GL_CALL(FramebufferTexture2D(fboTarget,
227 glTex->target(),
228 glTex->textureID(),
229 0 /*mipMapLevel*/));
230 }
231 fDMSAARenderToTextureFBOIsMultisample = useMultisampleFBO;
232 fNeedsStencilAttachmentBind[useMultisampleFBO] = true;
233 }
234
235 // Make sure the stencil attachment is valid. Even though a color buffer op doesn't use stencil,
236 // our FBO still needs to be "framebuffer complete".
237 if (fNeedsStencilAttachmentBind[useMultisampleFBO]) {
238 if (auto stencil = this->getStencilAttachment(useMultisampleFBO)) {
239 const GrGLAttachment* glStencil = static_cast<const GrGLAttachment*>(stencil);
240 GL_CALL(FramebufferRenderbuffer(fboTarget,
243 glStencil->renderbufferID()));
244 if (GrGLFormatIsPackedDepthStencil(glStencil->format())) {
245 GL_CALL(FramebufferRenderbuffer(fboTarget,
248 glStencil->renderbufferID()));
249 } else {
250 GL_CALL(FramebufferRenderbuffer(fboTarget,
253 0));
254 }
255 } else {
256 GL_CALL(FramebufferRenderbuffer(fboTarget,
259 0));
260 GL_CALL(FramebufferRenderbuffer(fboTarget,
263 0));
264 }
265#ifdef SK_DEBUG
266 if (!this->getGLGpu()->glCaps().skipErrorChecks() &&
267 !this->getGLGpu()->glCaps().rebindColorAttachmentAfterCheckFramebufferStatus()) {
268 GrGLenum status;
269 GL_CALL_RET(status, CheckFramebufferStatus(fboTarget));
270 if (status != GR_GL_FRAMEBUFFER_COMPLETE) {
271 // This can fail if the context has been asynchronously abandoned (see
272 // skbug.com/5200).
273 SkDebugf("WARNING: failed to attach stencil.\n");
274 }
275 }
276#endif
277 fNeedsStencilAttachmentBind[useMultisampleFBO] = false;
278 }
279}
280
282 // If the multisample FBO is nonzero, it means we always have something to resolve (even if the
283 // single sample buffer is FBO 0). If it's zero, then there's nothing to resolve.
284 SkASSERT(fMultisampleFBOID != 0);
285
286 // In the EXT_multisampled_render_to_texture case, we shouldn't be resolving anything.
288
289 if (resolveDirection == GrGLGpu::ResolveDirection::kMSAAToSingle) {
292 } else {
294 SkASSERT(this->getGLGpu()->glCaps().canResolveSingleToMSAA());
297 }
298}
299
301 if (GrBackendObjectOwnership::kBorrowed != fRTFBOOwnership) {
302 GrGLGpu* gpu = this->getGLGpu();
303 if (fSingleSampleFBOID) {
304 gpu->deleteFramebuffer(fSingleSampleFBOID);
305 }
306 if (fMultisampleFBOID && fMultisampleFBOID != fSingleSampleFBOID) {
307 gpu->deleteFramebuffer(fMultisampleFBOID);
308 }
309 if (fMSColorRenderbufferID) {
310 GL_CALL(DeleteRenderbuffers(1, &fMSColorRenderbufferID));
311 }
312 }
313 fMultisampleFBOID = 0;
314 fSingleSampleFBOID = 0;
315 fMSColorRenderbufferID = 0;
317}
318
320 fMultisampleFBOID = 0;
321 fSingleSampleFBOID = 0;
322 fMSColorRenderbufferID = 0;
324}
325
326GrGLGpu* GrGLRenderTarget::getGLGpu() const {
327 SkASSERT(!this->wasDestroyed());
328 return static_cast<GrGLGpu*>(this->getGpu());
329}
330
331bool GrGLRenderTarget::canAttemptStencilAttachment(bool useMultisampleFBO) const {
332 // This cap should have been handled at a higher level.
333 SkASSERT(!this->getGpu()->getContext()->priv().caps()->avoidStencilBuffers());
334 // Only modify the FBO's attachments if we have created the FBO. Public APIs do not currently
335 // allow for borrowed FBO ownership, so we can safely assume that if an object is owned,
336 // Skia created it.
337 return this->fRTFBOOwnership == GrBackendObjectOwnership::kOwned ||
338 // The dmsaa attachment is always owned and always supports adding stencil.
339 (this->numSamples() == 1 && useMultisampleFBO);
340}
341
343 // Don't check this->fRefsWrappedObjects, as we might be the base of a GrGLTextureRenderTarget
344 // which is multiply inherited from both ourselves and a texture. In these cases, one part
345 // (texture, rt) may be wrapped, while the other is owned by Skia.
346 bool refsWrappedRenderTargetObjects =
347 this->fRTFBOOwnership == GrBackendObjectOwnership::kBorrowed;
348 if (refsWrappedRenderTargetObjects && !traceMemoryDump->shouldDumpWrappedObjects()) {
349 return;
350 }
351
352 int numSamplesNotInTexture = fTotalMemorySamplesPerPixel;
353 if (this->asTexture()) {
354 --numSamplesNotInTexture; // GrGLTexture::dumpMemoryStatistics accounts for 1 sample.
355 }
356 if (numSamplesNotInTexture >= 1) {
358 this->dimensions(),
359 numSamplesNotInTexture,
361
362 // Due to this resource having both a texture and a renderbuffer component, dump as
363 // skia/gpu_resources/resource_#/renderbuffer
364 SkString resourceName = this->getResourceName();
365 resourceName.append("/renderbuffer");
366
367 this->dumpMemoryStatisticsPriv(traceMemoryDump, resourceName, "RenderTarget", size);
368
369 SkString renderbuffer_id;
370 renderbuffer_id.appendU32(fMSColorRenderbufferID);
371 traceMemoryDump->setMemoryBacking(resourceName.c_str(), "gl_renderbuffer",
372 renderbuffer_id.c_str());
373 }
374}
int GrBackendFormatStencilBits(const GrBackendFormat &format)
#define GR_GL_DRAW_FRAMEBUFFER
Definition: GrGLDefines.h:901
#define GR_GL_READ_FRAMEBUFFER
Definition: GrGLDefines.h:900
#define GR_GL_TEXTURE_2D
Definition: GrGLDefines.h:152
#define GR_GL_RENDERBUFFER
Definition: GrGLDefines.h:903
#define GR_GL_STENCIL_ATTACHMENT
Definition: GrGLDefines.h:935
#define GR_GL_DEPTH_ATTACHMENT
Definition: GrGLDefines.h:934
#define GR_GL_FRAMEBUFFER_COMPLETE
Definition: GrGLDefines.h:945
#define GR_GL_FRAMEBUFFER
Definition: GrGLDefines.h:899
#define GR_GL_COLOR_ATTACHMENT0
Definition: GrGLDefines.h:933
GrGLFormat stencil_bits_to_format(int stencilBits)
#define GL_CALL(X)
#define GL_CALL_RET(RET, X)
GrGLFormat
Definition: GrGLTypes.h:59
unsigned int GrGLuint
Definition: GrGLTypes.h:113
unsigned int GrGLenum
Definition: GrGLTypes.h:102
static constexpr GrGLenum GrGLFormatToEnum(GrGLFormat format)
Definition: GrGLUtil.h:445
static constexpr bool GrGLFormatIsPackedDepthStencil(GrGLFormat format)
Definition: GrGLUtil.h:552
#define SkASSERT(cond)
Definition: SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
Definition: GrCaps.h:57
bool msaaResolvesAutomatically() const
Definition: GrCaps.h:100
int internalMultisampleCount(const GrBackendFormat &format) const
Definition: GrCaps.h:271
GrResourceProvider * resourceProvider()
GrDirectContextPriv priv()
GrGLuint renderbufferID() const
static sk_sp< GrGLAttachment > MakeWrappedRenderBuffer(GrGpu *gpu, GrGLuint renderbufferID, SkISize dimensions, UsageFlags supportedUsages, int sampleCnt, GrGLFormat format)
GrGLFormat format() const
bool bindTexture0WhenChangingTextureFBOMultisampleCount() const
Definition: GrGLCaps.h:450
const GrGLCaps & glCaps() const
Definition: GrGLGpu.h:108
void bindFramebuffer(GrGLenum fboTarget, GrGLuint fboid)
Definition: GrGLGpu.cpp:3195
void deleteFramebuffer(GrGLuint fboid)
Definition: GrGLGpu.cpp:3203
bool canAttemptStencilAttachment(bool useMultisampleFBO) const override
void bindForResolve(ResolveDirection)
void onAbandon() override
GrGLRenderTarget(GrGLGpu *, const SkISize &, GrGLFormat, int sampleCount, const IDs &, skgpu::Protected, std::string_view label)
static sk_sp< GrGLRenderTarget > MakeWrapped(GrGLGpu *, const SkISize &, GrGLFormat, int sampleCount, const IDs &, int stencilBits, skgpu::Protected, std::string_view label)
void bindInternal(GrGLenum fboTarget, bool useMultisampleFBO)
GrBackendRenderTarget getBackendRenderTarget() const override
GrBackendFormat backendFormat() const override
GrGLFormat format() const
void init(GrGLFormat, const IDs &)
void dumpMemoryStatistics(SkTraceMemoryDump *traceMemoryDump) const override
bool ensureDynamicMSAAAttachment()
bool isMultisampledRenderToTexture() const
void onRelease() override
GrGpu * getGpu() const
void dumpMemoryStatisticsPriv(SkTraceMemoryDump *traceMemoryDump, const SkString &resourceName, const char *type, size_t size) const
const GrDirectContext * getContext() const
bool wasDestroyed() const
SkString getResourceName() const
const GrCaps * caps() const
Definition: GrGpu.h:73
GrAttachment * getStencilAttachment() const
void onAbandon() override
void onRelease() override
int numSamples() const
int numStencilBits(bool useMSAASurface) const
sk_sp< GrAttachment > getDiscardableMSAAAttachment(SkISize dimensions, const GrBackendFormat &format, int sampleCnt, skgpu::Protected isProtected, GrMemoryless memoryless)
const GrCaps * caps() const
SkISize dimensions() const
Definition: GrSurface.h:27
bool isProtected() const
Definition: GrSurface.h:87
int height() const
Definition: GrSurface.h:37
static size_t ComputeSize(const GrBackendFormat &, SkISize dimensions, int colorSamplesPerPixel, skgpu::Mipmapped, bool binSize=false)
Definition: GrSurface.cpp:21
void setGLRTFBOIDIs0()
Definition: GrSurface.h:111
virtual GrTexture * asTexture()
Definition: GrSurface.h:59
int width() const
Definition: GrSurface.h:32
void append(const char text[])
Definition: SkString.h:203
void appendU32(uint32_t value)
Definition: SkString.h:210
const char * c_str() const
Definition: SkString.h:133
virtual void setMemoryBacking(const char *dumpName, const char *backingType, const char *backingObjectId)=0
virtual bool shouldDumpWrappedObjects() const
void reset(T *ptr=nullptr)
Definition: SkRefCnt.h:310
FlPixelBufferTexturePrivate * priv
uint32_t uint32_t * format
SK_API GrBackendFormat MakeGL(GrGLenum format, GrGLenum target)
SK_API GrBackendRenderTarget MakeGL(int width, int height, int sampleCnt, int stencilBits, const GrGLFramebufferInfo &glInfo)
static bool init()
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Protected
Definition: GpuTypes.h:61
Definition: ref_ptr.h:256
skgpu::Protected fProtected
Definition: GrGLTypes.h:199
GrBackendObjectOwnership fRTFBOOwnership
Definition: SkSize.h:16