xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/vktShaderLibrary.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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(), &params);
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(), &params);
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(), &params);
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(), &params);
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(), &params);
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, &copyParams);
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                                &copyFinishBarrier[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