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