1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 Google Inc.
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 ShaderLibrary Vulkan implementation
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktShaderLibrary.hpp"
25 #include "vktTestCase.hpp"
26
27 #include "vkPrograms.hpp"
28 #include "vkRef.hpp"
29 #include "vkRefUtil.hpp"
30 #include "vkMemUtil.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkBuilderUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkImageUtil.hpp"
35 #include "vkCmdUtil.hpp"
36 #include "vkObjUtil.hpp"
37
38 #include "gluShaderLibrary.hpp"
39 #include "gluShaderUtil.hpp"
40
41 #include "tcuStringTemplate.hpp"
42 #include "tcuTexture.hpp"
43 #include "tcuTestLog.hpp"
44 #include "tcuVector.hpp"
45 #include "tcuVectorUtil.hpp"
46
47 #include "deStringUtil.hpp"
48 #include "deArrayUtil.hpp"
49 #include "deMemory.h"
50
51 #include <sstream>
52 #include <map>
53
54 namespace vkt
55 {
56
57 using std::map;
58 using std::ostringstream;
59 using std::pair;
60 using std::string;
61 using std::vector;
62
63 using de::MovePtr;
64 using de::UniquePtr;
65
66 using glu::DataType;
67 using glu::ProgramSources;
68 using glu::ShaderType;
69
70 using glu::sl::ProgramSpecializationParams;
71 using glu::sl::RequiredExtension;
72 using glu::sl::ShaderCaseSpecification;
73 using glu::sl::Value;
74 using glu::sl::ValueBlock;
75
76 using tcu::ConstPixelBufferAccess;
77 using tcu::StringTemplate;
78 using tcu::TestLog;
79 using tcu::TestStatus;
80 using tcu::TextureFormat;
81 using tcu::Vec2;
82
83 using vk::Move;
84 using vk::SourceCollections;
85 using vk::Unique;
86
87 namespace
88 {
89
90 enum
91 {
92 REFERENCE_UNIFORM_BINDING = 0,
93 USER_UNIFORM_BINDING = 1
94 };
95
getShaderName(ShaderType shaderType,size_t progNdx)96 string getShaderName(ShaderType shaderType, size_t progNdx)
97 {
98 ostringstream str;
99 str << glu::getShaderTypeName(shaderType);
100 if (progNdx > 0)
101 str << "_" << progNdx;
102 return str.str();
103 }
104
genUniformBlock(ostringstream & out,const string & blockName,const string & instanceName,int setNdx,int bindingNdx,const vector<Value> & uniforms)105 void genUniformBlock(ostringstream &out, const string &blockName, const string &instanceName, int setNdx,
106 int bindingNdx, const vector<Value> &uniforms)
107 {
108 out << "layout(";
109
110 if (setNdx != 0)
111 out << "set = " << setNdx << ", ";
112
113 out << "binding = " << bindingNdx << ", std140) uniform " << blockName << "\n"
114 << "{\n";
115
116 for (vector<Value>::const_iterator val = uniforms.begin(); val != uniforms.end(); ++val)
117 out << "\t" << glu::declare(val->type, val->name, 1) << ";\n";
118
119 out << "}";
120
121 if (!instanceName.empty())
122 out << " " << instanceName;
123
124 out << ";\n";
125 }
126
declareReferenceBlock(ostringstream & out,const ValueBlock & valueBlock)127 void declareReferenceBlock(ostringstream &out, const ValueBlock &valueBlock)
128 {
129 if (!valueBlock.outputs.empty())
130 genUniformBlock(out, "Reference", "ref", 0, REFERENCE_UNIFORM_BINDING, valueBlock.outputs);
131 }
132
declareUniforms(ostringstream & out,const ValueBlock & valueBlock)133 void declareUniforms(ostringstream &out, const ValueBlock &valueBlock)
134 {
135 if (!valueBlock.uniforms.empty())
136 genUniformBlock(out, "Uniforms", "", 0, USER_UNIFORM_BINDING, valueBlock.uniforms);
137 }
138
getTransportType(DataType valueType)139 DataType getTransportType(DataType valueType)
140 {
141 if (isDataTypeBoolOrBVec(valueType))
142 return glu::getDataTypeUintVec(getDataTypeScalarSize(valueType));
143 else
144 return valueType;
145 }
146
getNumTransportLocations(DataType valueType)147 int getNumTransportLocations(DataType valueType)
148 {
149 return isDataTypeMatrix(valueType) ? getDataTypeMatrixNumColumns(valueType) : 1;
150 }
151
152 // This functions builds a matching vertex shader for a 'both' case, when
153 // the fragment shader is being tested.
154 // We need to build attributes and varyings for each 'input'.
genVertexShader(const ShaderCaseSpecification & spec)155 string genVertexShader(const ShaderCaseSpecification &spec)
156 {
157 ostringstream res;
158 int curInputLoc = 0;
159 int curOutputLoc = 0;
160
161 res << glu::getGLSLVersionDeclaration(spec.targetVersion) << "\n";
162
163 // Declarations (position + attribute/varying for each input).
164 res << "precision highp float;\n";
165 res << "precision highp int;\n";
166 res << "\n";
167 res << "layout(location = 0) in highp vec4 dEQP_Position;\n";
168 curInputLoc += 1;
169
170 for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
171 {
172 const Value &val = spec.values.inputs[ndx];
173 const DataType valueType = val.type.getBasicType();
174 const DataType transportType = getTransportType(valueType);
175 const char *const transportTypeStr = getDataTypeName(transportType);
176 const int numLocs = getNumTransportLocations(valueType);
177
178 res << "layout(location = " << curInputLoc << ") in " << transportTypeStr << " a_" << val.name << ";\n";
179 res << "layout(location = " << curOutputLoc << ") flat out " << transportTypeStr << " "
180 << (transportType != valueType ? "v_" : "") << val.name << ";\n";
181
182 curInputLoc += numLocs;
183 curOutputLoc += numLocs;
184 }
185 res << "\n";
186
187 // Main function.
188 // - gl_Position = dEQP_Position;
189 // - for each input: write attribute directly to varying
190 res << "void main()\n";
191 res << "{\n";
192 res << " gl_Position = dEQP_Position;\n";
193 for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
194 {
195 const Value &val = spec.values.inputs[ndx];
196 const string &name = val.name;
197
198 res << " " << (getTransportType(val.type.getBasicType()) != val.type.getBasicType() ? "v_" : "") << name
199 << " = a_" << name << ";\n";
200 }
201
202 res << "}\n";
203 return res.str();
204 }
205
genCompareOp(ostringstream & output,const char * dstVec4Var,const ValueBlock & valueBlock,const char * checkVarName)206 void genCompareOp(ostringstream &output, const char *dstVec4Var, const ValueBlock &valueBlock, const char *checkVarName)
207 {
208 bool isFirstOutput = true;
209
210 for (size_t ndx = 0; ndx < valueBlock.outputs.size(); ndx++)
211 {
212 const Value &val = valueBlock.outputs[ndx];
213
214 // Check if we're only interested in one variable (then skip if not the right one).
215 if (checkVarName && val.name != checkVarName)
216 continue;
217
218 // Prefix.
219 if (isFirstOutput)
220 {
221 output << "bool RES = ";
222 isFirstOutput = false;
223 }
224 else
225 output << "RES = RES && ";
226
227 // Generate actual comparison.
228 if (getDataTypeScalarType(val.type.getBasicType()) == glu::TYPE_FLOAT)
229 output << "isOk(" << val.name << ", ref." << val.name << ", 0.05);\n";
230 else
231 output << "isOk(" << val.name << ", ref." << val.name << ");\n";
232 }
233
234 if (isFirstOutput)
235 output << dstVec4Var << " = vec4(1.0);\n";
236 else
237 output << dstVec4Var << " = vec4(RES, RES, RES, 1.0);\n";
238 }
239
genFragmentShader(const ShaderCaseSpecification & spec)240 string genFragmentShader(const ShaderCaseSpecification &spec)
241 {
242 ostringstream shader;
243 ostringstream setup;
244 int curInLoc = 0;
245
246 shader << glu::getGLSLVersionDeclaration(spec.targetVersion) << "\n";
247
248 shader << "precision highp float;\n";
249 shader << "precision highp int;\n";
250 shader << "\n";
251
252 shader << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
253 shader << "\n";
254
255 genCompareFunctions(shader, spec.values, false);
256 shader << "\n";
257
258 // Declarations (varying, reference for each output).
259 for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
260 {
261 const Value &val = spec.values.outputs[ndx];
262 const DataType valueType = val.type.getBasicType();
263 const char *const valueTypeStr = getDataTypeName(valueType);
264 const DataType transportType = getTransportType(valueType);
265 const char *const transportTypeStr = getDataTypeName(transportType);
266 const int numLocs = getNumTransportLocations(valueType);
267
268 shader << "layout(location = " << curInLoc << ") flat in " << transportTypeStr << " "
269 << (valueType != transportType ? "v_" : "") << val.name << ";\n";
270
271 if (valueType != transportType)
272 setup << " " << valueTypeStr << " " << val.name << " = " << valueTypeStr << "(v_" << val.name << ");\n";
273
274 curInLoc += numLocs;
275 }
276
277 declareReferenceBlock(shader, spec.values);
278
279 shader << "\n";
280 shader << "void main()\n";
281 shader << "{\n";
282
283 shader << setup.str();
284
285 shader << " ";
286 genCompareOp(shader, "dEQP_FragColor", spec.values, DE_NULL);
287
288 shader << "}\n";
289 return shader.str();
290 }
291
292 // Specialize a shader for the vertex shader test case.
specializeVertexShader(const ShaderCaseSpecification & spec,const string & src)293 string specializeVertexShader(const ShaderCaseSpecification &spec, const string &src)
294 {
295 ostringstream decl;
296 ostringstream setup;
297 ostringstream output;
298 int curInputLoc = 0;
299 int curOutputLoc = 0;
300
301 // generated from "both" case
302 DE_ASSERT(spec.caseType == glu::sl::CASETYPE_VERTEX_ONLY);
303
304 // Output (write out position).
305 output << "gl_Position = dEQP_Position;\n";
306
307 // Declarations (position + attribute for each input, varying for each output).
308 decl << "layout(location = 0) in highp vec4 dEQP_Position;\n";
309 curInputLoc += 1;
310
311 for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
312 {
313 const Value &val = spec.values.inputs[ndx];
314 const DataType valueType = val.type.getBasicType();
315 const char *const valueTypeStr = getDataTypeName(valueType);
316 const DataType transportType = getTransportType(valueType);
317 const char *const transportTypeStr = getDataTypeName(transportType);
318 const int numLocs = getNumTransportLocations(valueType);
319
320 decl << "layout(location = " << curInputLoc << ") in ";
321
322 curInputLoc += numLocs;
323
324 if (valueType == transportType)
325 decl << transportTypeStr << " " << val.name << ";\n";
326 else
327 {
328 decl << transportTypeStr << " a_" << val.name << ";\n";
329 setup << valueTypeStr << " " << val.name << " = " << valueTypeStr << "(a_" << val.name << ");\n";
330 }
331 }
332
333 declareUniforms(decl, spec.values);
334
335 for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
336 {
337 const Value &val = spec.values.outputs[ndx];
338 const DataType valueType = val.type.getBasicType();
339 const char *const valueTypeStr = getDataTypeName(valueType);
340 const DataType transportType = getTransportType(valueType);
341 const char *const transportTypeStr = getDataTypeName(transportType);
342 const int numLocs = getNumTransportLocations(valueType);
343
344 decl << "layout(location = " << curOutputLoc << ") flat out ";
345
346 curOutputLoc += numLocs;
347
348 if (valueType == transportType)
349 decl << transportTypeStr << " " << val.name << ";\n";
350 else
351 {
352 decl << transportTypeStr << " v_" << val.name << ";\n";
353 decl << valueTypeStr << " " << val.name << ";\n";
354
355 output << "v_" << val.name << " = " << transportTypeStr << "(" << val.name << ");\n";
356 }
357 }
358
359 // Shader specialization.
360 map<string, string> params;
361 params.insert(pair<string, string>("DECLARATIONS", decl.str()));
362 params.insert(pair<string, string>("SETUP", setup.str()));
363 params.insert(pair<string, string>("OUTPUT", output.str()));
364 params.insert(pair<string, string>("POSITION_FRAG_COLOR", "gl_Position"));
365
366 StringTemplate tmpl(src);
367 const string baseSrc = tmpl.specialize(params);
368 const string withExt =
369 injectExtensionRequirements(baseSrc, spec.programs[0].requiredExtensions, glu::SHADERTYPE_VERTEX);
370
371 return withExt;
372 }
373
374 // Specialize a shader for the fragment shader test case.
specializeFragmentShader(const ShaderCaseSpecification & spec,const string & src)375 string specializeFragmentShader(const ShaderCaseSpecification &spec, const string &src)
376 {
377 ostringstream decl;
378 ostringstream setup;
379 ostringstream output;
380 int curInputLoc = 0;
381
382 // generated from "both" case
383 DE_ASSERT(spec.caseType == glu::sl::CASETYPE_FRAGMENT_ONLY);
384
385 genCompareFunctions(decl, spec.values, false);
386 genCompareOp(output, "dEQP_FragColor", spec.values, DE_NULL);
387
388 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
389
390 for (size_t ndx = 0; ndx < spec.values.inputs.size(); ndx++)
391 {
392 const Value &val = spec.values.inputs[ndx];
393 const DataType valueType = val.type.getBasicType();
394 const char *const valueTypeStr = getDataTypeName(valueType);
395 const DataType transportType = getTransportType(valueType);
396 const char *const transportTypeStr = getDataTypeName(transportType);
397 const int numLocs = getNumTransportLocations(valueType);
398
399 decl << "layout(location = " << curInputLoc << ") flat in ";
400
401 curInputLoc += numLocs;
402
403 if (valueType == transportType)
404 decl << transportTypeStr << " " << val.name << ";\n";
405 else
406 {
407 decl << transportTypeStr << " v_" << val.name << ";\n";
408 setup << valueTypeStr << " " << val.name << " = " << valueTypeStr << "(v_" << val.name << ");\n";
409 }
410 }
411
412 declareUniforms(decl, spec.values);
413 declareReferenceBlock(decl, spec.values);
414
415 for (size_t ndx = 0; ndx < spec.values.outputs.size(); ndx++)
416 {
417 const Value &val = spec.values.outputs[ndx];
418 const DataType basicType = val.type.getBasicType();
419 const char *const refTypeStr = getDataTypeName(basicType);
420
421 decl << refTypeStr << " " << val.name << ";\n";
422 }
423
424 // Shader specialization.
425 map<string, string> params;
426 params.insert(pair<string, string>("DECLARATIONS", decl.str()));
427 params.insert(pair<string, string>("SETUP", setup.str()));
428 params.insert(pair<string, string>("OUTPUT", output.str()));
429 params.insert(pair<string, string>("POSITION_FRAG_COLOR", "dEQP_FragColor"));
430
431 StringTemplate tmpl(src);
432 const string baseSrc = tmpl.specialize(params);
433 const string withExt =
434 injectExtensionRequirements(baseSrc, spec.programs[0].requiredExtensions, glu::SHADERTYPE_FRAGMENT);
435
436 return withExt;
437 }
438
generateVertexSpecialization(const ProgramSpecializationParams & specParams)439 map<string, string> generateVertexSpecialization(const ProgramSpecializationParams &specParams)
440 {
441 ostringstream decl;
442 ostringstream setup;
443 map<string, string> params;
444 int curInputLoc = 0;
445
446 decl << "layout(location = 0) in highp vec4 dEQP_Position;\n";
447 curInputLoc += 1;
448
449 for (size_t ndx = 0; ndx < specParams.caseSpec.values.inputs.size(); ndx++)
450 {
451 const Value &val = specParams.caseSpec.values.inputs[ndx];
452 const DataType valueType = val.type.getBasicType();
453 const char *const valueTypeStr = getDataTypeName(valueType);
454 const DataType transportType = getTransportType(valueType);
455 const char *const transportTypeStr = getDataTypeName(transportType);
456 const int numLocs = getNumTransportLocations(valueType);
457
458 decl << "layout(location = " << curInputLoc << ") in ";
459
460 curInputLoc += numLocs;
461
462 if (valueType == transportType)
463 decl << transportTypeStr << " " << val.name << ";\n";
464 else
465 {
466 decl << transportTypeStr << " a_" << val.name << ";\n";
467 setup << valueTypeStr << " " << val.name << " = " << valueTypeStr << "(a_" << val.name << ");\n";
468 }
469 }
470
471 declareUniforms(decl, specParams.caseSpec.values);
472
473 params.insert(pair<string, string>("VERTEX_DECLARATIONS", decl.str()));
474 params.insert(pair<string, string>("VERTEX_SETUP", setup.str()));
475 params.insert(pair<string, string>("VERTEX_OUTPUT", string("gl_Position = dEQP_Position;\n")));
476
477 return params;
478 }
479
generateFragmentSpecialization(const ProgramSpecializationParams & specParams)480 map<string, string> generateFragmentSpecialization(const ProgramSpecializationParams &specParams)
481 {
482 ostringstream decl;
483 ostringstream output;
484 map<string, string> params;
485
486 genCompareFunctions(decl, specParams.caseSpec.values, false);
487 genCompareOp(output, "dEQP_FragColor", specParams.caseSpec.values, DE_NULL);
488
489 decl << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
490
491 for (size_t ndx = 0; ndx < specParams.caseSpec.values.outputs.size(); ndx++)
492 {
493 const Value &val = specParams.caseSpec.values.outputs[ndx];
494 const char *const refTypeStr = getDataTypeName(val.type.getBasicType());
495
496 decl << refTypeStr << " " << val.name << ";\n";
497 }
498
499 declareReferenceBlock(decl, specParams.caseSpec.values);
500 declareUniforms(decl, specParams.caseSpec.values);
501
502 params.insert(pair<string, string>("FRAGMENT_DECLARATIONS", decl.str()));
503 params.insert(pair<string, string>("FRAGMENT_OUTPUT", output.str()));
504 params.insert(pair<string, string>("FRAG_COLOR", "dEQP_FragColor"));
505
506 return params;
507 }
508
generateGeometrySpecialization(const ProgramSpecializationParams & specParams)509 map<string, string> generateGeometrySpecialization(const ProgramSpecializationParams &specParams)
510 {
511 ostringstream decl;
512 map<string, string> params;
513
514 decl << "layout (triangles) in;\n";
515 decl << "layout (triangle_strip, max_vertices=3) out;\n";
516 decl << "\n";
517
518 declareUniforms(decl, specParams.caseSpec.values);
519
520 params.insert(pair<string, string>("GEOMETRY_DECLARATIONS", decl.str()));
521
522 return params;
523 }
524
generateTessControlSpecialization(const ProgramSpecializationParams & specParams)525 map<string, string> generateTessControlSpecialization(const ProgramSpecializationParams &specParams)
526 {
527 ostringstream decl;
528 ostringstream output;
529 map<string, string> params;
530
531 decl << "layout (vertices=3) out;\n";
532 decl << "\n";
533
534 declareUniforms(decl, specParams.caseSpec.values);
535
536 output << "gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
537 "gl_TessLevelInner[0] = 2.0;\n"
538 "gl_TessLevelInner[1] = 2.0;\n"
539 "gl_TessLevelOuter[0] = 2.0;\n"
540 "gl_TessLevelOuter[1] = 2.0;\n"
541 "gl_TessLevelOuter[2] = 2.0;\n"
542 "gl_TessLevelOuter[3] = 2.0;";
543
544 params.insert(pair<string, string>("TESSELLATION_CONTROL_DECLARATIONS", decl.str()));
545 params.insert(pair<string, string>("TESSELLATION_CONTROL_OUTPUT", output.str()));
546 params.insert(pair<string, string>("GL_MAX_PATCH_VERTICES", de::toString(specParams.maxPatchVertices)));
547
548 return params;
549 }
550
generateTessEvalSpecialization(const ProgramSpecializationParams & specParams)551 map<string, string> generateTessEvalSpecialization(const ProgramSpecializationParams &specParams)
552 {
553 ostringstream decl;
554 ostringstream output;
555 map<string, string> params;
556
557 decl << "layout (triangles) in;\n";
558 decl << "\n";
559
560 declareUniforms(decl, specParams.caseSpec.values);
561
562 output << "gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position + gl_TessCoord[1] * gl_in[1].gl_Position + "
563 "gl_TessCoord[2] * gl_in[2].gl_Position;\n";
564
565 params.insert(pair<string, string>("TESSELLATION_EVALUATION_DECLARATIONS", decl.str()));
566 params.insert(pair<string, string>("TESSELLATION_EVALUATION_OUTPUT", output.str()));
567 params.insert(pair<string, string>("GL_MAX_PATCH_VERTICES", de::toString(specParams.maxPatchVertices)));
568
569 return params;
570 }
571
specializeShaderSources(ProgramSources & dst,const ProgramSources & src,const ProgramSpecializationParams & specParams,glu::ShaderType shaderType,map<string,string> (* specializationGenerator)(const ProgramSpecializationParams & specParams))572 void specializeShaderSources(
573 ProgramSources &dst, const ProgramSources &src, const ProgramSpecializationParams &specParams,
574 glu::ShaderType shaderType,
575 map<string, string> (*specializationGenerator)(const ProgramSpecializationParams &specParams))
576 {
577 if (!src.sources[shaderType].empty())
578 {
579 const map<string, string> tmplParams = specializationGenerator(specParams);
580
581 for (size_t ndx = 0; ndx < src.sources[shaderType].size(); ++ndx)
582 {
583 const StringTemplate tmpl(src.sources[shaderType][ndx]);
584 const string baseGLSLCode = tmpl.specialize(tmplParams);
585 const string sourceWithExts =
586 injectExtensionRequirements(baseGLSLCode, specParams.requiredExtensions, shaderType);
587
588 dst << glu::ShaderSource(shaderType, sourceWithExts);
589 }
590 }
591 }
592
specializeProgramSources(glu::ProgramSources & dst,const glu::ProgramSources & src,const ProgramSpecializationParams & specParams)593 void specializeProgramSources(glu::ProgramSources &dst, const glu::ProgramSources &src,
594 const ProgramSpecializationParams &specParams)
595 {
596 specializeShaderSources(dst, src, specParams, glu::SHADERTYPE_VERTEX, generateVertexSpecialization);
597 specializeShaderSources(dst, src, specParams, glu::SHADERTYPE_FRAGMENT, generateFragmentSpecialization);
598 specializeShaderSources(dst, src, specParams, glu::SHADERTYPE_GEOMETRY, generateGeometrySpecialization);
599 specializeShaderSources(dst, src, specParams, glu::SHADERTYPE_TESSELLATION_CONTROL,
600 generateTessControlSpecialization);
601 specializeShaderSources(dst, src, specParams, glu::SHADERTYPE_TESSELLATION_EVALUATION,
602 generateTessEvalSpecialization);
603
604 dst << glu::ProgramSeparable(src.separable);
605 }
606
607 struct ValueBufferLayout
608 {
609 struct Entry
610 {
611 int offset;
612 int vecStride; //! Applies to matrices only
613
Entryvkt::__anonb012f1360111::ValueBufferLayout::Entry614 Entry(void) : offset(0), vecStride(0)
615 {
616 }
Entryvkt::__anonb012f1360111::ValueBufferLayout::Entry617 Entry(int offset_, int vecStride_) : offset(offset_), vecStride(vecStride_)
618 {
619 }
620 };
621
622 vector<Entry> entries;
623 int size;
624
ValueBufferLayoutvkt::__anonb012f1360111::ValueBufferLayout625 ValueBufferLayout(void) : size(0)
626 {
627 }
628 };
629
computeStd140Layout(const vector<Value> & values)630 ValueBufferLayout computeStd140Layout(const vector<Value> &values)
631 {
632 ValueBufferLayout layout;
633
634 layout.entries.resize(values.size());
635
636 for (size_t ndx = 0; ndx < values.size(); ++ndx)
637 {
638 const DataType basicType = values[ndx].type.getBasicType();
639 const bool isMatrix = isDataTypeMatrix(basicType);
640 const int numVecs = isMatrix ? getDataTypeMatrixNumColumns(basicType) : 1;
641 const DataType vecType = isMatrix ? glu::getDataTypeFloatVec(getDataTypeMatrixNumRows(basicType)) : basicType;
642 const int vecSize = getDataTypeScalarSize(vecType);
643 const int alignment = ((isMatrix || vecSize == 3) ? 4 : vecSize) * int(sizeof(uint32_t));
644
645 layout.size = deAlign32(layout.size, alignment);
646 layout.entries[ndx] = ValueBufferLayout::Entry(layout.size, alignment);
647 layout.size += alignment * (numVecs - 1) + vecSize * int(sizeof(uint32_t));
648 }
649
650 return layout;
651 }
652
computeStd430Layout(const vector<Value> & values)653 ValueBufferLayout computeStd430Layout(const vector<Value> &values)
654 {
655 ValueBufferLayout layout;
656
657 layout.entries.resize(values.size());
658
659 for (size_t ndx = 0; ndx < values.size(); ++ndx)
660 {
661 const DataType basicType = values[ndx].type.getBasicType();
662 const int numVecs = isDataTypeMatrix(basicType) ? getDataTypeMatrixNumColumns(basicType) : 1;
663 const DataType vecType =
664 isDataTypeMatrix(basicType) ? glu::getDataTypeFloatVec(getDataTypeMatrixNumRows(basicType)) : basicType;
665 const int vecSize = getDataTypeScalarSize(vecType);
666 const int alignment = (vecSize == 3 ? 4 : vecSize) * int(sizeof(uint32_t));
667
668 layout.size = deAlign32(layout.size, alignment);
669 layout.entries[ndx] = ValueBufferLayout::Entry(layout.size, alignment);
670 layout.size += alignment * (numVecs - 1) + vecSize * int(sizeof(uint32_t));
671 }
672
673 return layout;
674 }
675
copyToLayout(void * dst,const ValueBufferLayout::Entry & entryLayout,const Value & value,int arrayNdx)676 void copyToLayout(void *dst, const ValueBufferLayout::Entry &entryLayout, const Value &value, int arrayNdx)
677 {
678 const DataType basicType = value.type.getBasicType();
679 const int scalarSize = getDataTypeScalarSize(basicType);
680 const int numVecs = isDataTypeMatrix(basicType) ? getDataTypeMatrixNumColumns(basicType) : 1;
681 const int numComps = isDataTypeMatrix(basicType) ? getDataTypeMatrixNumRows(basicType) : scalarSize;
682
683 DE_ASSERT(size_t((arrayNdx + 1) * scalarSize) <= value.elements.size());
684
685 if (isDataTypeBoolOrBVec(basicType))
686 {
687 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
688 {
689 for (int compNdx = 0; compNdx < numComps; compNdx++)
690 {
691 const uint32_t data =
692 value.elements[arrayNdx * scalarSize + vecNdx * numComps + compNdx].bool32 ? ~0u : 0u;
693
694 deMemcpy((uint8_t *)dst + entryLayout.offset + vecNdx * entryLayout.vecStride +
695 compNdx * sizeof(uint32_t),
696 &data, sizeof(uint32_t));
697 }
698 }
699 }
700 else
701 {
702 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
703 deMemcpy((uint8_t *)dst + entryLayout.offset + vecNdx * entryLayout.vecStride,
704 &value.elements[arrayNdx * scalarSize + vecNdx * numComps], numComps * sizeof(uint32_t));
705 }
706 }
707
copyToLayout(void * dst,const ValueBufferLayout & layout,const vector<Value> & values,int arrayNdx)708 void copyToLayout(void *dst, const ValueBufferLayout &layout, const vector<Value> &values, int arrayNdx)
709 {
710 DE_ASSERT(layout.entries.size() == values.size());
711
712 for (size_t ndx = 0; ndx < values.size(); ndx++)
713 copyToLayout(dst, layout.entries[ndx], values[ndx], arrayNdx);
714 }
715
getShaderStages(const ShaderCaseSpecification & spec)716 uint32_t getShaderStages(const ShaderCaseSpecification &spec)
717 {
718 if (spec.caseType == glu::sl::CASETYPE_COMPLETE)
719 {
720 uint32_t stages = 0u;
721
722 for (size_t progNdx = 0; progNdx < spec.programs.size(); progNdx++)
723 {
724 for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
725 {
726 if (!spec.programs[progNdx].sources.sources[shaderType].empty())
727 stages |= (1u << shaderType);
728 }
729 }
730
731 return stages;
732 }
733 else
734 return (1u << glu::SHADERTYPE_VERTEX) | (1u << glu::SHADERTYPE_FRAGMENT);
735 }
736
737 class PipelineProgram
738 {
739 public:
740 PipelineProgram(Context &context, const ShaderCaseSpecification &spec);
741
getStages(void) const742 uint32_t getStages(void) const
743 {
744 return m_stages;
745 }
746
hasShader(glu::ShaderType type) const747 bool hasShader(glu::ShaderType type) const
748 {
749 return (m_stages & (1u << type)) != 0;
750 }
getShader(glu::ShaderType type) const751 vk::VkShaderModule getShader(glu::ShaderType type) const
752 {
753 return *m_shaderModules[type];
754 }
755
756 private:
757 const uint32_t m_stages;
758 Move<vk::VkShaderModule> m_shaderModules[glu::SHADERTYPE_LAST];
759 };
760
PipelineProgram(Context & context,const ShaderCaseSpecification & spec)761 PipelineProgram::PipelineProgram(Context &context, const ShaderCaseSpecification &spec)
762 : m_stages(getShaderStages(spec))
763 {
764 // \note Currently only a single source program is supported as framework lacks SPIR-V linking capability
765 TCU_CHECK_INTERNAL(spec.programs.size() == 1);
766
767 for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
768 {
769 if ((m_stages & (1u << shaderType)) != 0)
770 {
771 m_shaderModules[shaderType] = vk::createShaderModule(
772 context.getDeviceInterface(), context.getDevice(),
773 context.getBinaryCollection().get(getShaderName((glu::ShaderType)shaderType, 0)), 0u);
774 }
775 }
776 }
777
createBuffer(Context & context,vk::VkDeviceSize size,vk::VkBufferUsageFlags usageFlags)778 Move<vk::VkBuffer> createBuffer(Context &context, vk::VkDeviceSize size, vk::VkBufferUsageFlags usageFlags)
779 {
780 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
781 const vk::VkBufferCreateInfo params = {
782 vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType
783 DE_NULL, // pNext
784 0u, // flags
785 size, // size
786 usageFlags, // usage
787 vk::VK_SHARING_MODE_EXCLUSIVE, // sharingMode
788 1u, // queueFamilyCount
789 &queueFamilyIndex, // pQueueFamilyIndices
790 };
791
792 return vk::createBuffer(context.getDeviceInterface(), context.getDevice(), ¶ms);
793 }
794
createImage2D(Context & context,uint32_t width,uint32_t height,vk::VkFormat format,vk::VkImageTiling tiling,vk::VkImageUsageFlags usageFlags)795 Move<vk::VkImage> createImage2D(Context &context, uint32_t width, uint32_t height, vk::VkFormat format,
796 vk::VkImageTiling tiling, vk::VkImageUsageFlags usageFlags)
797 {
798 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
799 const vk::VkImageCreateInfo params = {
800 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType
801 DE_NULL, // pNext
802 0u, // flags
803 vk::VK_IMAGE_TYPE_2D, // imageType
804 format, // format
805 {width, height, 1u}, // extent
806 1u, // mipLevels
807 1u, // arraySize
808 vk::VK_SAMPLE_COUNT_1_BIT, // samples
809 tiling, // tiling
810 usageFlags, // usage
811 vk::VK_SHARING_MODE_EXCLUSIVE, // sharingMode
812 1u, // queueFamilyCount
813 &queueFamilyIndex, // pQueueFamilyIndices
814 vk::VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout
815 };
816
817 return vk::createImage(context.getDeviceInterface(), context.getDevice(), ¶ms);
818 }
819
createAttachmentView(Context & context,vk::VkImage image,vk::VkFormat format)820 Move<vk::VkImageView> createAttachmentView(Context &context, vk::VkImage image, vk::VkFormat format)
821 {
822 const vk::VkImageViewCreateInfo params = {
823 vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType
824 DE_NULL, // pNext
825 0u, // flags
826 image, // image
827 vk::VK_IMAGE_VIEW_TYPE_2D, // viewType
828 format, // format
829 vk::makeComponentMappingRGBA(), // channels
830 {
831 vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
832 0u, // baseMipLevel
833 1u, // mipLevels
834 0u, // baseArrayLayer
835 1u, // arraySize
836 }, // subresourceRange
837 };
838
839 return vk::createImageView(context.getDeviceInterface(), context.getDevice(), ¶ms);
840 }
841
createRenderPass(Context & context,vk::VkFormat colorAttFormat,uint32_t size)842 Move<vk::VkRenderPass> createRenderPass(Context &context, vk::VkFormat colorAttFormat, uint32_t size)
843 {
844 vk::VkAttachmentDescription colorAttDesc[4];
845 vk::VkAttachmentReference colorAttRef[4];
846
847 for (uint32_t i = 0; i < size; i++)
848 {
849 vk::VkAttachmentDescription desc = {
850 0u, // flags
851 colorAttFormat, // format
852 vk::VK_SAMPLE_COUNT_1_BIT, // samples
853 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // loadOp
854 vk::VK_ATTACHMENT_STORE_OP_STORE, // storeOp
855 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp
856 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp
857 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // initialLayout
858 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // finalLayout
859 };
860 colorAttDesc[i] = desc;
861
862 vk::VkAttachmentReference ref = {
863 i, // attachment
864 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // layout
865 };
866 colorAttRef[i] = ref;
867 }
868
869 const vk::VkAttachmentReference dsAttRef = {
870 VK_ATTACHMENT_UNUSED, // attachment
871 vk::VK_IMAGE_LAYOUT_GENERAL, // layout
872 };
873 const vk::VkSubpassDescription subpassDesc = {
874 (vk::VkSubpassDescriptionFlags)0,
875 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
876 0u, // inputCount
877 DE_NULL, // pInputAttachments
878 size, // colorCount
879 &colorAttRef[0], // pColorAttachments
880 DE_NULL, // pResolveAttachments
881 &dsAttRef, // depthStencilAttachment
882 0u, // preserveCount
883 DE_NULL, // pPreserveAttachments
884
885 };
886 const vk::VkRenderPassCreateInfo renderPassParams = {
887 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // sType
888 DE_NULL, // pNext
889 (vk::VkRenderPassCreateFlags)0,
890 size, // attachmentCount
891 &colorAttDesc[0], // pAttachments
892 1u, // subpassCount
893 &subpassDesc, // pSubpasses
894 0u, // dependencyCount
895 DE_NULL, // pDependencies
896 };
897
898 return vk::createRenderPass(context.getDeviceInterface(), context.getDevice(), &renderPassParams);
899 }
900
getVkStageFlags(uint32_t stages)901 vk::VkShaderStageFlags getVkStageFlags(uint32_t stages)
902 {
903 vk::VkShaderStageFlags vkStages = 0u;
904
905 for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
906 {
907 if ((stages & (1u << shaderType)) != 0)
908 vkStages |= vk::getVkShaderStage((glu::ShaderType)shaderType);
909 }
910
911 return vkStages;
912 }
913
createDescriptorSetLayout(Context & context,uint32_t shaderStages)914 Move<vk::VkDescriptorSetLayout> createDescriptorSetLayout(Context &context, uint32_t shaderStages)
915 {
916 DE_STATIC_ASSERT(REFERENCE_UNIFORM_BINDING == 0);
917 DE_STATIC_ASSERT(USER_UNIFORM_BINDING == 1);
918
919 return vk::DescriptorSetLayoutBuilder()
920 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_FRAGMENT_BIT)
921 .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, getVkStageFlags(shaderStages))
922 .build(context.getDeviceInterface(), context.getDevice());
923 }
924
createPipelineLayout(Context & context,vk::VkDescriptorSetLayout descriptorSetLayout)925 Move<vk::VkPipelineLayout> createPipelineLayout(Context &context, vk::VkDescriptorSetLayout descriptorSetLayout)
926 {
927 const vk::VkPipelineLayoutCreateInfo params = {
928 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
929 DE_NULL, // pNext
930 (vk::VkPipelineLayoutCreateFlags)0,
931 1u, // descriptorSetCount
932 &descriptorSetLayout, // pSetLayouts
933 0u, // pushConstantRangeCount
934 DE_NULL, // pPushConstantRanges
935 };
936
937 return vk::createPipelineLayout(context.getDeviceInterface(), context.getDevice(), ¶ms);
938 }
939
getVecFormat(DataType scalarType,int scalarSize)940 vk::VkFormat getVecFormat(DataType scalarType, int scalarSize)
941 {
942 switch (scalarType)
943 {
944 case glu::TYPE_FLOAT:
945 {
946 const vk::VkFormat vecFmts[] = {
947 vk::VK_FORMAT_R32_SFLOAT,
948 vk::VK_FORMAT_R32G32_SFLOAT,
949 vk::VK_FORMAT_R32G32B32_SFLOAT,
950 vk::VK_FORMAT_R32G32B32A32_SFLOAT,
951 };
952 return de::getSizedArrayElement<4>(vecFmts, scalarSize - 1);
953 }
954
955 case glu::TYPE_INT:
956 {
957 const vk::VkFormat vecFmts[] = {
958 vk::VK_FORMAT_R32_SINT,
959 vk::VK_FORMAT_R32G32_SINT,
960 vk::VK_FORMAT_R32G32B32_SINT,
961 vk::VK_FORMAT_R32G32B32A32_SINT,
962 };
963 return de::getSizedArrayElement<4>(vecFmts, scalarSize - 1);
964 }
965
966 case glu::TYPE_UINT:
967 {
968 const vk::VkFormat vecFmts[] = {
969 vk::VK_FORMAT_R32_UINT,
970 vk::VK_FORMAT_R32G32_UINT,
971 vk::VK_FORMAT_R32G32B32_UINT,
972 vk::VK_FORMAT_R32G32B32A32_UINT,
973 };
974 return de::getSizedArrayElement<4>(vecFmts, scalarSize - 1);
975 }
976
977 case glu::TYPE_BOOL:
978 {
979 const vk::VkFormat vecFmts[] = {
980 vk::VK_FORMAT_R32_UINT,
981 vk::VK_FORMAT_R32G32_UINT,
982 vk::VK_FORMAT_R32G32B32_UINT,
983 vk::VK_FORMAT_R32G32B32A32_UINT,
984 };
985 return de::getSizedArrayElement<4>(vecFmts, scalarSize - 1);
986 }
987
988 default:
989 DE_FATAL("Unknown scalar type");
990 return vk::VK_FORMAT_R8G8B8A8_UINT;
991 }
992 }
993
getVertexAttributeDescriptions(const vector<Value> & inputValues,const ValueBufferLayout & layout)994 vector<vk::VkVertexInputAttributeDescription> getVertexAttributeDescriptions(const vector<Value> &inputValues,
995 const ValueBufferLayout &layout)
996 {
997 vector<vk::VkVertexInputAttributeDescription> attribs;
998
999 // Position
1000 {
1001 const vk::VkVertexInputAttributeDescription posDesc = {
1002 0u, // location
1003 0u, // binding
1004 vk::VK_FORMAT_R32G32_SFLOAT, // format
1005 0u, // offset
1006 };
1007
1008 attribs.push_back(posDesc);
1009 }
1010
1011 // Input values
1012 for (size_t inputNdx = 0; inputNdx < inputValues.size(); inputNdx++)
1013 {
1014 const Value &input = inputValues[inputNdx];
1015 const ValueBufferLayout::Entry &layoutEntry = layout.entries[inputNdx];
1016 const DataType basicType = input.type.getBasicType();
1017 const int numVecs = isDataTypeMatrix(basicType) ? getDataTypeMatrixNumColumns(basicType) : 1;
1018 const int vecSize =
1019 isDataTypeMatrix(basicType) ? getDataTypeMatrixNumRows(basicType) : getDataTypeScalarSize(basicType);
1020 const DataType scalarType = getDataTypeScalarType(basicType);
1021 const vk::VkFormat vecFmt = getVecFormat(scalarType, vecSize);
1022
1023 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
1024 {
1025 const uint32_t curLoc = (uint32_t)attribs.size();
1026 const uint32_t offset = (uint32_t)(layoutEntry.offset + layoutEntry.vecStride * vecNdx);
1027 const vk::VkVertexInputAttributeDescription desc = {
1028 curLoc, // location
1029 1u, // binding
1030 vecFmt, // format
1031 offset, // offset
1032 };
1033
1034 attribs.push_back(desc);
1035 }
1036 }
1037
1038 return attribs;
1039 }
1040
createPipeline(Context & context,const vector<Value> & inputValues,const ValueBufferLayout & inputLayout,const PipelineProgram & program,vk::VkRenderPass renderPass,vk::VkPipelineLayout pipelineLayout,tcu::UVec2 renderSize,uint32_t size)1041 Move<vk::VkPipeline> createPipeline(Context &context, const vector<Value> &inputValues,
1042 const ValueBufferLayout &inputLayout, const PipelineProgram &program,
1043 vk::VkRenderPass renderPass, vk::VkPipelineLayout pipelineLayout,
1044 tcu::UVec2 renderSize, uint32_t size)
1045 {
1046 const vk::VkShaderModule vertShader =
1047 program.hasShader(glu::SHADERTYPE_VERTEX) ? program.getShader(glu::SHADERTYPE_VERTEX) : DE_NULL;
1048 const vk::VkShaderModule tessControlShader = program.hasShader(glu::SHADERTYPE_TESSELLATION_CONTROL) ?
1049 program.getShader(glu::SHADERTYPE_TESSELLATION_CONTROL) :
1050 DE_NULL;
1051 const vk::VkShaderModule tessEvalShader = program.hasShader(glu::SHADERTYPE_TESSELLATION_EVALUATION) ?
1052 program.getShader(glu::SHADERTYPE_TESSELLATION_EVALUATION) :
1053 DE_NULL;
1054 const vk::VkShaderModule geomShader =
1055 program.hasShader(glu::SHADERTYPE_GEOMETRY) ? program.getShader(glu::SHADERTYPE_GEOMETRY) : DE_NULL;
1056 const vk::VkShaderModule fragShader =
1057 program.hasShader(glu::SHADERTYPE_FRAGMENT) ? program.getShader(glu::SHADERTYPE_FRAGMENT) : DE_NULL;
1058 const vector<vk::VkVertexInputAttributeDescription> vertexAttribParams(
1059 getVertexAttributeDescriptions(inputValues, inputLayout));
1060 const vector<vk::VkViewport> viewports(1, vk::makeViewport(renderSize));
1061 const vector<vk::VkRect2D> scissors(1, vk::makeRect2D(renderSize));
1062 const vk::VkVertexInputBindingDescription vertexBindings[] = {
1063 {
1064 0u, // binding
1065 (uint32_t)sizeof(tcu::Vec2), // stride
1066 vk::VK_VERTEX_INPUT_RATE_VERTEX, // stepRate
1067 },
1068 {
1069 1u, // binding
1070 0u, // stride
1071 vk::VK_VERTEX_INPUT_RATE_INSTANCE, // stepRate
1072 },
1073 };
1074 const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateParams = {
1075 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // sType
1076 DE_NULL, // pNext
1077 (vk::VkPipelineVertexInputStateCreateFlags)0,
1078 (inputValues.empty() ? 1u : 2u), // bindingCount
1079 vertexBindings, // pVertexBindingDescriptions
1080 (uint32_t)vertexAttribParams.size(), // attributeCount
1081 &vertexAttribParams[0], // pVertexAttributeDescriptions
1082 };
1083 const vk::VkColorComponentFlags allCompMask = vk::VK_COLOR_COMPONENT_R_BIT | vk::VK_COLOR_COMPONENT_G_BIT |
1084 vk::VK_COLOR_COMPONENT_B_BIT | vk::VK_COLOR_COMPONENT_A_BIT;
1085 vk::VkPipelineColorBlendAttachmentState attBlendParams[4];
1086 for (uint32_t i = 0; i < size; i++)
1087 {
1088 vk::VkPipelineColorBlendAttachmentState blend = {
1089 VK_FALSE, // blendEnable
1090 vk::VK_BLEND_FACTOR_ONE, // srcBlendColor
1091 vk::VK_BLEND_FACTOR_ZERO, // destBlendColor
1092 vk::VK_BLEND_OP_ADD, // blendOpColor
1093 vk::VK_BLEND_FACTOR_ONE, // srcBlendAlpha
1094 vk::VK_BLEND_FACTOR_ZERO, // destBlendAlpha
1095 vk::VK_BLEND_OP_ADD, // blendOpAlpha
1096 allCompMask, // componentWriteMask
1097 };
1098 attBlendParams[i] = blend;
1099 }
1100
1101 const vk::VkPipelineColorBlendStateCreateInfo blendParams = {
1102 vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // sType
1103 DE_NULL, // pNext
1104 (vk::VkPipelineColorBlendStateCreateFlags)0,
1105 VK_FALSE, // logicOpEnable
1106 vk::VK_LOGIC_OP_COPY, // logicOp
1107 size, // attachmentCount
1108 &attBlendParams[0], // pAttachments
1109 {0.0f, 0.0f, 0.0f, 0.0f}, // blendConstants
1110 };
1111
1112 return vk::makeGraphicsPipeline(
1113 context.getDeviceInterface(), // const DeviceInterface& vk
1114 context.getDevice(), // const VkDevice device
1115 pipelineLayout, // const VkPipelineLayout pipelineLayout
1116 vertShader, // const VkShaderModule vertexShaderModule
1117 tessControlShader, // const VkShaderModule tessellationControlShaderModule
1118 tessEvalShader, // const VkShaderModule tessellationEvalShaderModule
1119 geomShader, // const VkShaderModule geometryShaderModule
1120 fragShader, // const VkShaderModule fragmentShaderModule
1121 renderPass, // const VkRenderPass renderPass
1122 viewports, // const std::vector<VkViewport>& viewports
1123 scissors, // const std::vector<VkRect2D>& scissors
1124 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology
1125 0u, // const uint32_t subpass
1126 0u, // const uint32_t patchControlPoints
1127 &vertexInputStateParams, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo
1128 DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
1129 DE_NULL, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo
1130 DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo
1131 &blendParams); // const VkPipelineColorBlendStateCreateInfo* colorBlendStateCreateInfo
1132 }
1133
createFramebuffer(Context & context,vk::VkRenderPass renderPass,Move<vk::VkImageView> colorAttView[4],uint32_t size,int width,int height)1134 Move<vk::VkFramebuffer> createFramebuffer(Context &context, vk::VkRenderPass renderPass,
1135 Move<vk::VkImageView> colorAttView[4], uint32_t size, int width, int height)
1136 {
1137 vk::VkImageView att[4];
1138 for (uint32_t i = 0; i < size; i++)
1139 {
1140 att[i] = *colorAttView[i];
1141 }
1142 const vk::VkFramebufferCreateInfo framebufferParams = {
1143 vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // sType
1144 DE_NULL, // pNext
1145 (vk::VkFramebufferCreateFlags)0,
1146 renderPass, // renderPass
1147 size, // attachmentCount
1148 &att[0], // pAttachments
1149 (uint32_t)width, // width
1150 (uint32_t)height, // height
1151 1u, // layers
1152 };
1153
1154 return vk::createFramebuffer(context.getDeviceInterface(), context.getDevice(), &framebufferParams);
1155 }
1156
createCommandPool(Context & context)1157 Move<vk::VkCommandPool> createCommandPool(Context &context)
1158 {
1159 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1160
1161 return vk::createCommandPool(context.getDeviceInterface(), context.getDevice(), (vk::VkCommandPoolCreateFlags)0u,
1162 queueFamilyIndex);
1163 }
1164
createDescriptorPool(Context & context)1165 Move<vk::VkDescriptorPool> createDescriptorPool(Context &context)
1166 {
1167 return vk::DescriptorPoolBuilder()
1168 .addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2u)
1169 .build(context.getDeviceInterface(), context.getDevice(), vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
1170 1u);
1171 }
1172
allocateDescriptorSet(Context & context,vk::VkDescriptorPool descriptorPool,vk::VkDescriptorSetLayout setLayout)1173 Move<vk::VkDescriptorSet> allocateDescriptorSet(Context &context, vk::VkDescriptorPool descriptorPool,
1174 vk::VkDescriptorSetLayout setLayout)
1175 {
1176 const vk::VkDescriptorSetAllocateInfo params = {vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, DE_NULL,
1177 descriptorPool, 1u, &setLayout};
1178
1179 return vk::allocateDescriptorSet(context.getDeviceInterface(), context.getDevice(), ¶ms);
1180 }
1181
allocateCommandBuffer(Context & context,vk::VkCommandPool cmdPool)1182 Move<vk::VkCommandBuffer> allocateCommandBuffer(Context &context, vk::VkCommandPool cmdPool)
1183 {
1184 return vk::allocateCommandBuffer(context.getDeviceInterface(), context.getDevice(), cmdPool,
1185 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1186 }
1187
getRenderTargetFormat(DataType dataType)1188 vk::VkFormat getRenderTargetFormat(DataType dataType)
1189 {
1190 switch (dataType)
1191 {
1192 case glu::TYPE_FLOAT_VEC2:
1193 return vk::VK_FORMAT_R8G8_UNORM;
1194 case glu::TYPE_FLOAT_VEC3:
1195 return vk::VK_FORMAT_R5G6B5_UNORM_PACK16;
1196 case glu::TYPE_FLOAT_VEC4:
1197 return vk::VK_FORMAT_R8G8B8A8_UNORM;
1198 case glu::TYPE_INT_VEC2:
1199 return vk::VK_FORMAT_R8G8_SINT;
1200 case glu::TYPE_INT_VEC4:
1201 return vk::VK_FORMAT_R8G8B8A8_SINT;
1202 default:
1203 return vk::VK_FORMAT_R8G8B8A8_UNORM;
1204 }
1205 }
1206
allocateAndBindMemory(Context & context,vk::VkImage image,vk::MemoryRequirement memReqs)1207 MovePtr<vk::Allocation> allocateAndBindMemory(Context &context, vk::VkImage image, vk::MemoryRequirement memReqs)
1208 {
1209 const vk::DeviceInterface &vkd = context.getDeviceInterface();
1210 const vk::VkMemoryRequirements imgReqs = vk::getImageMemoryRequirements(vkd, context.getDevice(), image);
1211 MovePtr<vk::Allocation> memory = context.getDefaultAllocator().allocate(imgReqs, memReqs);
1212
1213 vkd.bindImageMemory(context.getDevice(), image, memory->getMemory(), memory->getOffset());
1214
1215 return memory;
1216 }
1217
writeValuesToMem(Context & context,const vk::Allocation & dst,const ValueBufferLayout & layout,const vector<Value> & values,int arrayNdx)1218 void writeValuesToMem(Context &context, const vk::Allocation &dst, const ValueBufferLayout &layout,
1219 const vector<Value> &values, int arrayNdx)
1220 {
1221 copyToLayout(dst.getHostPtr(), layout, values, arrayNdx);
1222
1223 // \note Buffers are not allocated with coherency / uncached requirement so we need to manually flush CPU write caches
1224 flushAlloc(context.getDeviceInterface(), context.getDevice(), dst);
1225 }
1226
1227 class ShaderCaseInstance : public TestInstance
1228 {
1229 public:
1230 ShaderCaseInstance(Context &context, const ShaderCaseSpecification &spec);
1231 ~ShaderCaseInstance(void);
1232
1233 TestStatus iterate(void);
1234
1235 private:
1236 enum
1237 {
1238 RENDER_WIDTH = 64,
1239 RENDER_HEIGHT = 64,
1240
1241 POSITIONS_OFFSET = 0,
1242 POSITIONS_SIZE = (int)sizeof(Vec2) * 4,
1243
1244 INDICES_OFFSET = POSITIONS_SIZE,
1245 INDICES_SIZE = (int)sizeof(uint16_t) * 6,
1246
1247 TOTAL_POS_NDX_SIZE = POSITIONS_SIZE + INDICES_SIZE
1248 };
1249
1250 const ShaderCaseSpecification &m_spec;
1251
1252 const Unique<vk::VkBuffer> m_posNdxBuffer;
1253 const UniquePtr<vk::Allocation> m_posNdxMem;
1254
1255 const ValueBufferLayout m_inputLayout;
1256 const Unique<vk::VkBuffer> m_inputBuffer; // Input values (attributes). Can be NULL if no inputs present
1257 const UniquePtr<vk::Allocation> m_inputMem; // Input memory, can be NULL if no input buffer exists
1258
1259 const ValueBufferLayout m_referenceLayout;
1260 const Unique<vk::VkBuffer> m_referenceBuffer; // Output (reference) values. Can be NULL if no outputs present
1261 const UniquePtr<vk::Allocation>
1262 m_referenceMem; // Output (reference) memory, can be NULL if no reference buffer exists
1263
1264 const ValueBufferLayout m_uniformLayout;
1265 const Unique<vk::VkBuffer> m_uniformBuffer; // Uniform values. Can be NULL if no uniforms present
1266 const UniquePtr<vk::Allocation> m_uniformMem; // Uniform memory, can be NULL if no uniform buffer exists
1267
1268 const vk::VkFormat m_rtFormat;
1269 uint32_t m_outputCount;
1270 Move<vk::VkImage> m_rtImage[4];
1271 MovePtr<vk::Allocation> m_rtMem[4];
1272 Move<vk::VkImageView> m_rtView[4];
1273
1274 Move<vk::VkBuffer> m_readImageBuffer[4];
1275 MovePtr<vk::Allocation> m_readImageMem[4];
1276
1277 const Unique<vk::VkRenderPass> m_renderPass;
1278 Move<vk::VkFramebuffer> m_framebuffer;
1279 const PipelineProgram m_program;
1280 const Unique<vk::VkDescriptorSetLayout> m_descriptorSetLayout;
1281 const Unique<vk::VkPipelineLayout> m_pipelineLayout;
1282 const Unique<vk::VkPipeline> m_pipeline;
1283
1284 const Unique<vk::VkDescriptorPool> m_descriptorPool;
1285 const Unique<vk::VkDescriptorSet> m_descriptorSet;
1286
1287 const Unique<vk::VkCommandPool> m_cmdPool;
1288 const Unique<vk::VkCommandBuffer> m_cmdBuffer;
1289
1290 int m_subCaseNdx;
1291 };
1292
ShaderCaseInstance(Context & context,const ShaderCaseSpecification & spec)1293 ShaderCaseInstance::ShaderCaseInstance(Context &context, const ShaderCaseSpecification &spec)
1294 : TestInstance(context)
1295 , m_spec(spec)
1296
1297 , m_posNdxBuffer(createBuffer(context, (vk::VkDeviceSize)TOTAL_POS_NDX_SIZE,
1298 vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT | vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT))
1299 , m_posNdxMem(vk::bindBuffer(context.getDeviceInterface(), context.getDevice(), m_context.getDefaultAllocator(),
1300 *m_posNdxBuffer, vk::MemoryRequirement::HostVisible))
1301
1302 , m_inputLayout(computeStd430Layout(spec.values.inputs))
1303 , m_inputBuffer(m_inputLayout.size > 0 ? createBuffer(context, (vk::VkDeviceSize)m_inputLayout.size,
1304 vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) :
1305 Move<vk::VkBuffer>())
1306 , m_inputMem(m_inputLayout.size > 0 ?
1307 vk::bindBuffer(context.getDeviceInterface(), context.getDevice(), m_context.getDefaultAllocator(),
1308 *m_inputBuffer, vk::MemoryRequirement::HostVisible) :
1309 MovePtr<vk::Allocation>())
1310
1311 , m_referenceLayout(computeStd140Layout(spec.values.outputs))
1312 , m_referenceBuffer(m_referenceLayout.size > 0 ? createBuffer(context, (vk::VkDeviceSize)m_referenceLayout.size,
1313 vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) :
1314 Move<vk::VkBuffer>())
1315 , m_referenceMem(m_referenceLayout.size > 0 ? vk::bindBuffer(context.getDeviceInterface(), context.getDevice(),
1316 m_context.getDefaultAllocator(), *m_referenceBuffer,
1317 vk::MemoryRequirement::HostVisible) :
1318 MovePtr<vk::Allocation>())
1319
1320 , m_uniformLayout(computeStd140Layout(spec.values.uniforms))
1321 , m_uniformBuffer(m_uniformLayout.size > 0 ? createBuffer(context, (vk::VkDeviceSize)m_uniformLayout.size,
1322 vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) :
1323 Move<vk::VkBuffer>())
1324 , m_uniformMem(m_uniformLayout.size > 0 ? vk::bindBuffer(context.getDeviceInterface(), context.getDevice(),
1325 m_context.getDefaultAllocator(), *m_uniformBuffer,
1326 vk::MemoryRequirement::HostVisible) :
1327 MovePtr<vk::Allocation>())
1328
1329 , m_rtFormat(getRenderTargetFormat(spec.outputFormat))
1330 , m_outputCount(((uint32_t)m_spec.values.outputs.size() == 0 || m_spec.outputType == glu::sl::OUTPUT_RESULT) ?
1331 1 :
1332 (uint32_t)m_spec.values.outputs.size())
1333 , m_rtImage()
1334 , m_rtMem()
1335 , m_rtView()
1336
1337 , m_readImageBuffer()
1338 , m_readImageMem()
1339
1340 , m_renderPass(createRenderPass(context, m_rtFormat, m_outputCount))
1341 , m_framebuffer()
1342 , m_program(context, spec)
1343 , m_descriptorSetLayout(createDescriptorSetLayout(context, m_program.getStages()))
1344 , m_pipelineLayout(createPipelineLayout(context, *m_descriptorSetLayout))
1345 , m_pipeline(createPipeline(context, spec.values.inputs, m_inputLayout, m_program, *m_renderPass, *m_pipelineLayout,
1346 tcu::UVec2(RENDER_WIDTH, RENDER_HEIGHT), m_outputCount))
1347
1348 , m_descriptorPool(createDescriptorPool(context))
1349 , m_descriptorSet(allocateDescriptorSet(context, *m_descriptorPool, *m_descriptorSetLayout))
1350
1351 , m_cmdPool(createCommandPool(context))
1352 , m_cmdBuffer(allocateCommandBuffer(context, *m_cmdPool))
1353
1354 , m_subCaseNdx(0)
1355 {
1356 {
1357 // Initialize the resources for each color attachment needed by the shader
1358 for (uint32_t outNdx = 0; outNdx < m_outputCount; outNdx++)
1359 {
1360 m_rtImage[outNdx] =
1361 createImage2D(context, RENDER_WIDTH, RENDER_HEIGHT, m_rtFormat, vk::VK_IMAGE_TILING_OPTIMAL,
1362 vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1363 m_rtMem[outNdx] = allocateAndBindMemory(context, *m_rtImage[outNdx], vk::MemoryRequirement::Any);
1364 m_rtView[outNdx] = createAttachmentView(context, *m_rtImage[outNdx], m_rtFormat);
1365
1366 m_readImageBuffer[outNdx] = createBuffer(
1367 context,
1368 (vk::VkDeviceSize)(RENDER_WIDTH * RENDER_HEIGHT * tcu::getPixelSize(vk::mapVkFormat(m_rtFormat))),
1369 vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
1370 m_readImageMem[outNdx] =
1371 vk::bindBuffer(context.getDeviceInterface(), context.getDevice(), m_context.getDefaultAllocator(),
1372 *m_readImageBuffer[outNdx], vk::MemoryRequirement::HostVisible);
1373 }
1374 m_framebuffer = createFramebuffer(context, *m_renderPass, m_rtView, m_outputCount, RENDER_WIDTH, RENDER_HEIGHT);
1375 }
1376
1377 const vk::DeviceInterface &vkd = context.getDeviceInterface();
1378 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1379
1380 {
1381 const Vec2 s_positions[] = {Vec2(-1.0f, -1.0f), Vec2(-1.0f, +1.0f), Vec2(+1.0f, -1.0f), Vec2(+1.0f, +1.0f)};
1382 const uint16_t s_indices[] = {0, 1, 2, 1, 3, 2};
1383
1384 DE_STATIC_ASSERT(sizeof(s_positions) == POSITIONS_SIZE);
1385 DE_STATIC_ASSERT(sizeof(s_indices) == INDICES_SIZE);
1386
1387 deMemcpy((uint8_t *)m_posNdxMem->getHostPtr() + POSITIONS_OFFSET, &s_positions[0], sizeof(s_positions));
1388 deMemcpy((uint8_t *)m_posNdxMem->getHostPtr() + INDICES_OFFSET, &s_indices[0], sizeof(s_indices));
1389
1390 flushAlloc(m_context.getDeviceInterface(), context.getDevice(), *m_posNdxMem);
1391 }
1392
1393 if (!m_spec.values.uniforms.empty())
1394 {
1395 const vk::VkDescriptorBufferInfo bufInfo = {*m_uniformBuffer,
1396 (vk::VkDeviceSize)0, // offset
1397 (vk::VkDeviceSize)m_uniformLayout.size};
1398
1399 vk::DescriptorSetUpdateBuilder()
1400 .writeSingle(*m_descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(USER_UNIFORM_BINDING),
1401 vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &bufInfo)
1402 .update(vkd, m_context.getDevice());
1403 }
1404
1405 if (!m_spec.values.outputs.empty())
1406 {
1407 const vk::VkDescriptorBufferInfo bufInfo = {*m_referenceBuffer,
1408 (vk::VkDeviceSize)0, // offset
1409 (vk::VkDeviceSize)m_referenceLayout.size};
1410
1411 vk::DescriptorSetUpdateBuilder()
1412 .writeSingle(*m_descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(REFERENCE_UNIFORM_BINDING),
1413 vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &bufInfo)
1414 .update(vkd, m_context.getDevice());
1415 }
1416
1417 // Record command buffer
1418
1419 beginCommandBuffer(vkd, *m_cmdBuffer, 0u);
1420
1421 {
1422 const vk::VkMemoryBarrier vertFlushBarrier = {
1423 vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER, // sType
1424 DE_NULL, // pNext
1425 vk::VK_ACCESS_HOST_WRITE_BIT, // srcAccessMask
1426 vk::VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | vk::VK_ACCESS_UNIFORM_READ_BIT, // dstAccessMask
1427 };
1428 vk::VkImageMemoryBarrier colorAttBarrier[4];
1429 for (uint32_t outNdx = 0; outNdx < m_outputCount; outNdx++)
1430 {
1431 vk::VkImageMemoryBarrier barrier = {
1432 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
1433 DE_NULL, // pNext
1434 0u, // srcAccessMask
1435 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // dstAccessMask
1436 vk::VK_IMAGE_LAYOUT_UNDEFINED, // oldLayout
1437 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
1438 queueFamilyIndex, // srcQueueFamilyIndex
1439 queueFamilyIndex, // destQueueFamilyIndex
1440 *m_rtImage[outNdx], // image
1441 {
1442 vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
1443 0u, // baseMipLevel
1444 1u, // mipLevels
1445 0u, // baseArraySlice
1446 1u, // arraySize
1447 } // subresourceRange
1448 };
1449 colorAttBarrier[outNdx] = barrier;
1450 }
1451 vkd.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
1452 (vk::VkDependencyFlags)0, 1, &vertFlushBarrier, 0,
1453 (const vk::VkBufferMemoryBarrier *)DE_NULL, m_outputCount, &colorAttBarrier[0]);
1454 }
1455
1456 {
1457 vk::VkClearValue clearValue[4];
1458 for (uint32_t outNdx = 0; outNdx < m_outputCount; outNdx++)
1459 {
1460 vk::VkClearValue value = vk::makeClearValueColorF32(0.125f, 0.25f, 0.75f, 1.0f);
1461 clearValue[outNdx] = value;
1462 }
1463 beginRenderPass(vkd, *m_cmdBuffer, *m_renderPass, *m_framebuffer,
1464 vk::makeRect2D(0, 0, RENDER_WIDTH, RENDER_HEIGHT), m_outputCount, clearValue);
1465 }
1466
1467 vkd.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
1468
1469 if (!m_spec.values.uniforms.empty() || !m_spec.values.outputs.empty())
1470 vkd.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1u,
1471 &*m_descriptorSet, 0u, DE_NULL);
1472
1473 {
1474 const vk::VkBuffer buffers[] = {*m_posNdxBuffer, *m_inputBuffer};
1475 const vk::VkDeviceSize offsets[] = {POSITIONS_OFFSET, 0u};
1476 const uint32_t numBuffers = buffers[1] != 0 ? 2u : 1u;
1477 vkd.cmdBindVertexBuffers(*m_cmdBuffer, 0u, numBuffers, buffers, offsets);
1478 }
1479
1480 vkd.cmdBindIndexBuffer(*m_cmdBuffer, *m_posNdxBuffer, (vk::VkDeviceSize)INDICES_OFFSET, vk::VK_INDEX_TYPE_UINT16);
1481 vkd.cmdDrawIndexed(*m_cmdBuffer, 6u, 1u, 0u, 0u, 0u);
1482 endRenderPass(vkd, *m_cmdBuffer);
1483
1484 {
1485 vk::VkImageMemoryBarrier renderFinishBarrier[4];
1486 for (uint32_t outNdx = 0; outNdx < m_outputCount; outNdx++)
1487 {
1488 vk::VkImageMemoryBarrier barrier = {
1489 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
1490 DE_NULL, // pNext
1491 vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // srcAccessMask
1492 vk::VK_ACCESS_TRANSFER_READ_BIT, // dstAccessMask
1493 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // oldLayout
1494 vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // newLayout
1495 queueFamilyIndex, // srcQueueFamilyIndex
1496 queueFamilyIndex, // destQueueFamilyIndex
1497 *m_rtImage[outNdx], // image
1498 {
1499 vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
1500 0u, // baseMipLevel
1501 1u, // mipLevels
1502 0u, // baseArraySlice
1503 1u, // arraySize
1504 } // subresourceRange
1505 };
1506 renderFinishBarrier[outNdx] = barrier;
1507 }
1508
1509 vkd.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
1510 (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier *)DE_NULL, 0,
1511 (const vk::VkBufferMemoryBarrier *)DE_NULL, m_outputCount, &renderFinishBarrier[0]);
1512 }
1513
1514 {
1515 for (uint32_t outNdx = 0; outNdx < m_outputCount; outNdx++)
1516 {
1517 const vk::VkBufferImageCopy copyParams = {
1518 (vk::VkDeviceSize)0u, // bufferOffset
1519 (uint32_t)RENDER_WIDTH, // bufferRowLength
1520 (uint32_t)RENDER_HEIGHT, // bufferImageHeight
1521 {
1522 vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspect
1523 0u, // mipLevel
1524 0u, // arrayLayer
1525 1u, // arraySize
1526 }, // imageSubresource
1527 {0u, 0u, 0u}, // imageOffset
1528 {RENDER_WIDTH, RENDER_HEIGHT, 1u} // imageExtent
1529 };
1530
1531 vkd.cmdCopyImageToBuffer(*m_cmdBuffer, *m_rtImage[outNdx], vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1532 *m_readImageBuffer[outNdx], 1u, ©Params);
1533 }
1534 }
1535
1536 {
1537 const vk::VkDeviceSize size =
1538 (vk::VkDeviceSize)(RENDER_WIDTH * RENDER_HEIGHT * tcu::getPixelSize(vk::mapVkFormat(m_rtFormat)));
1539 vk::VkBufferMemoryBarrier copyFinishBarrier[4];
1540 for (uint32_t outNdx = 0; outNdx < m_outputCount; outNdx++)
1541 {
1542 vk::VkBufferMemoryBarrier barrier = {
1543 vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // sType
1544 DE_NULL, // pNext
1545 vk::VK_ACCESS_TRANSFER_WRITE_BIT, // srcAccessMask
1546 vk::VK_ACCESS_HOST_READ_BIT, // dstAccessMask
1547 queueFamilyIndex, // srcQueueFamilyIndex
1548 queueFamilyIndex, // destQueueFamilyIndex
1549 *m_readImageBuffer[outNdx], // buffer
1550 0u, // offset
1551 size // size
1552 };
1553 copyFinishBarrier[outNdx] = barrier;
1554 }
1555 vkd.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT,
1556 (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier *)DE_NULL, m_outputCount,
1557 ©FinishBarrier[0], 0, (const vk::VkImageMemoryBarrier *)DE_NULL);
1558 }
1559
1560 endCommandBuffer(vkd, *m_cmdBuffer);
1561 }
1562
~ShaderCaseInstance(void)1563 ShaderCaseInstance::~ShaderCaseInstance(void)
1564 {
1565 }
1566
getNumSubCases(const ValueBlock & values)1567 int getNumSubCases(const ValueBlock &values)
1568 {
1569 if (!values.outputs.empty())
1570 return int(values.outputs[0].elements.size() / values.outputs[0].type.getScalarSize());
1571 else
1572 return 1; // Always run at least one iteration even if no output values are specified
1573 }
1574
checkResultImage(const ConstPixelBufferAccess & result)1575 bool checkResultImage(const ConstPixelBufferAccess &result)
1576 {
1577 const tcu::IVec4 refPix(255, 255, 255, 255);
1578
1579 for (int y = 0; y < result.getHeight(); y++)
1580 {
1581 for (int x = 0; x < result.getWidth(); x++)
1582 {
1583 const tcu::IVec4 resPix = result.getPixelInt(x, y);
1584
1585 if (boolAny(notEqual(resPix, refPix)))
1586 return false;
1587 }
1588 }
1589
1590 return true;
1591 }
1592
checkResultImageWithReference(const ConstPixelBufferAccess & result,tcu::IVec4 refPix)1593 bool checkResultImageWithReference(const ConstPixelBufferAccess &result, tcu::IVec4 refPix)
1594 {
1595 for (int y = 0; y < result.getHeight(); y++)
1596 {
1597 for (int x = 0; x < result.getWidth(); x++)
1598 {
1599 const tcu::IVec4 resPix = result.getPixelInt(x, y);
1600
1601 if (boolAny(notEqual(resPix, refPix)))
1602 return false;
1603 }
1604 }
1605
1606 return true;
1607 }
iterate(void)1608 TestStatus ShaderCaseInstance::iterate(void)
1609 {
1610 const vk::DeviceInterface &vkd = m_context.getDeviceInterface();
1611 const vk::VkDevice device = m_context.getDevice();
1612 const vk::VkQueue queue = m_context.getUniversalQueue();
1613
1614 if (!m_spec.values.inputs.empty())
1615 writeValuesToMem(m_context, *m_inputMem, m_inputLayout, m_spec.values.inputs, m_subCaseNdx);
1616
1617 if (!m_spec.values.outputs.empty())
1618 writeValuesToMem(m_context, *m_referenceMem, m_referenceLayout, m_spec.values.outputs, m_subCaseNdx);
1619
1620 if (!m_spec.values.uniforms.empty())
1621 writeValuesToMem(m_context, *m_uniformMem, m_uniformLayout, m_spec.values.uniforms, m_subCaseNdx);
1622
1623 submitCommandsAndWait(vkd, device, queue, m_cmdBuffer.get());
1624
1625 // Result was checked in fragment shader
1626 if (m_spec.outputType == glu::sl::OUTPUT_RESULT)
1627 {
1628 const ConstPixelBufferAccess imgAccess(TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8),
1629 RENDER_WIDTH, RENDER_HEIGHT, 1, m_readImageMem[0]->getHostPtr());
1630
1631 invalidateAlloc(vkd, device, *m_readImageMem[0]);
1632
1633 if (!checkResultImage(imgAccess))
1634 {
1635 TestLog &log = m_context.getTestContext().getLog();
1636
1637 log << TestLog::Message << "ERROR: Got non-white pixels on sub-case " << m_subCaseNdx << TestLog::EndMessage
1638 << TestLog::Image("Result", "Result", imgAccess);
1639
1640 dumpValues(log, m_spec.values, m_subCaseNdx);
1641
1642 return TestStatus::fail(string("Got invalid pixels at sub-case ") + de::toString(m_subCaseNdx));
1643 }
1644 }
1645 // Result was written to color buffer
1646 else
1647 {
1648 for (uint32_t outNdx = 0; outNdx < m_outputCount; outNdx++)
1649 {
1650 const ConstPixelBufferAccess imgAccess(vk::mapVkFormat(m_rtFormat), RENDER_WIDTH, RENDER_HEIGHT, 1,
1651 m_readImageMem[outNdx]->getHostPtr());
1652 const DataType dataType = m_spec.values.outputs[outNdx].type.getBasicType();
1653 const int numComponents = getDataTypeScalarSize(dataType);
1654 tcu::IVec4 reference(0, 0, 0, 1);
1655
1656 for (int refNdx = 0; refNdx < numComponents; refNdx++)
1657 {
1658 if (isDataTypeFloatOrVec(dataType))
1659 reference[refNdx] =
1660 (int)m_spec.values.outputs[outNdx].elements[m_subCaseNdx * numComponents + refNdx].float32;
1661 else if (isDataTypeIntOrIVec(dataType))
1662 reference[refNdx] =
1663 m_spec.values.outputs[outNdx].elements[m_subCaseNdx * numComponents + refNdx].int32;
1664 else
1665 DE_FATAL("Unknown data type");
1666 }
1667
1668 invalidateAlloc(vkd, device, *m_readImageMem[outNdx]);
1669
1670 if (!checkResultImageWithReference(imgAccess, reference))
1671 {
1672 TestLog &log = m_context.getTestContext().getLog();
1673
1674 log << TestLog::Message << "ERROR: Got nonmatching pixels on sub-case " << m_subCaseNdx << " output "
1675 << outNdx << TestLog::EndMessage << TestLog::Image("Result", "Result", imgAccess);
1676
1677 dumpValues(log, m_spec.values, m_subCaseNdx);
1678
1679 return TestStatus::fail(string("Got invalid pixels at sub-case ") + de::toString(m_subCaseNdx));
1680 }
1681 }
1682 }
1683
1684 if (++m_subCaseNdx < getNumSubCases(m_spec.values))
1685 return TestStatus::incomplete();
1686 else
1687 return TestStatus::pass("All sub-cases passed");
1688 }
1689
1690 class ShaderCase : public TestCase
1691 {
1692 public:
1693 ShaderCase(tcu::TestContext &testCtx, const string &name, const ShaderCaseSpecification &spec);
1694
1695 void initPrograms(SourceCollections &programCollection) const;
1696 TestInstance *createInstance(Context &context) const;
1697
1698 private:
1699 const ShaderCaseSpecification m_spec;
1700 };
1701
ShaderCase(tcu::TestContext & testCtx,const string & name,const ShaderCaseSpecification & spec)1702 ShaderCase::ShaderCase(tcu::TestContext &testCtx, const string &name, const ShaderCaseSpecification &spec)
1703 : TestCase(testCtx, name)
1704 , m_spec(spec)
1705 {
1706 }
1707
initPrograms(SourceCollections & sourceCollection) const1708 void ShaderCase::initPrograms(SourceCollections &sourceCollection) const
1709 {
1710 vector<ProgramSources> specializedSources(m_spec.programs.size());
1711
1712 DE_ASSERT(isValid(m_spec));
1713
1714 if (m_spec.expectResult != glu::sl::EXPECT_PASS)
1715 TCU_THROW(InternalError, "Only EXPECT_PASS is supported");
1716
1717 if (m_spec.caseType == glu::sl::CASETYPE_VERTEX_ONLY)
1718 {
1719 DE_ASSERT(m_spec.programs.size() == 1 &&
1720 m_spec.programs[0].sources.sources[glu::SHADERTYPE_VERTEX].size() == 1);
1721 specializedSources[0] << glu::VertexSource(specializeVertexShader(
1722 m_spec, m_spec.programs[0].sources.sources[glu::SHADERTYPE_VERTEX][0]))
1723 << glu::FragmentSource(genFragmentShader(m_spec));
1724 }
1725 else if (m_spec.caseType == glu::sl::CASETYPE_FRAGMENT_ONLY)
1726 {
1727 DE_ASSERT(m_spec.programs.size() == 1 &&
1728 m_spec.programs[0].sources.sources[glu::SHADERTYPE_FRAGMENT].size() == 1);
1729 specializedSources[0] << glu::VertexSource(genVertexShader(m_spec))
1730 << glu::FragmentSource(specializeFragmentShader(
1731 m_spec, m_spec.programs[0].sources.sources[glu::SHADERTYPE_FRAGMENT][0]));
1732 }
1733 else
1734 {
1735 DE_ASSERT(m_spec.caseType == glu::sl::CASETYPE_COMPLETE);
1736
1737 const int maxPatchVertices = 4; // \todo [2015-08-05 pyry] Query
1738
1739 for (size_t progNdx = 0; progNdx < m_spec.programs.size(); progNdx++)
1740 {
1741 const ProgramSpecializationParams progSpecParams(m_spec, m_spec.programs[progNdx].requiredExtensions,
1742 maxPatchVertices);
1743
1744 specializeProgramSources(specializedSources[progNdx], m_spec.programs[progNdx].sources, progSpecParams);
1745 }
1746 }
1747
1748 for (size_t progNdx = 0; progNdx < specializedSources.size(); progNdx++)
1749 {
1750 for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
1751 {
1752 if (!specializedSources[progNdx].sources[shaderType].empty())
1753 {
1754 vk::GlslSource &curSrc =
1755 sourceCollection.glslSources.add(getShaderName((glu::ShaderType)shaderType, progNdx));
1756 curSrc.sources[shaderType] = specializedSources[progNdx].sources[shaderType];
1757 }
1758 }
1759 }
1760 }
1761
createInstance(Context & context) const1762 TestInstance *ShaderCase::createInstance(Context &context) const
1763 {
1764 return new ShaderCaseInstance(context, m_spec);
1765 }
1766
1767 class ShaderCaseFactory : public glu::sl::ShaderCaseFactory
1768 {
1769 public:
ShaderCaseFactory(tcu::TestContext & testCtx)1770 ShaderCaseFactory(tcu::TestContext &testCtx) : m_testCtx(testCtx)
1771 {
1772 }
1773
createGroup(const string & name,const std::string & description,const vector<tcu::TestNode * > & children)1774 tcu::TestCaseGroup *createGroup(const string &name, const std::string &description,
1775 const vector<tcu::TestNode *> &children)
1776 {
1777 (void)description;
1778 return new tcu::TestCaseGroup(m_testCtx, name.c_str(), children);
1779 }
1780
createCase(const string & name,const std::string & description,const ShaderCaseSpecification & spec)1781 tcu::TestCase *createCase(const string &name, const std::string &description, const ShaderCaseSpecification &spec)
1782 {
1783 (void)description;
1784 return new ShaderCase(m_testCtx, name, spec);
1785 }
1786
1787 private:
1788 tcu::TestContext &m_testCtx;
1789 };
1790
1791 class ShaderLibraryGroup : public tcu::TestCaseGroup
1792 {
1793 public:
ShaderLibraryGroup(tcu::TestContext & testCtx,const string & name,const string & filename)1794 ShaderLibraryGroup(tcu::TestContext &testCtx, const string &name, const string &filename)
1795 : tcu::TestCaseGroup(testCtx, name.c_str())
1796 , m_filename(filename)
1797 {
1798 }
1799
init(void)1800 void init(void)
1801 {
1802 ShaderCaseFactory caseFactory(m_testCtx);
1803 const vector<tcu::TestNode *> children = glu::sl::parseFile(m_testCtx.getArchive(), m_filename, &caseFactory);
1804
1805 for (size_t ndx = 0; ndx < children.size(); ndx++)
1806 {
1807 try
1808 {
1809 addChild(children[ndx]);
1810 }
1811 catch (...)
1812 {
1813 for (; ndx < children.size(); ndx++)
1814 delete children[ndx];
1815 throw;
1816 }
1817 }
1818 }
1819
1820 private:
1821 const string m_filename;
1822 };
1823
1824 } // namespace
1825
createShaderLibraryGroup(tcu::TestContext & testCtx,const string & name,const string & filename)1826 MovePtr<tcu::TestCaseGroup> createShaderLibraryGroup(tcu::TestContext &testCtx, const string &name,
1827 const string &filename)
1828 {
1829 return MovePtr<tcu::TestCaseGroup>(new ShaderLibraryGroup(testCtx, name, filename));
1830 }
1831
1832 } // namespace vkt
1833