1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2022 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/ir/SkSLLayout.h"
9*c8dee2aaSAndroid Build Coastguard Worker
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkMathPriv.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLContext.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLErrorReporter.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLPosition.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/sksl/SkSLString.h"
16*c8dee2aaSAndroid Build Coastguard Worker
17*c8dee2aaSAndroid Build Coastguard Worker namespace SkSL {
18*c8dee2aaSAndroid Build Coastguard Worker
paddedDescription() const19*c8dee2aaSAndroid Build Coastguard Worker std::string Layout::paddedDescription() const {
20*c8dee2aaSAndroid Build Coastguard Worker std::string result;
21*c8dee2aaSAndroid Build Coastguard Worker auto separator = SkSL::String::Separator();
22*c8dee2aaSAndroid Build Coastguard Worker if (fFlags & LayoutFlag::kVulkan) {
23*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "vulkan";
24*c8dee2aaSAndroid Build Coastguard Worker }
25*c8dee2aaSAndroid Build Coastguard Worker if (fFlags & LayoutFlag::kMetal) {
26*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "metal";
27*c8dee2aaSAndroid Build Coastguard Worker }
28*c8dee2aaSAndroid Build Coastguard Worker if (fFlags & LayoutFlag::kWebGPU) {
29*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "webgpu";
30*c8dee2aaSAndroid Build Coastguard Worker }
31*c8dee2aaSAndroid Build Coastguard Worker if (fFlags & LayoutFlag::kDirect3D) {
32*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "direct3d";
33*c8dee2aaSAndroid Build Coastguard Worker }
34*c8dee2aaSAndroid Build Coastguard Worker if (fFlags & LayoutFlag::kRGBA8) {
35*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "rgba8";
36*c8dee2aaSAndroid Build Coastguard Worker }
37*c8dee2aaSAndroid Build Coastguard Worker if (fFlags & LayoutFlag::kRGBA32F) {
38*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "rgba32f";
39*c8dee2aaSAndroid Build Coastguard Worker }
40*c8dee2aaSAndroid Build Coastguard Worker if (fFlags & LayoutFlag::kR32F) {
41*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "r32f";
42*c8dee2aaSAndroid Build Coastguard Worker }
43*c8dee2aaSAndroid Build Coastguard Worker if (fLocation >= 0) {
44*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "location = " + std::to_string(fLocation);
45*c8dee2aaSAndroid Build Coastguard Worker }
46*c8dee2aaSAndroid Build Coastguard Worker if (fOffset >= 0) {
47*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "offset = " + std::to_string(fOffset);
48*c8dee2aaSAndroid Build Coastguard Worker }
49*c8dee2aaSAndroid Build Coastguard Worker if (fBinding >= 0) {
50*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "binding = " + std::to_string(fBinding);
51*c8dee2aaSAndroid Build Coastguard Worker }
52*c8dee2aaSAndroid Build Coastguard Worker if (fTexture >= 0) {
53*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "texture = " + std::to_string(fTexture);
54*c8dee2aaSAndroid Build Coastguard Worker }
55*c8dee2aaSAndroid Build Coastguard Worker if (fSampler >= 0) {
56*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "sampler = " + std::to_string(fSampler);
57*c8dee2aaSAndroid Build Coastguard Worker }
58*c8dee2aaSAndroid Build Coastguard Worker if (fIndex >= 0) {
59*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "index = " + std::to_string(fIndex);
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker if (fSet >= 0) {
62*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "set = " + std::to_string(fSet);
63*c8dee2aaSAndroid Build Coastguard Worker }
64*c8dee2aaSAndroid Build Coastguard Worker if (fBuiltin >= 0) {
65*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "builtin = " + std::to_string(fBuiltin);
66*c8dee2aaSAndroid Build Coastguard Worker }
67*c8dee2aaSAndroid Build Coastguard Worker if (fInputAttachmentIndex >= 0) {
68*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "input_attachment_index = " + std::to_string(fInputAttachmentIndex);
69*c8dee2aaSAndroid Build Coastguard Worker }
70*c8dee2aaSAndroid Build Coastguard Worker if (fFlags & LayoutFlag::kOriginUpperLeft) {
71*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "origin_upper_left";
72*c8dee2aaSAndroid Build Coastguard Worker }
73*c8dee2aaSAndroid Build Coastguard Worker if (fFlags & LayoutFlag::kBlendSupportAllEquations) {
74*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "blend_support_all_equations";
75*c8dee2aaSAndroid Build Coastguard Worker }
76*c8dee2aaSAndroid Build Coastguard Worker if (fFlags & LayoutFlag::kPushConstant) {
77*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "push_constant";
78*c8dee2aaSAndroid Build Coastguard Worker }
79*c8dee2aaSAndroid Build Coastguard Worker if (fFlags & LayoutFlag::kColor) {
80*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "color";
81*c8dee2aaSAndroid Build Coastguard Worker }
82*c8dee2aaSAndroid Build Coastguard Worker if (fLocalSizeX >= 0) {
83*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "local_size_x = " + std::to_string(fLocalSizeX);
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker if (fLocalSizeY >= 0) {
86*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "local_size_y = " + std::to_string(fLocalSizeY);
87*c8dee2aaSAndroid Build Coastguard Worker }
88*c8dee2aaSAndroid Build Coastguard Worker if (fLocalSizeZ >= 0) {
89*c8dee2aaSAndroid Build Coastguard Worker result += separator() + "local_size_z = " + std::to_string(fLocalSizeZ);
90*c8dee2aaSAndroid Build Coastguard Worker }
91*c8dee2aaSAndroid Build Coastguard Worker if (result.size() > 0) {
92*c8dee2aaSAndroid Build Coastguard Worker result = "layout (" + result + ") ";
93*c8dee2aaSAndroid Build Coastguard Worker }
94*c8dee2aaSAndroid Build Coastguard Worker return result;
95*c8dee2aaSAndroid Build Coastguard Worker }
96*c8dee2aaSAndroid Build Coastguard Worker
description() const97*c8dee2aaSAndroid Build Coastguard Worker std::string Layout::description() const {
98*c8dee2aaSAndroid Build Coastguard Worker std::string s = this->paddedDescription();
99*c8dee2aaSAndroid Build Coastguard Worker if (!s.empty()) {
100*c8dee2aaSAndroid Build Coastguard Worker s.pop_back();
101*c8dee2aaSAndroid Build Coastguard Worker }
102*c8dee2aaSAndroid Build Coastguard Worker return s;
103*c8dee2aaSAndroid Build Coastguard Worker }
104*c8dee2aaSAndroid Build Coastguard Worker
checkPermittedLayout(const Context & context,Position pos,LayoutFlags permittedLayoutFlags) const105*c8dee2aaSAndroid Build Coastguard Worker bool Layout::checkPermittedLayout(const Context& context,
106*c8dee2aaSAndroid Build Coastguard Worker Position pos,
107*c8dee2aaSAndroid Build Coastguard Worker LayoutFlags permittedLayoutFlags) const {
108*c8dee2aaSAndroid Build Coastguard Worker static constexpr struct { LayoutFlag flag; const char* name; } kLayoutFlags[] = {
109*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kOriginUpperLeft, "origin_upper_left"},
110*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kPushConstant, "push_constant"},
111*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kBlendSupportAllEquations, "blend_support_all_equations"},
112*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kColor, "color"},
113*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kLocation, "location"},
114*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kOffset, "offset"},
115*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kBinding, "binding"},
116*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kTexture, "texture"},
117*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kSampler, "sampler"},
118*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kIndex, "index"},
119*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kSet, "set"},
120*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kBuiltin, "builtin"},
121*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kInputAttachmentIndex, "input_attachment_index"},
122*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kVulkan, "vulkan"},
123*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kMetal, "metal"},
124*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kWebGPU, "webgpu"},
125*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kDirect3D, "direct3d"},
126*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kRGBA8, "rgba8"},
127*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kRGBA32F, "rgba32f"},
128*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kR32F, "r32f"},
129*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kLocalSizeX, "local_size_x"},
130*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kLocalSizeY, "local_size_y"},
131*c8dee2aaSAndroid Build Coastguard Worker { LayoutFlag::kLocalSizeZ, "local_size_z"},
132*c8dee2aaSAndroid Build Coastguard Worker };
133*c8dee2aaSAndroid Build Coastguard Worker
134*c8dee2aaSAndroid Build Coastguard Worker bool success = true;
135*c8dee2aaSAndroid Build Coastguard Worker LayoutFlags layoutFlags = fFlags;
136*c8dee2aaSAndroid Build Coastguard Worker
137*c8dee2aaSAndroid Build Coastguard Worker LayoutFlags backendFlags = layoutFlags & LayoutFlag::kAllBackends;
138*c8dee2aaSAndroid Build Coastguard Worker if (SkPopCount(backendFlags.value()) > 1) {
139*c8dee2aaSAndroid Build Coastguard Worker context.fErrors->error(pos, "only one backend qualifier can be used");
140*c8dee2aaSAndroid Build Coastguard Worker success = false;
141*c8dee2aaSAndroid Build Coastguard Worker }
142*c8dee2aaSAndroid Build Coastguard Worker
143*c8dee2aaSAndroid Build Coastguard Worker LayoutFlags pixelFormatFlags = layoutFlags & LayoutFlag::kAllPixelFormats;
144*c8dee2aaSAndroid Build Coastguard Worker if (SkPopCount(pixelFormatFlags.value()) > 1) {
145*c8dee2aaSAndroid Build Coastguard Worker context.fErrors->error(pos, "only one pixel format qualifier can be used");
146*c8dee2aaSAndroid Build Coastguard Worker success = false;
147*c8dee2aaSAndroid Build Coastguard Worker }
148*c8dee2aaSAndroid Build Coastguard Worker
149*c8dee2aaSAndroid Build Coastguard Worker if ((layoutFlags & (LayoutFlag::kTexture | LayoutFlag::kSampler)) &&
150*c8dee2aaSAndroid Build Coastguard Worker layoutFlags & LayoutFlag::kBinding) {
151*c8dee2aaSAndroid Build Coastguard Worker context.fErrors->error(pos, "'binding' modifier cannot coexist with 'texture'/'sampler'");
152*c8dee2aaSAndroid Build Coastguard Worker success = false;
153*c8dee2aaSAndroid Build Coastguard Worker }
154*c8dee2aaSAndroid Build Coastguard Worker // The `texture` and `sampler` flags are only allowed when targeting Metal, WebGPU or Direct3D.
155*c8dee2aaSAndroid Build Coastguard Worker if (!(layoutFlags & (LayoutFlag::kMetal | LayoutFlag::kWebGPU | LayoutFlag::kDirect3D))) {
156*c8dee2aaSAndroid Build Coastguard Worker permittedLayoutFlags &= ~LayoutFlag::kTexture;
157*c8dee2aaSAndroid Build Coastguard Worker permittedLayoutFlags &= ~LayoutFlag::kSampler;
158*c8dee2aaSAndroid Build Coastguard Worker }
159*c8dee2aaSAndroid Build Coastguard Worker // The `push_constant` flag is only allowed when targeting Vulkan or WebGPU.
160*c8dee2aaSAndroid Build Coastguard Worker if (!(layoutFlags & (LayoutFlag::kVulkan | LayoutFlag::kWebGPU))) {
161*c8dee2aaSAndroid Build Coastguard Worker permittedLayoutFlags &= ~LayoutFlag::kPushConstant;
162*c8dee2aaSAndroid Build Coastguard Worker }
163*c8dee2aaSAndroid Build Coastguard Worker // The `set` flag is not allowed when explicitly targeting Metal.
164*c8dee2aaSAndroid Build Coastguard Worker if (layoutFlags & LayoutFlag::kMetal) {
165*c8dee2aaSAndroid Build Coastguard Worker permittedLayoutFlags &= ~LayoutFlag::kSet;
166*c8dee2aaSAndroid Build Coastguard Worker }
167*c8dee2aaSAndroid Build Coastguard Worker
168*c8dee2aaSAndroid Build Coastguard Worker for (const auto& lf : kLayoutFlags) {
169*c8dee2aaSAndroid Build Coastguard Worker if (layoutFlags & lf.flag) {
170*c8dee2aaSAndroid Build Coastguard Worker if (!(permittedLayoutFlags & lf.flag)) {
171*c8dee2aaSAndroid Build Coastguard Worker context.fErrors->error(pos, "layout qualifier '" + std::string(lf.name) +
172*c8dee2aaSAndroid Build Coastguard Worker "' is not permitted here");
173*c8dee2aaSAndroid Build Coastguard Worker success = false;
174*c8dee2aaSAndroid Build Coastguard Worker }
175*c8dee2aaSAndroid Build Coastguard Worker layoutFlags &= ~lf.flag;
176*c8dee2aaSAndroid Build Coastguard Worker }
177*c8dee2aaSAndroid Build Coastguard Worker }
178*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(layoutFlags == LayoutFlag::kNone);
179*c8dee2aaSAndroid Build Coastguard Worker return success;
180*c8dee2aaSAndroid Build Coastguard Worker }
181*c8dee2aaSAndroid Build Coastguard Worker
operator ==(const Layout & other) const182*c8dee2aaSAndroid Build Coastguard Worker bool Layout::operator==(const Layout& other) const {
183*c8dee2aaSAndroid Build Coastguard Worker return fFlags == other.fFlags &&
184*c8dee2aaSAndroid Build Coastguard Worker fLocation == other.fLocation &&
185*c8dee2aaSAndroid Build Coastguard Worker fOffset == other.fOffset &&
186*c8dee2aaSAndroid Build Coastguard Worker fBinding == other.fBinding &&
187*c8dee2aaSAndroid Build Coastguard Worker fTexture == other.fTexture &&
188*c8dee2aaSAndroid Build Coastguard Worker fSampler == other.fSampler &&
189*c8dee2aaSAndroid Build Coastguard Worker fIndex == other.fIndex &&
190*c8dee2aaSAndroid Build Coastguard Worker fSet == other.fSet &&
191*c8dee2aaSAndroid Build Coastguard Worker fBuiltin == other.fBuiltin &&
192*c8dee2aaSAndroid Build Coastguard Worker fInputAttachmentIndex == other.fInputAttachmentIndex &&
193*c8dee2aaSAndroid Build Coastguard Worker fLocalSizeX == other.fLocalSizeX &&
194*c8dee2aaSAndroid Build Coastguard Worker fLocalSizeY == other.fLocalSizeY &&
195*c8dee2aaSAndroid Build Coastguard Worker fLocalSizeZ == other.fLocalSizeZ;
196*c8dee2aaSAndroid Build Coastguard Worker }
197*c8dee2aaSAndroid Build Coastguard Worker
198*c8dee2aaSAndroid Build Coastguard Worker } // namespace SkSL
199