xref: /aosp_15_r20/external/deqp/modules/glshared/glsShaderExecUtil.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL (ES) Module
3  * -----------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Shader execution utilities.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "glsShaderExecUtil.hpp"
25 #include "gluRenderContext.hpp"
26 #include "gluDrawUtil.hpp"
27 #include "gluObjectWrapper.hpp"
28 #include "gluShaderProgram.hpp"
29 #include "gluTextureUtil.hpp"
30 #include "gluProgramInterfaceQuery.hpp"
31 #include "gluPixelTransfer.hpp"
32 #include "gluStrUtil.hpp"
33 #include "tcuTestLog.hpp"
34 #include "glwFunctions.hpp"
35 #include "glwEnums.hpp"
36 #include "deSTLUtil.hpp"
37 #include "deStringUtil.hpp"
38 #include "deUniquePtr.hpp"
39 #include "deMemory.h"
40 
41 #include <map>
42 
43 namespace deqp
44 {
45 namespace gls
46 {
47 
48 namespace ShaderExecUtil
49 {
50 
51 using std::vector;
52 
isExtensionSupported(const glu::RenderContext & renderCtx,const std::string & extension)53 static bool isExtensionSupported(const glu::RenderContext &renderCtx, const std::string &extension)
54 {
55     const glw::Functions &gl = renderCtx.getFunctions();
56     int numExts              = 0;
57 
58     gl.getIntegerv(GL_NUM_EXTENSIONS, &numExts);
59 
60     for (int ndx = 0; ndx < numExts; ndx++)
61     {
62         const char *curExt = (const char *)gl.getStringi(GL_EXTENSIONS, ndx);
63 
64         if (extension == curExt)
65             return true;
66     }
67 
68     return false;
69 }
70 
checkExtension(const glu::RenderContext & renderCtx,const std::string & extension)71 static void checkExtension(const glu::RenderContext &renderCtx, const std::string &extension)
72 {
73     if (!isExtensionSupported(renderCtx, extension))
74         throw tcu::NotSupportedError(extension + " is not supported");
75 }
76 
checkLimit(const glu::RenderContext & renderCtx,uint32_t pname,int required)77 static void checkLimit(const glu::RenderContext &renderCtx, uint32_t pname, int required)
78 {
79     const glw::Functions &gl = renderCtx.getFunctions();
80     int implementationLimit  = -1;
81     uint32_t error;
82 
83     gl.getIntegerv(pname, &implementationLimit);
84     error = gl.getError();
85 
86     if (error != GL_NO_ERROR)
87         throw tcu::TestError("Failed to query " + de::toString(glu::getGettableStateStr(pname)) + " - got " +
88                              de::toString(glu::getErrorStr(error)));
89     if (implementationLimit < required)
90         throw tcu::NotSupportedError("Test requires " + de::toString(glu::getGettableStateStr(pname)) +
91                                      " >= " + de::toString(required) + ", got " + de::toString(implementationLimit));
92 }
93 
94 // Shader utilities
95 
generateVertexShader(const ShaderSpec & shaderSpec,const std::string & inputPrefix,const std::string & outputPrefix)96 static std::string generateVertexShader(const ShaderSpec &shaderSpec, const std::string &inputPrefix,
97                                         const std::string &outputPrefix)
98 {
99     const bool usesInout = glu::glslVersionUsesInOutQualifiers(shaderSpec.version);
100     const char *in       = usesInout ? "in" : "attribute";
101     const char *out      = usesInout ? "out" : "varying";
102     std::ostringstream src;
103 
104     DE_ASSERT(!inputPrefix.empty() && !outputPrefix.empty());
105 
106     src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
107 
108     if (!shaderSpec.globalDeclarations.empty())
109         src << shaderSpec.globalDeclarations << "\n";
110 
111     src << in << " highp vec4 a_position;\n";
112 
113     for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
114         src << in << " " << glu::declare(input->varType, inputPrefix + input->name) << ";\n";
115 
116     for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end();
117          ++output)
118     {
119         DE_ASSERT(output->varType.isBasicType());
120 
121         if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
122         {
123             const int vecSize               = glu::getDataTypeScalarSize(output->varType.getBasicType());
124             const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
125             const glu::VarType intType(intBaseType, glu::PRECISION_HIGHP);
126 
127             src << "flat " << out << " " << glu::declare(intType, outputPrefix + output->name) << ";\n";
128         }
129         else
130             src << "flat " << out << " " << glu::declare(output->varType, outputPrefix + output->name) << ";\n";
131     }
132 
133     src << "\n"
134         << "void main (void)\n"
135         << "{\n"
136         << "    gl_Position = a_position;\n"
137         << "    gl_PointSize = 1.0;\n\n";
138 
139     // Declare & fetch local input variables
140     for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
141         src << "\t" << glu::declare(input->varType, input->name) << " = " << inputPrefix << input->name << ";\n";
142 
143     // Declare local output variables
144     for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end();
145          ++output)
146         src << "\t" << glu::declare(output->varType, output->name) << ";\n";
147 
148     // Operation - indented to correct level.
149     {
150         std::istringstream opSrc(shaderSpec.source);
151         std::string line;
152 
153         while (std::getline(opSrc, line))
154             src << "\t" << line << "\n";
155     }
156 
157     // Assignments to outputs.
158     for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end();
159          ++output)
160     {
161         if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
162         {
163             const int vecSize               = glu::getDataTypeScalarSize(output->varType.getBasicType());
164             const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
165 
166             src << "\t" << outputPrefix << output->name << " = " << glu::getDataTypeName(intBaseType) << "("
167                 << output->name << ");\n";
168         }
169         else
170             src << "\t" << outputPrefix << output->name << " = " << output->name << ";\n";
171     }
172 
173     src << "}\n";
174 
175     return src.str();
176 }
177 
generateGeometryShader(const ShaderSpec & shaderSpec,const std::string & inputPrefix,const std::string & outputPrefix)178 static std::string generateGeometryShader(const ShaderSpec &shaderSpec, const std::string &inputPrefix,
179                                           const std::string &outputPrefix)
180 {
181     DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
182     DE_ASSERT(!inputPrefix.empty() && !outputPrefix.empty());
183 
184     std::ostringstream src;
185 
186     src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
187 
188     if (glu::glslVersionIsES(shaderSpec.version) && shaderSpec.version <= glu::GLSL_VERSION_310_ES)
189         src << "#extension GL_EXT_geometry_shader : require\n";
190 
191     if (!shaderSpec.globalDeclarations.empty())
192         src << shaderSpec.globalDeclarations << "\n";
193 
194     src << "layout(points) in;\n"
195         << "layout(points, max_vertices = 1) out;\n";
196 
197     for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
198         src << "flat in " << glu::declare(input->varType, inputPrefix + input->name) << "[];\n";
199 
200     for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end();
201          ++output)
202     {
203         DE_ASSERT(output->varType.isBasicType());
204 
205         if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
206         {
207             const int vecSize               = glu::getDataTypeScalarSize(output->varType.getBasicType());
208             const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
209             const glu::VarType intType(intBaseType, glu::PRECISION_HIGHP);
210 
211             src << "flat out " << glu::declare(intType, outputPrefix + output->name) << ";\n";
212         }
213         else
214             src << "flat out " << glu::declare(output->varType, outputPrefix + output->name) << ";\n";
215     }
216 
217     src << "\n"
218         << "void main (void)\n"
219         << "{\n"
220         << "    gl_Position = gl_in[0].gl_Position;\n\n";
221 
222     // Fetch input variables
223     for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
224         src << "\t" << glu::declare(input->varType, input->name) << " = " << inputPrefix << input->name << "[0];\n";
225 
226     // Declare local output variables.
227     for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end();
228          ++output)
229         src << "\t" << glu::declare(output->varType, output->name) << ";\n";
230 
231     src << "\n";
232 
233     // Operation - indented to correct level.
234     {
235         std::istringstream opSrc(shaderSpec.source);
236         std::string line;
237 
238         while (std::getline(opSrc, line))
239             src << "\t" << line << "\n";
240     }
241 
242     // Assignments to outputs.
243     for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end();
244          ++output)
245     {
246         if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
247         {
248             const int vecSize               = glu::getDataTypeScalarSize(output->varType.getBasicType());
249             const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
250 
251             src << "\t" << outputPrefix << output->name << " = " << glu::getDataTypeName(intBaseType) << "("
252                 << output->name << ");\n";
253         }
254         else
255             src << "\t" << outputPrefix << output->name << " = " << output->name << ";\n";
256     }
257 
258     src << "    EmitVertex();\n"
259         << "    EndPrimitive();\n"
260         << "}\n";
261 
262     return src.str();
263 }
264 
generateEmptyFragmentSource(glu::GLSLVersion version)265 static std::string generateEmptyFragmentSource(glu::GLSLVersion version)
266 {
267     const bool customOut = glu::glslVersionUsesInOutQualifiers(version);
268     std::ostringstream src;
269 
270     src << glu::getGLSLVersionDeclaration(version) << "\n";
271 
272     // \todo [2013-08-05 pyry] Do we need one unused output?
273 
274     src << "void main (void)\n{\n";
275     if (!customOut)
276         src << "    gl_FragColor = vec4(0.0);\n";
277     src << "}\n";
278 
279     return src.str();
280 }
281 
generatePassthroughVertexShader(const ShaderSpec & shaderSpec,const std::string & inputPrefix,const std::string & outputPrefix)282 static std::string generatePassthroughVertexShader(const ShaderSpec &shaderSpec, const std::string &inputPrefix,
283                                                    const std::string &outputPrefix)
284 {
285     // flat qualifier is not present in earlier versions?
286     DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
287 
288     std::ostringstream src;
289 
290     src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n"
291         << "in highp vec4 a_position;\n";
292 
293     for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
294     {
295         src << "in " << glu::declare(input->varType, inputPrefix + input->name) << ";\n"
296             << "flat out " << glu::declare(input->varType, outputPrefix + input->name) << ";\n";
297     }
298 
299     src << "\nvoid main (void)\n{\n"
300         << "    gl_Position = a_position;\n"
301         << "    gl_PointSize = 1.0;\n";
302 
303     for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
304         src << "\t" << outputPrefix << input->name << " = " << inputPrefix << input->name << ";\n";
305 
306     src << "}\n";
307 
308     return src.str();
309 }
310 
generateFragShaderOutputDecl(std::ostream & src,const ShaderSpec & shaderSpec,bool useIntOutputs,const std::map<std::string,int> & outLocationMap,const std::string & outputPrefix)311 static void generateFragShaderOutputDecl(std::ostream &src, const ShaderSpec &shaderSpec, bool useIntOutputs,
312                                          const std::map<std::string, int> &outLocationMap,
313                                          const std::string &outputPrefix)
314 {
315     DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
316 
317     for (int outNdx = 0; outNdx < (int)shaderSpec.outputs.size(); ++outNdx)
318     {
319         const Symbol &output         = shaderSpec.outputs[outNdx];
320         const int location           = de::lookup(outLocationMap, output.name);
321         const std::string outVarName = outputPrefix + output.name;
322         glu::VariableDeclaration decl(output.varType, outVarName, glu::STORAGE_OUT, glu::INTERPOLATION_LAST,
323                                       glu::Layout(location));
324 
325         TCU_CHECK_INTERNAL(output.varType.isBasicType());
326 
327         if (useIntOutputs && glu::isDataTypeFloatOrVec(output.varType.getBasicType()))
328         {
329             const int vecSize                 = glu::getDataTypeScalarSize(output.varType.getBasicType());
330             const glu::DataType uintBasicType = vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT;
331             const glu::VarType uintType(uintBasicType, glu::PRECISION_HIGHP);
332 
333             decl.varType = uintType;
334             src << decl << ";\n";
335         }
336         else if (glu::isDataTypeBoolOrBVec(output.varType.getBasicType()))
337         {
338             const int vecSize                = glu::getDataTypeScalarSize(output.varType.getBasicType());
339             const glu::DataType intBasicType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
340             const glu::VarType intType(intBasicType, glu::PRECISION_HIGHP);
341 
342             decl.varType = intType;
343             src << decl << ";\n";
344         }
345         else if (glu::isDataTypeMatrix(output.varType.getBasicType()))
346         {
347             const int vecSize                 = glu::getDataTypeMatrixNumRows(output.varType.getBasicType());
348             const int numVecs                 = glu::getDataTypeMatrixNumColumns(output.varType.getBasicType());
349             const glu::DataType uintBasicType = glu::getDataTypeUintVec(vecSize);
350             const glu::VarType uintType(uintBasicType, glu::PRECISION_HIGHP);
351 
352             decl.varType = uintType;
353             for (int vecNdx = 0; vecNdx < numVecs; ++vecNdx)
354             {
355                 decl.name            = outVarName + "_" + de::toString(vecNdx);
356                 decl.layout.location = location + vecNdx;
357                 src << decl << ";\n";
358             }
359         }
360         else
361             src << decl << ";\n";
362     }
363 }
364 
generateFragShaderOutAssign(std::ostream & src,const ShaderSpec & shaderSpec,bool useIntOutputs,const std::string & valuePrefix,const std::string & outputPrefix)365 static void generateFragShaderOutAssign(std::ostream &src, const ShaderSpec &shaderSpec, bool useIntOutputs,
366                                         const std::string &valuePrefix, const std::string &outputPrefix)
367 {
368     for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end();
369          ++output)
370     {
371         if (useIntOutputs && glu::isDataTypeFloatOrVec(output->varType.getBasicType()))
372             src << "    o_" << output->name << " = floatBitsToUint(" << valuePrefix << output->name << ");\n";
373         else if (glu::isDataTypeMatrix(output->varType.getBasicType()))
374         {
375             const int numVecs = glu::getDataTypeMatrixNumColumns(output->varType.getBasicType());
376 
377             for (int vecNdx = 0; vecNdx < numVecs; ++vecNdx)
378                 if (useIntOutputs)
379                     src << "\t" << outputPrefix << output->name << "_" << vecNdx << " = floatBitsToUint(" << valuePrefix
380                         << output->name << "[" << vecNdx << "]);\n";
381                 else
382                     src << "\t" << outputPrefix << output->name << "_" << vecNdx << " = " << valuePrefix << output->name
383                         << "[" << vecNdx << "];\n";
384         }
385         else if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
386         {
387             const int vecSize               = glu::getDataTypeScalarSize(output->varType.getBasicType());
388             const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
389 
390             src << "\t" << outputPrefix << output->name << " = " << glu::getDataTypeName(intBaseType) << "("
391                 << valuePrefix << output->name << ");\n";
392         }
393         else
394             src << "\t" << outputPrefix << output->name << " = " << valuePrefix << output->name << ";\n";
395     }
396 }
397 
generateFragmentShader(const ShaderSpec & shaderSpec,bool useIntOutputs,const std::map<std::string,int> & outLocationMap,const std::string & inputPrefix,const std::string & outputPrefix)398 static std::string generateFragmentShader(const ShaderSpec &shaderSpec, bool useIntOutputs,
399                                           const std::map<std::string, int> &outLocationMap,
400                                           const std::string &inputPrefix, const std::string &outputPrefix)
401 {
402     DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
403 
404     std::ostringstream src;
405 
406     src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
407 
408     if (!shaderSpec.globalDeclarations.empty())
409         src << shaderSpec.globalDeclarations << "\n";
410 
411     for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
412         src << "flat in " << glu::declare(input->varType, inputPrefix + input->name) << ";\n";
413 
414     generateFragShaderOutputDecl(src, shaderSpec, useIntOutputs, outLocationMap, outputPrefix);
415 
416     src << "\nvoid main (void)\n{\n";
417 
418     // Declare & fetch local input variables
419     for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
420         src << "\t" << glu::declare(input->varType, input->name) << " = " << inputPrefix << input->name << ";\n";
421 
422     // Declare output variables
423     for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end();
424          ++output)
425         src << "\t" << glu::declare(output->varType, output->name) << ";\n";
426 
427     // Operation - indented to correct level.
428     {
429         std::istringstream opSrc(shaderSpec.source);
430         std::string line;
431 
432         while (std::getline(opSrc, line))
433             src << "\t" << line << "\n";
434     }
435 
436     generateFragShaderOutAssign(src, shaderSpec, useIntOutputs, "", outputPrefix);
437 
438     src << "}\n";
439 
440     return src.str();
441 }
442 
generatePassthroughFragmentShader(const ShaderSpec & shaderSpec,bool useIntOutputs,const std::map<std::string,int> & outLocationMap,const std::string & inputPrefix,const std::string & outputPrefix)443 static std::string generatePassthroughFragmentShader(const ShaderSpec &shaderSpec, bool useIntOutputs,
444                                                      const std::map<std::string, int> &outLocationMap,
445                                                      const std::string &inputPrefix, const std::string &outputPrefix)
446 {
447     DE_ASSERT(glu::glslVersionUsesInOutQualifiers(shaderSpec.version));
448 
449     std::ostringstream src;
450 
451     src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
452 
453     if (!shaderSpec.globalDeclarations.empty())
454         src << shaderSpec.globalDeclarations << "\n";
455 
456     for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end();
457          ++output)
458     {
459         if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
460         {
461             const int vecSize               = glu::getDataTypeScalarSize(output->varType.getBasicType());
462             const glu::DataType intBaseType = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
463             const glu::VarType intType(intBaseType, glu::PRECISION_HIGHP);
464 
465             src << "flat in " << glu::declare(intType, inputPrefix + output->name) << ";\n";
466         }
467         else
468             src << "flat in " << glu::declare(output->varType, inputPrefix + output->name) << ";\n";
469     }
470 
471     generateFragShaderOutputDecl(src, shaderSpec, useIntOutputs, outLocationMap, outputPrefix);
472 
473     src << "\nvoid main (void)\n{\n";
474 
475     generateFragShaderOutAssign(src, shaderSpec, useIntOutputs, inputPrefix, outputPrefix);
476 
477     src << "}\n";
478 
479     return src.str();
480 }
481 
482 // ShaderExecutor
483 
ShaderExecutor(const glu::RenderContext & renderCtx,const ShaderSpec & shaderSpec)484 ShaderExecutor::ShaderExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec)
485     : m_renderCtx(renderCtx)
486     , m_inputs(shaderSpec.inputs)
487     , m_outputs(shaderSpec.outputs)
488 {
489 }
490 
~ShaderExecutor(void)491 ShaderExecutor::~ShaderExecutor(void)
492 {
493 }
494 
useProgram(void)495 void ShaderExecutor::useProgram(void)
496 {
497     DE_ASSERT(isOk());
498     m_renderCtx.getFunctions().useProgram(getProgram());
499 }
500 
501 // FragmentOutExecutor
502 
503 struct FragmentOutputLayout
504 {
505     std::vector<const Symbol *> locationSymbols; //! Symbols by location
506     std::map<std::string, int> locationMap;      //! Map from symbol name to start location
507 };
508 
509 class FragmentOutExecutor : public ShaderExecutor
510 {
511 public:
512     FragmentOutExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec);
513     ~FragmentOutExecutor(void);
514 
515     void execute(int numValues, const void *const *inputs, void *const *outputs);
516 
517 protected:
518     const FragmentOutputLayout m_outputLayout;
519 };
520 
computeFragmentOutputLayout(const std::vector<Symbol> & symbols)521 static FragmentOutputLayout computeFragmentOutputLayout(const std::vector<Symbol> &symbols)
522 {
523     FragmentOutputLayout ret;
524     int location = 0;
525 
526     for (std::vector<Symbol>::const_iterator it = symbols.begin(); it != symbols.end(); ++it)
527     {
528         const int numLocations = glu::getDataTypeNumLocations(it->varType.getBasicType());
529 
530         TCU_CHECK_INTERNAL(!de::contains(ret.locationMap, it->name));
531         de::insert(ret.locationMap, it->name, location);
532         location += numLocations;
533 
534         for (int ndx = 0; ndx < numLocations; ++ndx)
535             ret.locationSymbols.push_back(&*it);
536     }
537 
538     return ret;
539 }
540 
hasFloatRenderTargets(const glu::RenderContext & renderCtx)541 inline bool hasFloatRenderTargets(const glu::RenderContext &renderCtx)
542 {
543     glu::ContextType type = renderCtx.getType();
544     return glu::isContextTypeGLCore(type);
545 }
546 
FragmentOutExecutor(const glu::RenderContext & renderCtx,const ShaderSpec & shaderSpec)547 FragmentOutExecutor::FragmentOutExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec)
548     : ShaderExecutor(renderCtx, shaderSpec)
549     , m_outputLayout(computeFragmentOutputLayout(m_outputs))
550 {
551 }
552 
~FragmentOutExecutor(void)553 FragmentOutExecutor::~FragmentOutExecutor(void)
554 {
555 }
556 
queryInt(const glw::Functions & gl,uint32_t pname)557 inline int queryInt(const glw::Functions &gl, uint32_t pname)
558 {
559     int value = 0;
560     gl.getIntegerv(pname, &value);
561     return value;
562 }
563 
getRenderbufferFormatForOutput(const glu::VarType & outputType,bool useIntOutputs)564 static tcu::TextureFormat getRenderbufferFormatForOutput(const glu::VarType &outputType, bool useIntOutputs)
565 {
566     const tcu::TextureFormat::ChannelOrder channelOrderMap[] = {tcu::TextureFormat::R, tcu::TextureFormat::RG,
567                                                                 tcu::TextureFormat::RGBA, // No RGB variants available.
568                                                                 tcu::TextureFormat::RGBA};
569 
570     const glu::DataType basicType = outputType.getBasicType();
571     const int numComps            = glu::getDataTypeNumComponents(basicType);
572     tcu::TextureFormat::ChannelType channelType;
573 
574     switch (glu::getDataTypeScalarType(basicType))
575     {
576     case glu::TYPE_UINT:
577         channelType = tcu::TextureFormat::UNSIGNED_INT32;
578         break;
579     case glu::TYPE_INT:
580         channelType = tcu::TextureFormat::SIGNED_INT32;
581         break;
582     case glu::TYPE_BOOL:
583         channelType = tcu::TextureFormat::SIGNED_INT32;
584         break;
585     case glu::TYPE_FLOAT:
586         channelType = useIntOutputs ? tcu::TextureFormat::UNSIGNED_INT32 : tcu::TextureFormat::FLOAT;
587         break;
588     default:
589         throw tcu::InternalError("Invalid output type");
590     }
591 
592     DE_ASSERT(de::inRange<int>(numComps, 1, DE_LENGTH_OF_ARRAY(channelOrderMap)));
593 
594     return tcu::TextureFormat(channelOrderMap[numComps - 1], channelType);
595 }
596 
execute(int numValues,const void * const * inputs,void * const * outputs)597 void FragmentOutExecutor::execute(int numValues, const void *const *inputs, void *const *outputs)
598 {
599     const glw::Functions &gl      = m_renderCtx.getFunctions();
600     const bool useIntOutputs      = !hasFloatRenderTargets(m_renderCtx);
601     const int maxRenderbufferSize = queryInt(gl, GL_MAX_RENDERBUFFER_SIZE);
602     const int framebufferW        = de::min(maxRenderbufferSize, numValues);
603     const int framebufferH        = (numValues / framebufferW) + ((numValues % framebufferW != 0) ? 1 : 0);
604 
605     glu::Framebuffer framebuffer(m_renderCtx);
606     glu::RenderbufferVector renderbuffers(m_renderCtx, m_outputLayout.locationSymbols.size());
607 
608     vector<glu::VertexArrayBinding> vertexArrays;
609     vector<tcu::Vec2> positions(numValues);
610 
611     if (framebufferH > maxRenderbufferSize)
612         throw tcu::NotSupportedError("Value count is too high for maximum supported renderbuffer size");
613 
614     // Compute positions - 1px points are used to drive fragment shading.
615     for (int valNdx = 0; valNdx < numValues; valNdx++)
616     {
617         const int ix   = valNdx % framebufferW;
618         const int iy   = valNdx / framebufferW;
619         const float fx = -1.0f + 2.0f * ((float(ix) + 0.5f) / float(framebufferW));
620         const float fy = -1.0f + 2.0f * ((float(iy) + 0.5f) / float(framebufferH));
621 
622         positions[valNdx] = tcu::Vec2(fx, fy);
623     }
624 
625     // Vertex inputs.
626     vertexArrays.push_back(glu::va::Float("a_position", 2, numValues, 0, (const float *)&positions[0]));
627 
628     for (int inputNdx = 0; inputNdx < (int)m_inputs.size(); inputNdx++)
629     {
630         const Symbol &symbol          = m_inputs[inputNdx];
631         const std::string attribName  = "a_" + symbol.name;
632         const void *ptr               = inputs[inputNdx];
633         const glu::DataType basicType = symbol.varType.getBasicType();
634         const int vecSize             = glu::getDataTypeScalarSize(basicType);
635 
636         if (glu::isDataTypeFloatOrVec(basicType))
637             vertexArrays.push_back(glu::va::Float(attribName, vecSize, numValues, 0, (const float *)ptr));
638         else if (glu::isDataTypeIntOrIVec(basicType))
639             vertexArrays.push_back(glu::va::Int32(attribName, vecSize, numValues, 0, (const int32_t *)ptr));
640         else if (glu::isDataTypeUintOrUVec(basicType))
641             vertexArrays.push_back(glu::va::Uint32(attribName, vecSize, numValues, 0, (const uint32_t *)ptr));
642         else if (glu::isDataTypeMatrix(basicType))
643         {
644             int numRows = glu::getDataTypeMatrixNumRows(basicType);
645             int numCols = glu::getDataTypeMatrixNumColumns(basicType);
646             int stride  = numRows * numCols * (int)sizeof(float);
647 
648             for (int colNdx = 0; colNdx < numCols; ++colNdx)
649                 vertexArrays.push_back(glu::va::Float(attribName, colNdx, numRows, numValues, stride,
650                                                       ((const float *)ptr) + colNdx * numRows));
651         }
652         else
653             DE_ASSERT(false);
654     }
655 
656     // Construct framebuffer.
657     gl.bindFramebuffer(GL_FRAMEBUFFER, *framebuffer);
658 
659     for (int outNdx = 0; outNdx < (int)m_outputLayout.locationSymbols.size(); ++outNdx)
660     {
661         const Symbol &output        = *m_outputLayout.locationSymbols[outNdx];
662         const uint32_t renderbuffer = renderbuffers[outNdx];
663         const uint32_t format = glu::getInternalFormat(getRenderbufferFormatForOutput(output.varType, useIntOutputs));
664 
665         gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
666         gl.renderbufferStorage(GL_RENDERBUFFER, format, framebufferW, framebufferH);
667         gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + outNdx, GL_RENDERBUFFER, renderbuffer);
668     }
669     gl.bindRenderbuffer(GL_RENDERBUFFER, 0);
670     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to set up framebuffer object");
671     TCU_CHECK(gl.checkFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
672 
673     {
674         vector<uint32_t> drawBuffers(m_outputLayout.locationSymbols.size());
675         for (int ndx = 0; ndx < (int)m_outputLayout.locationSymbols.size(); ndx++)
676             drawBuffers[ndx] = GL_COLOR_ATTACHMENT0 + ndx;
677         gl.drawBuffers((int)drawBuffers.size(), &drawBuffers[0]);
678         GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawBuffers()");
679     }
680 
681     // Render
682     gl.viewport(0, 0, framebufferW, framebufferH);
683     glu::draw(m_renderCtx, this->getProgram(), (int)vertexArrays.size(), &vertexArrays[0], glu::pr::Points(numValues));
684     GLU_EXPECT_NO_ERROR(gl.getError(), "Error in draw");
685 
686     // Read back pixels.
687     {
688         tcu::TextureLevel tmpBuf;
689 
690         // \todo [2013-08-07 pyry] Some fast-paths could be added here.
691 
692         for (int outNdx = 0; outNdx < (int)m_outputs.size(); ++outNdx)
693         {
694             const Symbol &output            = m_outputs[outNdx];
695             const int outSize               = output.varType.getScalarSize();
696             const int outVecSize            = glu::getDataTypeNumComponents(output.varType.getBasicType());
697             const int outNumLocs            = glu::getDataTypeNumLocations(output.varType.getBasicType());
698             uint32_t *dstPtrBase            = static_cast<uint32_t *>(outputs[outNdx]);
699             const tcu::TextureFormat format = getRenderbufferFormatForOutput(output.varType, useIntOutputs);
700             const tcu::TextureFormat readFormat(tcu::TextureFormat::RGBA, format.type);
701             const int outLocation = de::lookup(m_outputLayout.locationMap, output.name);
702 
703             tmpBuf.setStorage(readFormat, framebufferW, framebufferH);
704 
705             for (int locNdx = 0; locNdx < outNumLocs; ++locNdx)
706             {
707                 gl.readBuffer(GL_COLOR_ATTACHMENT0 + outLocation + locNdx);
708                 glu::readPixels(m_renderCtx, 0, 0, tmpBuf.getAccess());
709                 GLU_EXPECT_NO_ERROR(gl.getError(), "Reading pixels");
710 
711                 if (outSize == 4 && outNumLocs == 1)
712                     deMemcpy(dstPtrBase, tmpBuf.getAccess().getDataPtr(), numValues * outVecSize * sizeof(uint32_t));
713                 else
714                 {
715                     for (int valNdx = 0; valNdx < numValues; valNdx++)
716                     {
717                         const uint32_t *srcPtr = (const uint32_t *)tmpBuf.getAccess().getDataPtr() + valNdx * 4;
718                         uint32_t *dstPtr       = &dstPtrBase[outSize * valNdx + outVecSize * locNdx];
719                         deMemcpy(dstPtr, srcPtr, outVecSize * sizeof(uint32_t));
720                     }
721                 }
722             }
723         }
724     }
725 
726     // \todo [2013-08-07 pyry] Clear draw buffers & viewport?
727     gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
728 }
729 
730 // VertexShaderExecutor
731 
732 class VertexShaderExecutor : public FragmentOutExecutor
733 {
734 public:
735     VertexShaderExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec);
736     ~VertexShaderExecutor(void);
737 
isOk(void) const738     bool isOk(void) const
739     {
740         return m_program.isOk();
741     }
log(tcu::TestLog & dst) const742     void log(tcu::TestLog &dst) const
743     {
744         dst << m_program;
745     }
getProgram(void) const746     uint32_t getProgram(void) const
747     {
748         return m_program.getProgram();
749     }
750 
751 protected:
752     const glu::ShaderProgram m_program;
753 };
754 
VertexShaderExecutor(const glu::RenderContext & renderCtx,const ShaderSpec & shaderSpec)755 VertexShaderExecutor::VertexShaderExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec)
756     : FragmentOutExecutor(renderCtx, shaderSpec)
757     , m_program(renderCtx, glu::ProgramSources()
758                                << glu::VertexSource(generateVertexShader(shaderSpec, "a_", "vtx_out_"))
759                                << glu::FragmentSource(
760                                       generatePassthroughFragmentShader(shaderSpec, !hasFloatRenderTargets(renderCtx),
761                                                                         m_outputLayout.locationMap, "vtx_out_", "o_")))
762 {
763 }
764 
~VertexShaderExecutor(void)765 VertexShaderExecutor::~VertexShaderExecutor(void)
766 {
767 }
768 
769 // GeometryShaderExecutor
770 
771 class GeometryShaderExecutor : public FragmentOutExecutor
772 {
773 public:
774     static GeometryShaderExecutor *create(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec);
775 
776     ~GeometryShaderExecutor(void);
777 
isOk(void) const778     bool isOk(void) const
779     {
780         return m_program.isOk();
781     }
log(tcu::TestLog & dst) const782     void log(tcu::TestLog &dst) const
783     {
784         dst << m_program;
785     }
getProgram(void) const786     uint32_t getProgram(void) const
787     {
788         return m_program.getProgram();
789     }
790 
791 protected:
792     const glu::ShaderProgram m_program;
793 
794 private:
795     GeometryShaderExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec);
796 };
797 
create(const glu::RenderContext & renderCtx,const ShaderSpec & shaderSpec)798 GeometryShaderExecutor *GeometryShaderExecutor::create(const glu::RenderContext &renderCtx,
799                                                        const ShaderSpec &shaderSpec)
800 {
801     if (glu::glslVersionIsES(shaderSpec.version) && shaderSpec.version <= glu::GLSL_VERSION_310_ES &&
802         !contextSupports(renderCtx.getType(), glu::ApiType::core(4, 5)))
803         checkExtension(renderCtx, "GL_EXT_geometry_shader");
804 
805     return new GeometryShaderExecutor(renderCtx, shaderSpec);
806 }
807 
GeometryShaderExecutor(const glu::RenderContext & renderCtx,const ShaderSpec & shaderSpec)808 GeometryShaderExecutor::GeometryShaderExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec)
809     : FragmentOutExecutor(renderCtx, shaderSpec)
810     , m_program(renderCtx, glu::ProgramSources()
811                                << glu::VertexSource(generatePassthroughVertexShader(shaderSpec, "a_", "vtx_out_"))
812                                << glu::GeometrySource(generateGeometryShader(shaderSpec, "vtx_out_", "geom_out_"))
813                                << glu::FragmentSource(
814                                       generatePassthroughFragmentShader(shaderSpec, !hasFloatRenderTargets(renderCtx),
815                                                                         m_outputLayout.locationMap, "geom_out_", "o_")))
816 {
817 }
818 
~GeometryShaderExecutor(void)819 GeometryShaderExecutor::~GeometryShaderExecutor(void)
820 {
821 }
822 
823 // FragmentShaderExecutor
824 
825 class FragmentShaderExecutor : public FragmentOutExecutor
826 {
827 public:
828     FragmentShaderExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec);
829     ~FragmentShaderExecutor(void);
830 
isOk(void) const831     bool isOk(void) const
832     {
833         return m_program.isOk();
834     }
log(tcu::TestLog & dst) const835     void log(tcu::TestLog &dst) const
836     {
837         dst << m_program;
838     }
getProgram(void) const839     uint32_t getProgram(void) const
840     {
841         return m_program.getProgram();
842     }
843 
844 protected:
845     const glu::ShaderProgram m_program;
846 };
847 
FragmentShaderExecutor(const glu::RenderContext & renderCtx,const ShaderSpec & shaderSpec)848 FragmentShaderExecutor::FragmentShaderExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec)
849     : FragmentOutExecutor(renderCtx, shaderSpec)
850     , m_program(
851           renderCtx, glu::ProgramSources()
852                          << glu::VertexSource(generatePassthroughVertexShader(shaderSpec, "a_", "vtx_out_"))
853                          << glu::FragmentSource(generateFragmentShader(shaderSpec, !hasFloatRenderTargets(renderCtx),
854                                                                        m_outputLayout.locationMap, "vtx_out_", "o_")))
855 {
856 }
857 
~FragmentShaderExecutor(void)858 FragmentShaderExecutor::~FragmentShaderExecutor(void)
859 {
860 }
861 
862 // Shared utilities for compute and tess executors
863 
getVecStd430ByteAlignment(glu::DataType type)864 static uint32_t getVecStd430ByteAlignment(glu::DataType type)
865 {
866     switch (glu::getDataTypeScalarSize(type))
867     {
868     case 1:
869         return 4u;
870     case 2:
871         return 8u;
872     case 3:
873         return 16u;
874     case 4:
875         return 16u;
876     default:
877         DE_ASSERT(false);
878         return 0u;
879     }
880 }
881 
882 class BufferIoExecutor : public ShaderExecutor
883 {
884 public:
885     BufferIoExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec,
886                      const glu::ProgramSources &sources);
887     ~BufferIoExecutor(void);
888 
isOk(void) const889     bool isOk(void) const
890     {
891         return m_program.isOk();
892     }
log(tcu::TestLog & dst) const893     void log(tcu::TestLog &dst) const
894     {
895         dst << m_program;
896     }
getProgram(void) const897     uint32_t getProgram(void) const
898     {
899         return m_program.getProgram();
900     }
901 
902 protected:
903     enum
904     {
905         INPUT_BUFFER_BINDING  = 0,
906         OUTPUT_BUFFER_BINDING = 1,
907     };
908 
909     void initBuffers(int numValues);
getInputBuffer(void) const910     uint32_t getInputBuffer(void) const
911     {
912         return *m_inputBuffer;
913     }
getOutputBuffer(void) const914     uint32_t getOutputBuffer(void) const
915     {
916         return *m_outputBuffer;
917     }
getInputStride(void) const918     uint32_t getInputStride(void) const
919     {
920         return getLayoutStride(m_inputLayout);
921     }
getOutputStride(void) const922     uint32_t getOutputStride(void) const
923     {
924         return getLayoutStride(m_outputLayout);
925     }
926 
927     void uploadInputBuffer(const void *const *inputPtrs, int numValues);
928     void readOutputBuffer(void *const *outputPtrs, int numValues);
929 
930     static void declareBufferBlocks(std::ostream &src, const ShaderSpec &spec);
931     static void generateExecBufferIo(std::ostream &src, const ShaderSpec &spec, const char *invocationNdxName);
932 
933     glu::ShaderProgram m_program;
934 
935 private:
936     struct VarLayout
937     {
938         uint32_t offset;
939         uint32_t stride;
940         uint32_t matrixStride;
941 
VarLayoutdeqp::gls::ShaderExecUtil::BufferIoExecutor::VarLayout942         VarLayout(void) : offset(0), stride(0), matrixStride(0)
943         {
944         }
945     };
946 
947     void resizeInputBuffer(int newSize);
948     void resizeOutputBuffer(int newSize);
949 
950     static void computeVarLayout(const std::vector<Symbol> &symbols, std::vector<VarLayout> *layout);
951     static uint32_t getLayoutStride(const vector<VarLayout> &layout);
952 
953     static void copyToBuffer(const glu::VarType &varType, const VarLayout &layout, int numValues,
954                              const void *srcBasePtr, void *dstBasePtr);
955     static void copyFromBuffer(const glu::VarType &varType, const VarLayout &layout, int numValues,
956                                const void *srcBasePtr, void *dstBasePtr);
957 
958     glu::Buffer m_inputBuffer;
959     glu::Buffer m_outputBuffer;
960 
961     vector<VarLayout> m_inputLayout;
962     vector<VarLayout> m_outputLayout;
963 };
964 
BufferIoExecutor(const glu::RenderContext & renderCtx,const ShaderSpec & shaderSpec,const glu::ProgramSources & sources)965 BufferIoExecutor::BufferIoExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec,
966                                    const glu::ProgramSources &sources)
967     : ShaderExecutor(renderCtx, shaderSpec)
968     , m_program(renderCtx, sources)
969     , m_inputBuffer(renderCtx)
970     , m_outputBuffer(renderCtx)
971 {
972     computeVarLayout(m_inputs, &m_inputLayout);
973     computeVarLayout(m_outputs, &m_outputLayout);
974 }
975 
~BufferIoExecutor(void)976 BufferIoExecutor::~BufferIoExecutor(void)
977 {
978 }
979 
resizeInputBuffer(int newSize)980 void BufferIoExecutor::resizeInputBuffer(int newSize)
981 {
982     const glw::Functions &gl = m_renderCtx.getFunctions();
983     gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *m_inputBuffer);
984     gl.bufferData(GL_SHADER_STORAGE_BUFFER, newSize, DE_NULL, GL_STATIC_DRAW);
985     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to allocate input buffer");
986 }
987 
resizeOutputBuffer(int newSize)988 void BufferIoExecutor::resizeOutputBuffer(int newSize)
989 {
990     const glw::Functions &gl = m_renderCtx.getFunctions();
991     gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, *m_outputBuffer);
992     gl.bufferData(GL_SHADER_STORAGE_BUFFER, newSize, DE_NULL, GL_STATIC_DRAW);
993     GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to allocate output buffer");
994 }
995 
initBuffers(int numValues)996 void BufferIoExecutor::initBuffers(int numValues)
997 {
998     const uint32_t inputStride  = getLayoutStride(m_inputLayout);
999     const uint32_t outputStride = getLayoutStride(m_outputLayout);
1000     const int inputBufferSize   = numValues * inputStride;
1001     const int outputBufferSize  = numValues * outputStride;
1002 
1003     resizeInputBuffer(inputBufferSize);
1004     resizeOutputBuffer(outputBufferSize);
1005 }
1006 
computeVarLayout(const std::vector<Symbol> & symbols,std::vector<VarLayout> * layout)1007 void BufferIoExecutor::computeVarLayout(const std::vector<Symbol> &symbols, std::vector<VarLayout> *layout)
1008 {
1009     uint32_t maxAlignment = 0;
1010     uint32_t curOffset    = 0;
1011 
1012     DE_ASSERT(layout->empty());
1013     layout->resize(symbols.size());
1014 
1015     for (size_t varNdx = 0; varNdx < symbols.size(); varNdx++)
1016     {
1017         const Symbol &symbol          = symbols[varNdx];
1018         const glu::DataType basicType = symbol.varType.getBasicType();
1019         VarLayout &layoutEntry        = (*layout)[varNdx];
1020 
1021         if (glu::isDataTypeScalarOrVector(basicType))
1022         {
1023             const uint32_t alignment = getVecStd430ByteAlignment(basicType);
1024             const uint32_t size      = (uint32_t)glu::getDataTypeScalarSize(basicType) * (int)sizeof(uint32_t);
1025 
1026             curOffset    = (uint32_t)deAlign32((int)curOffset, (int)alignment);
1027             maxAlignment = de::max(maxAlignment, alignment);
1028 
1029             layoutEntry.offset       = curOffset;
1030             layoutEntry.matrixStride = 0;
1031 
1032             curOffset += size;
1033         }
1034         else if (glu::isDataTypeMatrix(basicType))
1035         {
1036             const int numVecs           = glu::getDataTypeMatrixNumColumns(basicType);
1037             const glu::DataType vecType = glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType));
1038             const uint32_t vecAlignment = getVecStd430ByteAlignment(vecType);
1039 
1040             curOffset    = (uint32_t)deAlign32((int)curOffset, (int)vecAlignment);
1041             maxAlignment = de::max(maxAlignment, vecAlignment);
1042 
1043             layoutEntry.offset       = curOffset;
1044             layoutEntry.matrixStride = vecAlignment;
1045 
1046             curOffset += vecAlignment * numVecs;
1047         }
1048         else
1049             DE_ASSERT(false);
1050     }
1051 
1052     {
1053         const uint32_t totalSize = (uint32_t)deAlign32(curOffset, maxAlignment);
1054 
1055         for (vector<VarLayout>::iterator varIter = layout->begin(); varIter != layout->end(); ++varIter)
1056             varIter->stride = totalSize;
1057     }
1058 }
1059 
getLayoutStride(const vector<VarLayout> & layout)1060 inline uint32_t BufferIoExecutor::getLayoutStride(const vector<VarLayout> &layout)
1061 {
1062     return layout.empty() ? 0 : layout[0].stride;
1063 }
1064 
copyToBuffer(const glu::VarType & varType,const VarLayout & layout,int numValues,const void * srcBasePtr,void * dstBasePtr)1065 void BufferIoExecutor::copyToBuffer(const glu::VarType &varType, const VarLayout &layout, int numValues,
1066                                     const void *srcBasePtr, void *dstBasePtr)
1067 {
1068     if (varType.isBasicType())
1069     {
1070         const glu::DataType basicType = varType.getBasicType();
1071         const bool isMatrix           = glu::isDataTypeMatrix(basicType);
1072         const int scalarSize          = glu::getDataTypeScalarSize(basicType);
1073         const int numVecs             = isMatrix ? glu::getDataTypeMatrixNumColumns(basicType) : 1;
1074         const int numComps            = scalarSize / numVecs;
1075 
1076         for (int elemNdx = 0; elemNdx < numValues; elemNdx++)
1077         {
1078             for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
1079             {
1080                 const int srcOffset = (int)sizeof(uint32_t) * (elemNdx * scalarSize + vecNdx * numComps);
1081                 const int dstOffset =
1082                     layout.offset + layout.stride * elemNdx + (isMatrix ? layout.matrixStride * vecNdx : 0);
1083                 const uint8_t *srcPtr = (const uint8_t *)srcBasePtr + srcOffset;
1084                 uint8_t *dstPtr       = (uint8_t *)dstBasePtr + dstOffset;
1085 
1086                 deMemcpy(dstPtr, srcPtr, sizeof(uint32_t) * numComps);
1087             }
1088         }
1089     }
1090     else
1091         throw tcu::InternalError("Unsupported type");
1092 }
1093 
copyFromBuffer(const glu::VarType & varType,const VarLayout & layout,int numValues,const void * srcBasePtr,void * dstBasePtr)1094 void BufferIoExecutor::copyFromBuffer(const glu::VarType &varType, const VarLayout &layout, int numValues,
1095                                       const void *srcBasePtr, void *dstBasePtr)
1096 {
1097     if (varType.isBasicType())
1098     {
1099         const glu::DataType basicType = varType.getBasicType();
1100         const bool isMatrix           = glu::isDataTypeMatrix(basicType);
1101         const int scalarSize          = glu::getDataTypeScalarSize(basicType);
1102         const int numVecs             = isMatrix ? glu::getDataTypeMatrixNumColumns(basicType) : 1;
1103         const int numComps            = scalarSize / numVecs;
1104 
1105         for (int elemNdx = 0; elemNdx < numValues; elemNdx++)
1106         {
1107             for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
1108             {
1109                 const int srcOffset =
1110                     layout.offset + layout.stride * elemNdx + (isMatrix ? layout.matrixStride * vecNdx : 0);
1111                 const int dstOffset   = (int)sizeof(uint32_t) * (elemNdx * scalarSize + vecNdx * numComps);
1112                 const uint8_t *srcPtr = (const uint8_t *)srcBasePtr + srcOffset;
1113                 uint8_t *dstPtr       = (uint8_t *)dstBasePtr + dstOffset;
1114 
1115                 deMemcpy(dstPtr, srcPtr, sizeof(uint32_t) * numComps);
1116             }
1117         }
1118     }
1119     else
1120         throw tcu::InternalError("Unsupported type");
1121 }
1122 
uploadInputBuffer(const void * const * inputPtrs,int numValues)1123 void BufferIoExecutor::uploadInputBuffer(const void *const *inputPtrs, int numValues)
1124 {
1125     const glw::Functions &gl   = m_renderCtx.getFunctions();
1126     const uint32_t buffer      = *m_inputBuffer;
1127     const uint32_t inputStride = getLayoutStride(m_inputLayout);
1128     const int inputBufferSize  = inputStride * numValues;
1129 
1130     if (inputBufferSize == 0)
1131         return; // No inputs
1132 
1133     gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
1134     void *mapPtr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, inputBufferSize, GL_MAP_WRITE_BIT);
1135     GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
1136     TCU_CHECK(mapPtr);
1137 
1138     try
1139     {
1140         DE_ASSERT(m_inputs.size() == m_inputLayout.size());
1141         for (size_t inputNdx = 0; inputNdx < m_inputs.size(); ++inputNdx)
1142         {
1143             const glu::VarType &varType = m_inputs[inputNdx].varType;
1144             const VarLayout &layout     = m_inputLayout[inputNdx];
1145 
1146             copyToBuffer(varType, layout, numValues, inputPtrs[inputNdx], mapPtr);
1147         }
1148     }
1149     catch (...)
1150     {
1151         gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
1152         throw;
1153     }
1154 
1155     gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
1156     GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()");
1157 }
1158 
readOutputBuffer(void * const * outputPtrs,int numValues)1159 void BufferIoExecutor::readOutputBuffer(void *const *outputPtrs, int numValues)
1160 {
1161     const glw::Functions &gl    = m_renderCtx.getFunctions();
1162     const uint32_t buffer       = *m_outputBuffer;
1163     const uint32_t outputStride = getLayoutStride(m_outputLayout);
1164     const int outputBufferSize  = numValues * outputStride;
1165 
1166     DE_ASSERT(outputBufferSize > 0); // At least some outputs are required.
1167 
1168     gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1169     gl.bindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
1170     void *mapPtr = gl.mapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, outputBufferSize, GL_MAP_READ_BIT);
1171     GLU_EXPECT_NO_ERROR(gl.getError(), "glMapBufferRange()");
1172     TCU_CHECK(mapPtr);
1173 
1174     try
1175     {
1176         DE_ASSERT(m_outputs.size() == m_outputLayout.size());
1177         for (size_t outputNdx = 0; outputNdx < m_outputs.size(); ++outputNdx)
1178         {
1179             const glu::VarType &varType = m_outputs[outputNdx].varType;
1180             const VarLayout &layout     = m_outputLayout[outputNdx];
1181 
1182             copyFromBuffer(varType, layout, numValues, mapPtr, outputPtrs[outputNdx]);
1183         }
1184     }
1185     catch (...)
1186     {
1187         gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
1188         throw;
1189     }
1190 
1191     gl.unmapBuffer(GL_SHADER_STORAGE_BUFFER);
1192     GLU_EXPECT_NO_ERROR(gl.getError(), "glUnmapBuffer()");
1193 }
1194 
declareBufferBlocks(std::ostream & src,const ShaderSpec & spec)1195 void BufferIoExecutor::declareBufferBlocks(std::ostream &src, const ShaderSpec &spec)
1196 {
1197     // Input struct
1198     if (!spec.inputs.empty())
1199     {
1200         glu::StructType inputStruct("Inputs");
1201         for (vector<Symbol>::const_iterator symIter = spec.inputs.begin(); symIter != spec.inputs.end(); ++symIter)
1202             inputStruct.addMember(symIter->name.c_str(), symIter->varType);
1203         src << glu::declare(&inputStruct) << ";\n";
1204     }
1205 
1206     // Output struct
1207     {
1208         glu::StructType outputStruct("Outputs");
1209         for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter)
1210             outputStruct.addMember(symIter->name.c_str(), symIter->varType);
1211         src << glu::declare(&outputStruct) << ";\n";
1212     }
1213 
1214     src << "\n";
1215 
1216     if (!spec.inputs.empty())
1217     {
1218         src << "layout(binding = " << int(INPUT_BUFFER_BINDING) << ", std430) buffer InBuffer\n"
1219             << "{\n"
1220             << "    Inputs inputs[];\n"
1221             << "};\n";
1222     }
1223 
1224     src << "layout(binding = " << int(OUTPUT_BUFFER_BINDING) << ", std430) buffer OutBuffer\n"
1225         << "{\n"
1226         << "    Outputs outputs[];\n"
1227         << "};\n"
1228         << "\n";
1229 }
1230 
generateExecBufferIo(std::ostream & src,const ShaderSpec & spec,const char * invocationNdxName)1231 void BufferIoExecutor::generateExecBufferIo(std::ostream &src, const ShaderSpec &spec, const char *invocationNdxName)
1232 {
1233     for (vector<Symbol>::const_iterator symIter = spec.inputs.begin(); symIter != spec.inputs.end(); ++symIter)
1234         src << "\t" << glu::declare(symIter->varType, symIter->name) << " = inputs[" << invocationNdxName << "]."
1235             << symIter->name << ";\n";
1236 
1237     for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter)
1238         src << "\t" << glu::declare(symIter->varType, symIter->name) << ";\n";
1239 
1240     src << "\n";
1241 
1242     {
1243         std::istringstream opSrc(spec.source);
1244         std::string line;
1245 
1246         while (std::getline(opSrc, line))
1247             src << "\t" << line << "\n";
1248     }
1249 
1250     src << "\n";
1251     for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter)
1252         src << "\toutputs[" << invocationNdxName << "]." << symIter->name << " = " << symIter->name << ";\n";
1253 }
1254 
1255 // ComputeShaderExecutor
1256 
1257 class ComputeShaderExecutor : public BufferIoExecutor
1258 {
1259 public:
1260     ComputeShaderExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec);
1261     ~ComputeShaderExecutor(void);
1262 
1263     void execute(int numValues, const void *const *inputs, void *const *outputs);
1264 
1265 protected:
1266     static std::string generateComputeShader(const ShaderSpec &spec);
1267 
1268     tcu::IVec3 m_maxWorkSize;
1269 };
1270 
generateComputeShader(const ShaderSpec & spec)1271 std::string ComputeShaderExecutor::generateComputeShader(const ShaderSpec &spec)
1272 {
1273     std::ostringstream src;
1274 
1275     src << glu::getGLSLVersionDeclaration(spec.version) << "\n";
1276 
1277     if (!spec.globalDeclarations.empty())
1278         src << spec.globalDeclarations << "\n";
1279 
1280     src << "layout(local_size_x = 1) in;\n"
1281         << "\n";
1282 
1283     declareBufferBlocks(src, spec);
1284 
1285     src << "void main (void)\n"
1286         << "{\n"
1287         << "    uint invocationNdx = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z\n"
1288         << "                       + gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n";
1289 
1290     generateExecBufferIo(src, spec, "invocationNdx");
1291 
1292     src << "}\n";
1293 
1294     return src.str();
1295 }
1296 
ComputeShaderExecutor(const glu::RenderContext & renderCtx,const ShaderSpec & shaderSpec)1297 ComputeShaderExecutor::ComputeShaderExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec)
1298     : BufferIoExecutor(renderCtx, shaderSpec,
1299                        glu::ProgramSources() << glu::ComputeSource(generateComputeShader(shaderSpec)))
1300 {
1301     m_maxWorkSize = tcu::IVec3(128, 128, 64); // Minimum in 3plus
1302 }
1303 
~ComputeShaderExecutor(void)1304 ComputeShaderExecutor::~ComputeShaderExecutor(void)
1305 {
1306 }
1307 
execute(int numValues,const void * const * inputs,void * const * outputs)1308 void ComputeShaderExecutor::execute(int numValues, const void *const *inputs, void *const *outputs)
1309 {
1310     const glw::Functions &gl         = m_renderCtx.getFunctions();
1311     const int maxValuesPerInvocation = m_maxWorkSize[0];
1312     const uint32_t inputStride       = getInputStride();
1313     const uint32_t outputStride      = getOutputStride();
1314 
1315     initBuffers(numValues);
1316 
1317     // Setup input buffer & copy data
1318     uploadInputBuffer(inputs, numValues);
1319 
1320     // Perform compute invocations
1321     {
1322         int curOffset = 0;
1323         while (curOffset < numValues)
1324         {
1325             const int numToExec = de::min(maxValuesPerInvocation, numValues - curOffset);
1326 
1327             if (inputStride > 0)
1328                 gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, INPUT_BUFFER_BINDING, getInputBuffer(),
1329                                    curOffset * inputStride, numToExec * inputStride);
1330 
1331             gl.bindBufferRange(GL_SHADER_STORAGE_BUFFER, OUTPUT_BUFFER_BINDING, getOutputBuffer(),
1332                                curOffset * outputStride, numToExec * outputStride);
1333             GLU_EXPECT_NO_ERROR(gl.getError(), "glBindBufferRange(GL_SHADER_STORAGE_BUFFER)");
1334 
1335             gl.dispatchCompute(numToExec, 1, 1);
1336             GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()");
1337 
1338             curOffset += numToExec;
1339         }
1340     }
1341 
1342     // Read back data
1343     readOutputBuffer(outputs, numValues);
1344 }
1345 
1346 // Tessellation utils
1347 
generateVertexShaderForTess(glu::GLSLVersion version)1348 static std::string generateVertexShaderForTess(glu::GLSLVersion version)
1349 {
1350     std::ostringstream src;
1351 
1352     src << glu::getGLSLVersionDeclaration(version) << "\n";
1353 
1354     src << "void main (void)\n{\n"
1355         << "    gl_Position = vec4(gl_VertexID/2, gl_VertexID%2, 0.0, 1.0);\n"
1356         << "}\n";
1357 
1358     return src.str();
1359 }
1360 
checkTessSupport(const glu::RenderContext & renderCtx,const ShaderSpec & shaderSpec,glu::ShaderType stage)1361 void checkTessSupport(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec, glu::ShaderType stage)
1362 {
1363     const int numBlockRequired = 2; // highest binding is always 1 (output) i.e. count == 2
1364 
1365     if (glu::glslVersionIsES(shaderSpec.version) && shaderSpec.version <= glu::GLSL_VERSION_310_ES &&
1366         !contextSupports(renderCtx.getType(), glu::ApiType::core(4, 5)))
1367         checkExtension(renderCtx, "GL_EXT_tessellation_shader");
1368 
1369     if (stage == glu::SHADERTYPE_TESSELLATION_CONTROL)
1370         checkLimit(renderCtx, GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, numBlockRequired);
1371     else if (stage == glu::SHADERTYPE_TESSELLATION_EVALUATION)
1372         checkLimit(renderCtx, GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, numBlockRequired);
1373     else
1374         DE_ASSERT(false);
1375 }
1376 
1377 // TessControlExecutor
1378 
1379 class TessControlExecutor : public BufferIoExecutor
1380 {
1381 public:
1382     static TessControlExecutor *create(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec);
1383 
1384     ~TessControlExecutor(void);
1385 
1386     void execute(int numValues, const void *const *inputs, void *const *outputs);
1387 
1388 protected:
1389     static std::string generateTessControlShader(const ShaderSpec &shaderSpec);
1390 
1391 private:
1392     TessControlExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec);
1393 };
1394 
create(const glu::RenderContext & renderCtx,const ShaderSpec & shaderSpec)1395 TessControlExecutor *TessControlExecutor::create(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec)
1396 {
1397     checkTessSupport(renderCtx, shaderSpec, glu::SHADERTYPE_TESSELLATION_CONTROL);
1398 
1399     return new TessControlExecutor(renderCtx, shaderSpec);
1400 }
1401 
generateTessControlShader(const ShaderSpec & shaderSpec)1402 std::string TessControlExecutor::generateTessControlShader(const ShaderSpec &shaderSpec)
1403 {
1404     std::ostringstream src;
1405 
1406     src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
1407 
1408     if (glu::glslVersionIsES(shaderSpec.version) && shaderSpec.version <= glu::GLSL_VERSION_310_ES)
1409         src << "#extension GL_EXT_tessellation_shader : require\n";
1410 
1411     if (!shaderSpec.globalDeclarations.empty())
1412         src << shaderSpec.globalDeclarations << "\n";
1413 
1414     src << "\nlayout(vertices = 1) out;\n\n";
1415 
1416     declareBufferBlocks(src, shaderSpec);
1417 
1418     src << "void main (void)\n{\n";
1419 
1420     for (int ndx = 0; ndx < 2; ndx++)
1421         src << "\tgl_TessLevelInner[" << ndx << "] = 1.0;\n";
1422 
1423     for (int ndx = 0; ndx < 4; ndx++)
1424         src << "\tgl_TessLevelOuter[" << ndx << "] = 1.0;\n";
1425 
1426     src << "\n"
1427         << "\thighp uint invocationId = uint(gl_PrimitiveID);\n";
1428 
1429     generateExecBufferIo(src, shaderSpec, "invocationId");
1430 
1431     src << "}\n";
1432 
1433     return src.str();
1434 }
1435 
generateEmptyTessEvalShader(glu::GLSLVersion version)1436 static std::string generateEmptyTessEvalShader(glu::GLSLVersion version)
1437 {
1438     std::ostringstream src;
1439 
1440     src << glu::getGLSLVersionDeclaration(version) << "\n";
1441 
1442     if (glu::glslVersionIsES(version) && version <= glu::GLSL_VERSION_310_ES)
1443         src << "#extension GL_EXT_tessellation_shader : require\n\n";
1444 
1445     src << "layout(triangles, ccw) in;\n";
1446 
1447     src << "\nvoid main (void)\n{\n"
1448         << "\tgl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n"
1449         << "}\n";
1450 
1451     return src.str();
1452 }
1453 
TessControlExecutor(const glu::RenderContext & renderCtx,const ShaderSpec & shaderSpec)1454 TessControlExecutor::TessControlExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec)
1455     : BufferIoExecutor(renderCtx, shaderSpec,
1456                        glu::ProgramSources()
1457                            << glu::VertexSource(generateVertexShaderForTess(shaderSpec.version))
1458                            << glu::TessellationControlSource(generateTessControlShader(shaderSpec))
1459                            << glu::TessellationEvaluationSource(generateEmptyTessEvalShader(shaderSpec.version))
1460                            << glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version)))
1461 {
1462 }
1463 
~TessControlExecutor(void)1464 TessControlExecutor::~TessControlExecutor(void)
1465 {
1466 }
1467 
execute(int numValues,const void * const * inputs,void * const * outputs)1468 void TessControlExecutor::execute(int numValues, const void *const *inputs, void *const *outputs)
1469 {
1470     const glw::Functions &gl = m_renderCtx.getFunctions();
1471 
1472     initBuffers(numValues);
1473 
1474     // Setup input buffer & copy data
1475     uploadInputBuffer(inputs, numValues);
1476 
1477     if (!m_inputs.empty())
1478         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, INPUT_BUFFER_BINDING, getInputBuffer());
1479 
1480     gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, OUTPUT_BUFFER_BINDING, getOutputBuffer());
1481 
1482     uint32_t vertexArray;
1483     gl.genVertexArrays(1, &vertexArray);
1484     gl.bindVertexArray(vertexArray);
1485 
1486     // Render patches
1487     gl.patchParameteri(GL_PATCH_VERTICES, 3);
1488     gl.drawArrays(GL_PATCHES, 0, 3 * numValues);
1489 
1490     gl.bindVertexArray(0);
1491     gl.deleteVertexArrays(1, &vertexArray);
1492 
1493     // Read back data
1494     readOutputBuffer(outputs, numValues);
1495 }
1496 
1497 // TessEvaluationExecutor
1498 
1499 class TessEvaluationExecutor : public BufferIoExecutor
1500 {
1501 public:
1502     static TessEvaluationExecutor *create(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec);
1503 
1504     ~TessEvaluationExecutor(void);
1505 
1506     void execute(int numValues, const void *const *inputs, void *const *outputs);
1507 
1508 protected:
1509     static std::string generateTessEvalShader(const ShaderSpec &shaderSpec);
1510 
1511 private:
1512     TessEvaluationExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec);
1513 };
1514 
create(const glu::RenderContext & renderCtx,const ShaderSpec & shaderSpec)1515 TessEvaluationExecutor *TessEvaluationExecutor::create(const glu::RenderContext &renderCtx,
1516                                                        const ShaderSpec &shaderSpec)
1517 {
1518     checkTessSupport(renderCtx, shaderSpec, glu::SHADERTYPE_TESSELLATION_EVALUATION);
1519 
1520     return new TessEvaluationExecutor(renderCtx, shaderSpec);
1521 }
1522 
generatePassthroughTessControlShader(glu::GLSLVersion version)1523 static std::string generatePassthroughTessControlShader(glu::GLSLVersion version)
1524 {
1525     std::ostringstream src;
1526 
1527     src << glu::getGLSLVersionDeclaration(version) << "\n";
1528 
1529     if (glu::glslVersionIsES(version) && version <= glu::GLSL_VERSION_310_ES)
1530         src << "#extension GL_EXT_tessellation_shader : require\n\n";
1531 
1532     src << "layout(vertices = 1) out;\n\n";
1533 
1534     src << "void main (void)\n{\n";
1535 
1536     for (int ndx = 0; ndx < 2; ndx++)
1537         src << "\tgl_TessLevelInner[" << ndx << "] = 1.0;\n";
1538 
1539     for (int ndx = 0; ndx < 4; ndx++)
1540         src << "\tgl_TessLevelOuter[" << ndx << "] = 1.0;\n";
1541 
1542     src << "}\n";
1543 
1544     return src.str();
1545 }
1546 
generateTessEvalShader(const ShaderSpec & shaderSpec)1547 std::string TessEvaluationExecutor::generateTessEvalShader(const ShaderSpec &shaderSpec)
1548 {
1549     std::ostringstream src;
1550 
1551     src << glu::getGLSLVersionDeclaration(shaderSpec.version) << "\n";
1552 
1553     if (glu::glslVersionIsES(shaderSpec.version) && shaderSpec.version <= glu::GLSL_VERSION_310_ES)
1554         src << "#extension GL_EXT_tessellation_shader : require\n";
1555 
1556     if (!shaderSpec.globalDeclarations.empty())
1557         src << shaderSpec.globalDeclarations << "\n";
1558 
1559     src << "\n";
1560 
1561     src << "layout(isolines, equal_spacing) in;\n\n";
1562 
1563     declareBufferBlocks(src, shaderSpec);
1564 
1565     src << "void main (void)\n{\n"
1566         << "\tgl_Position = vec4(gl_TessCoord.x, 0.0, 0.0, 1.0);\n"
1567         << "\thighp uint invocationId = uint(gl_PrimitiveID)*2u + (gl_TessCoord.x > 0.5 ? 1u : 0u);\n";
1568 
1569     generateExecBufferIo(src, shaderSpec, "invocationId");
1570 
1571     src << "}\n";
1572 
1573     return src.str();
1574 }
1575 
TessEvaluationExecutor(const glu::RenderContext & renderCtx,const ShaderSpec & shaderSpec)1576 TessEvaluationExecutor::TessEvaluationExecutor(const glu::RenderContext &renderCtx, const ShaderSpec &shaderSpec)
1577     : BufferIoExecutor(renderCtx, shaderSpec,
1578                        glu::ProgramSources()
1579                            << glu::VertexSource(generateVertexShaderForTess(shaderSpec.version))
1580                            << glu::TessellationControlSource(generatePassthroughTessControlShader(shaderSpec.version))
1581                            << glu::TessellationEvaluationSource(generateTessEvalShader(shaderSpec))
1582                            << glu::FragmentSource(generateEmptyFragmentSource(shaderSpec.version)))
1583 {
1584 }
1585 
~TessEvaluationExecutor(void)1586 TessEvaluationExecutor::~TessEvaluationExecutor(void)
1587 {
1588 }
1589 
execute(int numValues,const void * const * inputs,void * const * outputs)1590 void TessEvaluationExecutor::execute(int numValues, const void *const *inputs, void *const *outputs)
1591 {
1592     const glw::Functions &gl = m_renderCtx.getFunctions();
1593     const int alignedValues  = deAlign32(numValues, 2);
1594 
1595     // Initialize buffers with aligned value count to make room for padding
1596     initBuffers(alignedValues);
1597 
1598     // Setup input buffer & copy data
1599     uploadInputBuffer(inputs, numValues);
1600 
1601     // \todo [2014-06-26 pyry] Duplicate last value in the buffer to prevent infinite loops for example?
1602 
1603     if (!m_inputs.empty())
1604         gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, INPUT_BUFFER_BINDING, getInputBuffer());
1605 
1606     gl.bindBufferBase(GL_SHADER_STORAGE_BUFFER, OUTPUT_BUFFER_BINDING, getOutputBuffer());
1607 
1608     uint32_t vertexArray;
1609     gl.genVertexArrays(1, &vertexArray);
1610     gl.bindVertexArray(vertexArray);
1611 
1612     // Render patches
1613     gl.patchParameteri(GL_PATCH_VERTICES, 2);
1614     gl.drawArrays(GL_PATCHES, 0, alignedValues);
1615 
1616     gl.bindVertexArray(0);
1617     gl.deleteVertexArrays(1, &vertexArray);
1618 
1619     // Read back data
1620     readOutputBuffer(outputs, numValues);
1621 }
1622 
1623 // Utilities
1624 
createExecutor(const glu::RenderContext & renderCtx,glu::ShaderType shaderType,const ShaderSpec & shaderSpec)1625 ShaderExecutor *createExecutor(const glu::RenderContext &renderCtx, glu::ShaderType shaderType,
1626                                const ShaderSpec &shaderSpec)
1627 {
1628     switch (shaderType)
1629     {
1630     case glu::SHADERTYPE_VERTEX:
1631         return new VertexShaderExecutor(renderCtx, shaderSpec);
1632     case glu::SHADERTYPE_TESSELLATION_CONTROL:
1633         return TessControlExecutor::create(renderCtx, shaderSpec);
1634     case glu::SHADERTYPE_TESSELLATION_EVALUATION:
1635         return TessEvaluationExecutor::create(renderCtx, shaderSpec);
1636     case glu::SHADERTYPE_GEOMETRY:
1637         return GeometryShaderExecutor::create(renderCtx, shaderSpec);
1638     case glu::SHADERTYPE_FRAGMENT:
1639         return new FragmentShaderExecutor(renderCtx, shaderSpec);
1640     case glu::SHADERTYPE_COMPUTE:
1641         return new ComputeShaderExecutor(renderCtx, shaderSpec);
1642     default:
1643         throw tcu::InternalError("Unsupported shader type");
1644     }
1645 }
1646 
executorSupported(glu::ShaderType shaderType)1647 bool executorSupported(glu::ShaderType shaderType)
1648 {
1649     switch (shaderType)
1650     {
1651     case glu::SHADERTYPE_VERTEX:
1652     case glu::SHADERTYPE_TESSELLATION_CONTROL:
1653     case glu::SHADERTYPE_TESSELLATION_EVALUATION:
1654     case glu::SHADERTYPE_GEOMETRY:
1655     case glu::SHADERTYPE_FRAGMENT:
1656     case glu::SHADERTYPE_COMPUTE:
1657         return true;
1658     default:
1659         return false;
1660     }
1661 }
1662 
1663 } // namespace ShaderExecUtil
1664 } // namespace gls
1665 } // namespace deqp
1666