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