1/*
2 * Copyright 2017 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// Include here to ensure SK_SUPPORT_GPU is set correctly before it is examined.
9#include "SkTypes.h"
10
11#if SK_SUPPORT_GPU
12#ifndef SK_DISABLE_DEFERRED_PROXIES
13#include "Test.h"
14
15#include "GrContextPriv.h"
16#include "GrGpu.h"
17#include "GrProxyProvider.h"
18#include "GrResourceAllocator.h"
19#include "GrResourceProvider.h"
20#include "GrSurfaceProxyPriv.h"
21#include "GrTest.h"
22#include "GrTexture.h"
23#include "GrTextureProxy.h"
24
25struct ProxyParams {
26    int             fSize;
27    bool            fIsRT;
28    GrPixelConfig   fConfig;
29    SkBackingFit    fFit;
30    int             fSampleCnt;
31    GrSurfaceOrigin fOrigin;
32    // TODO: do we care about mipmapping
33};
34
35static sk_sp<GrSurfaceProxy> make_deferred(GrProxyProvider* proxyProvider, const ProxyParams& p) {
36    GrSurfaceDesc desc;
37    desc.fFlags = p.fIsRT ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags;
38    desc.fOrigin = p.fOrigin;
39    desc.fWidth  = p.fSize;
40    desc.fHeight = p.fSize;
41    desc.fConfig = p.fConfig;
42    desc.fSampleCnt = p.fSampleCnt;
43
44    return proxyProvider->createProxy(desc, p.fFit, SkBudgeted::kNo);
45}
46
47static sk_sp<GrSurfaceProxy> make_backend(GrContext* context, const ProxyParams& p,
48                                          GrBackendTexture* backendTex) {
49    GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
50    GrGpu* gpu = context->contextPriv().getGpu();
51
52    *backendTex = gpu->createTestingOnlyBackendTexture(nullptr, p.fSize, p.fSize,
53                                                       p.fConfig, false,
54                                                       GrMipMapped::kNo);
55
56    return proxyProvider->createWrappedTextureProxy(*backendTex, p.fOrigin);
57}
58
59static void cleanup_backend(GrContext* context, GrBackendTexture* backendTex) {
60    context->contextPriv().getGpu()->deleteTestingOnlyBackendTexture(backendTex);
61}
62
63// Basic test that two proxies with overlapping intervals and compatible descriptors are
64// assigned different GrSurfaces.
65static void overlap_test(skiatest::Reporter* reporter, GrResourceProvider* resourceProvider,
66                         sk_sp<GrSurfaceProxy> p1, sk_sp<GrSurfaceProxy> p2,
67                         bool expectedResult) {
68    GrResourceAllocator alloc(resourceProvider);
69
70    alloc.addInterval(p1.get(), 0, 4);
71    alloc.addInterval(p2.get(), 1, 2);
72    alloc.markEndOfOpList(0);
73
74    int startIndex, stopIndex;
75    GrResourceAllocator::AssignError error;
76    alloc.assign(&startIndex, &stopIndex, &error);
77    REPORTER_ASSERT(reporter, GrResourceAllocator::AssignError::kNoError == error);
78
79    REPORTER_ASSERT(reporter, p1->priv().peekSurface());
80    REPORTER_ASSERT(reporter, p2->priv().peekSurface());
81    bool doTheBackingStoresMatch = p1->underlyingUniqueID() == p2->underlyingUniqueID();
82    REPORTER_ASSERT(reporter, expectedResult == doTheBackingStoresMatch);
83}
84
85// Test various cases when two proxies do not have overlapping intervals.
86// This mainly acts as a test of the ResourceAllocator's free pool.
87static void non_overlap_test(skiatest::Reporter* reporter, GrResourceProvider* resourceProvider,
88                             sk_sp<GrSurfaceProxy> p1, sk_sp<GrSurfaceProxy> p2,
89                             bool expectedResult) {
90    GrResourceAllocator alloc(resourceProvider);
91
92    alloc.addInterval(p1.get(), 0, 2);
93    alloc.addInterval(p2.get(), 3, 5);
94    alloc.markEndOfOpList(0);
95
96    int startIndex, stopIndex;
97    GrResourceAllocator::AssignError error;
98    alloc.assign(&startIndex, &stopIndex, &error);
99    REPORTER_ASSERT(reporter, GrResourceAllocator::AssignError::kNoError == error);
100
101    REPORTER_ASSERT(reporter, p1->priv().peekSurface());
102    REPORTER_ASSERT(reporter, p2->priv().peekSurface());
103    bool doTheBackingStoresMatch = p1->underlyingUniqueID() == p2->underlyingUniqueID();
104    REPORTER_ASSERT(reporter, expectedResult == doTheBackingStoresMatch);
105}
106
107DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceAllocatorTest, reporter, ctxInfo) {
108    GrProxyProvider* proxyProvider = ctxInfo.grContext()->contextPriv().proxyProvider();
109    GrResourceProvider* resourceProvider = ctxInfo.grContext()->contextPriv().resourceProvider();
110
111    struct TestCase {
112        ProxyParams   fP1;
113        ProxyParams   fP2;
114        bool          fExpectation;
115    };
116
117    constexpr bool kRT = true;
118    constexpr bool kNotRT = false;
119
120    constexpr bool kShare = true;
121    constexpr bool kDontShare = false;
122    // Non-RT GrSurfaces are never recycled on some platforms.
123    bool kConditionallyShare = resourceProvider->caps()->reuseScratchTextures();
124
125    const GrPixelConfig kRGBA = kRGBA_8888_GrPixelConfig;
126    const GrPixelConfig kBGRA = kBGRA_8888_GrPixelConfig;
127
128    const SkBackingFit kE = SkBackingFit::kExact;
129    const SkBackingFit kA = SkBackingFit::kApprox;
130
131    const GrSurfaceOrigin kTL = kTopLeft_GrSurfaceOrigin;
132    const GrSurfaceOrigin kBL = kBottomLeft_GrSurfaceOrigin;
133
134    //--------------------------------------------------------------------------------------------
135    TestCase gOverlappingTests[] = {
136        //----------------------------------------------------------------------------------------
137        // Two proxies with overlapping intervals and compatible descriptors should never share
138        // RT version
139        { { 64,    kRT, kRGBA, kA, 0, kTL }, { 64,    kRT, kRGBA, kA, 0, kTL }, kDontShare },
140        // non-RT version
141        { { 64, kNotRT, kRGBA, kA, 0, kTL }, { 64, kNotRT, kRGBA, kA, 0, kTL }, kDontShare },
142    };
143
144    for (auto test : gOverlappingTests) {
145        sk_sp<GrSurfaceProxy> p1 = make_deferred(proxyProvider, test.fP1);
146        sk_sp<GrSurfaceProxy> p2 = make_deferred(proxyProvider, test.fP2);
147        overlap_test(reporter, resourceProvider,
148                     std::move(p1), std::move(p2), test.fExpectation);
149    }
150
151    int k2 = ctxInfo.grContext()->caps()->getSampleCount(2, kRGBA);
152    int k4 = ctxInfo.grContext()->caps()->getSampleCount(4, kRGBA);
153
154    //--------------------------------------------------------------------------------------------
155    TestCase gNonOverlappingTests[] = {
156        //----------------------------------------------------------------------------------------
157        // Two non-overlapping intervals w/ compatible proxies should share
158        // both same size & approx
159        { { 64,    kRT, kRGBA, kA, 0, kTL }, { 64,    kRT, kRGBA, kA, 0, kTL }, kShare },
160        { { 64, kNotRT, kRGBA, kA, 0, kTL }, { 64, kNotRT, kRGBA, kA, 0, kTL }, kConditionallyShare },
161        // diffs sizes but still approx
162        { { 64,    kRT, kRGBA, kA, 0, kTL }, { 50,    kRT, kRGBA, kA, 0, kTL }, kShare },
163        { { 64, kNotRT, kRGBA, kA, 0, kTL }, { 50, kNotRT, kRGBA, kA, 0, kTL }, kConditionallyShare },
164        // sames sizes but exact
165        { { 64,    kRT, kRGBA, kE, 0, kTL }, { 64,    kRT, kRGBA, kE, 0, kTL }, kShare },
166        { { 64, kNotRT, kRGBA, kE, 0, kTL }, { 64, kNotRT, kRGBA, kE, 0, kTL }, kConditionallyShare },
167        //----------------------------------------------------------------------------------------
168        // Two non-overlapping intervals w/ different exact sizes should not share
169        { { 56,    kRT, kRGBA, kE, 0, kTL }, { 54,    kRT, kRGBA, kE, 0, kTL }, kDontShare },
170        // Two non-overlapping intervals w/ _very different_ approx sizes should not share
171        { { 255,   kRT, kRGBA, kA, 0, kTL }, { 127,   kRT, kRGBA, kA, 0, kTL }, kDontShare },
172        // Two non-overlapping intervals w/ different MSAA sample counts should not share
173        { { 64,    kRT, kRGBA, kA, k2, kTL },{ 64,    kRT, kRGBA, kA, k4, kTL}, k2 == k4 },
174        // Two non-overlapping intervals w/ different configs should not share
175        { { 64,    kRT, kRGBA, kA, 0, kTL }, { 64,    kRT, kBGRA, kA, 0, kTL }, kDontShare },
176        // Two non-overlapping intervals w/ different RT classifications should never share
177        { { 64,    kRT, kRGBA, kA, 0, kTL }, { 64, kNotRT, kRGBA, kA, 0, kTL }, kDontShare },
178        { { 64, kNotRT, kRGBA, kA, 0, kTL }, { 64,    kRT, kRGBA, kA, 0, kTL }, kDontShare },
179        // Two non-overlapping intervals w/ different origins should share
180        { { 64,    kRT, kRGBA, kA, 0, kTL }, { 64,    kRT, kRGBA, kA, 0, kBL }, kShare },
181    };
182
183    for (auto test : gNonOverlappingTests) {
184        sk_sp<GrSurfaceProxy> p1 = make_deferred(proxyProvider, test.fP1);
185        sk_sp<GrSurfaceProxy> p2 = make_deferred(proxyProvider, test.fP2);
186        if (!p1 || !p2) {
187            continue; // creation can fail (i.e., for msaa4 on iOS)
188        }
189        non_overlap_test(reporter, resourceProvider,
190                         std::move(p1), std::move(p2), test.fExpectation);
191    }
192
193    {
194        // Wrapped backend textures should never be reused
195        TestCase t[1] = {
196            { { 64, kNotRT, kRGBA, kE, 0, kTL }, { 64, kNotRT, kRGBA, kE, 0, kTL }, kDontShare }
197        };
198
199        GrBackendTexture backEndTex;
200        sk_sp<GrSurfaceProxy> p1 = make_backend(ctxInfo.grContext(), t[0].fP1, &backEndTex);
201        sk_sp<GrSurfaceProxy> p2 = make_deferred(proxyProvider, t[0].fP2);
202        non_overlap_test(reporter, resourceProvider,
203                         std::move(p1), std::move(p2), t[0].fExpectation);
204        cleanup_backend(ctxInfo.grContext(), &backEndTex);
205    }
206}
207
208#endif
209#endif
210