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 // This is a GPU-backend specific test.
9
10 #include "include/gpu/GrBackendSurface.h"
11 #include "include/gpu/GrDirectContext.h"
12 #include "src/gpu/GrDirectContextPriv.h"
13 #include "src/gpu/GrGpu.h"
14 #include "src/gpu/GrProxyProvider.h"
15 #include "src/gpu/GrRenderTarget.h"
16 #include "src/gpu/GrRenderTargetProxy.h"
17 #include "src/gpu/GrResourceProvider.h"
18 #include "src/gpu/GrSurface.h"
19 #include "src/gpu/GrSurfaceProxyPriv.h"
20 #include "src/gpu/GrTexture.h"
21 #include "src/gpu/GrTextureProxy.h"
22 #include "src/gpu/SkGr.h"
23 #include "tests/Test.h"
24 #include "tools/gpu/ManagedBackendTexture.h"
25 #ifdef SK_GL
26 #include "src/gpu/gl/GrGLDefines.h"
27 #include "src/gpu/gl/GrGLUtil.h"
28 #endif
29
30 #include "tests/TestUtils.h"
31
32 // Check that the surface proxy's member vars are set as expected
check_surface(skiatest::Reporter * reporter,GrSurfaceProxy * proxy,int width,int height,SkBudgeted budgeted)33 static void check_surface(skiatest::Reporter* reporter,
34 GrSurfaceProxy* proxy,
35 int width, int height,
36 SkBudgeted budgeted) {
37 REPORTER_ASSERT(reporter, proxy->width() == width);
38 REPORTER_ASSERT(reporter, proxy->height() == height);
39 REPORTER_ASSERT(reporter, !proxy->uniqueID().isInvalid());
40 REPORTER_ASSERT(reporter, proxy->isBudgeted() == budgeted);
41 }
42
check_rendertarget(skiatest::Reporter * reporter,const GrCaps & caps,GrResourceProvider * provider,GrRenderTargetProxy * rtProxy,int numSamples,SkBackingFit fit,int expectedMaxWindowRects)43 static void check_rendertarget(skiatest::Reporter* reporter,
44 const GrCaps& caps,
45 GrResourceProvider* provider,
46 GrRenderTargetProxy* rtProxy,
47 int numSamples,
48 SkBackingFit fit,
49 int expectedMaxWindowRects) {
50 REPORTER_ASSERT(reporter, rtProxy->maxWindowRectangles(caps) == expectedMaxWindowRects);
51 REPORTER_ASSERT(reporter, rtProxy->numSamples() == numSamples);
52
53 GrSurfaceProxy::UniqueID idBefore = rtProxy->uniqueID();
54 bool preinstantiated = rtProxy->isInstantiated();
55 REPORTER_ASSERT(reporter, rtProxy->instantiate(provider));
56 GrRenderTarget* rt = rtProxy->peekRenderTarget();
57
58 REPORTER_ASSERT(reporter, rtProxy->uniqueID() == idBefore);
59 // Deferred resources should always have a different ID from their instantiated rendertarget
60 if (preinstantiated) {
61 REPORTER_ASSERT(reporter, rtProxy->uniqueID().asUInt() == rt->uniqueID().asUInt());
62 } else {
63 REPORTER_ASSERT(reporter, rtProxy->uniqueID().asUInt() != rt->uniqueID().asUInt());
64 }
65
66 if (SkBackingFit::kExact == fit) {
67 REPORTER_ASSERT(reporter, rt->dimensions() == rtProxy->dimensions());
68 } else {
69 REPORTER_ASSERT(reporter, rt->width() >= rtProxy->width());
70 REPORTER_ASSERT(reporter, rt->height() >= rtProxy->height());
71 }
72 REPORTER_ASSERT(reporter, rt->backendFormat() == rtProxy->backendFormat());
73
74 REPORTER_ASSERT(reporter, rt->numSamples() == rtProxy->numSamples());
75 REPORTER_ASSERT(reporter, rt->flags() == rtProxy->testingOnly_getFlags());
76 }
77
check_texture(skiatest::Reporter * reporter,GrResourceProvider * provider,GrTextureProxy * texProxy,SkBackingFit fit)78 static void check_texture(skiatest::Reporter* reporter,
79 GrResourceProvider* provider,
80 GrTextureProxy* texProxy,
81 SkBackingFit fit) {
82 GrSurfaceProxy::UniqueID idBefore = texProxy->uniqueID();
83
84 bool preinstantiated = texProxy->isInstantiated();
85 // The instantiated texture should have these dimensions. If the fit is kExact, then
86 // 'backingStoreDimensions' reports the original WxH. If it is kApprox, make sure that
87 // the texture is that size and didn't reuse one of the kExact surfaces in the provider.
88 // This is important because upstream usage (e.g. SkImage) reports size based on the
89 // backingStoreDimensions and client code may rely on that if they are creating backend
90 // resources.
91 // NOTE: we store these before instantiating, since after instantiation backingStoreDimensions
92 // just returns the target's dimensions. In this instance, we want to ensure the target's
93 // dimensions are no different from the original approximate (or exact) dimensions.
94 SkISize expectedSize = texProxy->backingStoreDimensions();
95
96 REPORTER_ASSERT(reporter, texProxy->instantiate(provider));
97 GrTexture* tex = texProxy->peekTexture();
98
99 REPORTER_ASSERT(reporter, texProxy->uniqueID() == idBefore);
100 // Deferred resources should always have a different ID from their instantiated texture
101 if (preinstantiated) {
102 REPORTER_ASSERT(reporter, texProxy->uniqueID().asUInt() == tex->uniqueID().asUInt());
103 } else {
104 REPORTER_ASSERT(reporter, texProxy->uniqueID().asUInt() != tex->uniqueID().asUInt());
105 }
106
107 REPORTER_ASSERT(reporter, tex->dimensions() == expectedSize);
108
109 REPORTER_ASSERT(reporter, tex->backendFormat() == texProxy->backendFormat());
110 }
111
112
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DeferredProxyTest,reporter,ctxInfo)113 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DeferredProxyTest, reporter, ctxInfo) {
114 auto direct = ctxInfo.directContext();
115 GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
116 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
117 const GrCaps& caps = *direct->priv().caps();
118
119 int attempt = 0; // useful for debugging
120
121 for (auto widthHeight : {100, 128, 1048576}) {
122 for (auto ct : {GrColorType::kAlpha_8, GrColorType::kBGR_565, GrColorType::kRGBA_8888,
123 GrColorType::kRGBA_1010102}) {
124 for (auto fit : {SkBackingFit::kExact, SkBackingFit::kApprox}) {
125 for (auto budgeted : {SkBudgeted::kYes, SkBudgeted::kNo}) {
126 for (auto numSamples : {1, 4, 16, 128}) {
127 SkISize dims = {widthHeight, widthHeight};
128
129 auto format = caps.getDefaultBackendFormat(ct, GrRenderable::kYes);
130 if (!format.isValid()) {
131 continue;
132 }
133
134 // Renderable
135 {
136 sk_sp<GrTexture> tex;
137 if (SkBackingFit::kApprox == fit) {
138 tex = resourceProvider->createApproxTexture(
139 dims, format, GrTextureType::k2D, GrRenderable::kYes,
140 numSamples, GrProtected::kNo);
141 } else {
142 tex = resourceProvider->createTexture(
143 dims, format, GrTextureType::k2D, GrRenderable::kYes,
144 numSamples, GrMipmapped::kNo, budgeted, GrProtected::kNo);
145 }
146
147 sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(
148 format, dims, GrRenderable::kYes, numSamples, GrMipmapped::kNo,
149 fit, budgeted, GrProtected::kNo);
150 REPORTER_ASSERT(reporter, SkToBool(tex) == SkToBool(proxy));
151 if (proxy) {
152 REPORTER_ASSERT(reporter, proxy->asRenderTargetProxy());
153 // This forces the proxy to compute and cache its
154 // pre-instantiation size guess. Later, when it is actually
155 // instantiated, it checks that the instantiated size is <= to
156 // the pre-computation. If the proxy never computed its
157 // pre-instantiation size then the check is skipped.
158 proxy->gpuMemorySize();
159
160 check_surface(reporter, proxy.get(), widthHeight, widthHeight,
161 budgeted);
162 int supportedSamples =
163 caps.getRenderTargetSampleCount(numSamples, format);
164 check_rendertarget(reporter, caps, resourceProvider,
165 proxy->asRenderTargetProxy(), supportedSamples,
166 fit, caps.maxWindowRectangles());
167 }
168 }
169
170 // Not renderable
171 {
172 sk_sp<GrTexture> tex;
173 if (SkBackingFit::kApprox == fit) {
174 tex = resourceProvider->createApproxTexture(
175 dims, format, GrTextureType::k2D, GrRenderable::kNo,
176 numSamples, GrProtected::kNo);
177 } else {
178 tex = resourceProvider->createTexture(
179 dims, format, GrTextureType::k2D, GrRenderable::kNo,
180 numSamples, GrMipmapped::kNo, budgeted, GrProtected::kNo);
181 }
182
183 sk_sp<GrTextureProxy> proxy(proxyProvider->createProxy(
184 format, dims, GrRenderable::kNo, numSamples, GrMipmapped::kNo,
185 fit, budgeted, GrProtected::kNo));
186 REPORTER_ASSERT(reporter, SkToBool(tex) == SkToBool(proxy));
187 if (proxy) {
188 // This forces the proxy to compute and cache its
189 // pre-instantiation size guess. Later, when it is actually
190 // instantiated, it checks that the instantiated size is <= to
191 // the pre-computation. If the proxy never computed its
192 // pre-instantiation size then the check is skipped.
193 proxy->gpuMemorySize();
194
195 check_surface(reporter, proxy.get(), widthHeight, widthHeight,
196 budgeted);
197 check_texture(reporter, resourceProvider, proxy->asTextureProxy(),
198 fit);
199 }
200 }
201
202 attempt++;
203 }
204 }
205 }
206 }
207 }
208 }
209
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WrappedProxyTest,reporter,ctxInfo)210 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WrappedProxyTest, reporter, ctxInfo) {
211 auto direct = ctxInfo.directContext();
212 GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
213 GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
214 GrGpu* gpu = direct->priv().getGpu();
215 const GrCaps& caps = *direct->priv().caps();
216
217 static const int kWidthHeight = 100;
218
219 for (auto colorType :
220 {kAlpha_8_SkColorType, kRGBA_8888_SkColorType, kRGBA_1010102_SkColorType}) {
221 GrColorType grColorType = SkColorTypeToGrColorType(colorType);
222
223 // External on-screen render target.
224 // Tests wrapBackendRenderTarget with a GrBackendRenderTarget
225 // Our test-only function that creates a backend render target doesn't currently support
226 // sample counts :(.
227 if (direct->colorTypeSupportedAsSurface(colorType)) {
228 GrBackendRenderTarget backendRT = gpu->createTestingOnlyBackendRenderTarget(
229 {kWidthHeight, kWidthHeight}, grColorType);
230 sk_sp<GrSurfaceProxy> sProxy(
231 proxyProvider->wrapBackendRenderTarget(backendRT, nullptr));
232 check_surface(reporter, sProxy.get(), kWidthHeight, kWidthHeight, SkBudgeted::kNo);
233 static constexpr int kExpectedNumSamples = 1;
234 check_rendertarget(reporter, caps, resourceProvider, sProxy->asRenderTargetProxy(),
235 kExpectedNumSamples, SkBackingFit::kExact,
236 caps.maxWindowRectangles());
237 gpu->deleteTestingOnlyBackendRenderTarget(backendRT);
238 }
239
240 for (auto numSamples : {1, 4}) {
241 auto beFormat = caps.getDefaultBackendFormat(grColorType, GrRenderable::kYes);
242 int supportedNumSamples = caps.getRenderTargetSampleCount(numSamples, beFormat);
243 if (!supportedNumSamples) {
244 continue;
245 }
246
247 #ifdef SK_GL
248 // Test wrapping FBO 0 (with made up properties). This tests sample count and the
249 // special case where FBO 0 doesn't support window rectangles.
250 if (GrBackendApi::kOpenGL == ctxInfo.backend()) {
251 GrGLFramebufferInfo fboInfo;
252 fboInfo.fFBOID = 0;
253 fboInfo.fFormat = GrGLFormatToEnum(beFormat.asGLFormat());
254 SkASSERT(fboInfo.fFormat);
255 static constexpr int kStencilBits = 8;
256 GrBackendRenderTarget backendRT(kWidthHeight, kWidthHeight, numSamples,
257 kStencilBits, fboInfo);
258 sk_sp<GrSurfaceProxy> sProxy(
259 proxyProvider->wrapBackendRenderTarget(backendRT, nullptr));
260 check_surface(reporter, sProxy.get(), kWidthHeight, kWidthHeight, SkBudgeted::kNo);
261 check_rendertarget(reporter, caps, resourceProvider, sProxy->asRenderTargetProxy(),
262 supportedNumSamples, SkBackingFit::kExact, 0);
263 }
264 #endif
265
266 // Tests wrapBackendTexture that is only renderable
267 {
268 auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(direct,
269 kWidthHeight,
270 kWidthHeight,
271 colorType,
272 GrMipmapped::kNo,
273 GrRenderable::kYes);
274 if (!mbet) {
275 ERRORF(reporter,
276 "Could not create renderable backend texture of color type %d",
277 colorType);
278 continue;
279 }
280 sk_sp<GrSurfaceProxy> sProxy = proxyProvider->wrapRenderableBackendTexture(
281 mbet->texture(), supportedNumSamples, kBorrow_GrWrapOwnership,
282 GrWrapCacheable::kNo, nullptr);
283 if (!sProxy) {
284 ERRORF(reporter, "wrapRenderableBackendTexture failed");
285 continue;
286 }
287
288 check_surface(reporter, sProxy.get(), kWidthHeight, kWidthHeight, SkBudgeted::kNo);
289 check_rendertarget(reporter, caps, resourceProvider, sProxy->asRenderTargetProxy(),
290 supportedNumSamples, SkBackingFit::kExact,
291 caps.maxWindowRectangles());
292 }
293
294 {
295 // Tests wrapBackendTexture that is only textureable
296 auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(direct,
297 kWidthHeight,
298 kWidthHeight,
299 colorType,
300 GrMipmapped::kNo,
301 GrRenderable::kNo);
302 if (!mbet) {
303 ERRORF(reporter,
304 "Could not create non-renderable backend texture of color type %d",
305 colorType);
306 continue;
307 }
308 sk_sp<GrSurfaceProxy> sProxy = proxyProvider->wrapBackendTexture(
309 mbet->texture(), kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
310 kRead_GrIOType, mbet->refCountedCallback());
311 if (!sProxy) {
312 ERRORF(reporter, "wrapBackendTexture failed");
313 continue;
314 }
315
316 check_surface(reporter, sProxy.get(), kWidthHeight, kWidthHeight, SkBudgeted::kNo);
317 check_texture(reporter, resourceProvider, sProxy->asTextureProxy(),
318 SkBackingFit::kExact);
319 }
320 }
321 }
322 }
323
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ZeroSizedProxyTest,reporter,ctxInfo)324 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ZeroSizedProxyTest, reporter, ctxInfo) {
325 auto direct = ctxInfo.directContext();
326 GrProxyProvider* provider = direct->priv().proxyProvider();
327
328 for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
329 for (auto fit : { SkBackingFit::kExact, SkBackingFit::kApprox }) {
330 for (int width : { 0, 100 }) {
331 for (int height : { 0, 100}) {
332 if (width && height) {
333 continue; // not zero-sized
334 }
335
336 const GrBackendFormat format =
337 direct->priv().caps()->getDefaultBackendFormat(
338 GrColorType::kRGBA_8888,
339 renderable);
340
341 sk_sp<GrTextureProxy> proxy = provider->createProxy(
342 format, {width, height}, renderable, 1, GrMipmapped::kNo, fit,
343 SkBudgeted::kNo, GrProtected::kNo);
344 REPORTER_ASSERT(reporter, !proxy);
345 }
346 }
347 }
348 }
349 }
350