Merge "Fix error double accounting in fuzzyCompare()" am: 0cf17c4bf8
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / tessellation / vktTessellationMiscDrawTests.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 Miscellaneous Draw Tests
23  *//*--------------------------------------------------------------------*/
24
25 #include "vktTessellationMiscDrawTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
28
29 #include "tcuTestLog.hpp"
30 #include "tcuImageIO.hpp"
31 #include "tcuTexture.hpp"
32 #include "tcuImageCompare.hpp"
33
34 #include "vkDefs.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkStrUtil.hpp"
40
41 #include "deUniquePtr.hpp"
42 #include "deStringUtil.hpp"
43
44 #include <string>
45 #include <vector>
46
47 namespace vkt
48 {
49 namespace tessellation
50 {
51
52 using namespace vk;
53
54 namespace
55 {
56
57 struct CaseDefinition
58 {
59         TessPrimitiveType       primitiveType;
60         SpacingMode                     spacingMode;
61         std::string                     referenceImagePathPrefix;       //!< without case suffix and extension (e.g. "_1.png")
62 };
63
64 inline CaseDefinition makeCaseDefinition (const TessPrimitiveType       primitiveType,
65                                                                                   const SpacingMode                     spacingMode,
66                                                                                   const std::string&            referenceImagePathPrefix)
67 {
68         CaseDefinition caseDef;
69         caseDef.primitiveType = primitiveType;
70         caseDef.spacingMode = spacingMode;
71         caseDef.referenceImagePathPrefix = referenceImagePathPrefix;
72         return caseDef;
73 }
74
75 std::vector<TessLevels> genTessLevelCases (const SpacingMode spacingMode)
76 {
77         static const TessLevels tessLevelCases[] =
78         {
79                 { { 9.0f,       9.0f    },      { 9.0f,         9.0f,   9.0f,   9.0f    } },
80                 { { 8.0f,       11.0f   },      { 13.0f,        15.0f,  18.0f,  21.0f   } },
81                 { { 17.0f,      14.0f   },      { 3.0f,         6.0f,   9.0f,   12.0f   } },
82         };
83
84         std::vector<TessLevels> resultTessLevels(DE_LENGTH_OF_ARRAY(tessLevelCases));
85
86         for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(tessLevelCases); ++tessLevelCaseNdx)
87         {
88                 TessLevels& tessLevels = resultTessLevels[tessLevelCaseNdx];
89
90                 for (int i = 0; i < 2; ++i)
91                         tessLevels.inner[i] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, tessLevelCases[tessLevelCaseNdx].inner[i]));
92
93                 for (int i = 0; i < 4; ++i)
94                         tessLevels.outer[i] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, tessLevelCases[tessLevelCaseNdx].outer[i]));
95         }
96
97         return resultTessLevels;
98 }
99
100 std::vector<tcu::Vec2> genVertexPositions (const TessPrimitiveType primitiveType)
101 {
102         std::vector<tcu::Vec2> positions;
103         positions.reserve(4);
104
105         if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
106         {
107                 positions.push_back(tcu::Vec2( 0.8f,    0.6f));
108                 positions.push_back(tcu::Vec2( 0.0f, -0.786f));
109                 positions.push_back(tcu::Vec2(-0.8f,    0.6f));
110         }
111         else if (primitiveType == TESSPRIMITIVETYPE_QUADS || primitiveType == TESSPRIMITIVETYPE_ISOLINES)
112         {
113                 positions.push_back(tcu::Vec2(-0.8f, -0.8f));
114                 positions.push_back(tcu::Vec2( 0.8f, -0.8f));
115                 positions.push_back(tcu::Vec2(-0.8f,  0.8f));
116                 positions.push_back(tcu::Vec2( 0.8f,  0.8f));
117         }
118         else
119                 DE_ASSERT(false);
120
121         return positions;
122 }
123
124 //! Common test function used by all test cases.
125 tcu::TestStatus runTest (Context& context, const CaseDefinition caseDef)
126 {
127         requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
128
129         const DeviceInterface&  vk                                      = context.getDeviceInterface();
130         const VkDevice                  device                          = context.getDevice();
131         const VkQueue                   queue                           = context.getUniversalQueue();
132         const deUint32                  queueFamilyIndex        = context.getUniversalQueueFamilyIndex();
133         Allocator&                              allocator                       = context.getDefaultAllocator();
134
135         const std::vector<TessLevels> tessLevelCases = genTessLevelCases(caseDef.spacingMode);
136         const std::vector<tcu::Vec2>  vertexData         = genVertexPositions(caseDef.primitiveType);
137         const deUint32                            inPatchSize    = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
138
139         // Vertex input: positions
140
141         const VkFormat     vertexFormat            = VK_FORMAT_R32G32_SFLOAT;
142         const deUint32     vertexStride            = tcu::getPixelSize(mapVkFormat(vertexFormat));
143         const VkDeviceSize vertexDataSizeBytes = sizeInBytes(vertexData);
144
145         const Buffer vertexBuffer(vk, device, allocator,
146                 makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
147
148         DE_ASSERT(inPatchSize == vertexData.size());
149         DE_ASSERT(sizeof(vertexData[0]) == vertexStride);
150
151         {
152                 const Allocation& alloc = vertexBuffer.getAllocation();
153                 deMemcpy(alloc.getHostPtr(), &vertexData[0], static_cast<std::size_t>(vertexDataSizeBytes));
154
155                 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), vertexDataSizeBytes);
156                 // No barrier needed, flushed memory is automatically visible
157         }
158
159         // Color attachment
160
161         const tcu::IVec2                          renderSize                             = tcu::IVec2(256, 256);
162         const VkFormat                            colorFormat                            = VK_FORMAT_R8G8B8A8_UNORM;
163         const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
164         const Image                                       colorAttachmentImage           (vk, device, allocator,
165                                                                                                                          makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
166                                                                                                                          MemoryRequirement::Any);
167
168         // Color output buffer: image will be copied here for verification
169
170         const VkDeviceSize colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
171         const Buffer       colorBuffer                  (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
172
173         // Input buffer: tessellation levels. Data is filled in later.
174
175         const Buffer tessLevelsBuffer(vk, device, allocator,
176                 makeBufferCreateInfo(sizeof(TessLevels), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
177
178         // Descriptors
179
180         const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
181                 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
182                 .build(vk, device));
183
184         const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
185                 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
186                 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
187
188         const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
189
190         const VkDescriptorBufferInfo tessLevelsBufferInfo = makeDescriptorBufferInfo(tessLevelsBuffer.get(), 0ull, sizeof(TessLevels));
191
192         DescriptorSetUpdateBuilder()
193                 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &tessLevelsBufferInfo)
194                 .update(vk, device);
195
196         // Pipeline
197
198         const Unique<VkImageView>               colorAttachmentView     (makeImageView(vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
199         const Unique<VkRenderPass>              renderPass                      (makeRenderPass(vk, device, colorFormat));
200         const Unique<VkFramebuffer>             framebuffer                     (makeFramebuffer(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), 1u));
201         const Unique<VkPipelineLayout>  pipelineLayout          (makePipelineLayout(vk, device, *descriptorSetLayout));
202         const Unique<VkCommandPool>             cmdPool                         (makeCommandPool(vk, device, queueFamilyIndex));
203         const Unique<VkCommandBuffer>   cmdBuffer                       (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
204
205         const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder()
206                 .setRenderSize                            (renderSize)
207                 .setVertexInputSingleAttribute(vertexFormat, vertexStride)
208                 .setPatchControlPoints            (inPatchSize)
209                 .setShader                                        (vk, device, VK_SHADER_STAGE_VERTEX_BIT,                                      context.getBinaryCollection().get("vert"), DE_NULL)
210                 .setShader                                        (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,        context.getBinaryCollection().get("tesc"), DE_NULL)
211                 .setShader                                        (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"), DE_NULL)
212                 .setShader                                        (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,                            context.getBinaryCollection().get("frag"), DE_NULL)
213                 .build                                            (vk, device, *pipelineLayout, *renderPass));
214
215         // Draw commands
216
217         deUint32 numPassedCases = 0;
218
219         for (deUint32 tessLevelCaseNdx = 0; tessLevelCaseNdx < tessLevelCases.size(); ++tessLevelCaseNdx)
220         {
221                 context.getTestContext().getLog()
222                         << tcu::TestLog::Message
223                         << "Tessellation levels: " << getTessellationLevelsString(tessLevelCases[tessLevelCaseNdx], caseDef.primitiveType)
224                         << tcu::TestLog::EndMessage;
225
226                 // Upload tessellation levels data to the input buffer
227                 {
228                         const Allocation& alloc = tessLevelsBuffer.getAllocation();
229                         TessLevels* const bufferTessLevels = static_cast<TessLevels*>(alloc.getHostPtr());
230                         *bufferTessLevels = tessLevelCases[tessLevelCaseNdx];
231                         flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), sizeof(TessLevels));
232                 }
233
234                 // Reset the command buffer and begin recording.
235                 beginCommandBuffer(vk, *cmdBuffer);
236
237                 // Change color attachment image layout
238                 {
239                         // State is slightly different on the first iteration.
240                         const VkImageLayout currentLayout = (tessLevelCaseNdx == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
241                         const VkAccessFlags srcFlags      = (tessLevelCaseNdx == 0 ? (VkAccessFlags)0 : (VkAccessFlags)VK_ACCESS_TRANSFER_READ_BIT);
242
243                         const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
244                                 srcFlags, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
245                                 currentLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
246                                 *colorAttachmentImage, colorImageSubresourceRange);
247
248                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
249                                 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
250                 }
251
252                 // Begin render pass
253                 {
254                         const VkRect2D renderArea = {
255                                 makeOffset2D(0, 0),
256                                 makeExtent2D(renderSize.x(), renderSize.y()),
257                         };
258                         const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
259
260                         beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
261                 }
262
263                 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
264                 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
265                 {
266                         const VkDeviceSize vertexBufferOffset = 0ull;
267                         vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
268                 }
269
270                 // Process enough vertices to make a patch.
271                 vk.cmdDraw(*cmdBuffer, inPatchSize, 1u, 0u, 0u);
272                 endRenderPass(vk, *cmdBuffer);
273
274                 // Copy render result to a host-visible buffer
275                 {
276                         const VkImageMemoryBarrier colorAttachmentPreCopyBarrier = makeImageMemoryBarrier(
277                                 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
278                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
279                                 *colorAttachmentImage, colorImageSubresourceRange);
280
281                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
282                                 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentPreCopyBarrier);
283                 }
284                 {
285                         const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(renderSize.x(), renderSize.y(), 1), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
286                         vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, &copyRegion);
287                 }
288                 {
289                         const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(
290                                 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, colorBufferSizeBytes);
291
292                         vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
293                                 0u, DE_NULL, 1u, &postCopyBarrier, 0u, DE_NULL);
294                 }
295
296                 endCommandBuffer(vk, *cmdBuffer);
297                 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
298
299                 {
300                         const Allocation& colorBufferAlloc = colorBuffer.getAllocation();
301                         invalidateMappedMemoryRange(vk, device, colorBufferAlloc.getMemory(), colorBufferAlloc.getOffset(), colorBufferSizeBytes);
302
303                         // Verify case result
304                         const tcu::ConstPixelBufferAccess resultImageAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc.getHostPtr());
305
306                         // Load reference image
307                         const std::string referenceImagePath = caseDef.referenceImagePathPrefix + "_" + de::toString(tessLevelCaseNdx) + ".png";
308                         tcu::TextureLevel referenceImage;
309                         tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), referenceImagePath.c_str());
310
311                         if (tcu::fuzzyCompare(context.getTestContext().getLog(), "ImageComparison", "Image Comparison",
312                                                                   referenceImage.getAccess(), resultImageAccess, 0.002f, tcu::COMPARE_LOG_RESULT))
313                                 ++numPassedCases;
314                 }
315         } // tessLevelCaseNdx
316
317         return (numPassedCases == tessLevelCases.size() ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
318 }
319
320 inline const char* getTessLevelsSSBODeclaration (void)
321 {
322         return  "layout(set = 0, binding = 0, std430) readonly restrict buffer TessLevels {\n"
323                         "    float inner0;\n"
324                         "    float inner1;\n"
325                         "    float outer0;\n"
326                         "    float outer1;\n"
327                         "    float outer2;\n"
328                         "    float outer3;\n"
329                         "} sb_levels;\n";
330 }
331
332 //! Add vertex, fragment, and tessellation control shaders.
333 void initCommonPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
334 {
335         DE_ASSERT(!programCollection.glslSources.contains("vert"));
336         DE_ASSERT(!programCollection.glslSources.contains("tesc"));
337         DE_ASSERT(!programCollection.glslSources.contains("frag"));
338
339         // Vertex shader
340         {
341                 std::ostringstream src;
342                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
343                         << "\n"
344                         << "layout(location = 0) in  highp vec2 in_v_position;\n"
345                         << "layout(location = 0) out highp vec2 in_tc_position;\n"
346                         << "\n"
347                         << "void main (void)\n"
348                         << "{\n"
349                         << "    in_tc_position = in_v_position;\n"
350                         << "}\n";
351
352                 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
353         }
354
355         // Tessellation control shader
356         {
357                 const int numVertices = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
358
359                 std::ostringstream src;
360                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
361                         << "#extension GL_EXT_tessellation_shader : require\n"
362                         << "\n"
363                         << "layout(vertices = " << numVertices << ") out;\n"
364                         << "\n"
365                         << getTessLevelsSSBODeclaration()
366                         << "\n"
367                         << "layout(location = 0) in  highp vec2 in_tc_position[];\n"
368                         << "layout(location = 0) out highp vec2 in_te_position[];\n"
369                         << "\n"
370                         << "void main (void)\n"
371                         << "{\n"
372                         << "    in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
373                         << "\n"
374                         << "    gl_TessLevelInner[0] = sb_levels.inner0;\n"
375                         << "    gl_TessLevelInner[1] = sb_levels.inner1;\n"
376                         << "\n"
377                         << "    gl_TessLevelOuter[0] = sb_levels.outer0;\n"
378                         << "    gl_TessLevelOuter[1] = sb_levels.outer1;\n"
379                         << "    gl_TessLevelOuter[2] = sb_levels.outer2;\n"
380                         << "    gl_TessLevelOuter[3] = sb_levels.outer3;\n"
381                         << "}\n";
382
383                 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
384         }
385
386         // Fragment shader
387         {
388                 std::ostringstream src;
389                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
390                         << "\n"
391                         << "layout(location = 0) in  highp   vec4 in_f_color;\n"
392                         << "layout(location = 0) out mediump vec4 o_color;\n"
393                         << "\n"
394                         << "void main (void)\n"
395                         << "{\n"
396                         << "    o_color = in_f_color;\n"
397                         << "}\n";
398
399                 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
400         }
401 }
402
403 void initProgramsFillCoverCase (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
404 {
405         DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
406
407         initCommonPrograms(programCollection, caseDef);
408
409         // Tessellation evaluation shader
410         {
411                 std::ostringstream src;
412                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
413                         << "#extension GL_EXT_tessellation_shader : require\n"
414                         << "\n"
415                         << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
416                                                  << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
417                         << "\n"
418                         << "layout(location = 0) in  highp vec2 in_te_position[];\n"
419                         << "layout(location = 0) out highp vec4 in_f_color;\n"
420                         << "\n"
421                         << "void main (void)\n"
422                         << "{\n"
423                         <<      (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
424                                         "    highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
425                                         "    highp vec2 corner0 = in_te_position[0];\n"
426                                         "    highp vec2 corner1 = in_te_position[1];\n"
427                                         "    highp vec2 corner2 = in_te_position[2];\n"
428                                         "    highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
429                                         "    highp vec2 fromCenter = pos - (corner0 + corner1 + corner2) / 3.0;\n"
430                                         "    highp float f = (1.0 - length(fromCenter)) * (1.5 - d);\n"
431                                         "    pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
432                                         "    gl_Position = vec4(pos, 0.0, 1.0);\n"
433                                 : caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
434                                         "    highp vec2 corner0 = in_te_position[0];\n"
435                                         "    highp vec2 corner1 = in_te_position[1];\n"
436                                         "    highp vec2 corner2 = in_te_position[2];\n"
437                                         "    highp vec2 corner3 = in_te_position[3];\n"
438                                         "    highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
439                                         "                   + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
440                                         "                   + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
441                                         "                   + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
442                                         "    highp float d = 2.0 * min(abs(gl_TessCoord.x-0.5), abs(gl_TessCoord.y-0.5));\n"
443                                         "    highp vec2 fromCenter = pos - (corner0 + corner1 + corner2 + corner3) / 4.0;\n"
444                                         "    highp float f = (1.0 - length(fromCenter)) * sqrt(1.7 - d);\n"
445                                         "    pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
446                                         "    gl_Position = vec4(pos, 0.0, 1.0);\n"
447                                 : "")
448                         << "    in_f_color = vec4(1.0);\n"
449                         << "}\n";
450
451                 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
452         }
453 }
454
455 void initProgramsFillNonOverlapCase (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
456 {
457         DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
458
459         initCommonPrograms(programCollection, caseDef);
460
461         // Tessellation evaluation shader
462         {
463                 std::ostringstream src;
464                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
465                         << "#extension GL_EXT_tessellation_shader : require\n"
466                         << "\n"
467                         << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
468                                                  << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
469                         << "\n"
470                         << getTessLevelsSSBODeclaration()
471                         << "\n"
472                         << "layout(location = 0) in  highp vec2 in_te_position[];\n"
473                         << "layout(location = 0) out highp vec4 in_f_color;\n"
474                         << "\n"
475                         << "void main (void)\n"
476                         << "{\n"
477                         <<      (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
478                                         "    highp vec2 corner0 = in_te_position[0];\n"
479                                         "    highp vec2 corner1 = in_te_position[1];\n"
480                                         "    highp vec2 corner2 = in_te_position[2];\n"
481                                         "    highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
482                                         "    gl_Position = vec4(pos, 0.0, 1.0);\n"
483                                         "    highp int numConcentricTriangles = int(round(sb_levels.inner0)) / 2 + 1;\n"
484                                         "    highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
485                                         "    highp int phase = int(d*float(numConcentricTriangles)) % 3;\n"
486                                         "    in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
487                                         "               : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
488                                         "               :              vec4(0.0, 0.0, 1.0, 1.0);\n"
489                                 : caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
490                                         "    highp vec2 corner0 = in_te_position[0];\n"
491                                         "    highp vec2 corner1 = in_te_position[1];\n"
492                                         "    highp vec2 corner2 = in_te_position[2];\n"
493                                         "    highp vec2 corner3 = in_te_position[3];\n"
494                                         "    highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
495                                         "                   + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
496                                         "                   + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
497                                         "                   + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
498                                         "    gl_Position = vec4(pos, 0.0, 1.0);\n"
499                                         "    highp int phaseX = int(round((0.5 - abs(gl_TessCoord.x-0.5)) * sb_levels.inner0));\n"
500                                         "    highp int phaseY = int(round((0.5 - abs(gl_TessCoord.y-0.5)) * sb_levels.inner1));\n"
501                                         "    highp int phase = min(phaseX, phaseY) % 3;\n"
502                                         "    in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
503                                         "               : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
504                                         "               :              vec4(0.0, 0.0, 1.0, 1.0);\n"
505                                         : "")
506                         << "}\n";
507
508                 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
509         }
510 }
511
512 void initProgramsIsolinesCase (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
513 {
514         DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_ISOLINES);
515
516         initCommonPrograms(programCollection, caseDef);
517
518         // Tessellation evaluation shader
519         {
520                 std::ostringstream src;
521                 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
522                         << "#extension GL_EXT_tessellation_shader : require\n"
523                         << "\n"
524                         << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
525                                                  << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
526                         << "\n"
527                         << getTessLevelsSSBODeclaration()
528                         << "\n"
529                         << "layout(location = 0) in  highp vec2 in_te_position[];\n"
530                         << "layout(location = 0) out highp vec4 in_f_color;\n"
531                         << "\n"
532                         << "void main (void)\n"
533                         << "{\n"
534                         << "    highp vec2 corner0 = in_te_position[0];\n"
535                         << "    highp vec2 corner1 = in_te_position[1];\n"
536                         << "    highp vec2 corner2 = in_te_position[2];\n"
537                         << "    highp vec2 corner3 = in_te_position[3];\n"
538                         << "    highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
539                         << "                   + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
540                         << "                   + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
541                         << "                   + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
542                         << "    pos.y += 0.15*sin(gl_TessCoord.x*10.0);\n"
543                         << "    gl_Position = vec4(pos, 0.0, 1.0);\n"
544                         << "    highp int phaseX = int(round(gl_TessCoord.x*sb_levels.outer1));\n"
545                         << "    highp int phaseY = int(round(gl_TessCoord.y*sb_levels.outer0));\n"
546                         << "    highp int phase = (phaseX + phaseY) % 3;\n"
547                         << "    in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
548                         << "               : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
549                         << "               :              vec4(0.0, 0.0, 1.0, 1.0);\n"
550                         << "}\n";
551
552                 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
553         }
554 }
555
556 inline std::string getReferenceImagePathPrefix (const std::string& caseName)
557 {
558         return "vulkan/data/tessellation/" + caseName + "_ref";
559 }
560
561 } // anonymous
562
563 //! These tests correspond to dEQP-GLES31.functional.tessellation.misc_draw.*
564 tcu::TestCaseGroup* createMiscDrawTests (tcu::TestContext& testCtx)
565 {
566         de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "misc_draw", "Miscellaneous draw-result-verifying cases"));
567
568         static const TessPrimitiveType primitivesNoIsolines[] =
569         {
570                 TESSPRIMITIVETYPE_TRIANGLES,
571                 TESSPRIMITIVETYPE_QUADS,
572         };
573
574         // Triangle fill case
575         for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
576         for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
577         {
578                 const TessPrimitiveType primitiveType = primitivesNoIsolines[primitiveTypeNdx];
579                 const SpacingMode               spacingMode       = static_cast<SpacingMode>(spacingModeNdx);
580                 const std::string               caseName          = std::string() + "fill_cover_" + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getSpacingModeShaderName(spacingMode);
581
582                 addFunctionCaseWithPrograms(group.get(), caseName, "Check that there are no obvious gaps in the triangle-filled area of a tessellated shape",
583                                                                         initProgramsFillCoverCase, runTest, makeCaseDefinition(primitiveType, spacingMode, getReferenceImagePathPrefix(caseName)));
584         }
585
586         // Triangle non-overlap case
587         for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
588         for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
589         {
590                 const TessPrimitiveType primitiveType = primitivesNoIsolines[primitiveTypeNdx];
591                 const SpacingMode               spacingMode       = static_cast<SpacingMode>(spacingModeNdx);
592                 const std::string               caseName          = std::string() + "fill_overlap_" + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getSpacingModeShaderName(spacingMode);
593
594                 addFunctionCaseWithPrograms(group.get(), caseName, "Check that there are no obvious triangle overlaps in the triangle-filled area of a tessellated shape",
595                                                                         initProgramsFillNonOverlapCase, runTest, makeCaseDefinition(primitiveType, spacingMode, getReferenceImagePathPrefix(caseName)));
596         }
597
598         // Isolines
599         for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
600         {
601                 const SpacingMode spacingMode = static_cast<SpacingMode>(spacingModeNdx);
602                 const std::string caseName    = std::string() + "isolines_" + getSpacingModeShaderName(spacingMode);
603
604                 addFunctionCaseWithPrograms(group.get(), caseName, "Basic isolines render test",
605                                                                         initProgramsIsolinesCase, runTest, makeCaseDefinition(TESSPRIMITIVETYPE_ISOLINES, spacingMode, getReferenceImagePathPrefix(caseName)));
606         }
607
608         return group.release();
609 }
610
611 } // tessellation
612 } // vkt