Merge "Fix error double accounting in fuzzyCompare()" am: 0cf17c4bf8
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / tessellation / vktTessellationGeometryPassthroughTests.cpp
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2014 The Android Open Source Project
6  * Copyright (c) 2016 The Khronos Group Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22 * \brief Tessellation Geometry Interaction - Passthrough
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktTessellationGeometryPassthroughTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
28
29 #include "tcuTestLog.hpp"
30 #include "tcuImageCompare.hpp"
31
32 #include "vkDefs.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkBuilderUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkImageUtil.hpp"
37
38 #include "deUniquePtr.hpp"
39
40 #include <string>
41 #include <vector>
42
43 namespace vkt
44 {
45 namespace tessellation
46 {
47
48 using namespace vk;
49
50 namespace
51 {
52
53 void addVertexAndFragmentShaders (vk::SourceCollections&  programCollection)
54 {
55         // Vertex shader
56         {
57                 std::ostringstream src;
58                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
59                         << "\n"
60                         << "layout(location = 0) in  highp vec4 a_position;\n"
61                         << "layout(location = 0) out highp vec4 v_vertex_color;\n"
62                         << "\n"
63                         << "void main (void)\n"
64                         << "{\n"
65                         << "    gl_Position = a_position;\n"
66                         << "    v_vertex_color = vec4(a_position.x * 0.5 + 0.5, a_position.y * 0.5 + 0.5, 1.0, 0.4);\n"
67                         << "}\n";
68
69                 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
70         }
71
72         // Fragment shader
73         {
74                 std::ostringstream src;
75                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
76                         << "\n"
77                         << "layout(location = 0) in  highp   vec4 v_fragment_color;\n"
78                         << "layout(location = 0) out mediump vec4 fragColor;\n"
79                         << "void main (void)\n"
80                         << "{\n"
81                         << "    fragColor = v_fragment_color;\n"
82                         << "}\n";
83
84                 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
85         }
86 }
87
88 //! Tessellation evaluation shader used in passthrough geometry shader case.
89 std::string generateTessellationEvaluationShader (const TessPrimitiveType primitiveType, const std::string& colorOutputName)
90 {
91         std::ostringstream      src;
92         src <<  glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
93                 << "#extension GL_EXT_tessellation_shader : require\n"
94                 << "layout(" << getTessPrimitiveTypeShaderName(primitiveType) << ") in;\n"
95                 << "\n"
96                 << "layout(location = 0) in  highp vec4 v_patch_color[];\n"
97                 << "layout(location = 0) out highp vec4 " << colorOutputName << ";\n"
98                 << "\n"
99                 << "// note: No need to use precise gl_Position since we do not require gapless geometry\n"
100                 << "void main (void)\n"
101                 << "{\n";
102
103         if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
104                 src << "    vec3 weights = vec3(pow(gl_TessCoord.x, 1.3), pow(gl_TessCoord.y, 1.3), pow(gl_TessCoord.z, 1.3));\n"
105                         << "    vec3 cweights = gl_TessCoord;\n"
106                         << "    gl_Position = vec4(weights.x * gl_in[0].gl_Position.xyz + weights.y * gl_in[1].gl_Position.xyz + weights.z * gl_in[2].gl_Position.xyz, 1.0);\n"
107                         << "    " << colorOutputName << " = cweights.x * v_patch_color[0] + cweights.y * v_patch_color[1] + cweights.z * v_patch_color[2];\n";
108         else if (primitiveType == TESSPRIMITIVETYPE_QUADS || primitiveType == TESSPRIMITIVETYPE_ISOLINES)
109                 src << "    vec2 normalizedCoord = (gl_TessCoord.xy * 2.0 - vec2(1.0));\n"
110                         << "    vec2 normalizedWeights = normalizedCoord * (vec2(1.0) - 0.3 * cos(normalizedCoord.yx * 1.57));\n"
111                         << "    vec2 weights = normalizedWeights * 0.5 + vec2(0.5);\n"
112                         << "    vec2 cweights = gl_TessCoord.xy;\n"
113                         << "    gl_Position = mix(mix(gl_in[0].gl_Position, gl_in[1].gl_Position, weights.y), mix(gl_in[2].gl_Position, gl_in[3].gl_Position, weights.y), weights.x);\n"
114                         << "    " << colorOutputName << " = mix(mix(v_patch_color[0], v_patch_color[1], cweights.y), mix(v_patch_color[2], v_patch_color[3], cweights.y), cweights.x);\n";
115         else
116                 DE_ASSERT(false);
117
118         src <<  "}\n";
119
120         return src.str();
121 }
122
123 class IdentityGeometryShaderTestCase : public TestCase
124 {
125 public:
126         void                    initPrograms    (vk::SourceCollections& programCollection) const;
127         TestInstance*   createInstance  (Context& context) const;
128
129         IdentityGeometryShaderTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType)
130                 : TestCase                      (testCtx, name, description)
131                 , m_primitiveType       (primitiveType)
132         {
133         }
134
135 private:
136         const TessPrimitiveType m_primitiveType;
137 };
138
139 void IdentityGeometryShaderTestCase::initPrograms (vk::SourceCollections& programCollection) const
140 {
141         addVertexAndFragmentShaders(programCollection);
142
143         // Tessellation control
144         {
145                 std::ostringstream src;
146                 src <<  glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
147                         << "#extension GL_EXT_tessellation_shader : require\n"
148                         << "layout(vertices = 4) out;\n"
149                         << "\n"
150                         << "layout(set = 0, binding = 0, std430) readonly restrict buffer TessLevels {\n"
151                         << "    float inner0;\n"
152                         << "    float inner1;\n"
153                         << "    float outer0;\n"
154                         << "    float outer1;\n"
155                         << "    float outer2;\n"
156                         << "    float outer3;\n"
157                         << "} sb_levels;\n"
158                         << "\n"
159                         << "layout(location = 0) in  highp vec4 v_vertex_color[];\n"
160                         << "layout(location = 0) out highp vec4 v_patch_color[];\n"
161                         << "\n"
162                         << "void main (void)\n"
163                         << "{\n"
164                         << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
165                         << "    v_patch_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
166                         << "\n"
167                         << "    gl_TessLevelInner[0] = sb_levels.inner0;\n"
168                         << "    gl_TessLevelInner[1] = sb_levels.inner1;\n"
169                         << "    gl_TessLevelOuter[0] = sb_levels.outer0;\n"
170                         << "    gl_TessLevelOuter[1] = sb_levels.outer1;\n"
171                         << "    gl_TessLevelOuter[2] = sb_levels.outer2;\n"
172                         << "    gl_TessLevelOuter[3] = sb_levels.outer3;\n"
173                         <<      "}\n";
174
175                 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
176         }
177
178         // Tessellation evaluation shader
179         {
180                 programCollection.glslSources.add("tese_to_frag")
181                         << glu::TessellationEvaluationSource(generateTessellationEvaluationShader(m_primitiveType, "v_fragment_color"));
182                 programCollection.glslSources.add("tese_to_geom")
183                         << glu::TessellationEvaluationSource(generateTessellationEvaluationShader(m_primitiveType, "v_evaluated_color"));
184         }
185
186         // Geometry shader
187         {
188                 std::ostringstream      src;
189                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
190                         << "#extension GL_EXT_geometry_shader : require\n"
191                         << "layout(" << getGeometryShaderInputPrimitiveTypeShaderName(m_primitiveType, false) << ") in;\n"
192                         << "layout(" << getGeometryShaderOutputPrimitiveTypeShaderName(m_primitiveType, false)
193                                                  << ", max_vertices=" << numVerticesPerPrimitive(m_primitiveType, false) << ") out;\n"
194                         << "\n"
195                         << "layout(location = 0) in  highp vec4 v_evaluated_color[];\n"
196                         << "layout(location = 0) out highp vec4 v_fragment_color;\n"
197                         << "\n"
198                         << "void main (void)\n"
199                         << "{\n"
200                         << "    for (int ndx = 0; ndx < gl_in.length(); ++ndx)\n"
201                         << "    {\n"
202                         << "        gl_Position = gl_in[ndx].gl_Position;\n"
203                         << "        v_fragment_color = v_evaluated_color[ndx];\n"
204                         << "        EmitVertex();\n"
205                         << "    }\n"
206                         << "}\n";
207
208                 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
209         }
210 }
211
212 class IdentityTessellationShaderTestCase : public TestCase
213 {
214 public:
215         void                    initPrograms    (vk::SourceCollections& programCollection) const;
216         TestInstance*   createInstance  (Context& context) const;
217
218         IdentityTessellationShaderTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType)
219                 : TestCase                      (testCtx, name, description)
220                 , m_primitiveType       (primitiveType)
221         {
222         }
223
224 private:
225         const TessPrimitiveType m_primitiveType;
226 };
227
228 //! Geometry shader used in passthrough tessellation shader case.
229 std::string generateGeometryShader (const TessPrimitiveType primitiveType, const std::string& colorSourceName)
230 {
231         const int numEmitVertices = (primitiveType == TESSPRIMITIVETYPE_ISOLINES ? 11 : 8);
232
233         std::ostringstream src;
234         src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
235                 << "#extension GL_EXT_geometry_shader : require\n"
236                 << "layout(" << getGeometryShaderInputPrimitiveTypeShaderName(primitiveType, false) << ") in;\n"
237                 << "layout(" << getGeometryShaderOutputPrimitiveTypeShaderName(primitiveType, false)
238                                           << ", max_vertices=" << numEmitVertices << ") out;\n"
239                 << "\n"
240                 << "layout(location = 0) in  highp vec4 " << colorSourceName << "[];\n"
241                 << "layout(location = 0) out highp vec4 v_fragment_color;\n"
242                 << "\n"
243                 << "void main (void)\n"
244                 << "{\n";
245
246         if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
247         {
248                 src << "        vec4 centerPos = (gl_in[0].gl_Position + gl_in[1].gl_Position + gl_in[2].gl_Position) / 3.0f;\n"
249                         << "\n"
250                         << "    for (int ndx = 0; ndx < 4; ++ndx)\n"
251                         << "    {\n"
252                         << "            gl_Position = centerPos + (centerPos - gl_in[ndx % 3].gl_Position);\n"
253                         << "            v_fragment_color = " << colorSourceName << "[ndx % 3];\n"
254                         << "            EmitVertex();\n"
255                         << "\n"
256                         << "            gl_Position = centerPos + 0.7 * (centerPos - gl_in[ndx % 3].gl_Position);\n"
257                         << "            v_fragment_color = " << colorSourceName << "[ndx % 3];\n"
258                         << "            EmitVertex();\n"
259                         << "    }\n";
260         }
261         else if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
262         {
263                 src << "        vec4 mdir = vec4(gl_in[0].gl_Position.y - gl_in[1].gl_Position.y, gl_in[1].gl_Position.x - gl_in[0].gl_Position.x, 0.0, 0.0);\n"
264                         << "    for (int i = 0; i <= 10; ++i)\n"
265                         << "    {\n"
266                         << "            float xweight = cos(float(i) / 10.0 * 6.28) * 0.5 + 0.5;\n"
267                         << "            float mweight = sin(float(i) / 10.0 * 6.28) * 0.1 + 0.1;\n"
268                         << "            gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, xweight) + mweight * mdir;\n"
269                         << "            v_fragment_color = mix(" << colorSourceName << "[0], " << colorSourceName << "[1], xweight);\n"
270                         << "            EmitVertex();\n"
271                         << "    }\n";
272         }
273         else
274                 DE_ASSERT(false);
275
276         src << "}\n";
277
278         return src.str();
279 }
280
281 void IdentityTessellationShaderTestCase::initPrograms (vk::SourceCollections& programCollection) const
282 {
283         addVertexAndFragmentShaders(programCollection);
284
285         // Tessellation control
286         {
287                 std::ostringstream src;
288                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
289                         << "#extension GL_EXT_tessellation_shader : require\n"
290                         << "layout(vertices = " << numVerticesPerPrimitive(m_primitiveType, false) << ") out;\n"
291                         << "\n"
292                         << "layout(location = 0) in  highp vec4 v_vertex_color[];\n"
293                         << "layout(location = 0) out highp vec4 v_control_color[];\n"
294                         << "\n"
295                         << "void main (void)\n"
296                         << "{\n"
297                         << "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
298                         << "    v_control_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
299                         << "\n"
300                         << "    gl_TessLevelInner[0] = 1.0;\n"
301                         << "    gl_TessLevelInner[1] = 1.0;\n"
302                         << "    gl_TessLevelOuter[0] = 1.0;\n"
303                         << "    gl_TessLevelOuter[1] = 1.0;\n"
304                         << "    gl_TessLevelOuter[2] = 1.0;\n"
305                         << "    gl_TessLevelOuter[3] = 1.0;\n"
306                         <<      "}\n";
307
308                 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
309         }
310
311         // Tessellation evaluation shader
312         {
313                 std::ostringstream src;
314                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
315                         << "#extension GL_EXT_tessellation_shader : require\n"
316                         << "layout(" << getTessPrimitiveTypeShaderName(m_primitiveType) << ") in;\n"
317                         << "\n"
318                         << "layout(location = 0) in  highp vec4 v_control_color[];\n"
319                         << "layout(location = 0) out highp vec4 v_evaluated_color;\n"
320                         << "\n"
321                         << "// note: No need to use precise gl_Position since we do not require gapless geometry\n"
322                         << "void main (void)\n"
323                         << "{\n";
324
325                 if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
326                         src << "    gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n"
327                                 << "    v_evaluated_color = gl_TessCoord.x * v_control_color[0] + gl_TessCoord.y * v_control_color[1] + gl_TessCoord.z * v_control_color[2];\n";
328                 else if (m_primitiveType == TESSPRIMITIVETYPE_ISOLINES)
329                         src << "    gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
330                                 << "    v_evaluated_color = mix(v_control_color[0], v_control_color[1], gl_TessCoord.x);\n";
331                 else
332                         DE_ASSERT(false);
333
334                 src << "}\n";
335
336                 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
337         }
338
339         // Geometry shader
340         {
341                 programCollection.glslSources.add("geom_from_tese") << glu::GeometrySource(
342                         generateGeometryShader(m_primitiveType, "v_evaluated_color"));
343                 programCollection.glslSources.add("geom_from_vert") << glu::GeometrySource(
344                         generateGeometryShader(m_primitiveType, "v_vertex_color"));
345         }
346 }
347
348 inline tcu::ConstPixelBufferAccess getPixelBufferAccess (const DeviceInterface& vk,
349                                                                                                                  const VkDevice                 device,
350                                                                                                                  const Buffer&                  colorBuffer,
351                                                                                                                  const VkFormat                 colorFormat,
352                                                                                                                  const VkDeviceSize             colorBufferSizeBytes,
353                                                                                                                  const tcu::IVec2&              renderSize)
354 {
355         const Allocation& alloc = colorBuffer.getAllocation();
356         invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), colorBufferSizeBytes);
357         return tcu::ConstPixelBufferAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, alloc.getHostPtr());
358 }
359
360 //! When a test case disables tessellation stage and we need to derive a primitive type.
361 VkPrimitiveTopology getPrimitiveTopology (const TessPrimitiveType primitiveType)
362 {
363         switch (primitiveType)
364         {
365                 case TESSPRIMITIVETYPE_TRIANGLES:
366                 case TESSPRIMITIVETYPE_QUADS:
367                         return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
368
369                 case TESSPRIMITIVETYPE_ISOLINES:
370                         return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
371
372                 default:
373                         DE_ASSERT(false);
374                         return VK_PRIMITIVE_TOPOLOGY_LAST;
375         }
376 }
377
378 enum Constants
379 {
380         PIPELINE_CASES  = 2,
381         RENDER_SIZE             = 256,
382 };
383
384 class PassthroughTestInstance : public TestInstance
385 {
386 public:
387         struct PipelineDescription
388         {
389                 bool            useTessellation;
390                 bool            useGeometry;
391                 std::string     tessEvalShaderName;
392                 std::string     geomShaderName;
393                 std::string description;
394
395                 PipelineDescription (void) : useTessellation(), useGeometry() {}
396         };
397
398         struct Params
399         {
400                 bool                                    useTessLevels;
401                 TessLevels                              tessLevels;
402                 TessPrimitiveType               primitiveType;
403                 int                                             inputPatchVertices;
404                 std::vector<tcu::Vec4>  vertices;
405                 PipelineDescription             pipelineCases[PIPELINE_CASES];  //!< Each test case renders with two pipelines and compares results
406                 std::string                             message;
407
408                 Params (void) : useTessLevels(), tessLevels(), primitiveType(), inputPatchVertices() {}
409         };
410
411                                                                 PassthroughTestInstance (Context& context, const Params& params) : TestInstance(context), m_params(params) {}
412         tcu::TestStatus                         iterate                                 (void);
413
414 private:
415         const Params                            m_params;
416 };
417
418 tcu::TestStatus PassthroughTestInstance::iterate (void)
419 {
420         requireFeatures(m_context.getInstanceInterface(), m_context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER | FEATURE_GEOMETRY_SHADER);
421         DE_STATIC_ASSERT(PIPELINE_CASES == 2);
422
423         const DeviceInterface&  vk                                      = m_context.getDeviceInterface();
424         const VkDevice                  device                          = m_context.getDevice();
425         const VkQueue                   queue                           = m_context.getUniversalQueue();
426         const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
427         Allocator&                              allocator                       = m_context.getDefaultAllocator();
428
429         // Tessellation levels
430         const Buffer tessLevelsBuffer (vk, device, allocator, makeBufferCreateInfo(sizeof(TessLevels), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
431
432         if (m_params.useTessLevels)
433         {
434                 const Allocation& alloc = tessLevelsBuffer.getAllocation();
435                 TessLevels* const bufferTessLevels = static_cast<TessLevels*>(alloc.getHostPtr());
436                 *bufferTessLevels = m_params.tessLevels;
437                 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), sizeof(TessLevels));
438         }
439
440         // Vertex attributes
441
442         const VkDeviceSize      vertexDataSizeBytes = sizeInBytes(m_params.vertices);
443         const VkFormat          vertexFormat            = VK_FORMAT_R32G32B32A32_SFLOAT;
444         const Buffer            vertexBuffer            (vk, device, allocator, makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
445
446         {
447                 const Allocation& alloc = vertexBuffer.getAllocation();
448                 deMemcpy(alloc.getHostPtr(), &m_params.vertices[0], static_cast<std::size_t>(vertexDataSizeBytes));
449                 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), vertexDataSizeBytes);
450         }
451
452         // Descriptors - make descriptor for tessellation levels, even if we don't use them, to simplify code
453
454         const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
455                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
456                 .build(vk, device));
457
458         const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
459                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
460                 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
461
462         const Unique<VkDescriptorSet> descriptorSet                (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
463         const VkDescriptorBufferInfo  tessLevelsBufferInfo = makeDescriptorBufferInfo(*tessLevelsBuffer, 0ull, sizeof(TessLevels));
464
465         DescriptorSetUpdateBuilder()
466                 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &tessLevelsBufferInfo)
467                 .update(vk, device);
468
469         // Color attachment
470
471         const tcu::IVec2                          renderSize                             = tcu::IVec2(RENDER_SIZE, RENDER_SIZE);
472         const VkFormat                            colorFormat                            = VK_FORMAT_R8G8B8A8_UNORM;
473         const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
474         const Image                                       colorAttachmentImage           (vk, device, allocator,
475                                                                                                                          makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
476                                                                                                                          MemoryRequirement::Any);
477
478         // Color output buffer: image will be copied here for verification.
479         //                      We use two buffers, one for each case.
480
481         const VkDeviceSize      colorBufferSizeBytes            = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
482         const Buffer            colorBuffer1                            (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
483         const Buffer            colorBuffer2                            (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
484         const Buffer* const colorBuffer[PIPELINE_CASES] = { &colorBuffer1, &colorBuffer2 };
485
486         // Pipeline
487
488         const Unique<VkImageView>               colorAttachmentView(makeImageView(vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
489         const Unique<VkRenderPass>              renderPass                 (makeRenderPass(vk, device, colorFormat));
490         const Unique<VkFramebuffer>             framebuffer                (makeFramebuffer(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), 1u));
491         const Unique<VkPipelineLayout>  pipelineLayout     (makePipelineLayout(vk, device, *descriptorSetLayout));
492         const Unique<VkCommandPool>             cmdPool                    (makeCommandPool(vk, device, queueFamilyIndex));
493         const Unique<VkCommandBuffer>   cmdBuffer                  (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
494
495         // Message explaining the test
496         {
497                 tcu::TestLog& log = m_context.getTestContext().getLog();
498                 log << tcu::TestLog::Message << m_params.message << tcu::TestLog::EndMessage;
499
500                 if (m_params.useTessLevels)
501                         log << tcu::TestLog::Message << "Tessellation levels: " << getTessellationLevelsString(m_params.tessLevels, m_params.primitiveType) << tcu::TestLog::EndMessage;
502         }
503
504         for (int pipelineNdx = 0; pipelineNdx < PIPELINE_CASES; ++pipelineNdx)
505         {
506                 const PipelineDescription& pipelineDescription = m_params.pipelineCases[pipelineNdx];
507                 GraphicsPipelineBuilder    pipelineBuilder;
508
509                 pipelineBuilder
510                         .setPrimitiveTopology             (getPrimitiveTopology(m_params.primitiveType))
511                         .setRenderSize                            (renderSize)
512                         .setBlend                                         (true)
513                         .setVertexInputSingleAttribute(vertexFormat, tcu::getPixelSize(mapVkFormat(vertexFormat)))
514                         .setPatchControlPoints            (m_params.inputPatchVertices)
515                         .setShader                                        (vk, device, VK_SHADER_STAGE_VERTEX_BIT,                                      m_context.getBinaryCollection().get("vert"), DE_NULL)
516                         .setShader                                        (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,                            m_context.getBinaryCollection().get("frag"), DE_NULL);
517
518                 if (pipelineDescription.useTessellation)
519                         pipelineBuilder
520                                 .setShader                                (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,        m_context.getBinaryCollection().get("tesc"), DE_NULL)
521                                 .setShader                                (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get(pipelineDescription.tessEvalShaderName), DE_NULL);
522
523                 if (pipelineDescription.useGeometry)
524                         pipelineBuilder
525                                 .setShader                                (vk, device, VK_SHADER_STAGE_GEOMETRY_BIT,                            m_context.getBinaryCollection().get(pipelineDescription.geomShaderName), DE_NULL);
526
527                 const Unique<VkPipeline> pipeline (pipelineBuilder.build(vk, device, *pipelineLayout, *renderPass));
528
529                 // Draw commands
530
531                 beginCommandBuffer(vk, *cmdBuffer);
532
533                 // Change color attachment image layout
534                 {
535                         // State is slightly different on the first iteration.
536                         const VkImageLayout currentLayout = (pipelineNdx == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
537                         const VkAccessFlags srcFlags      = (pipelineNdx == 0 ? (VkAccessFlags)0          : (VkAccessFlags)VK_ACCESS_TRANSFER_READ_BIT);
538
539                         const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
540                                 srcFlags, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
541                                 currentLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
542                                 *colorAttachmentImage, colorImageSubresourceRange);
543
544                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
545                                 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
546                 }
547
548                 // Begin render pass
549                 {
550                         const VkRect2D renderArea = {
551                                 makeOffset2D(0, 0),
552                                 makeExtent2D(renderSize.x(), renderSize.y()),
553                         };
554                         const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
555
556                         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
557                 }
558
559                 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
560                 {
561                         const VkDeviceSize vertexBufferOffset = 0ull;
562                         vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
563                 }
564
565                 if (m_params.useTessLevels)
566                         vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
567
568                 vk.cmdDraw(*cmdBuffer, static_cast<deUint32>(m_params.vertices.size()), 1u, 0u, 0u);
569                 endRenderPass(vk, *cmdBuffer);
570
571                 // Copy render result to a host-visible buffer
572                 {
573                         const VkImageMemoryBarrier colorAttachmentPreCopyBarrier = makeImageMemoryBarrier(
574                                 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
575                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
576                                 *colorAttachmentImage, colorImageSubresourceRange);
577
578                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
579                                 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentPreCopyBarrier);
580                 }
581                 {
582                         const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(renderSize.x(), renderSize.y(), 1), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
583                         vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer[pipelineNdx]->get(), 1u, &copyRegion);
584                 }
585                 {
586                         const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(
587                                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, colorBuffer[pipelineNdx]->get(), 0ull, colorBufferSizeBytes);
588
589                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
590                                 0u, DE_NULL, 1u, &postCopyBarrier, 0u, DE_NULL);
591                 }
592
593                 endCommandBuffer(vk, *cmdBuffer);
594                 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
595         }
596
597         // Verify results
598
599         tcu::ConstPixelBufferAccess image0 = getPixelBufferAccess(vk, device, *colorBuffer[0], colorFormat, colorBufferSizeBytes, renderSize);
600         tcu::ConstPixelBufferAccess image1 = getPixelBufferAccess(vk, device, *colorBuffer[1], colorFormat, colorBufferSizeBytes, renderSize);
601
602         const tcu::UVec4 colorThreshold    (8, 8, 8, 255);
603         const tcu::IVec3 positionDeviation (1, 1, 0);           // 3x3 search kernel
604         const bool               ignoreOutOfBounds = true;
605
606         tcu::TestLog& log = m_context.getTestContext().getLog();
607         log << tcu::TestLog::Message
608                 << "In image comparison:\n"
609                 << "  Reference - " << m_params.pipelineCases[0].description << "\n"
610                 << "  Result    - " << m_params.pipelineCases[1].description << "\n"
611                 << tcu::TestLog::EndMessage;
612
613         const bool ok = tcu::intThresholdPositionDeviationCompare(
614                 log, "ImageCompare", "Image comparison", image0, image1, colorThreshold, positionDeviation, ignoreOutOfBounds, tcu::COMPARE_LOG_RESULT);
615
616         return (ok ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Image comparison failed"));
617 }
618
619 TestInstance* IdentityGeometryShaderTestCase::createInstance (Context& context) const
620 {
621         PassthroughTestInstance::Params params;
622
623         const float level                  = 14.0;
624         params.useTessLevels       = true;
625         params.tessLevels.inner[0] = level;
626         params.tessLevels.inner[1] = level;
627         params.tessLevels.outer[0] = level;
628         params.tessLevels.outer[1] = level;
629         params.tessLevels.outer[2] = level;
630         params.tessLevels.outer[3] = level;
631
632         params.primitiveType       = m_primitiveType;
633         params.inputPatchVertices  = (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
634
635         params.vertices.push_back(tcu::Vec4( -0.9f, -0.9f, 0.0f, 1.0f ));
636         params.vertices.push_back(tcu::Vec4( -0.9f,  0.9f, 0.0f, 1.0f ));
637         params.vertices.push_back(tcu::Vec4(  0.9f, -0.9f, 0.0f, 1.0f ));
638         params.vertices.push_back(tcu::Vec4(  0.9f,  0.9f, 0.0f, 1.0f ));
639
640         params.pipelineCases[0].useTessellation         = true;
641         params.pipelineCases[0].useGeometry                     = true;
642         params.pipelineCases[0].tessEvalShaderName      = "tese_to_geom";
643         params.pipelineCases[0].geomShaderName          = "geom";
644         params.pipelineCases[0].description                     = "passthrough geometry shader";
645
646         params.pipelineCases[1].useTessellation         = true;
647         params.pipelineCases[1].useGeometry                     = false;
648         params.pipelineCases[1].tessEvalShaderName      = "tese_to_frag";
649         params.pipelineCases[1].geomShaderName          = "geom";
650         params.pipelineCases[1].description                     = "no geometry shader in the pipeline";
651
652         params.message = "Testing tessellating shader program output does not change when a passthrough geometry shader is attached.\n"
653                                          "Rendering two images, first with and second without a geometry shader. Expecting similar results.\n"
654                                          "Using additive blending to detect overlap.\n";
655
656         return new PassthroughTestInstance(context, params);
657 };
658
659 TestInstance* IdentityTessellationShaderTestCase::createInstance (Context& context) const
660 {
661         PassthroughTestInstance::Params params;
662
663         params.useTessLevels       = false;
664         params.primitiveType       = m_primitiveType;
665         params.inputPatchVertices  = (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 2);
666
667         params.vertices.push_back(        tcu::Vec4( -0.4f,  0.4f, 0.0f, 1.0f ));
668         params.vertices.push_back(        tcu::Vec4(  0.0f, -0.5f, 0.0f, 1.0f ));
669         if (params.inputPatchVertices == 3)
670                 params.vertices.push_back(tcu::Vec4(  0.4f,  0.4f, 0.0f, 1.0f ));
671
672         params.pipelineCases[0].useTessellation         = true;
673         params.pipelineCases[0].useGeometry                     = true;
674         params.pipelineCases[0].tessEvalShaderName      = "tese";
675         params.pipelineCases[0].geomShaderName          = "geom_from_tese";
676         params.pipelineCases[0].description                     = "passthrough tessellation shaders";
677
678         params.pipelineCases[1].useTessellation         = false;
679         params.pipelineCases[1].useGeometry                     = true;
680         params.pipelineCases[1].tessEvalShaderName      = "tese";
681         params.pipelineCases[1].geomShaderName          = "geom_from_vert";
682         params.pipelineCases[1].description                     = "no tessellation shaders in the pipeline";
683
684         params.message = "Testing geometry shading shader program output does not change when a passthrough tessellation shader is attached.\n"
685                                          "Rendering two images, first with and second without a tessellation shader. Expecting similar results.\n"
686                                          "Using additive blending to detect overlap.\n";
687
688         return new PassthroughTestInstance(context, params);
689 };
690
691 inline TestCase* makeIdentityGeometryShaderCase (tcu::TestContext& testCtx, const TessPrimitiveType primitiveType)
692 {
693         return new IdentityGeometryShaderTestCase(
694                 testCtx,
695                 "tessellate_" + de::toString(getTessPrimitiveTypeShaderName(primitiveType)) + "_passthrough_geometry_no_change",
696                 "Passthrough geometry shader has no effect",
697                 primitiveType);
698 }
699
700 inline TestCase* makeIdentityTessellationShaderCase (tcu::TestContext& testCtx, const TessPrimitiveType primitiveType)
701 {
702         return new IdentityTessellationShaderTestCase(
703                 testCtx,
704                 "passthrough_tessellation_geometry_shade_" + de::toString(getTessPrimitiveTypeShaderName(primitiveType)) + "_no_change",
705                 "Passthrough tessellation shader has no effect",
706                 primitiveType);
707 }
708
709 } // anonymous
710
711
712 //! Ported from dEQP-GLES31.functional.tessellation_geometry_interaction.render.passthrough.*
713 tcu::TestCaseGroup* createGeometryPassthroughTests (tcu::TestContext& testCtx)
714 {
715         de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "passthrough", "Render various types with either passthrough geometry or tessellation shader"));
716
717         // Passthrough geometry shader
718         group->addChild(makeIdentityGeometryShaderCase(testCtx, TESSPRIMITIVETYPE_TRIANGLES));
719         group->addChild(makeIdentityGeometryShaderCase(testCtx, TESSPRIMITIVETYPE_QUADS));
720         group->addChild(makeIdentityGeometryShaderCase(testCtx, TESSPRIMITIVETYPE_ISOLINES));
721
722         // Passthrough tessellation shader
723         group->addChild(makeIdentityTessellationShaderCase(testCtx, TESSPRIMITIVETYPE_TRIANGLES));
724         group->addChild(makeIdentityTessellationShaderCase(testCtx, TESSPRIMITIVETYPE_ISOLINES));
725
726         return group.release();
727 }
728
729 } // tessellation
730 } // vkt