1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "spirv_cross_helpers_gles.h"
17
18 #include <cmath>
19
20 #include "gles/device_gles.h"
21 #include "gles/gl_functions.h"
22 #include "util/log.h"
23
24 using namespace BASE_NS;
25
26 RENDER_BEGIN_NAMESPACE()
27 namespace Gles {
FindConstant(const array_view<const PushConstantReflection> reflections,const PushConstantReflection & reflection)28 int32_t FindConstant(
29 const array_view<const PushConstantReflection> reflections, const PushConstantReflection& reflection)
30 {
31 for (size_t i = 0; i < reflections.size(); i++) {
32 if (reflection.name == reflections[i].name) {
33 // Check that it's actually same and not a conflict!.
34 if (reflection.type != reflections[i].type) {
35 return -2;
36 }
37 if (reflection.offset != reflections[i].offset) {
38 return -2;
39 }
40 if (reflection.size != reflections[i].size) {
41 return -2;
42 }
43 if (reflection.arraySize != reflections[i].arraySize) {
44 return -2;
45 }
46 if (reflection.arrayStride != reflections[i].arrayStride) {
47 return -2;
48 }
49 if (reflection.matrixStride != reflections[i].matrixStride) {
50 return -2;
51 }
52 return (int32_t)i;
53 }
54 }
55 return -1;
56 }
57
DefineForSpec(const array_view<const ShaderSpecialization::Constant> reflectionInfo,const uint32_t spcid,const uintptr_t offset,string & result)58 bool DefineForSpec(const array_view<const ShaderSpecialization::Constant> reflectionInfo, const uint32_t spcid,
59 const uintptr_t offset, string& result)
60 {
61 // "#define SPIRV_CROSS_CONSTANT_ID_4294967295 4294967295\n" //worst case for bool
62 // "#define SPIRV_CROSS_CONSTANT_ID_4294967295 4294967295\n" //worst case for uint32
63 // "#define SPIRV_CROSS_CONSTANT_ID_4294967295 -2147483648\n"//worst case for int32
64 // and floats can be REALLY long..
65 char buf[1024];
66 bool ok = false;
67 for (const auto& c : reflectionInfo) {
68 if (c.id == spcid) {
69 // The constant_id can only be applied to a scalar *int*, a scalar *float* or a scalar *bool*.
70 // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_gl_spirv.txt
71 switch (c.type) {
72 default:
73 [[fallthrough]];
74 case ShaderSpecialization::Constant::Type::INVALID:
75 PLUGIN_ASSERT_MSG(false, "Unhandled specialization constant type");
76 break;
77
78 case ShaderSpecialization::Constant::Type::BOOL:
79 [[fallthrough]];
80 case ShaderSpecialization::Constant::Type::UINT32: {
81 const uint32_t value = *reinterpret_cast<uint32_t*>(offset);
82 const int len = sprintf_s(buf, sizeof(buf), "%u %uu\n", c.id, value);
83 ok = len > 0;
84 break;
85 }
86
87 case ShaderSpecialization::Constant::Type::INT32: {
88 const int32_t value = *reinterpret_cast<int32_t*>(offset);
89 const int len = sprintf_s(buf, sizeof(buf), "%u %d\n", c.id, value);
90 ok = len > 0;
91 break;
92 }
93
94 case ShaderSpecialization::Constant::Type::FLOAT: {
95 const float value = *reinterpret_cast<float_t*>(offset);
96 // NOTE: resulting constant might not be the same. due to float -> string -> float conversions.
97 const int len = sprintf_s(buf, sizeof(buf), "%u %f\n", c.id, value);
98 ok = len > 0;
99 break;
100 }
101 }
102 if (ok) {
103 result.append("#define SPIRV_CROSS_CONSTANT_ID_");
104 result.append(buf);
105 }
106 break;
107 }
108 }
109 return ok;
110 }
111
InsertDefines(const string_view shaderIn,const string_view Defines)112 string InsertDefines(const string_view shaderIn, const string_view Defines)
113 {
114 string shaderOut;
115 // Create defines..
116 if (!shaderIn.empty()) {
117 const size_t voff = shaderIn.find_first_of('\n');
118 shaderOut.reserve(shaderIn.length() + Defines.length());
119 shaderOut.append(shaderIn.substr(0, voff + 1));
120 shaderOut.append(Defines);
121 shaderOut.append(shaderIn.substr(voff + 1));
122 } else {
123 shaderOut = Defines;
124 }
125 return shaderOut;
126 }
127
Specialize(ShaderStageFlags mask,const string_view shaderTemplate,const array_view<const ShaderSpecialization::Constant> info,const ShaderSpecializationConstantDataView & data)128 string Specialize(ShaderStageFlags mask, const string_view shaderTemplate,
129 const array_view<const ShaderSpecialization::Constant> info, const ShaderSpecializationConstantDataView& data)
130 {
131 if (shaderTemplate.empty()) {
132 return {};
133 }
134 if (data.data.empty()) {
135 // missing specialization constant values
136 return string(shaderTemplate);
137 }
138 bool ok = false;
139 for (const auto& spc : data.constants) {
140 if (spc.shaderStage & mask) {
141 ok = true;
142 break;
143 }
144 }
145 if (!ok) {
146 // nothing to specialize
147 return string(shaderTemplate);
148 }
149 // Create defines..
150 const uintptr_t base = (uintptr_t)data.data.data();
151 string defines;
152 defines.reserve(256);
153 for (const auto& spc : data.constants) {
154 if (spc.shaderStage & mask) {
155 const uintptr_t offset = base + spc.offset;
156 DefineForSpec(info, spc.id, offset, defines);
157 }
158 }
159 // inject defines to shader source.
160 return InsertDefines(shaderTemplate, defines);
161 }
162 } // namespace Gles
163 RENDER_END_NAMESPACE()
164