1 /*
2 * Copyright (c) 2022 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/gl_functions.h"
21 #include "util/log.h"
22
23 using namespace BASE_NS;
24
25 RENDER_BEGIN_NAMESPACE()
26 namespace Gles {
FindConstant(const array_view<const PushConstantReflection> reflections,const PushConstantReflection & reflection)27 int32_t FindConstant(
28 const array_view<const PushConstantReflection> reflections, const PushConstantReflection& reflection)
29 {
30 for (size_t i = 0; i < reflections.size(); i++) {
31 if (reflection.name == reflections[i].name) {
32 // Check that it's actually same and not a conflict!.
33 if (reflection.type != reflections[i].type) {
34 return -2;
35 }
36 if (reflection.offset != reflections[i].offset) {
37 return -2;
38 }
39 if (reflection.size != reflections[i].size) {
40 return -2;
41 }
42 if (reflection.arraySize != reflections[i].arraySize) {
43 return -2;
44 }
45 if (reflection.arrayStride != reflections[i].arrayStride) {
46 return -2;
47 }
48 if (reflection.matrixStride != reflections[i].matrixStride) {
49 return -2;
50 }
51 return (int32_t)i;
52 }
53 }
54 return -1;
55 }
56
DefineForSpec(const array_view<const ShaderSpecialization::Constant> reflectionInfo,const uint32_t spcid,const uintptr_t offset,string & result)57 bool DefineForSpec(const array_view<const ShaderSpecialization::Constant> reflectionInfo, const uint32_t spcid,
58 const uintptr_t offset, string& result)
59 {
60 // "#define SPIRV_CROSS_CONSTANT_ID_4294967295 4294967295\n" //worst case for bool
61 // "#define SPIRV_CROSS_CONSTANT_ID_4294967295 4294967295\n" //worst case for uint32
62 // "#define SPIRV_CROSS_CONSTANT_ID_4294967295 -2147483648\n"//worst case for int32
63 // and floats can be REALLY long..
64 char buf[1024];
65 bool ok = false;
66 for (const auto& c : reflectionInfo) {
67 if (c.id == spcid) {
68 // The constant_id can only be applied to a scalar *int*, a scalar *float* or a scalar *bool*.
69 // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_gl_spirv.txt
70 switch (c.type) {
71 default:
72 [[fallthrough]];
73 case ShaderSpecialization::Constant::Type::INVALID:
74 PLUGIN_ASSERT_MSG(false, "Unhandled specialization constant type");
75 break;
76
77 case ShaderSpecialization::Constant::Type::BOOL:
78 [[fallthrough]];
79 case ShaderSpecialization::Constant::Type::UINT32: {
80 const uint32_t value = *reinterpret_cast<uint32_t*>(offset);
81 const int len = sprintf_s(buf, sizeof(buf), "%u %uu\n", c.id, value);
82 ok = len > 0;
83 break;
84 }
85
86 case ShaderSpecialization::Constant::Type::INT32: {
87 const int32_t value = *reinterpret_cast<int32_t*>(offset);
88 const int len = sprintf_s(buf, sizeof(buf), "%u %d\n", c.id, value);
89 ok = len > 0;
90 break;
91 }
92
93 case ShaderSpecialization::Constant::Type::FLOAT: {
94 const float value = *reinterpret_cast<float_t*>(offset);
95 // NOTE: resulting constant might not be the same. due to float -> string -> float conversions.
96 const int len = sprintf_s(buf, sizeof(buf), "%u %f\n", c.id, value);
97 ok = len > 0;
98 break;
99 }
100 }
101 if (ok) {
102 result.append("#define SPIRV_CROSS_CONSTANT_ID_");
103 result.append(buf);
104 }
105 break;
106 }
107 }
108 return ok;
109 }
110
InsertDefines(const string_view shaderIn,const string_view Defines)111 string InsertDefines(const string_view shaderIn, const string_view Defines)
112 {
113 string shaderOut;
114 // Create defines..
115 if (!shaderIn.empty()) {
116 const size_t voff = shaderIn.find_first_of('\n');
117 shaderOut.reserve(shaderIn.length() + Defines.length());
118 shaderOut.append(shaderIn.substr(0, voff + 1));
119 shaderOut.append(Defines);
120 shaderOut.append(shaderIn.substr(voff + 1));
121 } else {
122 shaderOut = Defines;
123 }
124 return shaderOut;
125 }
126
Specialize(ShaderStageFlags mask,const string_view shaderTemplate,const array_view<const ShaderSpecialization::Constant> info,const ShaderSpecializationConstantDataView & data)127 string Specialize(ShaderStageFlags mask, const string_view shaderTemplate,
128 const array_view<const ShaderSpecialization::Constant> info, const ShaderSpecializationConstantDataView& data)
129 {
130 if (shaderTemplate.empty()) {
131 return {};
132 }
133 if (data.data.empty()) {
134 // missing specialization constant values
135 return string(shaderTemplate);
136 }
137 bool ok = false;
138 for (const auto& spc : data.constants) {
139 if (spc.shaderStage & mask) {
140 ok = true;
141 break;
142 }
143 }
144 if (!ok) {
145 // nothing to specialize
146 return string(shaderTemplate);
147 }
148 // Create defines..
149 const auto base = (uintptr_t)data.data.data();
150 string defines;
151 defines.reserve(256);
152 for (const auto& spc : data.constants) {
153 if (spc.shaderStage & mask) {
154 const uintptr_t offset = base + spc.offset;
155 DefineForSpec(info, spc.id, offset, defines);
156 }
157 }
158 // inject defines to shader source.
159 return InsertDefines(shaderTemplate, defines);
160 }
161 } // namespace Gles
162 RENDER_END_NAMESPACE()
163