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, GrRenderable::kYes, numSamples,
140                                         GrProtected::kNo);
141                             } else {
142                                 tex = resourceProvider->createTexture(
143                                         dims, format, GrRenderable::kYes, numSamples,
144                                         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, GrRenderable::kNo, numSamples,
176                                         GrProtected::kNo);
177                             } else {
178                                 tex = resourceProvider->createTexture(
179                                         dims, format, GrRenderable::kNo, numSamples,
180                                         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