1 /*
2 * Copyright 2016 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/ganesh/GrRenderTargetProxy.h"
9
10 #include "include/core/SkSize.h"
11 #include "include/gpu/GpuTypes.h"
12 #include "include/gpu/ganesh/GrBackendSurface.h"
13 #include "include/gpu/ganesh/GrTypes.h"
14 #include "include/private/base/SkTo.h"
15 #include "src/gpu/SkBackingFit.h"
16 #include "src/gpu/ganesh/GrCaps.h"
17 #include "src/gpu/ganesh/GrGpuResourcePriv.h"
18 #include "src/gpu/ganesh/GrRenderTarget.h"
19 #include "src/gpu/ganesh/GrSurface.h"
20 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
21
22 #include <utility>
23
24 #ifdef SK_DEBUG
25 #include "include/gpu/ganesh/GrDirectContext.h"
26 #include "src/gpu/ganesh/GrDirectContextPriv.h"
27 #endif
28
29 // Deferred version
30 // TODO: we can probably munge the 'desc' in both the wrapped and deferred
31 // cases to make the sampleConfig/numSamples stuff more rational.
GrRenderTargetProxy(const GrCaps & caps,const GrBackendFormat & format,SkISize dimensions,int sampleCount,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected,GrInternalSurfaceFlags surfaceFlags,UseAllocator useAllocator,std::string_view label)32 GrRenderTargetProxy::GrRenderTargetProxy(const GrCaps& caps,
33 const GrBackendFormat& format,
34 SkISize dimensions,
35 int sampleCount,
36 SkBackingFit fit,
37 skgpu::Budgeted budgeted,
38 GrProtected isProtected,
39 GrInternalSurfaceFlags surfaceFlags,
40 UseAllocator useAllocator,
41 std::string_view label)
42 : INHERITED(
43 format, dimensions, fit, budgeted, isProtected, surfaceFlags, useAllocator, label)
44 , fSampleCnt(sampleCount)
45 , fWrapsVkSecondaryCB(WrapsVkSecondaryCB::kNo) {}
46
47 // Lazy-callback version
GrRenderTargetProxy(LazyInstantiateCallback && callback,const GrBackendFormat & format,SkISize dimensions,int sampleCount,SkBackingFit fit,skgpu::Budgeted budgeted,GrProtected isProtected,GrInternalSurfaceFlags surfaceFlags,UseAllocator useAllocator,WrapsVkSecondaryCB wrapsVkSecondaryCB,std::string_view label)48 GrRenderTargetProxy::GrRenderTargetProxy(LazyInstantiateCallback&& callback,
49 const GrBackendFormat& format,
50 SkISize dimensions,
51 int sampleCount,
52 SkBackingFit fit,
53 skgpu::Budgeted budgeted,
54 GrProtected isProtected,
55 GrInternalSurfaceFlags surfaceFlags,
56 UseAllocator useAllocator,
57 WrapsVkSecondaryCB wrapsVkSecondaryCB,
58 std::string_view label)
59 : INHERITED(std::move(callback),
60 format,
61 dimensions,
62 fit,
63 budgeted,
64 isProtected,
65 surfaceFlags,
66 useAllocator,
67 label)
68 , fSampleCnt(sampleCount)
69 , fWrapsVkSecondaryCB(wrapsVkSecondaryCB) {}
70
71 // Wrapped version
GrRenderTargetProxy(sk_sp<GrSurface> surf,UseAllocator useAllocator,WrapsVkSecondaryCB wrapsVkSecondaryCB)72 GrRenderTargetProxy::GrRenderTargetProxy(sk_sp<GrSurface> surf,
73 UseAllocator useAllocator,
74 WrapsVkSecondaryCB wrapsVkSecondaryCB)
75 : INHERITED(std::move(surf), SkBackingFit::kExact, useAllocator)
76 , fSampleCnt(fTarget->asRenderTarget()->numSamples())
77 , fWrapsVkSecondaryCB(wrapsVkSecondaryCB) {
78 // The kRequiresManualMSAAResolve flag better not be set if we are not multisampled or if
79 // MSAA resolve should happen automatically.
80 //
81 // From the other side, we don't know enough about the wrapped surface to assert when
82 // kRequiresManualMSAAResolve *should* be set. e.g., The caller might be wrapping a backend
83 // texture as a render target at this point but we wouldn't know it.
84 SkASSERT(!(this->numSamples() <= 1 ||
85 fTarget->getContext()->priv().caps()->msaaResolvesAutomatically()) ||
86 !this->requiresManualMSAAResolve());
87 }
88
maxWindowRectangles(const GrCaps & caps) const89 int GrRenderTargetProxy::maxWindowRectangles(const GrCaps& caps) const {
90 return this->glRTFBOIDIs0() ? 0 : caps.maxWindowRectangles();
91 }
92
instantiate(GrResourceProvider * resourceProvider)93 bool GrRenderTargetProxy::instantiate(GrResourceProvider* resourceProvider) {
94 if (this->isLazy()) {
95 return false;
96 }
97 if (!this->instantiateImpl(resourceProvider, fSampleCnt, GrRenderable::kYes,
98 skgpu::Mipmapped::kNo, nullptr)) {
99 return false;
100 }
101
102 SkASSERT(this->peekRenderTarget());
103 SkASSERT(!this->peekTexture());
104 return true;
105 }
106
canUseStencil(const GrCaps & caps) const107 bool GrRenderTargetProxy::canUseStencil(const GrCaps& caps) const {
108 if (caps.avoidStencilBuffers() || this->wrapsVkSecondaryCB()) {
109 return false;
110 }
111 if (!this->isInstantiated()) {
112 if (this->isLazy() && this->backendFormat().backend() == GrBackendApi::kOpenGL) {
113 // It's possible for wrapped GL render targets to not have stencil. We don't currently
114 // have an exact way of knowing whether the target will be able to use stencil, so we do
115 // the best we can: if a lazy GL proxy doesn't have a texture, then it might be a
116 // wrapped target without stencil, so we conservatively block stencil.
117 // FIXME: skbug.com/11943: GrSurfaceCharacterization needs a "canUseStencil" flag.
118 return SkToBool(this->asTextureProxy());
119 } else {
120 // Otherwise the target will definitely not be wrapped. Ganesh is free to attach
121 // stencils on internal render targets.
122 return true;
123 }
124 }
125 // Just ask the actual target if we can use stencil.
126 GrRenderTarget* rt = this->peekRenderTarget();
127 // The dmsaa attachment (if any) always supports stencil. The real question is whether the
128 // non-dmsaa attachment supports stencil.
129 bool useMSAASurface = rt->numSamples() > 1;
130 return rt->getStencilAttachment(useMSAASurface) ||
131 rt->canAttemptStencilAttachment(useMSAASurface);
132 }
133
createSurface(GrResourceProvider * resourceProvider) const134 sk_sp<GrSurface> GrRenderTargetProxy::createSurface(GrResourceProvider* resourceProvider) const {
135 sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, fSampleCnt,
136 GrRenderable::kYes, skgpu::Mipmapped::kNo);
137 if (!surface) {
138 return nullptr;
139 }
140 SkASSERT(surface->asRenderTarget());
141 SkASSERT(!surface->asTexture());
142 return surface;
143 }
144
onUninstantiatedGpuMemorySize() const145 size_t GrRenderTargetProxy::onUninstantiatedGpuMemorySize() const {
146 int colorSamplesPerPixel = this->numSamples();
147 if (colorSamplesPerPixel > 1) {
148 // Add one for the resolve buffer.
149 ++colorSamplesPerPixel;
150 }
151
152 // TODO: do we have enough information to improve this worst case estimate?
153 return GrSurface::ComputeSize(this->backendFormat(), this->dimensions(),
154 colorSamplesPerPixel, skgpu::Mipmapped::kNo,
155 !this->priv().isExact());
156 }
157
refsWrappedObjects() const158 bool GrRenderTargetProxy::refsWrappedObjects() const {
159 if (!this->isInstantiated()) {
160 return false;
161 }
162
163 GrSurface* surface = this->peekSurface();
164 return surface->resourcePriv().refsWrappedObjects();
165 }
166
callbackDesc() const167 GrSurfaceProxy::LazySurfaceDesc GrRenderTargetProxy::callbackDesc() const {
168 // We only expect exactly sized lazy RT proxies.
169 SkASSERT(!this->isFullyLazy());
170 SkASSERT(this->isFunctionallyExact());
171 return {
172 this->dimensions(),
173 SkBackingFit::kExact,
174 GrRenderable::kYes,
175 skgpu::Mipmapped::kNo,
176 this->numSamples(),
177 this->backendFormat(),
178 GrTextureType::kNone,
179 this->isProtected(),
180 this->isBudgeted(),
181 this->getLabel(),
182 };
183 }
184
185 #ifdef SK_DEBUG
onValidateSurface(const GrSurface * surface)186 void GrRenderTargetProxy::onValidateSurface(const GrSurface* surface) {
187 // We do not check that surface->asTexture returns null since, when replaying DDLs we
188 // can fulfill a renderTarget-only proxy w/ a textureRenderTarget.
189
190 // Anything that is checked here should be duplicated in GrTextureRenderTargetProxy's version
191 SkASSERT(surface->asRenderTarget());
192 SkASSERT(surface->asRenderTarget()->numSamples() == this->numSamples());
193
194 GrInternalSurfaceFlags proxyFlags = fSurfaceFlags;
195 GrInternalSurfaceFlags surfaceFlags = surface->flags();
196 if (proxyFlags & GrInternalSurfaceFlags::kGLRTFBOIDIs0 && this->numSamples() == 1) {
197 // Ganesh never internally creates FBO0 proxies or surfaces so this must be a wrapped
198 // proxy. In this case, with no MSAA, rendering to FBO0 is strictly more limited than
199 // rendering to an arbitrary surface so we allow a non-FBO0 surface to be matched with
200 // the proxy.
201 surfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0;
202 }
203 SkASSERT(((int)proxyFlags & kGrInternalRenderTargetFlagsMask) ==
204 ((int)surfaceFlags & kGrInternalRenderTargetFlagsMask));
205
206 // We manually check the kVkRTSupportsInputAttachment since we only require it on the surface if
207 // the proxy has it set. If the proxy doesn't have the flag it is legal for the surface to
208 // have the flag.
209 if (proxyFlags & GrInternalSurfaceFlags::kVkRTSupportsInputAttachment) {
210 SkASSERT(surfaceFlags & GrInternalSurfaceFlags::kVkRTSupportsInputAttachment);
211 }
212 }
213 #endif
214