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/GrTextureRenderTargetProxy.h"
9
10#include "src/gpu/GrCaps.h"
11#include "src/gpu/GrRenderTarget.h"
12#include "src/gpu/GrRenderTargetProxyPriv.h"
13#include "src/gpu/GrSurface.h"
14#include "src/gpu/GrSurfaceProxyPriv.h"
15#include "src/gpu/GrTexture.h"
16#include "src/gpu/GrTextureProxyPriv.h"
17
18#ifdef SK_DEBUG
19#include "include/gpu/GrDirectContext.h"
20#include "src/gpu/GrContextPriv.h"
21#endif
22
23// Deferred version
24// This class is virtually derived from GrSurfaceProxy (via both GrTextureProxy and
25// GrRenderTargetProxy) so its constructor must be explicitly called.
26GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps,
27 const GrBackendFormat& format,
28 SkISize dimensions,
29 int sampleCnt,
30 GrMipmapped mipMapped,
31 GrMipmapStatus mipmapStatus,
32 SkBackingFit fit,
33 SkBudgeted budgeted,
34 GrProtected isProtected,
35 GrInternalSurfaceFlags surfaceFlags,
36 UseAllocator useAllocator,
37 GrDDLProvider creatingProvider)
38 : GrSurfaceProxy(format, dimensions, fit, budgeted, isProtected, surfaceFlags, useAllocator)
39 // for now textures w/ data are always wrapped
40 , GrRenderTargetProxy(caps, format, dimensions, sampleCnt, fit, budgeted, isProtected,
41 surfaceFlags, useAllocator)
42 , GrTextureProxy(format, dimensions, mipMapped, mipmapStatus, fit, budgeted, isProtected,
43 surfaceFlags, useAllocator, creatingProvider) {
44 this->initSurfaceFlags(caps);
45}
46
47// Lazy-callback version
48GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps,
49 LazyInstantiateCallback&& callback,
50 const GrBackendFormat& format,
51 SkISize dimensions,
52 int sampleCnt,
53 GrMipmapped mipMapped,
54 GrMipmapStatus mipmapStatus,
55 SkBackingFit fit,
56 SkBudgeted budgeted,
57 GrProtected isProtected,
58 GrInternalSurfaceFlags surfaceFlags,
59 UseAllocator useAllocator,
60 GrDDLProvider creatingProvider)
61 : GrSurfaceProxy(std::move(callback), format, dimensions, fit, budgeted, isProtected,
62 surfaceFlags, useAllocator)
63 // Since we have virtual inheritance, we initialize GrSurfaceProxy directly. Send null
64 // callbacks to the texture and RT proxies simply to route to the appropriate constructors.
65 , GrRenderTargetProxy(LazyInstantiateCallback(), format, dimensions, sampleCnt, fit,
66 budgeted, isProtected, surfaceFlags, useAllocator,
67 WrapsVkSecondaryCB::kNo)
68 , GrTextureProxy(LazyInstantiateCallback(), format, dimensions, mipMapped, mipmapStatus,
69 fit, budgeted, isProtected, surfaceFlags, useAllocator,
70 creatingProvider) {
71 this->initSurfaceFlags(caps);
72}
73
74// Wrapped version
75// This class is virtually derived from GrSurfaceProxy (via both GrTextureProxy and
76// GrRenderTargetProxy) so its constructor must be explicitly called.
77GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(sk_sp<GrSurface> surf,
78 UseAllocator useAllocator,
79 GrDDLProvider creatingProvider)
80 : GrSurfaceProxy(surf, SkBackingFit::kExact, useAllocator)
81 , GrRenderTargetProxy(surf, useAllocator)
82 , GrTextureProxy(surf, useAllocator, creatingProvider) {
83 SkASSERT(surf->asTexture());
84 SkASSERT(surf->asRenderTarget());
85 SkASSERT(fSurfaceFlags == fTarget->flags());
86 SkASSERT((this->numSamples() <= 1 ||
87 fTarget->getContext()->priv().caps()->msaaResolvesAutomatically()) !=
88 this->requiresManualMSAAResolve());
89}
90
91void GrTextureRenderTargetProxy::initSurfaceFlags(const GrCaps& caps) {
92 // FBO 0 should never be wrapped as a texture render target.
93 SkASSERT(!this->rtPriv().glRTFBOIDIs0());
94 if (this->numSamples() > 1 && !caps.msaaResolvesAutomatically()) {
95 // MSAA texture-render-targets always require manual resolve if we are not using a
96 // multisampled-render-to-texture extension.
97 //
98 // NOTE: This is the only instance where we need to set the manual resolve flag on a proxy.
99 // Any other proxies that require manual resolve (e.g., wrapBackendTextureAsRenderTarget())
100 // will be wrapped, and the wrapped version of the GrSurface constructor will automatically
101 // get the manual resolve flag when copying the target GrSurface's flags.
102 fSurfaceFlags |= GrInternalSurfaceFlags::kRequiresManualMSAAResolve;
103 }
104}
105
106size_t GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize(const GrCaps& caps) const {
107 int colorSamplesPerPixel = this->numSamples();
108 if (colorSamplesPerPixel > 1) {
109 // Add one to account for the resolve buffer.
110 ++colorSamplesPerPixel;
111 }
112
113 // TODO: do we have enough information to improve this worst case estimate?
114 return GrSurface::ComputeSize(caps, this->backendFormat(), this->dimensions(),
115 colorSamplesPerPixel, this->proxyMipmapped(),
116 !this->priv().isExact());
117}
118
119bool GrTextureRenderTargetProxy::instantiate(GrResourceProvider* resourceProvider) {
120 if (this->isLazy()) {
121 return false;
122 }
123
124 const GrUniqueKey& key = this->getUniqueKey();
125
126 if (!this->instantiateImpl(resourceProvider, this->numSamples(), GrRenderable::kYes,
127 this->mipmapped(), key.isValid() ? &key : nullptr)) {
128 return false;
129 }
130 if (key.isValid()) {
131 SkASSERT(key == this->getUniqueKey());
132 }
133
134 SkASSERT(this->peekRenderTarget());
135 SkASSERT(this->peekTexture());
136
137 return true;
138}
139
140sk_sp<GrSurface> GrTextureRenderTargetProxy::createSurface(
141 GrResourceProvider* resourceProvider) const {
142 sk_sp<GrSurface> surface = this->createSurfaceImpl(resourceProvider, this->numSamples(),
143 GrRenderable::kYes, this->mipmapped());
144 if (!surface) {
145 return nullptr;
146 }
147 SkASSERT(surface->asRenderTarget());
148 SkASSERT(surface->asTexture());
149
150 return surface;
151}
152
153GrSurfaceProxy::LazySurfaceDesc GrTextureRenderTargetProxy::callbackDesc() const {
154 SkISize dims;
155 SkBackingFit fit;
156 if (this->isFullyLazy()) {
157 fit = SkBackingFit::kApprox;
158 dims = {-1, -1};
159 } else {
160 fit = this->isFunctionallyExact() ? SkBackingFit::kExact : SkBackingFit::kApprox;
161 dims = this->dimensions();
162 }
163 return {
164 dims,
165 fit,
166 GrRenderable::kYes,
167 this->mipmapped(),
168 this->numSamples(),
169 this->backendFormat(),
170 this->isProtected(),
171 this->isBudgeted(),
172 };
173}
174
175#ifdef SK_DEBUG
176void GrTextureRenderTargetProxy::onValidateSurface(const GrSurface* surface) {
177 // Anything checked here should also be checking the GrTextureProxy version
178 SkASSERT(surface->asTexture());
179 SkASSERT(GrMipmapped::kNo == this->proxyMipmapped() ||
180 GrMipmapped::kYes == surface->asTexture()->mipmapped());
181
182 // Anything checked here should also be checking the GrRenderTargetProxy version
183 SkASSERT(surface->asRenderTarget());
184 SkASSERT(surface->asRenderTarget()->numSamples() == this->numSamples());
185
186 SkASSERT(surface->asTexture()->textureType() == this->textureType());
187
188 GrInternalSurfaceFlags proxyFlags = fSurfaceFlags;
189 GrInternalSurfaceFlags surfaceFlags = surface->flags();
190
191 // Only non-RT textures can be read only.
192 SkASSERT(!(proxyFlags & GrInternalSurfaceFlags::kReadOnly));
193 SkASSERT(!(surfaceFlags & GrInternalSurfaceFlags::kReadOnly));
194
195 SkASSERT(((int)proxyFlags & kGrInternalTextureRenderTargetFlagsMask) ==
196 ((int)surfaceFlags & kGrInternalTextureRenderTargetFlagsMask));
197}
198#endif
199
200