/* * Copyright 2016 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkTypes.h" #include "SkPoint.h" #include "Test.h" #include #if SK_SUPPORT_GPU #include "GrRenderTargetContext.h" #include "GrRenderTargetPriv.h" #include "GrTypesPriv.h" #include "GrPipelineBuilder.h" #include "gl/GrGLGpu.h" #include "gl/debug/DebugGLTestContext.h" typedef std::vector SamplePattern; static const SamplePattern kTestPatterns[] = { SamplePattern{ // Intel on mac, msaa8, offscreen. {0.562500, 0.312500}, {0.437500, 0.687500}, {0.812500, 0.562500}, {0.312500, 0.187500}, {0.187500, 0.812500}, {0.062500, 0.437500}, {0.687500, 0.937500}, {0.937500, 0.062500} }, SamplePattern{ // Intel on mac, msaa8, on-screen. {0.562500, 0.687500}, {0.437500, 0.312500}, {0.812500, 0.437500}, {0.312500, 0.812500}, {0.187500, 0.187500}, {0.062500, 0.562500}, {0.687500, 0.062500}, {0.937500, 0.937500} }, SamplePattern{ // NVIDIA, msaa16. {0.062500, 0.000000}, {0.250000, 0.125000}, {0.187500, 0.375000}, {0.437500, 0.312500}, {0.500000, 0.062500}, {0.687500, 0.187500}, {0.750000, 0.437500}, {0.937500, 0.250000}, {0.000000, 0.500000}, {0.312500, 0.625000}, {0.125000, 0.750000}, {0.375000, 0.875000}, {0.562500, 0.562500}, {0.812500, 0.687500}, {0.625000, 0.812500}, {0.875000, 0.937500} }, SamplePattern{ // NVIDIA, mixed samples, 16:1. {0.250000, 0.125000}, {0.625000, 0.812500}, {0.500000, 0.062500}, {0.812500, 0.687500}, {0.187500, 0.375000}, {0.875000, 0.937500}, {0.125000, 0.750000}, {0.750000, 0.437500}, {0.937500, 0.250000}, {0.312500, 0.625000}, {0.437500, 0.312500}, {0.000000, 0.500000}, {0.375000, 0.875000}, {0.687500, 0.187500}, {0.062500, 0.000000}, {0.562500, 0.562500} } }; constexpr int numTestPatterns = SK_ARRAY_COUNT(kTestPatterns); class TestSampleLocationsInterface : public SkNoncopyable { public: virtual void overrideSamplePattern(const SamplePattern&) = 0; virtual ~TestSampleLocationsInterface() {} }; static GrPipeline* construct_dummy_pipeline(GrRenderTargetContext* dc, void* storage) { GrPipelineBuilder dummyBuilder(GrPaint(), GrAAType::kNone); GrScissorState dummyScissor; GrWindowRectsState dummyWindows; GrPipelineOptimizations dummyOverrides; GrPipeline::CreateArgs args; args.fPipelineBuilder = &dummyBuilder; args.fRenderTargetContext = dc; args.fCaps = dc->caps(); args.fScissor = &dummyScissor; args.fWindowRectsState = &dummyWindows; args.fHasStencilClip = false; args.fDstTexture = GrXferProcessor::DstTexture(); GrPipeline::CreateAt(storage, args, &dummyOverrides); return reinterpret_cast(storage); } void assert_equal(skiatest::Reporter* reporter, const SamplePattern& pattern, const GrGpu::MultisampleSpecs& specs, bool flipY) { GrAlwaysAssert(specs.fSampleLocations); if ((int)pattern.size() != specs.fEffectiveSampleCnt) { REPORT_FAILURE(reporter, "", SkString("Sample pattern has wrong number of samples.")); return; } for (int i = 0; i < specs.fEffectiveSampleCnt; ++i) { SkPoint expectedLocation = specs.fSampleLocations[i]; if (flipY) { expectedLocation.fY = 1 - expectedLocation.fY; } if (pattern[i] != expectedLocation) { REPORT_FAILURE(reporter, "", SkString("Sample pattern has wrong sample location.")); return; } } } void test_sampleLocations(skiatest::Reporter* reporter, TestSampleLocationsInterface* testInterface, GrContext* ctx) { SkRandom rand; sk_sp bottomUps[numTestPatterns]; sk_sp topDowns[numTestPatterns]; for (int i = 0; i < numTestPatterns; ++i) { int numSamples = (int)kTestPatterns[i].size(); GrAlwaysAssert(numSamples > 1 && SkIsPow2(numSamples)); bottomUps[i] = ctx->makeRenderTargetContextWithFallback( SkBackingFit::kExact, 100, 100, kRGBA_8888_GrPixelConfig, nullptr, rand.nextRangeU(1 + numSamples / 2, numSamples), kBottomLeft_GrSurfaceOrigin); topDowns[i] = ctx->makeRenderTargetContextWithFallback( SkBackingFit::kExact, 100, 100, kRGBA_8888_GrPixelConfig, nullptr, rand.nextRangeU(1 + numSamples / 2, numSamples), kTopLeft_GrSurfaceOrigin); } // Ensure all sample locations get queried and/or cached properly. SkAlignedSTStorage<1, GrPipeline> pipelineStorage; for (int repeat = 0; repeat < 2; ++repeat) { for (int i = 0; i < numTestPatterns; ++i) { testInterface->overrideSamplePattern(kTestPatterns[i]); for (GrRenderTargetContext* dc : {bottomUps[i].get(), topDowns[i].get()}) { GrPipeline* dummyPipe = construct_dummy_pipeline(dc, pipelineStorage.get()); GrRenderTarget* rt = dc->accessRenderTarget(); assert_equal(reporter, kTestPatterns[i], rt->renderTargetPriv().getMultisampleSpecs(*dummyPipe), kBottomLeft_GrSurfaceOrigin == rt->origin()); dummyPipe->~GrPipeline(); } } } } //////////////////////////////////////////////////////////////////////////////////////////////////// class GLTestSampleLocationsInterface : public TestSampleLocationsInterface, public GrGLInterface { public: GLTestSampleLocationsInterface() : fTestContext(sk_gpu_test::CreateDebugGLTestContext()) { fStandard = fTestContext->gl()->fStandard; fExtensions = fTestContext->gl()->fExtensions; fFunctions = fTestContext->gl()->fFunctions; fFunctions.fGetIntegerv = [&](GrGLenum pname, GrGLint* params) { GrAlwaysAssert(GR_GL_EFFECTIVE_RASTER_SAMPLES != pname); if (GR_GL_SAMPLES == pname) { GrAlwaysAssert(!fSamplePattern.empty()); *params = (int)fSamplePattern.size(); } else { fTestContext->gl()->fFunctions.fGetIntegerv(pname, params); } }; fFunctions.fGetMultisamplefv = [&](GrGLenum pname, GrGLuint index, GrGLfloat* val) { GrAlwaysAssert(GR_GL_SAMPLE_POSITION == pname); val[0] = fSamplePattern[index].fX; val[1] = fSamplePattern[index].fY; }; } operator GrBackendContext() { return reinterpret_cast(static_cast(this)); } void overrideSamplePattern(const SamplePattern& newPattern) override { fSamplePattern = newPattern; } private: std::unique_ptr fTestContext; SamplePattern fSamplePattern; }; DEF_GPUTEST(GLSampleLocations, reporter, /*factory*/) { GLTestSampleLocationsInterface testInterface; sk_sp ctx(GrContext::Create(kOpenGL_GrBackend, testInterface)); test_sampleLocations(reporter, &testInterface, ctx.get()); } #endif