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/GrBackendSurface.h"
16 #include "include/gpu/GrDirectContext.h"
17 #include "include/gpu/GrTypes.h"
18 #include "include/gpu/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 "src/gpu/ganesh/gl/GrGLUtil.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     auto direct = ctxInfo.directContext();
131     GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
132     GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
133     const GrCaps& caps = *direct->priv().caps();
134 
135 
136     for (auto widthHeight : {100, 128, 1048576}) {
137         for (auto ct : {GrColorType::kAlpha_8, GrColorType::kBGR_565, GrColorType::kRGBA_8888,
138                         GrColorType::kRGBA_1010102}) {
139             for (auto fit : {SkBackingFit::kExact, SkBackingFit::kApprox}) {
140                 for (auto budgeted : {skgpu::Budgeted::kYes, skgpu::Budgeted::kNo}) {
141                     for (auto numSamples : {1, 4, 16, 128}) {
142                         SkISize dims = {widthHeight, widthHeight};
143 
144                         auto format = caps.getDefaultBackendFormat(ct, GrRenderable::kYes);
145                         if (!format.isValid()) {
146                             continue;
147                         }
148 
149                         // Renderable
150                         {
151                             sk_sp<GrTexture> tex;
152                             if (SkBackingFit::kApprox == fit) {
153                                 tex = resourceProvider->createApproxTexture(dims,
154                                                                             format,
155                                                                             GrTextureType::k2D,
156                                                                             GrRenderable::kYes,
157                                                                             numSamples,
158                                                                             GrProtected::kNo,
159                                                                             /*label=*/{});
160                             } else {
161                                 tex = resourceProvider->createTexture(dims,
162                                                                       format,
163                                                                       GrTextureType::k2D,
164                                                                       GrRenderable::kYes,
165                                                                       numSamples,
166                                                                       GrMipmapped::kNo,
167                                                                       budgeted,
168                                                                       GrProtected::kNo,
169                                                                       /*label=*/{});
170                             }
171 
172                             sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(
173                                     format, dims, GrRenderable::kYes, numSamples, GrMipmapped::kNo,
174                                     fit, budgeted, GrProtected::kNo, /*label=*/{});
175                             REPORTER_ASSERT(reporter, SkToBool(tex) == SkToBool(proxy));
176                             if (proxy) {
177                                 REPORTER_ASSERT(reporter, proxy->asRenderTargetProxy());
178                                 // This forces the proxy to compute and cache its
179                                 // pre-instantiation size guess. Later, when it is actually
180                                 // instantiated, it checks that the instantiated size is <= to
181                                 // the pre-computation. If the proxy never computed its
182                                 // pre-instantiation size then the check is skipped.
183                                 proxy->gpuMemorySize();
184 
185                                 check_surface(reporter, proxy.get(), widthHeight, widthHeight,
186                                               budgeted);
187                                 int supportedSamples =
188                                         caps.getRenderTargetSampleCount(numSamples, format);
189                                 check_rendertarget(reporter, caps, resourceProvider,
190                                                    proxy->asRenderTargetProxy(), supportedSamples,
191                                                    fit, caps.maxWindowRectangles());
192                             }
193                         }
194 
195                         // Not renderable
196                         {
197                             sk_sp<GrTexture> tex;
198                             if (SkBackingFit::kApprox == fit) {
199                                 tex = resourceProvider->createApproxTexture(dims,
200                                                                             format,
201                                                                             GrTextureType::k2D,
202                                                                             GrRenderable::kNo,
203                                                                             numSamples,
204                                                                             GrProtected::kNo,
205                                                                             /*label=*/{});
206                             } else {
207                                 tex = resourceProvider->createTexture(dims,
208                                                                       format,
209                                                                       GrTextureType::k2D,
210                                                                       GrRenderable::kNo,
211                                                                       numSamples,
212                                                                       GrMipmapped::kNo,
213                                                                       budgeted,
214                                                                       GrProtected::kNo,
215                                                                       /*label=*/{});
216                             }
217 
218                             sk_sp<GrTextureProxy> proxy(proxyProvider->createProxy(
219                                     format, dims, GrRenderable::kNo, numSamples, GrMipmapped::kNo,
220                                     fit, budgeted, GrProtected::kNo, /*label=*/{}));
221                             REPORTER_ASSERT(reporter, SkToBool(tex) == SkToBool(proxy));
222                             if (proxy) {
223                                 // This forces the proxy to compute and cache its
224                                 // pre-instantiation size guess. Later, when it is actually
225                                 // instantiated, it checks that the instantiated size is <= to
226                                 // the pre-computation. If the proxy never computed its
227                                 // pre-instantiation size then the check is skipped.
228                                 proxy->gpuMemorySize();
229 
230                                 check_surface(reporter, proxy.get(), widthHeight, widthHeight,
231                                               budgeted);
232                                 check_texture(reporter, resourceProvider, proxy->asTextureProxy(),
233                                               fit);
234                             }
235                         }
236                     }
237                 }
238             }
239         }
240     }
241 }
242 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(WrappedProxyTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)243 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(WrappedProxyTest,
244                                        reporter,
245                                        ctxInfo,
246                                        CtsEnforcement::kApiLevel_T) {
247     auto direct = ctxInfo.directContext();
248     GrProxyProvider* proxyProvider = direct->priv().proxyProvider();
249     GrResourceProvider* resourceProvider = direct->priv().resourceProvider();
250     GrGpu* gpu = direct->priv().getGpu();
251     const GrCaps& caps = *direct->priv().caps();
252 
253     static const int kWidthHeight = 100;
254 
255     for (auto colorType :
256          {kAlpha_8_SkColorType, kRGBA_8888_SkColorType, kRGBA_1010102_SkColorType}) {
257         GrColorType grColorType = SkColorTypeToGrColorType(colorType);
258 
259         // External on-screen render target.
260         // Tests wrapBackendRenderTarget with a GrBackendRenderTarget
261         // Our test-only function that creates a backend render target doesn't currently support
262         // sample counts :(.
263         if (direct->colorTypeSupportedAsSurface(colorType)) {
264             GrBackendRenderTarget backendRT = gpu->createTestingOnlyBackendRenderTarget(
265                     {kWidthHeight, kWidthHeight}, grColorType);
266             sk_sp<GrSurfaceProxy> sProxy(
267                     proxyProvider->wrapBackendRenderTarget(backendRT, nullptr));
268             check_surface(reporter, sProxy.get(), kWidthHeight, kWidthHeight, skgpu::Budgeted::kNo);
269             static constexpr int kExpectedNumSamples = 1;
270             check_rendertarget(reporter, caps, resourceProvider, sProxy->asRenderTargetProxy(),
271                                kExpectedNumSamples, SkBackingFit::kExact,
272                                caps.maxWindowRectangles());
273             gpu->deleteTestingOnlyBackendRenderTarget(backendRT);
274         }
275 
276         for (auto numSamples : {1, 4}) {
277             auto beFormat = caps.getDefaultBackendFormat(grColorType, GrRenderable::kYes);
278             int supportedNumSamples = caps.getRenderTargetSampleCount(numSamples, beFormat);
279             if (!supportedNumSamples) {
280                 continue;
281             }
282 
283 #ifdef SK_GL
284             // Test wrapping FBO 0 (with made up properties). This tests sample count and the
285             // special case where FBO 0 doesn't support window rectangles.
286             if (GrBackendApi::kOpenGL == ctxInfo.backend()) {
287                 GrGLFramebufferInfo fboInfo;
288                 fboInfo.fFBOID = 0;
289                 fboInfo.fFormat = GrGLFormatToEnum(beFormat.asGLFormat());
290                 SkASSERT(fboInfo.fFormat);
291                 static constexpr int kStencilBits = 8;
292                 GrBackendRenderTarget backendRT(kWidthHeight, kWidthHeight, numSamples,
293                                                 kStencilBits, fboInfo);
294                 sk_sp<GrSurfaceProxy> sProxy(
295                         proxyProvider->wrapBackendRenderTarget(backendRT, nullptr));
296                 check_surface(
297                         reporter, sProxy.get(), kWidthHeight, kWidthHeight, skgpu::Budgeted::kNo);
298                 check_rendertarget(reporter, caps, resourceProvider, sProxy->asRenderTargetProxy(),
299                                    supportedNumSamples, SkBackingFit::kExact, 0);
300             }
301 #endif
302 
303             // Tests wrapBackendTexture that is only renderable
304             {
305                 auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(direct,
306                                                                                 kWidthHeight,
307                                                                                 kWidthHeight,
308                                                                                 colorType,
309                                                                                 GrMipmapped::kNo,
310                                                                                 GrRenderable::kYes);
311                 if (!mbet) {
312                     ERRORF(reporter,
313                            "Could not create renderable backend texture of color type %d",
314                            colorType);
315                     continue;
316                 }
317                 sk_sp<GrSurfaceProxy> sProxy = proxyProvider->wrapRenderableBackendTexture(
318                         mbet->texture(), supportedNumSamples, kBorrow_GrWrapOwnership,
319                         GrWrapCacheable::kNo, nullptr);
320                 if (!sProxy) {
321                     ERRORF(reporter, "wrapRenderableBackendTexture failed");
322                     continue;
323                 }
324 
325                 check_surface(
326                         reporter, sProxy.get(), kWidthHeight, kWidthHeight, skgpu::Budgeted::kNo);
327                 check_rendertarget(reporter, caps, resourceProvider, sProxy->asRenderTargetProxy(),
328                                    supportedNumSamples, SkBackingFit::kExact,
329                                    caps.maxWindowRectangles());
330             }
331 
332             {
333                 // Tests wrapBackendTexture that is only textureable
334                 auto mbet = sk_gpu_test::ManagedBackendTexture::MakeWithoutData(direct,
335                                                                                 kWidthHeight,
336                                                                                 kWidthHeight,
337                                                                                 colorType,
338                                                                                 GrMipmapped::kNo,
339                                                                                 GrRenderable::kNo);
340                 if (!mbet) {
341                     ERRORF(reporter,
342                            "Could not create non-renderable backend texture of color type %d",
343                            colorType);
344                     continue;
345                 }
346                 sk_sp<GrSurfaceProxy> sProxy = proxyProvider->wrapBackendTexture(
347                         mbet->texture(), kBorrow_GrWrapOwnership, GrWrapCacheable::kNo,
348                         kRead_GrIOType, mbet->refCountedCallback());
349                 if (!sProxy) {
350                     ERRORF(reporter, "wrapBackendTexture failed");
351                     continue;
352                 }
353 
354                 check_surface(
355                         reporter, sProxy.get(), kWidthHeight, kWidthHeight, skgpu::Budgeted::kNo);
356                 check_texture(reporter, resourceProvider, sProxy->asTextureProxy(),
357                               SkBackingFit::kExact);
358             }
359         }
360     }
361 }
362 
DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ZeroSizedProxyTest,reporter,ctxInfo,CtsEnforcement::kApiLevel_T)363 DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ZeroSizedProxyTest,
364                                        reporter,
365                                        ctxInfo,
366                                        CtsEnforcement::kApiLevel_T) {
367     auto direct = ctxInfo.directContext();
368     GrProxyProvider* provider = direct->priv().proxyProvider();
369 
370     for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
371         for (auto fit : { SkBackingFit::kExact, SkBackingFit::kApprox }) {
372             for (int width : { 0, 100 }) {
373                 for (int height : { 0, 100}) {
374                     if (width && height) {
375                         continue; // not zero-sized
376                     }
377 
378                     const GrBackendFormat format =
379                             direct->priv().caps()->getDefaultBackendFormat(
380                                 GrColorType::kRGBA_8888,
381                                 renderable);
382 
383                     sk_sp<GrTextureProxy> proxy = provider->createProxy(format,
384                                                                         {width, height},
385                                                                         renderable,
386                                                                         1,
387                                                                         GrMipmapped::kNo,
388                                                                         fit,
389                                                                         skgpu::Budgeted::kNo,
390                                                                         GrProtected::kNo,
391                                                                         /*label=*/{});
392                     REPORTER_ASSERT(reporter, !proxy);
393                 }
394             }
395         }
396     }
397 }
398