xref: /aosp_15_r20/external/skia/src/sksl/ir/SkSLLayout.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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