• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 Google LLC
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 "tests/Test.h"
9 
10 #include "src/gpu/GrFragmentProcessor.h"
11 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
12 #include "src/gpu/v1/SurfaceDrawContext_v1.h"
13 
14 static void run_test(skiatest::Reporter*, GrDirectContext*,
15                      skgpu::v1::SurfaceDrawContext*, SkVector a,
16                      SkVector b, float expectedCrossProduct);
17 
18 // This is a GPU test that ensures the SkSL 2d cross() intrinsic returns the correct sign (negative,
19 // positive, or zero).
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkSLCross,reporter,ctxInfo)20 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(SkSLCross, reporter, ctxInfo) {
21     GrDirectContext* dContext = ctxInfo.directContext();
22     auto sdc = skgpu::v1::SurfaceDrawContext::Make(dContext, GrColorType::kRGBA_8888, nullptr,
23                                                    SkBackingFit::kExact, {1, 1}, SkSurfaceProps());
24     if (!sdc) {
25         ERRORF(reporter, "could not create render target context.");
26         return;
27     }
28     run_test(reporter, dContext, sdc.get(), {3,4}, {5,6}, -2);  // Negative.
29     run_test(reporter, dContext, sdc.get(), {3,4}, {-5,-6}, 2);  // Positive.
30     run_test(reporter, dContext, sdc.get(), {0, 2.287f}, {0, -7.741f}, 0);  // Zero.
31     run_test(reporter, dContext, sdc.get(), {62.17f, 0}, {-43.49f, 0}, 0);  // Zero.
32 }
33 
34 namespace {
35 
36 // Outputs:
37 //     Green if cross(a,b) > 0
38 //     Red if cross(a,b) < 0
39 //     Black if cross(a,b) == 0
40 class VisualizeCrossProductSignFP : public GrFragmentProcessor {
41 public:
VisualizeCrossProductSignFP(SkVector a,SkVector b)42     VisualizeCrossProductSignFP(SkVector a, SkVector b)
43             : GrFragmentProcessor(kTestFP_ClassID, kPreservesOpaqueInput_OptimizationFlag)
44             , fA(a), fB(b) {
45     }
46 
name() const47     const char* name() const override { return "VisualizeCrossProductSignFP"; }
48 
clone() const49     std::unique_ptr<GrFragmentProcessor> clone() const override {
50         return std::unique_ptr<GrFragmentProcessor>(new VisualizeCrossProductSignFP(fA, fB));
51     }
52 
53 private:
onAddToKey(const GrShaderCaps &,GrProcessorKeyBuilder *) const54     void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
onIsEqual(const GrFragmentProcessor &) const55     bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
56 
onMakeProgramImpl() const57     std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
58         class Impl : public ProgramImpl {
59         public:
60             void emitCode(EmitArgs& args) override {
61                 auto& fp = args.fFp.cast<VisualizeCrossProductSignFP>();
62                 const char *a, *b;
63                 fAUniform = args.fUniformHandler->addUniform(&fp, kFragment_GrShaderFlag,
64                                                              GrSLType::kFloat2_GrSLType, "a", &a);
65                 fBUniform = args.fUniformHandler->addUniform(&fp, kFragment_GrShaderFlag,
66                                                              GrSLType::kFloat2_GrSLType, "b", &b);
67                 args.fFragBuilder->codeAppendf(R"(
68                     float crossProduct = cross(%s, %s);
69                     float2 visualization = clamp(float2(-sign(crossProduct), sign(crossProduct)),
70                                                  float2(0), float2(1));
71                 return half2(visualization).xy01;)", a, b);
72             }
73 
74         private:
75             void onSetData(const GrGLSLProgramDataManager& pdman,
76                            const GrFragmentProcessor& processor) override {
77                 const auto& fp = processor.cast<VisualizeCrossProductSignFP>();
78                 pdman.set2f(fAUniform, fp.fA.x(), fp.fA.y());
79                 pdman.set2f(fBUniform, fp.fB.x(), fp.fB.y());
80             }
81             GrGLSLUniformHandler::UniformHandle fAUniform;
82             GrGLSLUniformHandler::UniformHandle fBUniform;
83         };
84 
85         return std::make_unique<Impl>();
86     }
87     const SkVector fA, fB;
88 };
89 
90 }  // namespace
91 
run_test(skiatest::Reporter * reporter,GrDirectContext * directContext,skgpu::v1::SurfaceDrawContext * sdc,SkVector a,SkVector b,float expectedCrossProduct)92 static void run_test(skiatest::Reporter* reporter, GrDirectContext* directContext,
93                      skgpu::v1::SurfaceDrawContext* sdc, SkVector a, SkVector b,
94                      float expectedCrossProduct) {
95     SkASSERT(sdc->width() == 1);
96     SkASSERT(sdc->height() == 1);
97 
98     sdc->clear(SkPMColor4f::FromBytes_RGBA(0xbaaaaaad));
99 
100     GrPaint crossPaint;
101     crossPaint.setColor4f(SK_PMColor4fWHITE);
102     crossPaint.setPorterDuffXPFactory(SkBlendMode::kSrcOver);
103     crossPaint.setColorFragmentProcessor(std::make_unique<VisualizeCrossProductSignFP>(a, b));
104     sdc->drawRect(/*clip=*/nullptr, std::move(crossPaint), GrAA::kNo, SkMatrix::I(),
105                   SkRect::MakeWH(1,1));
106 
107     GrColor result;
108     GrPixmap resultPM(SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kPremul_SkAlphaType),
109                       &result,
110                       sizeof(GrColor));
111     sdc->readPixels(directContext, resultPM, {0, 0});
112 
113     SkASSERT(expectedCrossProduct == a.cross(b));
114     if (expectedCrossProduct > 0) {
115         REPORTER_ASSERT(reporter, result == GrColorPackRGBA(0, 255, 0, 255));  // Green.
116     } else if (expectedCrossProduct < 0) {
117         REPORTER_ASSERT(reporter, result == GrColorPackRGBA(255, 0, 0, 255));  // Red.
118     } else {
119         REPORTER_ASSERT(reporter, result == GrColorPackRGBA(0, 0, 0, 255));  // Black.
120     }
121 }
122