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 #include "vkBufferWithMemory.hpp"
44 #include "vkImageWithMemory.hpp"
45
46 #include "deUniquePtr.hpp"
47 #include "deStringUtil.hpp"
48
49 #include <string>
50 #include <vector>
51 #include <utility>
52
53 namespace vkt
54 {
55 namespace tessellation
56 {
57
58 using namespace vk;
59
60 namespace
61 {
62
63 struct CaseDefinition
64 {
65 TessPrimitiveType primitiveType;
66 SpacingMode spacingMode;
67 std::string referenceImagePathPrefix; //!< without case suffix and extension (e.g. "_1.png")
68 };
69
makeCaseDefinition(const TessPrimitiveType primitiveType,const SpacingMode spacingMode,const std::string & referenceImagePathPrefix)70 inline CaseDefinition makeCaseDefinition (const TessPrimitiveType primitiveType,
71 const SpacingMode spacingMode,
72 const std::string& referenceImagePathPrefix)
73 {
74 CaseDefinition caseDef;
75 caseDef.primitiveType = primitiveType;
76 caseDef.spacingMode = spacingMode;
77 caseDef.referenceImagePathPrefix = referenceImagePathPrefix;
78 return caseDef;
79 }
80
genTessLevelCases(const SpacingMode spacingMode)81 std::vector<TessLevels> genTessLevelCases (const SpacingMode spacingMode)
82 {
83 static const TessLevels tessLevelCases[] =
84 {
85 { { 9.0f, 9.0f }, { 9.0f, 9.0f, 9.0f, 9.0f } },
86 { { 8.0f, 11.0f }, { 13.0f, 15.0f, 18.0f, 21.0f } },
87 { { 17.0f, 14.0f }, { 3.0f, 6.0f, 9.0f, 12.0f } },
88 };
89
90 std::vector<TessLevels> resultTessLevels(DE_LENGTH_OF_ARRAY(tessLevelCases));
91
92 for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(tessLevelCases); ++tessLevelCaseNdx)
93 {
94 TessLevels& tessLevels = resultTessLevels[tessLevelCaseNdx];
95
96 for (int i = 0; i < 2; ++i)
97 tessLevels.inner[i] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, tessLevelCases[tessLevelCaseNdx].inner[i]));
98
99 for (int i = 0; i < 4; ++i)
100 tessLevels.outer[i] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, tessLevelCases[tessLevelCaseNdx].outer[i]));
101 }
102
103 return resultTessLevels;
104 }
105
genVertexPositions(const TessPrimitiveType primitiveType)106 std::vector<tcu::Vec2> genVertexPositions (const TessPrimitiveType primitiveType)
107 {
108 std::vector<tcu::Vec2> positions;
109 positions.reserve(4);
110
111 if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
112 {
113 positions.push_back(tcu::Vec2( 0.8f, 0.6f));
114 positions.push_back(tcu::Vec2( 0.0f, -0.786f));
115 positions.push_back(tcu::Vec2(-0.8f, 0.6f));
116 }
117 else if (primitiveType == TESSPRIMITIVETYPE_QUADS || primitiveType == TESSPRIMITIVETYPE_ISOLINES)
118 {
119 positions.push_back(tcu::Vec2(-0.8f, -0.8f));
120 positions.push_back(tcu::Vec2( 0.8f, -0.8f));
121 positions.push_back(tcu::Vec2(-0.8f, 0.8f));
122 positions.push_back(tcu::Vec2( 0.8f, 0.8f));
123 }
124 else
125 DE_ASSERT(false);
126
127 return positions;
128 }
129
130 //! Common test function used by all test cases.
runTest(Context & context,const CaseDefinition caseDef)131 tcu::TestStatus runTest (Context& context, const CaseDefinition caseDef)
132 {
133 requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
134
135 const DeviceInterface& vk = context.getDeviceInterface();
136 const VkDevice device = context.getDevice();
137 const VkQueue queue = context.getUniversalQueue();
138 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex();
139 Allocator& allocator = context.getDefaultAllocator();
140
141 const std::vector<TessLevels> tessLevelCases = genTessLevelCases(caseDef.spacingMode);
142 const std::vector<tcu::Vec2> vertexData = genVertexPositions(caseDef.primitiveType);
143 const deUint32 inPatchSize = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
144
145 // Vertex input: positions
146
147 const VkFormat vertexFormat = VK_FORMAT_R32G32_SFLOAT;
148 const deUint32 vertexStride = tcu::getPixelSize(mapVkFormat(vertexFormat));
149 const VkDeviceSize vertexDataSizeBytes = sizeInBytes(vertexData);
150
151 const BufferWithMemory vertexBuffer(vk, device, allocator,
152 makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
153
154 DE_ASSERT(inPatchSize == vertexData.size());
155 DE_ASSERT(sizeof(vertexData[0]) == vertexStride);
156
157 {
158 const Allocation& alloc = vertexBuffer.getAllocation();
159
160 deMemcpy(alloc.getHostPtr(), &vertexData[0], static_cast<std::size_t>(vertexDataSizeBytes));
161 flushAlloc(vk, device, alloc);
162 // No barrier needed, flushed memory is automatically visible
163 }
164
165 // Color attachment
166
167 const tcu::IVec2 renderSize = tcu::IVec2(256, 256);
168 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
169 const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
170 const ImageWithMemory colorAttachmentImage (vk, device, allocator,
171 makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
172 MemoryRequirement::Any);
173
174 // Color output buffer: image will be copied here for verification
175
176 const VkDeviceSize colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
177 const BufferWithMemory colorBuffer (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
178
179 // Input buffer: tessellation levels. Data is filled in later.
180
181 const BufferWithMemory tessLevelsBuffer(vk, device, allocator,
182 makeBufferCreateInfo(sizeof(TessLevels), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
183
184 // Descriptors
185
186 const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
187 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
188 .build(vk, device));
189
190 const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
191 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
192 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
193
194 const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
195
196 const VkDescriptorBufferInfo tessLevelsBufferInfo = makeDescriptorBufferInfo(tessLevelsBuffer.get(), 0ull, sizeof(TessLevels));
197
198 DescriptorSetUpdateBuilder()
199 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &tessLevelsBufferInfo)
200 .update(vk, device);
201
202 // Pipeline
203
204 const Unique<VkImageView> colorAttachmentView (makeImageView(vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
205 const Unique<VkRenderPass> renderPass (makeRenderPass(vk, device, colorFormat));
206 const Unique<VkFramebuffer> framebuffer (makeFramebuffer(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y()));
207 const Unique<VkPipelineLayout> pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout));
208 const Unique<VkCommandPool> cmdPool (makeCommandPool(vk, device, queueFamilyIndex));
209 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
210
211 const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder()
212 .setRenderSize (renderSize)
213 .setVertexInputSingleAttribute(vertexFormat, vertexStride)
214 .setPatchControlPoints (inPatchSize)
215 .setShader (vk, device, VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"), DE_NULL)
216 .setShader (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, context.getBinaryCollection().get("tesc"), DE_NULL)
217 .setShader (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"), DE_NULL)
218 .setShader (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"), DE_NULL)
219 .build (vk, device, *pipelineLayout, *renderPass));
220
221 // Draw commands
222
223 deUint32 numPassedCases = 0;
224
225 for (deUint32 tessLevelCaseNdx = 0; tessLevelCaseNdx < tessLevelCases.size(); ++tessLevelCaseNdx)
226 {
227 context.getTestContext().getLog()
228 << tcu::TestLog::Message
229 << "Tessellation levels: " << getTessellationLevelsString(tessLevelCases[tessLevelCaseNdx], caseDef.primitiveType)
230 << tcu::TestLog::EndMessage;
231
232 // Upload tessellation levels data to the input buffer
233 {
234 const Allocation& alloc = tessLevelsBuffer.getAllocation();
235 TessLevels* const bufferTessLevels = static_cast<TessLevels*>(alloc.getHostPtr());
236
237 *bufferTessLevels = tessLevelCases[tessLevelCaseNdx];
238 flushAlloc(vk, device, alloc);
239 }
240
241 // Reset the command buffer and begin recording.
242 beginCommandBuffer(vk, *cmdBuffer);
243
244 // Change color attachment image layout
245 {
246 // State is slightly different on the first iteration.
247 const VkImageLayout currentLayout = (tessLevelCaseNdx == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
248 const VkAccessFlags srcFlags = (tessLevelCaseNdx == 0 ? (VkAccessFlags)0 : (VkAccessFlags)VK_ACCESS_TRANSFER_READ_BIT);
249
250 const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
251 srcFlags, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
252 currentLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
253 *colorAttachmentImage, colorImageSubresourceRange);
254
255 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
256 0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
257 }
258
259 // Begin render pass
260 {
261 const VkRect2D renderArea = makeRect2D(renderSize);
262 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f);
263
264 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
265 }
266
267 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
268 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
269 {
270 const VkDeviceSize vertexBufferOffset = 0ull;
271 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
272 }
273
274 // Process enough vertices to make a patch.
275 vk.cmdDraw(*cmdBuffer, inPatchSize, 1u, 0u, 0u);
276 endRenderPass(vk, *cmdBuffer);
277
278 // Copy render result to a host-visible buffer
279 copyImageToBuffer(vk, *cmdBuffer, *colorAttachmentImage, *colorBuffer, renderSize);
280
281 endCommandBuffer(vk, *cmdBuffer);
282 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
283
284 {
285 const Allocation& colorBufferAlloc = colorBuffer.getAllocation();
286
287 invalidateAlloc(vk, device, colorBufferAlloc);
288
289 // Verify case result
290 const tcu::ConstPixelBufferAccess resultImageAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc.getHostPtr());
291
292 // Load reference image
293 const std::string referenceImagePath = caseDef.referenceImagePathPrefix + "_" + de::toString(tessLevelCaseNdx) + ".png";
294
295 tcu::TextureLevel referenceImage;
296 tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), referenceImagePath.c_str());
297
298 if (tcu::fuzzyCompare(context.getTestContext().getLog(), "ImageComparison", "Image Comparison",
299 referenceImage.getAccess(), resultImageAccess, 0.002f, tcu::COMPARE_LOG_RESULT))
300 ++numPassedCases;
301 }
302 } // tessLevelCaseNdx
303
304 return (numPassedCases == tessLevelCases.size() ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
305 }
306
getTessLevelsSSBODeclaration(void)307 inline const char* getTessLevelsSSBODeclaration (void)
308 {
309 return "layout(set = 0, binding = 0, std430) readonly restrict buffer TessLevels {\n"
310 " float inner0;\n"
311 " float inner1;\n"
312 " float outer0;\n"
313 " float outer1;\n"
314 " float outer2;\n"
315 " float outer3;\n"
316 "} sb_levels;\n";
317 }
318
319 //! Add vertex, fragment, and tessellation control shaders.
initCommonPrograms(vk::SourceCollections & programCollection,const CaseDefinition caseDef)320 void initCommonPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
321 {
322 DE_ASSERT(!programCollection.glslSources.contains("vert"));
323 DE_ASSERT(!programCollection.glslSources.contains("tesc"));
324 DE_ASSERT(!programCollection.glslSources.contains("frag"));
325
326 // Vertex shader
327 {
328 std::ostringstream src;
329 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
330 << "\n"
331 << "layout(location = 0) in highp vec2 in_v_position;\n"
332 << "layout(location = 0) out highp vec2 in_tc_position;\n"
333 << "\n"
334 << "void main (void)\n"
335 << "{\n"
336 << " in_tc_position = in_v_position;\n"
337 << "}\n";
338
339 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
340 }
341
342 // Tessellation control shader
343 {
344 const int numVertices = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
345
346 std::ostringstream src;
347 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
348 << "#extension GL_EXT_tessellation_shader : require\n"
349 << "\n"
350 << "layout(vertices = " << numVertices << ") out;\n"
351 << "\n"
352 << getTessLevelsSSBODeclaration()
353 << "\n"
354 << "layout(location = 0) in highp vec2 in_tc_position[];\n"
355 << "layout(location = 0) out highp vec2 in_te_position[];\n"
356 << "\n"
357 << "void main (void)\n"
358 << "{\n"
359 << " in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
360 << "\n"
361 << " gl_TessLevelInner[0] = sb_levels.inner0;\n"
362 << " gl_TessLevelInner[1] = sb_levels.inner1;\n"
363 << "\n"
364 << " gl_TessLevelOuter[0] = sb_levels.outer0;\n"
365 << " gl_TessLevelOuter[1] = sb_levels.outer1;\n"
366 << " gl_TessLevelOuter[2] = sb_levels.outer2;\n"
367 << " gl_TessLevelOuter[3] = sb_levels.outer3;\n"
368 << "}\n";
369
370 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
371 }
372
373 // Fragment shader
374 {
375 std::ostringstream src;
376 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
377 << "\n"
378 << "layout(location = 0) in highp vec4 in_f_color;\n"
379 << "layout(location = 0) out mediump vec4 o_color;\n"
380 << "\n"
381 << "void main (void)\n"
382 << "{\n"
383 << " o_color = in_f_color;\n"
384 << "}\n";
385
386 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
387 }
388 }
389
initProgramsFillCoverCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)390 void initProgramsFillCoverCase (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
391 {
392 DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
393
394 initCommonPrograms(programCollection, caseDef);
395
396 // Tessellation evaluation shader
397 {
398 std::ostringstream src;
399 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
400 << "#extension GL_EXT_tessellation_shader : require\n"
401 << "\n"
402 << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
403 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
404 << "\n"
405 << "layout(location = 0) in highp vec2 in_te_position[];\n"
406 << "layout(location = 0) out highp vec4 in_f_color;\n"
407 << "\n"
408 << "void main (void)\n"
409 << "{\n"
410 << (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
411 " highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
412 " highp vec2 corner0 = in_te_position[0];\n"
413 " highp vec2 corner1 = in_te_position[1];\n"
414 " highp vec2 corner2 = in_te_position[2];\n"
415 " highp vec2 pos = corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
416 " highp vec2 fromCenter = pos - (corner0 + corner1 + corner2) / 3.0;\n"
417 " highp float f = (1.0 - length(fromCenter)) * (1.5 - d);\n"
418 " pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
419 " gl_Position = vec4(pos, 0.0, 1.0);\n"
420 : caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
421 " highp vec2 corner0 = in_te_position[0];\n"
422 " highp vec2 corner1 = in_te_position[1];\n"
423 " highp vec2 corner2 = in_te_position[2];\n"
424 " highp vec2 corner3 = in_te_position[3];\n"
425 " highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
426 " + ( gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
427 " + (1.0-gl_TessCoord.x)*( gl_TessCoord.y)*corner2\n"
428 " + ( gl_TessCoord.x)*( gl_TessCoord.y)*corner3;\n"
429 " highp float d = 2.0 * min(abs(gl_TessCoord.x-0.5), abs(gl_TessCoord.y-0.5));\n"
430 " highp vec2 fromCenter = pos - (corner0 + corner1 + corner2 + corner3) / 4.0;\n"
431 " highp float f = (1.0 - length(fromCenter)) * sqrt(1.7 - d);\n"
432 " pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
433 " gl_Position = vec4(pos, 0.0, 1.0);\n"
434 : "")
435 << " in_f_color = vec4(1.0);\n"
436 << "}\n";
437
438 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
439 }
440 }
441
initProgramsFillNonOverlapCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)442 void initProgramsFillNonOverlapCase (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
443 {
444 DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
445
446 initCommonPrograms(programCollection, caseDef);
447
448 // Tessellation evaluation shader
449 {
450 std::ostringstream src;
451 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
452 << "#extension GL_EXT_tessellation_shader : require\n"
453 << "\n"
454 << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
455 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
456 << "\n"
457 << getTessLevelsSSBODeclaration()
458 << "\n"
459 << "layout(location = 0) in highp vec2 in_te_position[];\n"
460 << "layout(location = 0) out highp vec4 in_f_color;\n"
461 << "\n"
462 << "void main (void)\n"
463 << "{\n"
464 << (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
465 " highp vec2 corner0 = in_te_position[0];\n"
466 " highp vec2 corner1 = in_te_position[1];\n"
467 " highp vec2 corner2 = in_te_position[2];\n"
468 " highp vec2 pos = corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
469 " gl_Position = vec4(pos, 0.0, 1.0);\n"
470 " highp int numConcentricTriangles = int(round(sb_levels.inner0)) / 2 + 1;\n"
471 " highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
472 " highp int phase = int(d*float(numConcentricTriangles)) % 3;\n"
473 " in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
474 " : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
475 " : vec4(0.0, 0.0, 1.0, 1.0);\n"
476 : caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
477 " highp vec2 corner0 = in_te_position[0];\n"
478 " highp vec2 corner1 = in_te_position[1];\n"
479 " highp vec2 corner2 = in_te_position[2];\n"
480 " highp vec2 corner3 = in_te_position[3];\n"
481 " highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
482 " + ( gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
483 " + (1.0-gl_TessCoord.x)*( gl_TessCoord.y)*corner2\n"
484 " + ( gl_TessCoord.x)*( gl_TessCoord.y)*corner3;\n"
485 " gl_Position = vec4(pos, 0.0, 1.0);\n"
486 " highp int phaseX = int(round((0.5 - abs(gl_TessCoord.x-0.5)) * sb_levels.inner0));\n"
487 " highp int phaseY = int(round((0.5 - abs(gl_TessCoord.y-0.5)) * sb_levels.inner1));\n"
488 " highp int phase = min(phaseX, phaseY) % 3;\n"
489 " in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
490 " : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
491 " : vec4(0.0, 0.0, 1.0, 1.0);\n"
492 : "")
493 << "}\n";
494
495 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
496 }
497 }
498
initProgramsIsolinesCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)499 void initProgramsIsolinesCase (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
500 {
501 DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_ISOLINES);
502
503 initCommonPrograms(programCollection, caseDef);
504
505 // Tessellation evaluation shader
506 {
507 std::ostringstream src;
508 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
509 << "#extension GL_EXT_tessellation_shader : require\n"
510 << "\n"
511 << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
512 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
513 << "\n"
514 << getTessLevelsSSBODeclaration()
515 << "\n"
516 << "layout(location = 0) in highp vec2 in_te_position[];\n"
517 << "layout(location = 0) out highp vec4 in_f_color;\n"
518 << "\n"
519 << "void main (void)\n"
520 << "{\n"
521 << " highp vec2 corner0 = in_te_position[0];\n"
522 << " highp vec2 corner1 = in_te_position[1];\n"
523 << " highp vec2 corner2 = in_te_position[2];\n"
524 << " highp vec2 corner3 = in_te_position[3];\n"
525 << " highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
526 << " + ( gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
527 << " + (1.0-gl_TessCoord.x)*( gl_TessCoord.y)*corner2\n"
528 << " + ( gl_TessCoord.x)*( gl_TessCoord.y)*corner3;\n"
529 << " pos.y += 0.15*sin(gl_TessCoord.x*10.0);\n"
530 << " gl_Position = vec4(pos, 0.0, 1.0);\n"
531 << " highp int phaseX = int(round(gl_TessCoord.x*sb_levels.outer1));\n"
532 << " highp int phaseY = int(round(gl_TessCoord.y*sb_levels.outer0));\n"
533 << " highp int phase = (phaseX + phaseY) % 3;\n"
534 << " in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
535 << " : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
536 << " : vec4(0.0, 0.0, 1.0, 1.0);\n"
537 << "}\n";
538
539 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
540 }
541 }
542
getReferenceImagePathPrefix(const std::string & caseName)543 inline std::string getReferenceImagePathPrefix (const std::string& caseName)
544 {
545 return "vulkan/data/tessellation/" + caseName + "_ref";
546 }
547
548 struct TessStateSwitchParams
549 {
550 const std::pair<TessPrimitiveType, TessPrimitiveType> patchTypes;
551 const std::pair<SpacingMode, SpacingMode> spacing;
552 const std::pair<VkTessellationDomainOrigin, VkTessellationDomainOrigin> domainOrigin;
553 const bool geometryShader;
554
nonDefaultDomainOriginvkt::tessellation::__anonae63b47f0111::TessStateSwitchParams555 bool nonDefaultDomainOrigin (void) const
556 {
557 return (domainOrigin.first != VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT ||
558 domainOrigin.second != VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT);
559 }
560 };
561
562 class TessStateSwitchInstance : public vkt::TestInstance
563 {
564 public:
TessStateSwitchInstance(Context & context,const TessStateSwitchParams & params)565 TessStateSwitchInstance (Context& context, const TessStateSwitchParams& params)
566 : vkt::TestInstance (context)
567 , m_params (params)
568 {}
569
~TessStateSwitchInstance(void)570 virtual ~TessStateSwitchInstance (void) {}
571
572 tcu::TestStatus iterate (void);
573
574 protected:
575 const TessStateSwitchParams m_params;
576 };
577
578 class TessStateSwitchCase : public vkt::TestCase
579 {
580 public:
TessStateSwitchCase(tcu::TestContext & testCtx,const std::string & name,const TessStateSwitchParams & params)581 TessStateSwitchCase (tcu::TestContext& testCtx, const std::string& name, const TessStateSwitchParams& params)
582 : vkt::TestCase (testCtx, name)
583 , m_params (params)
584 {}
585
~TessStateSwitchCase(void)586 virtual ~TessStateSwitchCase (void) {}
587
588 void checkSupport (Context& context) const;
589 void initPrograms (vk::SourceCollections& programCollection) const;
createInstance(Context & context) const590 TestInstance* createInstance (Context& context) const { return new TessStateSwitchInstance(context, m_params); }
591
592 protected:
593 const TessStateSwitchParams m_params;
594 };
595
checkSupport(Context & context) const596 void TessStateSwitchCase::checkSupport (Context& context) const
597 {
598 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
599
600 if (m_params.geometryShader)
601 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
602
603 if (m_params.nonDefaultDomainOrigin())
604 context.requireDeviceFunctionality("VK_KHR_maintenance2");
605 }
606
initPrograms(vk::SourceCollections & programCollection) const607 void TessStateSwitchCase::initPrograms (vk::SourceCollections& programCollection) const
608 {
609 std::ostringstream vert;
610 vert
611 << "#version 460\n"
612 << "layout (location=0) in vec4 inPos;\n"
613 << "layout (push_constant, std430) uniform PushConstantBlock { vec2 offset; } pc;\n"
614 << "out gl_PerVertex\n"
615 << "{\n"
616 << " vec4 gl_Position;\n"
617 << "};\n"
618 << "void main() {\n"
619 << " gl_Position = inPos + vec4(pc.offset, 0.0, 0.0);\n"
620 << "}\n"
621 ;
622 programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
623
624 if (m_params.geometryShader)
625 {
626 std::ostringstream geom;
627 geom
628 << "#version 460\n"
629 << "layout (triangles) in;\n"
630 << "layout (triangle_strip, max_vertices=3) out;\n"
631 << "in gl_PerVertex\n"
632 << "{\n"
633 << " vec4 gl_Position;\n"
634 << "} gl_in[3];\n"
635 << "out gl_PerVertex\n"
636 << "{\n"
637 << " vec4 gl_Position;\n"
638 << "};\n"
639 << "void main() {\n"
640 << " gl_Position = gl_in[0].gl_Position; EmitVertex();\n"
641 << " gl_Position = gl_in[1].gl_Position; EmitVertex();\n"
642 << " gl_Position = gl_in[2].gl_Position; EmitVertex();\n"
643 << " gl_PrimitiveID = gl_PrimitiveIDIn; EndPrimitive();\n"
644 << "}\n"
645 ;
646 programCollection.glslSources.add("geom") << glu::GeometrySource(geom.str());
647 }
648
649 const auto even = (m_params.spacing.second == SPACINGMODE_FRACTIONAL_EVEN);
650 const auto extraLevel = (even ? "1.0" : "0.0");
651
652 std::ostringstream tesc;
653 tesc
654 << "#version 460\n"
655 << "layout (vertices=4) out;\n"
656 << "in gl_PerVertex\n"
657 << "{\n"
658 << " vec4 gl_Position;\n"
659 << "} gl_in[gl_MaxPatchVertices];\n"
660 << "out gl_PerVertex\n"
661 << "{\n"
662 << " vec4 gl_Position;\n"
663 << "} gl_out[];\n"
664 << "void main() {\n"
665 << " const float extraLevel = " << extraLevel << ";\n"
666 << " gl_TessLevelInner[0] = 10.0 + extraLevel;\n"
667 << " gl_TessLevelInner[1] = 10.0 + extraLevel;\n"
668 << " gl_TessLevelOuter[0] = 50.0 + extraLevel;\n"
669 << " gl_TessLevelOuter[1] = 40.0 + extraLevel;\n"
670 << " gl_TessLevelOuter[2] = 30.0 + extraLevel;\n"
671 << " gl_TessLevelOuter[3] = 20.0 + extraLevel;\n"
672 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
673 << "}\n"
674 ;
675 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tesc.str());
676
677 for (uint32_t i = 0u; i < 2u; ++i)
678 {
679 const auto& primType = ((i == 0u) ? m_params.patchTypes.first : m_params.patchTypes.second);
680 const auto& spacing = ((i == 0u) ? m_params.spacing.first : m_params.spacing.second);
681
682 std::ostringstream tese;
683 tese
684 << "#version 460\n"
685 << "layout (" << getTessPrimitiveTypeShaderName(primType) << ", " << getSpacingModeShaderName(spacing) << ", ccw) in;\n"
686 << "in gl_PerVertex\n"
687 << "{\n"
688 << " vec4 gl_Position;\n"
689 << "} gl_in[gl_MaxPatchVertices];\n"
690 << "out gl_PerVertex\n"
691 << "{\n"
692 << " vec4 gl_Position;\n"
693 << "};\n"
694 << "\n"
695 << "// This assumes 2D, calculates barycentrics for point p inside triangle (a, b, c)\n"
696 << "vec3 calcBaryCoords(vec2 p, vec2 a, vec2 b, vec2 c)\n"
697 << "{\n"
698 << " const vec2 v0 = b - a;\n"
699 << " const vec2 v1 = c - a;\n"
700 << " const vec2 v2 = p - a;\n"
701 << "\n"
702 << " const float den = v0.x * v1.y - v1.x * v0.y;\n"
703 << " const float v = (v2.x * v1.y - v1.x * v2.y) / den;\n"
704 << " const float w = (v0.x * v2.y - v2.x * v0.y) / den;\n"
705 << " const float u = 1.0 - v - w;\n"
706 << "\n"
707 << " return vec3(u, v, w);\n"
708 << "}\n"
709 << "\n"
710 << "void main() {\n"
711 << ((primType == TESSPRIMITIVETYPE_QUADS)
712 // For quads.
713 ? " const float u = gl_TessCoord.x;\n"
714 " const float v = gl_TessCoord.y;\n"
715 " gl_Position = (1 - u) * (1 - v) * gl_in[0].gl_Position + (1 - u) * v * gl_in[1].gl_Position + u * (1 - v) * gl_in[2].gl_Position + u * v * gl_in[3].gl_Position;\n"
716 // For triangles.
717 : " // We have a patch with 4 corners (v0,v1,v2,v3), but triangle-based tessellation.\n"
718 " // Lets suppose the triangle covers half the patch (triangle v0,v2,v1).\n"
719 " // Expand the triangle by virtually grabbing it from the midpoint between v1 and v2 (which should fall in the middle of the patch) and stretching that point to the fourth corner (v3).\n"
720 " const vec4 origpoint = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
721 " (gl_TessCoord.y * gl_in[2].gl_Position) +\n"
722 " (gl_TessCoord.z * gl_in[1].gl_Position);\n"
723 " const vec4 midpoint = 0.5 * gl_in[1].gl_Position + 0.5 * gl_in[2].gl_Position;\n"
724 "\n"
725 " // Find out if it falls on left or right side of the triangle.\n"
726 " vec4 halfTriangle[3];\n"
727 " vec4 stretchedHalf[3];\n"
728 "\n"
729 " if (gl_TessCoord.z >= gl_TessCoord.y)\n"
730 " {\n"
731 " halfTriangle[0] = gl_in[0].gl_Position;\n"
732 " halfTriangle[1] = midpoint;\n"
733 " halfTriangle[2] = gl_in[1].gl_Position;\n"
734 "\n"
735 " stretchedHalf[0] = gl_in[0].gl_Position;\n"
736 " stretchedHalf[1] = gl_in[3].gl_Position;\n"
737 " stretchedHalf[2] = gl_in[1].gl_Position;\n"
738 " }\n"
739 " else\n"
740 " {\n"
741 " halfTriangle[0] = gl_in[0].gl_Position;\n"
742 " halfTriangle[1] = gl_in[2].gl_Position;\n"
743 " halfTriangle[2] = midpoint;\n"
744 "\n"
745 " stretchedHalf[0] = gl_in[0].gl_Position;\n"
746 " stretchedHalf[1] = gl_in[2].gl_Position;\n"
747 " stretchedHalf[2] = gl_in[3].gl_Position;\n"
748 " }\n"
749 "\n"
750 " // Calculate the barycentric coordinates for the left or right sides.\n"
751 " vec3 sideBaryCoord = calcBaryCoords(origpoint.xy, halfTriangle[0].xy, halfTriangle[1].xy, halfTriangle[2].xy);\n"
752 "\n"
753 " // Move the point by stretching the half triangle and dragging the midpoint vertex to v3.\n"
754 " gl_Position = sideBaryCoord.x * stretchedHalf[0] + sideBaryCoord.y * stretchedHalf[1] + sideBaryCoord.z * stretchedHalf[2];\n"
755 )
756 << "}\n"
757 ;
758 programCollection.glslSources.add("tese" + std::to_string(i)) << glu::TessellationEvaluationSource(tese.str());
759 }
760
761 std::ostringstream frag;
762 frag
763 << "#version 460\n"
764 << "layout (location=0) out vec4 outColor;\n"
765 << "void main() {\n"
766 << " outColor = vec4(0.5, 0.5, 0.5, 1.0);\n"
767 << "}\n"
768 ;
769 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
770 }
771
iterate(void)772 tcu::TestStatus TessStateSwitchInstance::iterate (void)
773 {
774 const auto& ctx = m_context.getContextCommonData();
775 const tcu::IVec3 fbExtent (128, 128, 1);
776 const auto vkExtent = makeExtent3D(fbExtent);
777 const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
778 const auto tcuFormat = mapVkFormat(colorFormat);
779 const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
780 const auto imageType = VK_IMAGE_TYPE_2D;
781 const auto colorSRR = makeDefaultImageSubresourceRange();
782 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
783
784 ImageWithBuffer referenceBuffer (ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, imageType, colorSRR);
785 ImageWithBuffer resultBuffer (ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, imageType, colorSRR);
786
787 // Vertex buffer containing a single full-screen patch.
788 const std::vector<tcu::Vec4> vertices
789 {
790 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
791 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
792 tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
793 tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f),
794 };
795 const auto vertexCount = de::sizeU32(vertices);
796 const auto patchControlPoints = vertexCount;
797
798 const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(vertices));
799 const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
800 BufferWithMemory vertexBuffer (ctx.vkd, ctx.device, ctx.allocator, vertexBufferInfo, MemoryRequirement::HostVisible);
801 auto& vertexBufferAlloc = vertexBuffer.getAllocation();
802 void* vertexBufferData = vertexBufferAlloc.getHostPtr();
803 const auto vertexBufferOffset = static_cast<VkDeviceSize>(0);
804
805 deMemcpy(vertexBufferData, de::dataOrNull(vertices), de::dataSize(vertices));
806 flushAlloc(ctx.vkd, ctx.device, vertexBufferAlloc);
807
808 const auto pcSize = static_cast<uint32_t>(sizeof(tcu::Vec2));
809 const auto pcStages = static_cast<VkShaderStageFlags>(VK_SHADER_STAGE_VERTEX_BIT);
810 const auto pcRange = makePushConstantRange(pcStages, 0u, pcSize);
811
812 const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device, VK_NULL_HANDLE, &pcRange);
813
814 const auto renderPass = makeRenderPass(ctx.vkd, ctx.device, colorFormat);
815
816 // Framebuffers.
817 const auto framebuffer0 = makeFramebuffer(ctx.vkd, ctx.device, *renderPass, referenceBuffer.getImageView(), vkExtent.width, vkExtent.height);
818 const auto framebuffer1 = makeFramebuffer(ctx.vkd, ctx.device, *renderPass, resultBuffer.getImageView(), vkExtent.width, vkExtent.height);
819
820 // Viewport and scissor.
821 const std::vector<VkViewport> viewports (1u, makeViewport(fbExtent));
822 const std::vector<VkRect2D> scissors (1u, makeRect2D(fbExtent));
823
824 // Shaders.
825 const auto& binaries = m_context.getBinaryCollection();
826 const auto vertModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
827 const auto tescModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("tesc"));
828 const auto teseModule0 = createShaderModule(ctx.vkd, ctx.device, binaries.get("tese0"));
829 const auto teseModule1 = createShaderModule(ctx.vkd, ctx.device, binaries.get("tese1"));
830 const auto geomModule = (m_params.geometryShader ? createShaderModule(ctx.vkd, ctx.device, binaries.get("geom")) : Move<VkShaderModule>());
831 const auto fragModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
832
833 const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo =
834 {
835 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
836 nullptr, // const void* pNext;
837 0u, // VkPipelineInputAssemblyStateCreateFlags flags;
838 VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, // VkPrimitiveTopology topology;
839 VK_FALSE, // VkBool32 primitiveRestartEnable;
840 };
841
842 VkPipelineTessellationDomainOriginStateCreateInfo domainOriginStateCreateInfo =
843 {
844 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, // VkStructureType sType;
845 nullptr, // const void* pNext;
846 m_params.domainOrigin.first, // VkTessellationDomainOrigin domainOrigin;
847 };
848
849 const auto tessPNext = (m_params.nonDefaultDomainOrigin() ? &domainOriginStateCreateInfo : nullptr);
850 const VkPipelineTessellationStateCreateInfo tessellationStateCreateInfo =
851 {
852 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType;
853 tessPNext, // const void* pNext;
854 0u, // VkPipelineTessellationStateCreateFlags flags;
855 patchControlPoints, // uint32_t patchControlPoints;
856 };
857
858 const VkPipelineViewportStateCreateInfo viewportStateCreateInfo =
859 {
860 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
861 nullptr, // const void* pNext;
862 0u, // VkPipelineViewportStateCreateFlags flags;
863 de::sizeU32(viewports), // uint32_t viewportCount;
864 de::dataOrNull(viewports), // const VkViewport* pViewports;
865 de::sizeU32(scissors), // uint32_t scissorCount;
866 de::dataOrNull(scissors), // const VkRect2D* pScissors;
867 };
868
869 // In the rasterization parameters, use wireframe mode to see each triangle if possible.
870 // This makes the test harder to pass by mistake.
871 // We also cull back faces, which will help test domain origin.
872 // The front face changes with the domain origin.
873 const auto frontFace = ((m_params.domainOrigin.second == VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT)
874 ? VK_FRONT_FACE_COUNTER_CLOCKWISE // With the default value it's as specified in the shader.
875 : VK_FRONT_FACE_CLOCKWISE); // Otherwise the winding order changes.
876 const auto polygonMode = ((m_context.getDeviceFeatures().fillModeNonSolid)
877 ? VK_POLYGON_MODE_LINE
878 : VK_POLYGON_MODE_FILL);
879 const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
880 {
881 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
882 nullptr, // const void* pNext;
883 0u, // VkPipelineRasterizationStateCreateFlags flags;
884 VK_FALSE, // VkBool32 depthClampEnable;
885 VK_FALSE, // VkBool32 rasterizerDiscardEnable;
886 polygonMode, // VkPolygonMode polygonMode;
887 VK_CULL_MODE_BACK_BIT, // VkCullModeFlags cullMode;
888 frontFace, // VkFrontFace frontFace;
889 VK_FALSE, // VkBool32 depthBiasEnable;
890 0.0f, // float depthBiasConstantFactor;
891 0.0f, // float depthBiasClamp;
892 0.0f, // float depthBiasSlopeFactor;
893 1.0f, // float lineWidth;
894 };
895
896 // Create two pipelines varying the tessellation evaluation module.
897 const auto pipeline0 = makeGraphicsPipeline(ctx.vkd, ctx.device, *pipelineLayout,
898 *vertModule, *tescModule, *teseModule0, *geomModule, *fragModule,
899 *renderPass, 0u, nullptr, &inputAssemblyStateCreateInfo, &tessellationStateCreateInfo, &viewportStateCreateInfo,
900 &rasterizationStateCreateInfo);
901
902 domainOriginStateCreateInfo.domainOrigin = m_params.domainOrigin.second;
903
904 const auto pipeline1 = makeGraphicsPipeline(ctx.vkd, ctx.device, *pipelineLayout,
905 *vertModule, *tescModule, *teseModule1, *geomModule, *fragModule,
906 *renderPass, 0u, nullptr, &inputAssemblyStateCreateInfo, &tessellationStateCreateInfo, &viewportStateCreateInfo,
907 &rasterizationStateCreateInfo);
908
909 const auto cmdPool = makeCommandPool(ctx.vkd, ctx.device, ctx.qfIndex);
910 const auto cmdBufferRef = allocateCommandBuffer(ctx.vkd, ctx.device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
911 const auto cmdBufferRes = allocateCommandBuffer(ctx.vkd, ctx.device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
912
913 const tcu::Vec2 noOffset (0.0f, 0.0f);
914 const tcu::Vec2 offscreenOffset (50.0f, 50.0f);
915 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f);
916
917 // Reference image.
918 beginCommandBuffer(ctx.vkd, *cmdBufferRef);
919 beginRenderPass(ctx.vkd, *cmdBufferRef, *renderPass, *framebuffer0, scissors.at(0u), clearColor);
920 ctx.vkd.cmdBindVertexBuffers(*cmdBufferRef, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
921 ctx.vkd.cmdBindPipeline(*cmdBufferRef, bindPoint, *pipeline1);
922 ctx.vkd.cmdPushConstants(*cmdBufferRef, *pipelineLayout, pcStages, 0u, pcSize, &noOffset);
923 ctx.vkd.cmdDraw(*cmdBufferRef, vertexCount, 1u, 0u, 0u);
924 endRenderPass(ctx.vkd, *cmdBufferRef);
925 copyImageToBuffer(ctx.vkd, *cmdBufferRef, referenceBuffer.getImage(), referenceBuffer.getBuffer(), fbExtent.swizzle(0, 1),
926 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
927 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
928 endCommandBuffer(ctx.vkd, *cmdBufferRef);
929 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, *cmdBufferRef);
930
931 // Result image.
932 beginCommandBuffer(ctx.vkd, *cmdBufferRes);
933 beginRenderPass(ctx.vkd, *cmdBufferRes, *renderPass, *framebuffer1, scissors.at(0u), clearColor);
934 ctx.vkd.cmdBindVertexBuffers(*cmdBufferRes, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
935 // Draw offscreen first to force tessellation state emission.
936 ctx.vkd.cmdBindPipeline(*cmdBufferRes, bindPoint, *pipeline0);
937 ctx.vkd.cmdPushConstants(*cmdBufferRes, *pipelineLayout, pcStages, 0u, pcSize, &offscreenOffset);
938 ctx.vkd.cmdDraw(*cmdBufferRes, vertexCount, 1u, 0u, 0u);
939 // Draw on screen second changing some tessellation state.
940 ctx.vkd.cmdBindPipeline(*cmdBufferRes, bindPoint, *pipeline1);
941 ctx.vkd.cmdPushConstants(*cmdBufferRes, *pipelineLayout, pcStages, 0u, pcSize, &noOffset);
942 ctx.vkd.cmdDraw(*cmdBufferRes, vertexCount, 1u, 0u, 0u);
943 endRenderPass(ctx.vkd, *cmdBufferRes);
944 copyImageToBuffer(ctx.vkd, *cmdBufferRes, resultBuffer.getImage(), resultBuffer.getBuffer(), fbExtent.swizzle(0, 1),
945 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
946 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
947 endCommandBuffer(ctx.vkd, *cmdBufferRes);
948 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, *cmdBufferRes);
949
950 invalidateAlloc(ctx.vkd, ctx.device, referenceBuffer.getBufferAllocation());
951 invalidateAlloc(ctx.vkd, ctx.device, resultBuffer.getBufferAllocation());
952
953 tcu::ConstPixelBufferAccess referenceAccess (tcuFormat, fbExtent, referenceBuffer.getBufferAllocation().getHostPtr());
954 tcu::ConstPixelBufferAccess resultAccess (tcuFormat, fbExtent, resultBuffer.getBufferAllocation().getHostPtr());
955
956 auto& log = m_context.getTestContext().getLog();
957 const float threshold = 0.005f; // 1/255 < 0.005 < 2/255
958 const tcu::Vec4 thresholdVec (threshold, threshold, threshold, 0.0f);
959
960 if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, thresholdVec, tcu::COMPARE_LOG_ON_ERROR))
961 return tcu::TestStatus::fail("Color result does not match reference image -- check log for details");
962
963 // Render pass and framebuffers.const DeviceCoreFeature requiredDeviceCoreFeature
964 return tcu::TestStatus::pass("Pass");
965 }
966
getDomainOriginName(VkTessellationDomainOrigin value)967 std::string getDomainOriginName(VkTessellationDomainOrigin value)
968 {
969 static const size_t prefixLen = strlen("VK_TESSELLATION_DOMAIN_ORIGIN_");
970 std::string nameStr = getTessellationDomainOriginName(value);
971
972 return de::toLower(nameStr.substr(prefixLen));
973 }
974
975 } // anonymous
976
977 //! These tests correspond to dEQP-GLES31.functional.tessellation.misc_draw.*
createMiscDrawTests(tcu::TestContext & testCtx)978 tcu::TestCaseGroup* createMiscDrawTests (tcu::TestContext& testCtx)
979 {
980 // Miscellaneous draw-result-verifying cases
981 de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "misc_draw"));
982
983 static const TessPrimitiveType primitivesNoIsolines[] =
984 {
985 TESSPRIMITIVETYPE_TRIANGLES,
986 TESSPRIMITIVETYPE_QUADS,
987 };
988
989 // Triangle fill case
990 for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
991 for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
992 {
993 const TessPrimitiveType primitiveType = primitivesNoIsolines[primitiveTypeNdx];
994 const SpacingMode spacingMode = static_cast<SpacingMode>(spacingModeNdx);
995 const std::string caseName = std::string() + "fill_cover_" + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getSpacingModeShaderName(spacingMode);
996
997 // Check that there are no obvious gaps in the triangle-filled area of a tessellated shape
998 addFunctionCaseWithPrograms(group.get(), caseName,
999 initProgramsFillCoverCase, runTest, makeCaseDefinition(primitiveType, spacingMode, getReferenceImagePathPrefix(caseName)));
1000 }
1001
1002 // Triangle non-overlap case
1003 for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
1004 for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
1005 {
1006 const TessPrimitiveType primitiveType = primitivesNoIsolines[primitiveTypeNdx];
1007 const SpacingMode spacingMode = static_cast<SpacingMode>(spacingModeNdx);
1008 const std::string caseName = std::string() + "fill_overlap_" + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getSpacingModeShaderName(spacingMode);
1009
1010 // Check that there are no obvious triangle overlaps in the triangle-filled area of a tessellated shape
1011 addFunctionCaseWithPrograms(group.get(), caseName,
1012 initProgramsFillNonOverlapCase, runTest, makeCaseDefinition(primitiveType, spacingMode, getReferenceImagePathPrefix(caseName)));
1013 }
1014
1015 // Isolines
1016 for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
1017 {
1018 const SpacingMode spacingMode = static_cast<SpacingMode>(spacingModeNdx);
1019 const std::string caseName = std::string() + "isolines_" + getSpacingModeShaderName(spacingMode);
1020
1021 // Basic isolines render test
1022 addFunctionCaseWithPrograms(group.get(), caseName, checkSupportCase,
1023 initProgramsIsolinesCase, runTest, makeCaseDefinition(TESSPRIMITIVETYPE_ISOLINES, spacingMode, getReferenceImagePathPrefix(caseName)));
1024 }
1025
1026 // Test switching tessellation parameters on the fly.
1027 for (const auto& geometryShader : { false, true })
1028 {
1029 const auto nameSuffix = (geometryShader ? "_with_geom_shader" : "");
1030
1031 static const VkTessellationDomainOrigin domainOrigins[] =
1032 {
1033 VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT,
1034 VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT,
1035 };
1036
1037 for (const auto& firstPrimitiveType : primitivesNoIsolines)
1038 for (const auto& secondPrimitiveType : primitivesNoIsolines)
1039 {
1040 if (firstPrimitiveType == secondPrimitiveType)
1041 continue;
1042
1043 const TessStateSwitchParams params
1044 {
1045 std::make_pair(firstPrimitiveType, secondPrimitiveType),
1046 std::make_pair(SPACINGMODE_EQUAL, SPACINGMODE_EQUAL),
1047 std::make_pair(VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT),
1048 geometryShader,
1049 };
1050
1051 const auto testName = std::string("switch_primitive_") + getTessPrimitiveTypeShaderName(params.patchTypes.first) + "_to_" + getTessPrimitiveTypeShaderName(params.patchTypes.second) + nameSuffix;
1052 group->addChild(new TessStateSwitchCase(testCtx, testName, params));
1053 }
1054
1055 for (const auto& firstDomainOrigin : domainOrigins)
1056 for (const auto& secondDomainOrigin : domainOrigins)
1057 {
1058 if (firstDomainOrigin == secondDomainOrigin)
1059 continue;
1060
1061 const TessStateSwitchParams params
1062 {
1063 std::make_pair(TESSPRIMITIVETYPE_QUADS, TESSPRIMITIVETYPE_QUADS),
1064 std::make_pair(SPACINGMODE_EQUAL, SPACINGMODE_EQUAL),
1065 std::make_pair(firstDomainOrigin, secondDomainOrigin),
1066 geometryShader,
1067 };
1068
1069 const auto testName = std::string("switch_domain_origin_") + getDomainOriginName(params.domainOrigin.first) + "_to_" + getDomainOriginName(params.domainOrigin.second) + nameSuffix;
1070 group->addChild(new TessStateSwitchCase(testCtx, testName, params));
1071 }
1072
1073 for (int firstSpacingModeNdx = 0; firstSpacingModeNdx < SPACINGMODE_LAST; ++firstSpacingModeNdx)
1074 for (int secondSpacingModeNdx = 0; secondSpacingModeNdx < SPACINGMODE_LAST; ++secondSpacingModeNdx)
1075 {
1076 if (firstSpacingModeNdx == secondSpacingModeNdx)
1077 continue;
1078
1079 const SpacingMode firstSpacingMode = static_cast<SpacingMode>(firstSpacingModeNdx);
1080 const SpacingMode secondSpacingMode = static_cast<SpacingMode>(secondSpacingModeNdx);
1081
1082 const TessStateSwitchParams params
1083 {
1084 std::make_pair(TESSPRIMITIVETYPE_QUADS, TESSPRIMITIVETYPE_QUADS),
1085 std::make_pair(firstSpacingMode, secondSpacingMode),
1086 std::make_pair(VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT),
1087 geometryShader,
1088 };
1089
1090 const auto testName = std::string("switch_spacing_mode_") + getSpacingModeShaderName(params.spacing.first) + "_to_" + getSpacingModeShaderName(params.spacing.second) + nameSuffix;
1091 group->addChild(new TessStateSwitchCase(testCtx, testName, params));
1092 }
1093 }
1094
1095 return group.release();
1096 }
1097
1098 } // tessellation
1099 } // vkt
1100