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