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#include "SkTypes.h"
9#include "SkPoint.h"
10#include "Test.h"
11#include <vector>
12
13#if SK_SUPPORT_GPU
14
15#include "GrAppliedClip.h"
16#include "GrPipelineBuilder.h"
17#include "GrRenderTargetContext.h"
18#include "GrRenderTargetPriv.h"
19#include "GrTypesPriv.h"
20#include "gl/GrGLGpu.h"
21#include "gl/debug/DebugGLTestContext.h"
22
23typedef std::vector<SkPoint> SamplePattern;
24
25static const SamplePattern kTestPatterns[] = {
26    SamplePattern{ // Intel on mac, msaa8, offscreen.
27        {0.562500, 0.312500},
28        {0.437500, 0.687500},
29        {0.812500, 0.562500},
30        {0.312500, 0.187500},
31        {0.187500, 0.812500},
32        {0.062500, 0.437500},
33        {0.687500, 0.937500},
34        {0.937500, 0.062500}
35    },
36
37    SamplePattern{ // Intel on mac, msaa8, on-screen.
38        {0.562500, 0.687500},
39        {0.437500, 0.312500},
40        {0.812500, 0.437500},
41        {0.312500, 0.812500},
42        {0.187500, 0.187500},
43        {0.062500, 0.562500},
44        {0.687500, 0.062500},
45        {0.937500, 0.937500}
46    },
47
48    SamplePattern{ // NVIDIA, msaa16.
49        {0.062500, 0.000000},
50        {0.250000, 0.125000},
51        {0.187500, 0.375000},
52        {0.437500, 0.312500},
53        {0.500000, 0.062500},
54        {0.687500, 0.187500},
55        {0.750000, 0.437500},
56        {0.937500, 0.250000},
57        {0.000000, 0.500000},
58        {0.312500, 0.625000},
59        {0.125000, 0.750000},
60        {0.375000, 0.875000},
61        {0.562500, 0.562500},
62        {0.812500, 0.687500},
63        {0.625000, 0.812500},
64        {0.875000, 0.937500}
65    },
66
67    SamplePattern{ // NVIDIA, mixed samples, 16:1.
68        {0.250000, 0.125000},
69        {0.625000, 0.812500},
70        {0.500000, 0.062500},
71        {0.812500, 0.687500},
72        {0.187500, 0.375000},
73        {0.875000, 0.937500},
74        {0.125000, 0.750000},
75        {0.750000, 0.437500},
76        {0.937500, 0.250000},
77        {0.312500, 0.625000},
78        {0.437500, 0.312500},
79        {0.000000, 0.500000},
80        {0.375000, 0.875000},
81        {0.687500, 0.187500},
82        {0.062500, 0.000000},
83        {0.562500, 0.562500}
84    }
85};
86constexpr int numTestPatterns = SK_ARRAY_COUNT(kTestPatterns);
87
88class TestSampleLocationsInterface : public SkNoncopyable {
89public:
90    virtual void overrideSamplePattern(const SamplePattern&) = 0;
91    virtual ~TestSampleLocationsInterface() {}
92};
93
94static void construct_dummy_pipeline(GrRenderTargetContext* dc, GrPipeline* pipeline) {
95    GrPipelineBuilder dummyBuilder(GrPaint(), GrAAType::kNone);
96    GrScissorState dummyScissor;
97    GrWindowRectsState dummyWindows;
98
99    GrProcessorSet::FragmentProcessorAnalysis analysis;
100    GrPipeline::InitArgs args;
101    dummyBuilder.getPipelineInitArgs(&args);
102    args.fRenderTarget = dc->accessRenderTarget();
103    args.fAnalysis = &analysis;
104    args.fCaps = dc->caps();
105    args.fDstTexture = GrXferProcessor::DstTexture();
106    pipeline->init(args);
107}
108
109void assert_equal(skiatest::Reporter* reporter, const SamplePattern& pattern,
110                  const GrGpu::MultisampleSpecs& specs, bool flipY) {
111    GrAlwaysAssert(specs.fSampleLocations);
112    if ((int)pattern.size() != specs.fEffectiveSampleCnt) {
113        REPORT_FAILURE(reporter, "", SkString("Sample pattern has wrong number of samples."));
114        return;
115    }
116    for (int i = 0; i < specs.fEffectiveSampleCnt; ++i) {
117        SkPoint expectedLocation = specs.fSampleLocations[i];
118        if (flipY) {
119            expectedLocation.fY = 1 - expectedLocation.fY;
120        }
121        if (pattern[i] != expectedLocation) {
122            REPORT_FAILURE(reporter, "", SkString("Sample pattern has wrong sample location."));
123            return;
124        }
125    }
126}
127
128void test_sampleLocations(skiatest::Reporter* reporter, TestSampleLocationsInterface* testInterface,
129                          GrContext* ctx) {
130    SkRandom rand;
131    sk_sp<GrRenderTargetContext> bottomUps[numTestPatterns];
132    sk_sp<GrRenderTargetContext> topDowns[numTestPatterns];
133    for (int i = 0; i < numTestPatterns; ++i) {
134        int numSamples = (int)kTestPatterns[i].size();
135        GrAlwaysAssert(numSamples > 1 && SkIsPow2(numSamples));
136        bottomUps[i] = ctx->makeRenderTargetContextWithFallback(
137                           SkBackingFit::kExact, 100, 100, kRGBA_8888_GrPixelConfig, nullptr,
138                           rand.nextRangeU(1 + numSamples / 2, numSamples),
139                           kBottomLeft_GrSurfaceOrigin);
140        topDowns[i] = ctx->makeRenderTargetContextWithFallback(
141                          SkBackingFit::kExact, 100, 100, kRGBA_8888_GrPixelConfig, nullptr,
142                          rand.nextRangeU(1 + numSamples / 2, numSamples),
143                          kTopLeft_GrSurfaceOrigin);
144    }
145
146    // Ensure all sample locations get queried and/or cached properly.
147    for (int repeat = 0; repeat < 2; ++repeat) {
148        for (int i = 0; i < numTestPatterns; ++i) {
149            testInterface->overrideSamplePattern(kTestPatterns[i]);
150            for (GrRenderTargetContext* dc : {bottomUps[i].get(), topDowns[i].get()}) {
151                GrPipeline dummyPipeline;
152                construct_dummy_pipeline(dc, &dummyPipeline);
153                GrRenderTarget* rt = dc->accessRenderTarget();
154                assert_equal(reporter, kTestPatterns[i],
155                             rt->renderTargetPriv().getMultisampleSpecs(dummyPipeline),
156                             kBottomLeft_GrSurfaceOrigin == rt->origin());
157            }
158        }
159    }
160
161}
162
163////////////////////////////////////////////////////////////////////////////////////////////////////
164
165class GLTestSampleLocationsInterface : public TestSampleLocationsInterface, public GrGLInterface {
166public:
167    GLTestSampleLocationsInterface() : fTestContext(sk_gpu_test::CreateDebugGLTestContext()) {
168        fStandard = fTestContext->gl()->fStandard;
169        fExtensions = fTestContext->gl()->fExtensions;
170        fFunctions = fTestContext->gl()->fFunctions;
171
172        fFunctions.fGetIntegerv = [&](GrGLenum pname, GrGLint* params) {
173            GrAlwaysAssert(GR_GL_EFFECTIVE_RASTER_SAMPLES != pname);
174            if (GR_GL_SAMPLES == pname) {
175                GrAlwaysAssert(!fSamplePattern.empty());
176                *params = (int)fSamplePattern.size();
177            } else {
178                fTestContext->gl()->fFunctions.fGetIntegerv(pname, params);
179            }
180        };
181
182        fFunctions.fGetMultisamplefv = [&](GrGLenum pname, GrGLuint index, GrGLfloat* val) {
183            GrAlwaysAssert(GR_GL_SAMPLE_POSITION == pname);
184            val[0] = fSamplePattern[index].fX;
185            val[1] = fSamplePattern[index].fY;
186        };
187    }
188
189    operator GrBackendContext() {
190        return reinterpret_cast<GrBackendContext>(static_cast<GrGLInterface*>(this));
191    }
192
193    void overrideSamplePattern(const SamplePattern& newPattern) override {
194        fSamplePattern = newPattern;
195    }
196
197private:
198    std::unique_ptr<sk_gpu_test::GLTestContext> fTestContext;
199    SamplePattern                               fSamplePattern;
200};
201
202DEF_GPUTEST(GLSampleLocations, reporter, /*factory*/) {
203    GLTestSampleLocationsInterface testInterface;
204    sk_sp<GrContext> ctx(GrContext::Create(kOpenGL_GrBackend, testInterface));
205    test_sampleLocations(reporter, &testInterface, ctx.get());
206}
207
208#endif
209