• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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