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