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