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