• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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 
11 #include "src/base/SkArenaAlloc.h"
12 #include "src/gpu/graphite/ContextPriv.h"
13 #include "src/gpu/graphite/PaintParamsKey.h"
14 #include "src/gpu/graphite/ShaderCodeDictionary.h"
15 
16 using namespace skgpu::graphite;
17 
18 namespace {
19 
add_block(PaintParamsKeyBuilder * builder,int snippetID)20 void add_block(PaintParamsKeyBuilder* builder, int snippetID) {
21     builder->beginBlock(snippetID);
22     builder->endBlock();
23 }
24 
create_key(const ShaderCodeDictionary * dict,int snippetID,SkArenaAlloc * arena)25 PaintParamsKey create_key(const ShaderCodeDictionary* dict, int snippetID, SkArenaAlloc* arena) {
26     PaintParamsKeyBuilder builder{dict};
27     add_block(&builder, snippetID);
28 
29     AutoLockBuilderAsKey keyView{&builder};
30     return keyView->clone(arena);
31 }
32 
coeff_equal(SkBlendModeCoeff skCoeff,skgpu::BlendCoeff gpuCoeff)33 bool coeff_equal(SkBlendModeCoeff skCoeff, skgpu::BlendCoeff gpuCoeff) {
34     switch(skCoeff) {
35         case SkBlendModeCoeff::kZero: return skgpu::BlendCoeff::kZero == gpuCoeff;
36         case SkBlendModeCoeff::kOne:  return skgpu::BlendCoeff::kOne == gpuCoeff;
37         case SkBlendModeCoeff::kSC:   return skgpu::BlendCoeff::kSC == gpuCoeff;
38         case SkBlendModeCoeff::kISC:  return skgpu::BlendCoeff::kISC == gpuCoeff;
39         case SkBlendModeCoeff::kDC:   return skgpu::BlendCoeff::kDC == gpuCoeff;
40         case SkBlendModeCoeff::kIDC:  return skgpu::BlendCoeff::kIDC == gpuCoeff;
41         case SkBlendModeCoeff::kSA:   return skgpu::BlendCoeff::kSA == gpuCoeff;
42         case SkBlendModeCoeff::kISA:  return skgpu::BlendCoeff::kISA == gpuCoeff;
43         case SkBlendModeCoeff::kDA:   return skgpu::BlendCoeff::kDA == gpuCoeff;
44         case SkBlendModeCoeff::kIDA:  return skgpu::BlendCoeff::kIDA == gpuCoeff;
45         default:                      return false;
46     }
47 }
48 
49 } // anonymous namespace
50 
51 // These are intended to be unit tests of the PaintParamsKeyBuilder and PaintParamsKey.
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(KeyWithInvalidCodeSnippetIDTest,reporter,context,CtsEnforcement::kNextRelease)52 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(KeyWithInvalidCodeSnippetIDTest, reporter, context,
53                                    CtsEnforcement::kNextRelease) {
54     SkArenaAlloc arena{256};
55     ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
56 
57     // A builder without any data is invalid. The Builder and the PaintParamKeys can include
58     // invalid IDs without themselves becoming invalid. Normally adding an invalid ID triggers an
59     // assert in debug builds, since the properly functioning key system should never encounter an
60     // invalid ID.
61     PaintParamsKeyBuilder builder(dict);
62     AutoLockBuilderAsKey keyView{&builder};
63     REPORTER_ASSERT(reporter, !keyView->isValid());
64     REPORTER_ASSERT(reporter, !PaintParamsKey::Invalid().isValid());
65 
66     // However, if the program gets in a malformed state on release builds, the key
67     // could contain an invalid ID. In that case the invalid snippet IDs are detected when
68     // reconstructing the key into an effect tree for SkSL generation. To test this, we manually
69     // construct an invalid span and test that it returns a null shader node tree when treated as
70     // a PaintParamsKey.
71     // NOTE: This is intentionally abusing memory to create a corrupt scenario and is dependent on
72     // the structure of PaintParamsKey (just SkSpan<const int32_t>).
73     int32_t invalidKeyData[3] = {(int32_t) BuiltInCodeSnippetID::kSolidColorShader,
74                                  SkKnownRuntimeEffects::kSkiaBuiltInReservedCnt - 1,
75                                  (int32_t) BuiltInCodeSnippetID::kFixedFunctionSrcBlendMode};
76     SkSpan<const int32_t> invalidKeySpan{invalidKeyData, std::size(invalidKeyData)*sizeof(int32_t)};
77     const PaintParamsKey* fakeKey = reinterpret_cast<const PaintParamsKey*>(&invalidKeySpan);
78     REPORTER_ASSERT(reporter, fakeKey->getRootNodes(dict, &arena).empty());
79 }
80 
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(KeyEqualityChecksSnippetID,reporter,context,CtsEnforcement::kNextRelease)81 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(KeyEqualityChecksSnippetID, reporter, context,
82                                    CtsEnforcement::kNextRelease) {
83     SkArenaAlloc arena{256};
84     ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
85 
86     int userSnippetID1 = dict->addRuntimeEffectSnippet("key1");
87     int userSnippetID2 = dict->addRuntimeEffectSnippet("key2");
88 
89     PaintParamsKey keyA = create_key(dict, userSnippetID1, &arena);
90     PaintParamsKey keyB = create_key(dict, userSnippetID1, &arena);
91     PaintParamsKey keyC = create_key(dict, userSnippetID2, &arena);
92 
93     // Verify that keyA matches keyB, and that it does not match keyC.
94     REPORTER_ASSERT(reporter, keyA == keyB);
95     REPORTER_ASSERT(reporter, keyA != keyC);
96     REPORTER_ASSERT(reporter, !(keyA == keyC));
97     REPORTER_ASSERT(reporter, !(keyA != keyB));
98 }
99 
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ShaderInfoDetectsFixedFunctionBlend,reporter,context,CtsEnforcement::kNextRelease)100 DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(ShaderInfoDetectsFixedFunctionBlend, reporter, context,
101                                    CtsEnforcement::kNextRelease) {
102     ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
103 
104     for (int bm = 0; bm <= (int) SkBlendMode::kLastCoeffMode; ++bm) {
105         PaintParamsKeyBuilder builder(dict);
106         add_block(&builder, bm + kFixedFunctionBlendModeIDOffset);
107         UniquePaintParamsID paintID = dict->findOrCreate(&builder);
108 
109         ShaderInfo shaderInfo{paintID, dict, /*rteDict=*/nullptr, /*ssboIndex=*/""};
110 
111         SkBlendModeCoeff expectedSrc, expectedDst;
112         REPORTER_ASSERT(reporter, SkBlendMode_AsCoeff(static_cast<SkBlendMode>(bm),
113                                                       &expectedSrc, &expectedDst));
114         REPORTER_ASSERT(reporter, coeff_equal(expectedSrc, shaderInfo.blendInfo().fSrcBlend));
115         REPORTER_ASSERT(reporter, coeff_equal(expectedDst, shaderInfo.blendInfo().fDstBlend));
116         REPORTER_ASSERT(reporter, shaderInfo.blendInfo().fEquation == skgpu::BlendEquation::kAdd);
117         REPORTER_ASSERT(reporter, shaderInfo.blendInfo().fBlendConstant == SK_PMColor4fTRANSPARENT);
118 
119         bool expectedWriteColor = BlendModifiesDst(skgpu::BlendEquation::kAdd,
120                                                    shaderInfo.blendInfo().fSrcBlend,
121                                                    shaderInfo.blendInfo().fDstBlend);
122         REPORTER_ASSERT(reporter, shaderInfo.blendInfo().fWritesColor == expectedWriteColor);
123     }
124 }
125 
126 // TODO: Add unit tests for converting a complex key to a ShaderInfo
127