• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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