1 //
2 // Copyright 2020 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 
25 #include "pxr/imaging/hgiGL/shaderGenerator.h"
26 #include "pxr/imaging/hgi/tokens.h"
27 
28 PXR_NAMESPACE_OPEN_SCOPE
29 
30 static const std::string &
_GetMacroBlob()31 _GetMacroBlob()
32 {
33     // Allows metal and GL to both handle out function params.
34     // On the metal side, the ref(space,type) parameter defines
35     // if items are in device or thread domain.
36     const static std::string header =
37         "#define REF(space,type) inout type\n";
38     return header;
39 }
40 
HgiGLShaderGenerator(const HgiShaderFunctionDesc & descriptor)41 HgiGLShaderGenerator::HgiGLShaderGenerator(
42     const HgiShaderFunctionDesc &descriptor)
43   : HgiShaderGenerator(descriptor)
44 {
45     //Write out all GL shaders and add to shader sections
46     GetShaderSections()->push_back(
47         std::make_unique<HgiGLMacroShaderSection>(
48             _GetMacroBlob(), ""));
49 
50     _WriteTextures(descriptor.textures);
51     _WriteBuffers(descriptor.buffers);
52     _WriteInOuts(descriptor.stageInputs, "in");
53     _WriteConstantParams(descriptor.constantParams);
54     _WriteInOuts(descriptor.stageOutputs, "out");
55 }
56 
57 void
_WriteTextures(const HgiShaderFunctionTextureDescVector & textures)58 HgiGLShaderGenerator::_WriteTextures(
59     const HgiShaderFunctionTextureDescVector &textures)
60 {
61     //Extract texture descriptors and add appropriate texture sections
62     for(size_t i=0; i<textures.size(); i++) {
63         const HgiShaderFunctionTextureDesc &textureDescription = textures[i];
64         const HgiShaderSectionAttributeVector attrs = {
65             HgiShaderSectionAttribute{"binding", std::to_string(i)}};
66 
67         GetShaderSections()->push_back(
68             std::make_unique<HgiGLTextureShaderSection>(
69                 textureDescription.nameInShader,
70                 i,
71                 textureDescription.dimensions,
72                 textureDescription.format,
73                 attrs));
74     }
75 }
76 
77 void
_WriteBuffers(const HgiShaderFunctionBufferDescVector & buffers)78 HgiGLShaderGenerator::_WriteBuffers(
79     const HgiShaderFunctionBufferDescVector &buffers)
80 {
81     //Extract buffer descriptors and add appropriate buffer sections
82     for(size_t i=0; i<buffers.size(); i++) {
83         const HgiShaderFunctionBufferDesc &bufferDescription = buffers[i];
84         const HgiShaderSectionAttributeVector attrs = {
85             HgiShaderSectionAttribute{"std430", ""},
86             HgiShaderSectionAttribute{"binding", std::to_string(i + 1)}};
87 
88         GetShaderSections()->push_back(
89             std::make_unique<HgiGLBufferShaderSection>(
90                 bufferDescription.nameInShader,
91                 i + 1,
92                 bufferDescription.type,
93                 attrs));
94     }
95 }
96 
97 void
_WriteConstantParams(const HgiShaderFunctionParamDescVector & parameters)98 HgiGLShaderGenerator::_WriteConstantParams(
99     const HgiShaderFunctionParamDescVector &parameters)
100 {
101     if (parameters.size() < 1) {
102         return;
103     }
104     GetShaderSections()->push_back(
105         std::make_unique<HgiGLBlockShaderSection>(
106             "ParamBuffer",
107             parameters,
108             0));
109 }
110 
111 void
_WriteInOuts(const HgiShaderFunctionParamDescVector & parameters,const std::string & qualifier)112 HgiGLShaderGenerator::_WriteInOuts(
113     const HgiShaderFunctionParamDescVector &parameters,
114     const std::string &qualifier)
115 {
116     uint32_t counter = 0;
117 
118     //To unify glslfx across different apis, other apis
119     //may want these to be defined, but since they are
120     //taken in opengl we ignore them
121     const static std::set<std::string> takenOutParams {
122         "gl_Position",
123         "gl_FragColor",
124         "gl_FragDepth"
125     };
126     const static std::map<std::string, std::string> takenInParams {
127         { HgiShaderKeywordTokens->hdPosition, "gl_Position"},
128         { HgiShaderKeywordTokens->hdGlobalInvocationID, "gl_GlobalInvocationID"}
129     };
130 
131     const bool in_qualifier = qualifier == "in";
132     const bool out_qualifier = qualifier == "out";
133     for(const HgiShaderFunctionParamDesc &param : parameters) {
134         //Skip writing out taken parameter names
135         const std::string &paramName = param.nameInShader;
136         if (out_qualifier &&
137                 takenOutParams.find(paramName) != takenOutParams.end()) {
138             continue;
139         }
140         if (in_qualifier) {
141             const std::string &role = param.role;
142             auto const& keyword = takenInParams.find(role);
143             if (keyword != takenInParams.end()) {
144                 GetShaderSections()->push_back(
145                     std::make_unique<HgiGLKeywordShaderSection>(
146                         paramName,
147                         param.type,
148                         keyword->second));
149                 continue;
150             }
151         }
152 
153         const HgiShaderSectionAttributeVector attrs {
154             HgiShaderSectionAttribute{"location", std::to_string(counter)}
155         };
156 
157         GetShaderSections()->push_back(
158             std::make_unique<HgiGLMemberShaderSection>(
159                 paramName,
160                 param.type,
161                 attrs,
162                 qualifier));
163         counter++;
164     }
165 }
166 
167 void
_Execute(std::ostream & ss,const std::string & originalShaderShader)168 HgiGLShaderGenerator::_Execute(
169     std::ostream &ss,
170     const std::string &originalShaderShader)
171 {
172     ss << _GetVersion() << " \n";
173 
174     HgiGLShaderSectionUniquePtrVector* shaderSections = GetShaderSections();
175     //For all shader sections, visit the areas defined for all
176     //shader apis. We assume all shader apis have a global space
177     //section, capabilities to define macros in global space,
178     //and abilities to declare some members or functions there
179 
180     for (const std::unique_ptr<HgiGLShaderSection>
181             &shaderSection : *shaderSections) {
182         shaderSection->VisitGlobalIncludes(ss);
183         ss << "\n";
184     }
185 
186     for (const std::unique_ptr<HgiGLShaderSection>
187             &shaderSection : *shaderSections) {
188         shaderSection->VisitGlobalMacros(ss);
189         ss << "\n";
190     }
191 
192     for (const std::unique_ptr<HgiGLShaderSection>
193             &shaderSection : *shaderSections) {
194         shaderSection->VisitGlobalStructs(ss);
195         ss << "\n";
196     }
197 
198     for (const std::unique_ptr<HgiGLShaderSection>
199             &shaderSection : *shaderSections) {
200         shaderSection->VisitGlobalMemberDeclarations(ss);
201         ss << "\n";
202     }
203 
204     for (const std::unique_ptr<HgiGLShaderSection>
205             &shaderSection : *shaderSections) {
206         shaderSection->VisitGlobalFunctionDefinitions(ss);
207         ss << "\n";
208     }
209 
210     ss << "\n";
211     const char* cstr = originalShaderShader.c_str();
212 
213     //write all the original shader except the version string
214     ss.write(
215         cstr + _GetVersion().length(),
216         originalShaderShader.length() - _GetVersion().length());
217 }
218 
219 HgiGLShaderSectionUniquePtrVector*
GetShaderSections()220 HgiGLShaderGenerator::GetShaderSections()
221 {
222     return &_shaderSections;
223 }
224 
225 PXR_NAMESPACE_CLOSE_SCOPE
226