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 "Test.h"
11
12#if SK_SUPPORT_GPU
13#include "GrRenderTargetPriv.h"
14#include "GrRenderTargetProxy.h"
15#include "GrResourceProvider.h"
16#include "GrSurfaceProxy.h"
17#include "GrTextureProxy.h"
18
19// Check that the surface proxy's member vars are set as expected
20static void check_surface(skiatest::Reporter* reporter,
21                          GrSurfaceProxy* proxy,
22                          GrSurfaceOrigin origin,
23                          int width, int height,
24                          GrPixelConfig config,
25                          const GrGpuResource::UniqueID& uniqueID,
26                          SkBudgeted budgeted) {
27    REPORTER_ASSERT(reporter, proxy->origin() == origin);
28    REPORTER_ASSERT(reporter, proxy->width() == width);
29    REPORTER_ASSERT(reporter, proxy->height() == height);
30    REPORTER_ASSERT(reporter, proxy->config() == config);
31    if (!uniqueID.isInvalid()) {
32        REPORTER_ASSERT(reporter, proxy->uniqueID().asUInt() == uniqueID.asUInt());
33    } else {
34        REPORTER_ASSERT(reporter, !proxy->uniqueID().isInvalid());
35    }
36    REPORTER_ASSERT(reporter, proxy->isBudgeted() == budgeted);
37}
38
39static void check_rendertarget(skiatest::Reporter* reporter,
40                               const GrCaps& caps,
41                               GrResourceProvider* provider,
42                               GrRenderTargetProxy* rtProxy,
43                               int numSamples,
44                               SkBackingFit fit,
45                               int expectedMaxWindowRects,
46                               bool wasWrapped) {
47    REPORTER_ASSERT(reporter, rtProxy->maxWindowRectangles(caps) == expectedMaxWindowRects);
48    REPORTER_ASSERT(reporter, rtProxy->numStencilSamples() == numSamples);
49
50    GrSurfaceProxy::UniqueID idBefore = rtProxy->uniqueID();
51    GrRenderTarget* rt = rtProxy->instantiate(provider);
52    REPORTER_ASSERT(reporter, rt);
53
54    REPORTER_ASSERT(reporter, rtProxy->uniqueID() == idBefore);
55    if (wasWrapped) {
56        // Wrapped resources share their uniqueID with the wrapping RenderTargetProxy
57        REPORTER_ASSERT(reporter, rtProxy->uniqueID().asUInt() == rt->uniqueID().asUInt());
58    } else {
59        // Deferred resources should always have a different ID from their instantiated rendertarget
60        REPORTER_ASSERT(reporter, rtProxy->uniqueID().asUInt() != rt->uniqueID().asUInt());
61    }
62
63    REPORTER_ASSERT(reporter, rt->origin() == rtProxy->origin());
64    if (SkBackingFit::kExact == fit) {
65        REPORTER_ASSERT(reporter, rt->width() == rtProxy->width());
66        REPORTER_ASSERT(reporter, rt->height() == rtProxy->height());
67    } else {
68        REPORTER_ASSERT(reporter, rt->width() >= rtProxy->width());
69        REPORTER_ASSERT(reporter, rt->height() >= rtProxy->height());
70    }
71    REPORTER_ASSERT(reporter, rt->config() == rtProxy->config());
72
73    REPORTER_ASSERT(reporter, rt->isUnifiedMultisampled() == rtProxy->isUnifiedMultisampled());
74    REPORTER_ASSERT(reporter, rt->isStencilBufferMultisampled() ==
75                              rtProxy->isStencilBufferMultisampled());
76    REPORTER_ASSERT(reporter, rt->numColorSamples() == rtProxy->numColorSamples());
77    REPORTER_ASSERT(reporter, rt->numStencilSamples() == rtProxy->numStencilSamples());
78    REPORTER_ASSERT(reporter, rt->isMixedSampled() == rtProxy->isMixedSampled());
79    REPORTER_ASSERT(reporter, rt->renderTargetPriv().flags() == rtProxy->testingOnly_getFlags());
80}
81
82static void check_texture(skiatest::Reporter* reporter,
83                          GrResourceProvider* provider,
84                          GrTextureProxy* texProxy,
85                          SkBackingFit fit,
86                          bool wasWrapped) {
87    GrSurfaceProxy::UniqueID idBefore = texProxy->uniqueID();
88    GrTexture* tex = texProxy->instantiate(provider);
89    REPORTER_ASSERT(reporter, tex);
90
91    REPORTER_ASSERT(reporter, texProxy->uniqueID() == idBefore);
92    if (wasWrapped) {
93        // Wrapped resources share their uniqueID with the wrapping TextureProxy
94        REPORTER_ASSERT(reporter, texProxy->uniqueID().asUInt() == tex->uniqueID().asUInt());
95    } else {
96        // Deferred resources should always have a different ID from their instantiated texture
97        REPORTER_ASSERT(reporter, texProxy->uniqueID().asUInt() != tex->uniqueID().asUInt());
98    }
99
100    REPORTER_ASSERT(reporter, tex->origin() == texProxy->origin());
101    if (SkBackingFit::kExact == fit) {
102        REPORTER_ASSERT(reporter, tex->width() == texProxy->width());
103        REPORTER_ASSERT(reporter, tex->height() == texProxy->height());
104    } else {
105        REPORTER_ASSERT(reporter, tex->width() >= texProxy->width());
106        REPORTER_ASSERT(reporter, tex->height() >= texProxy->height());
107    }
108    REPORTER_ASSERT(reporter, tex->config() == texProxy->config());
109}
110
111
112DEF_GPUTEST_FOR_RENDERING_CONTEXTS(DeferredProxyTest, reporter, ctxInfo) {
113    GrResourceProvider* provider = ctxInfo.grContext()->resourceProvider();
114    const GrCaps& caps = *ctxInfo.grContext()->caps();
115
116    const GrGpuResource::UniqueID kInvalidResourceID = GrGpuResource::UniqueID::InvalidID();
117
118    int attempt = 0; // useful for debugging
119
120    for (auto origin : { kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin }) {
121        for (auto widthHeight : { 100, 128, 1048576 }) {
122            for (auto config : { kAlpha_8_GrPixelConfig, kRGB_565_GrPixelConfig,
123                                 kETC1_GrPixelConfig, kRGBA_8888_GrPixelConfig }) {
124                for (auto fit : { SkBackingFit::kExact, SkBackingFit::kApprox }) {
125                    for (auto budgeted : { SkBudgeted::kYes, SkBudgeted::kNo }) {
126                        for (auto numSamples : { 0, 4, 16, 128 }) {
127                            GrSurfaceDesc desc;
128                            desc.fFlags = kRenderTarget_GrSurfaceFlag;
129                            desc.fOrigin = origin;
130                            desc.fWidth = widthHeight;
131                            desc.fHeight = widthHeight;
132                            desc.fConfig = config;
133                            desc.fSampleCnt = numSamples;
134
135                            {
136                                sk_sp<GrTexture> tex;
137                                if (SkBackingFit::kApprox == fit) {
138                                    tex.reset(provider->createApproxTexture(desc, 0));
139                                } else {
140                                    tex.reset(provider->createTexture(desc, budgeted));
141                                }
142
143                                sk_sp<GrTextureProxy> proxy(GrSurfaceProxy::MakeDeferred(
144                                                                                provider, desc,
145                                                                                fit, budgeted));
146                                REPORTER_ASSERT(reporter, SkToBool(tex) == SkToBool(proxy));
147                                if (proxy) {
148                                    REPORTER_ASSERT(reporter, proxy->asRenderTargetProxy());
149                                    // This forces the proxy to compute and cache its
150                                    // pre-instantiation size guess. Later, when it is actually
151                                    // instantiated, it checks that the instantiated size is <= to
152                                    // the pre-computation. If the proxy never computed its
153                                    // pre-instantiation size then the check is skipped.
154                                    proxy->gpuMemorySize();
155
156                                    check_surface(reporter, proxy.get(), origin,
157                                                  widthHeight, widthHeight, config,
158                                                  kInvalidResourceID, budgeted);
159                                    check_rendertarget(reporter, caps, provider,
160                                                       proxy->asRenderTargetProxy(),
161                                                       SkTMin(numSamples, caps.maxSampleCount()),
162                                                       fit, caps.maxWindowRectangles(), false);
163                                }
164                            }
165
166                            desc.fFlags = kNone_GrSurfaceFlags;
167
168                            {
169                                sk_sp<GrTexture> tex;
170                                if (SkBackingFit::kApprox == fit) {
171                                    tex.reset(provider->createApproxTexture(desc, 0));
172                                } else {
173                                    tex.reset(provider->createTexture(desc, budgeted));
174                                }
175
176                                sk_sp<GrTextureProxy> proxy(GrSurfaceProxy::MakeDeferred(provider,
177                                                                                         desc,
178                                                                                         fit,
179                                                                                         budgeted));
180                                REPORTER_ASSERT(reporter, SkToBool(tex) == SkToBool(proxy));
181                                if (proxy) {
182                                    // This forces the proxy to compute and cache its pre-instantiation
183                                    // size guess. Later, when it is actually instantiated, it checks
184                                    // that the instantiated size is <= to the pre-computation.
185                                    // If the proxy never computed its pre-instantiation size then the
186                                    // check is skipped.
187                                    proxy->gpuMemorySize();
188
189                                    check_surface(reporter, proxy.get(), origin,
190                                                  widthHeight, widthHeight, config,
191                                                  kInvalidResourceID, budgeted);
192                                    check_texture(reporter, provider, proxy->asTextureProxy(),
193                                                  fit, false);
194                                }
195                            }
196
197                            attempt++;
198                        }
199                    }
200                }
201            }
202        }
203    }
204}
205
206DEF_GPUTEST_FOR_RENDERING_CONTEXTS(WrappedProxyTest, reporter, ctxInfo) {
207    GrResourceProvider* provider = ctxInfo.grContext()->resourceProvider();
208    const GrCaps& caps = *ctxInfo.grContext()->caps();
209
210    static const int kWidthHeight = 100;
211
212    for (auto origin : { kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin }) {
213        for (auto config : { kAlpha_8_GrPixelConfig, kRGBA_8888_GrPixelConfig }) {
214            for (auto budgeted : { SkBudgeted::kYes, SkBudgeted::kNo }) {
215                for (auto numSamples: { 0, 4}) {
216                    bool renderable = caps.isConfigRenderable(config, numSamples > 0);
217
218                    GrSurfaceDesc desc;
219                    desc.fOrigin = origin;
220                    desc.fWidth = kWidthHeight;
221                    desc.fHeight = kWidthHeight;
222                    desc.fConfig = config;
223                    desc.fSampleCnt = numSamples;
224
225                    // External on-screen render target.
226                    if (renderable && kOpenGL_GrBackend == ctxInfo.backend()) {
227                        GrBackendRenderTargetDesc backendDesc;
228                        backendDesc.fWidth = kWidthHeight;
229                        backendDesc.fHeight = kWidthHeight;
230                        backendDesc.fConfig = config;
231                        backendDesc.fOrigin = origin;
232                        backendDesc.fSampleCnt = numSamples;
233                        backendDesc.fStencilBits = 8;
234                        backendDesc.fRenderTargetHandle = 0;
235
236                        sk_sp<GrRenderTarget> defaultFBO(
237                            provider->wrapBackendRenderTarget(backendDesc));
238
239                        sk_sp<GrSurfaceProxy> sProxy(GrSurfaceProxy::MakeWrapped(defaultFBO));
240                        check_surface(reporter, sProxy.get(), origin,
241                                      kWidthHeight, kWidthHeight, config,
242                                      defaultFBO->uniqueID(), SkBudgeted::kNo);
243                        check_rendertarget(reporter, caps, provider, sProxy->asRenderTargetProxy(),
244                                           numSamples, SkBackingFit::kExact, 0, true);
245                    }
246
247                    sk_sp<GrTexture> tex;
248
249                    // Internal offscreen render target.
250                    if (renderable) {
251                        desc.fFlags = kRenderTarget_GrSurfaceFlag;
252                        tex.reset(provider->createTexture(desc, budgeted));
253                        sk_sp<GrRenderTarget> rt(sk_ref_sp(tex->asRenderTarget()));
254
255                        sk_sp<GrSurfaceProxy> sProxy(GrSurfaceProxy::MakeWrapped(rt));
256                        check_surface(reporter, sProxy.get(), origin,
257                                      kWidthHeight, kWidthHeight, config,
258                                      rt->uniqueID(), budgeted);
259                        check_rendertarget(reporter, caps, provider, sProxy->asRenderTargetProxy(),
260                                           numSamples, SkBackingFit::kExact,
261                                           caps.maxWindowRectangles(), true);
262                    }
263
264                    if (!tex) {
265                        SkASSERT(kNone_GrSurfaceFlags == desc.fFlags );
266                        desc.fSampleCnt = 0;
267                        tex.reset(provider->createTexture(desc, budgeted));
268                    }
269
270                    sk_sp<GrSurfaceProxy> sProxy(GrSurfaceProxy::MakeWrapped(tex));
271                    check_surface(reporter, sProxy.get(), origin,
272                                  kWidthHeight, kWidthHeight, config, tex->uniqueID(), budgeted);
273                    check_texture(reporter, provider, sProxy->asTextureProxy(),
274                                  SkBackingFit::kExact, true);
275                }
276            }
277        }
278    }
279}
280
281#endif
282