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