1 /*
2 * Copyright 2022 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 "include/core/SkSpan.h"
9 #include "include/private/SkSLModifiers.h"
10 #include "include/private/SkSLString.h"
11 #include "include/sksl/SkSLErrorReporter.h"
12 #include "src/sksl/SkSLBuiltinTypes.h"
13 #include "src/sksl/SkSLCompiler.h"
14 #include "src/sksl/SkSLContext.h"
15 #include "src/sksl/SkSLProgramSettings.h"
16 #include "src/sksl/SkSLThreadContext.h"
17 #include "src/sksl/ir/SkSLField.h"
18 #include "src/sksl/ir/SkSLInterfaceBlock.h"
19 #include "src/sksl/ir/SkSLSymbolTable.h"
20
21 #include <cstddef>
22 #include <cstdint>
23 #include <vector>
24
25 namespace SkSL {
26
27 enum class ProgramKind : int8_t;
28
~InterfaceBlock()29 InterfaceBlock::~InterfaceBlock() {
30 // Unhook this InterfaceBlock from its associated Variable, since we're being deleted.
31 if (fVariable) {
32 fVariable->detachDeadInterfaceBlock();
33 }
34 }
35
find_rt_adjust_index(SkSpan<const Type::Field> fields)36 static std::optional<int> find_rt_adjust_index(SkSpan<const Type::Field> fields) {
37 for (size_t index = 0; index < fields.size(); ++index) {
38 const SkSL::Type::Field& f = fields[index];
39 if (f.fName == SkSL::Compiler::RTADJUST_NAME) {
40 return index;
41 }
42 }
43
44 return std::nullopt;
45 }
46
Convert(const Context & context,Position pos,Variable * variable,std::shared_ptr<SymbolTable> symbols)47 std::unique_ptr<InterfaceBlock> InterfaceBlock::Convert(const Context& context,
48 Position pos,
49 Variable* variable,
50 std::shared_ptr<SymbolTable> symbols) {
51 if (SkSL::ProgramKind kind = context.fConfig->fKind; !ProgramConfig::IsFragment(kind) &&
52 !ProgramConfig::IsVertex(kind) &&
53 !ProgramConfig::IsCompute(kind)) {
54 context.fErrors->error(pos, "interface blocks are not allowed in this kind of program");
55 return nullptr;
56 }
57
58 // Find sk_RTAdjust and error out if it's not of type `float4`.
59 SkSpan<const Type::Field> fields = variable->type().componentType().fields();
60 std::optional<int> rtAdjustIndex = find_rt_adjust_index(fields);
61 if (rtAdjustIndex.has_value()) {
62 const Type::Field& rtAdjustField = fields[*rtAdjustIndex];
63 if (!rtAdjustField.fType->matches(*context.fTypes.fFloat4)) {
64 context.fErrors->error(rtAdjustField.fPosition, "sk_RTAdjust must have type 'float4'");
65 return nullptr;
66 }
67 }
68 return InterfaceBlock::Make(context, pos, variable, rtAdjustIndex, symbols);
69 }
70
Make(const Context & context,Position pos,Variable * variable,std::optional<int> rtAdjustIndex,std::shared_ptr<SymbolTable> symbols)71 std::unique_ptr<InterfaceBlock> InterfaceBlock::Make(const Context& context,
72 Position pos,
73 Variable* variable,
74 std::optional<int> rtAdjustIndex,
75 std::shared_ptr<SymbolTable> symbols) {
76 SkASSERT(ProgramConfig::IsFragment(context.fConfig->fKind) ||
77 ProgramConfig::IsVertex(context.fConfig->fKind) ||
78 ProgramConfig::IsCompute(context.fConfig->fKind));
79
80 SkASSERT(variable->type().componentType().isInterfaceBlock());
81 SkSpan<const Type::Field> fields = variable->type().componentType().fields();
82
83 if (rtAdjustIndex.has_value()) {
84 [[maybe_unused]] const Type::Field& rtAdjustField = fields[*rtAdjustIndex];
85 SkASSERT(rtAdjustField.fName == SkSL::Compiler::RTADJUST_NAME);
86 SkASSERT(rtAdjustField.fType->matches(*context.fTypes.fFloat4));
87
88 ThreadContext::RTAdjustData& rtAdjustData = ThreadContext::RTAdjustState();
89 rtAdjustData.fInterfaceBlock = variable;
90 rtAdjustData.fFieldIndex = *rtAdjustIndex;
91 }
92
93 if (variable->name().empty()) {
94 // This interface block is anonymous. Add each field to the top-level symbol table.
95 for (size_t i = 0; i < fields.size(); ++i) {
96 symbols->add(std::make_unique<SkSL::Field>(fields[i].fPosition, variable, i));
97 }
98 } else {
99 // Add the global variable to the top-level symbol table.
100 symbols->addWithoutOwnership(variable);
101 }
102
103 return std::make_unique<SkSL::InterfaceBlock>(pos, variable, symbols);
104 }
105
clone() const106 std::unique_ptr<ProgramElement> InterfaceBlock::clone() const {
107 return std::make_unique<InterfaceBlock>(fPosition,
108 this->var(),
109 SymbolTable::WrapIfBuiltin(this->typeOwner()));
110 }
111
description() const112 std::string InterfaceBlock::description() const {
113 std::string result = this->var()->modifiers().description() +
114 std::string(this->typeName()) + " {\n";
115 const Type* structType = &this->var()->type();
116 if (structType->isArray()) {
117 structType = &structType->componentType();
118 }
119 for (const auto& f : structType->fields()) {
120 result += f.description() + "\n";
121 }
122 result += "}";
123 if (!this->instanceName().empty()) {
124 result += " " + std::string(this->instanceName());
125 if (this->arraySize() > 0) {
126 String::appendf(&result, "[%d]", this->arraySize());
127 }
128 }
129 return result + ";";
130 }
131
132 } // namespace SkSL
133