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