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 "tcuTextureUtil.hpp"
33 #include "tcuImageCompare.hpp"
34
35 #include "vkDefs.hpp"
36 #include "vkBarrierUtil.hpp"
37 #include "vkQueryUtil.hpp"
38 #include "vkBuilderUtil.hpp"
39 #include "vkImageUtil.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkStrUtil.hpp"
42 #include "vkCmdUtil.hpp"
43 #include "vkObjUtil.hpp"
44 #include "vkBufferWithMemory.hpp"
45 #include "vkImageWithMemory.hpp"
46
47 #include "deUniquePtr.hpp"
48 #include "deStringUtil.hpp"
49
50 #include "rrRenderer.hpp"
51
52 #include <string>
53 #include <vector>
54 #include <utility>
55
56 namespace vkt
57 {
58 namespace tessellation
59 {
60
61 using namespace vk;
62
63 namespace
64 {
65
66 typedef de::MovePtr<vk::Allocation> AllocationMp;
67
68 struct CaseDefinition
69 {
70 TessPrimitiveType primitiveType;
71 SpacingMode spacingMode;
72 DrawType drawType;
73 std::string referenceImagePathPrefix; //!< without case suffix and extension (e.g. "_1.png")
74 };
75
makeCaseDefinition(const TessPrimitiveType primitiveType,const SpacingMode spacingMode,const DrawType drawType,const std::string & referenceImagePathPrefix)76 inline CaseDefinition makeCaseDefinition(const TessPrimitiveType primitiveType, const SpacingMode spacingMode,
77 const DrawType drawType, const std::string &referenceImagePathPrefix)
78 {
79 CaseDefinition caseDef;
80 caseDef.primitiveType = primitiveType;
81 caseDef.spacingMode = spacingMode;
82 caseDef.drawType = drawType;
83 caseDef.referenceImagePathPrefix = referenceImagePathPrefix;
84 return caseDef;
85 }
86
genTessLevelCases(const SpacingMode spacingMode)87 std::vector<TessLevels> genTessLevelCases(const SpacingMode spacingMode)
88 {
89 static const TessLevels tessLevelCases[] = {
90 {{9.0f, 9.0f}, {9.0f, 9.0f, 9.0f, 9.0f}},
91 {{8.0f, 11.0f}, {13.0f, 15.0f, 18.0f, 21.0f}},
92 {{17.0f, 14.0f}, {3.0f, 6.0f, 9.0f, 12.0f}},
93 };
94
95 std::vector<TessLevels> resultTessLevels(DE_LENGTH_OF_ARRAY(tessLevelCases));
96
97 for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(tessLevelCases); ++tessLevelCaseNdx)
98 {
99 TessLevels &tessLevels = resultTessLevels[tessLevelCaseNdx];
100
101 for (int i = 0; i < 2; ++i)
102 tessLevels.inner[i] =
103 static_cast<float>(getClampedRoundedTessLevel(spacingMode, tessLevelCases[tessLevelCaseNdx].inner[i]));
104
105 for (int i = 0; i < 4; ++i)
106 tessLevels.outer[i] =
107 static_cast<float>(getClampedRoundedTessLevel(spacingMode, tessLevelCases[tessLevelCaseNdx].outer[i]));
108 }
109
110 return resultTessLevels;
111 }
112
genVertexPositions(const TessPrimitiveType primitiveType)113 std::vector<tcu::Vec2> genVertexPositions(const TessPrimitiveType primitiveType)
114 {
115 std::vector<tcu::Vec2> positions;
116 positions.reserve(4);
117
118 if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
119 {
120 positions.push_back(tcu::Vec2(0.8f, 0.6f));
121 positions.push_back(tcu::Vec2(0.0f, -0.786f));
122 positions.push_back(tcu::Vec2(-0.8f, 0.6f));
123 }
124 else if (primitiveType == TESSPRIMITIVETYPE_QUADS || primitiveType == TESSPRIMITIVETYPE_ISOLINES)
125 {
126 positions.push_back(tcu::Vec2(-0.8f, -0.8f));
127 positions.push_back(tcu::Vec2(0.8f, -0.8f));
128 positions.push_back(tcu::Vec2(-0.8f, 0.8f));
129 positions.push_back(tcu::Vec2(0.8f, 0.8f));
130 }
131 else
132 DE_ASSERT(false);
133
134 return positions;
135 }
136
137 //! Common test function used by all test cases.
runTest(Context & context,const CaseDefinition caseDef)138 tcu::TestStatus runTest(Context &context, const CaseDefinition caseDef)
139 {
140 requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
141
142 const DeviceInterface &vk = context.getDeviceInterface();
143 const VkDevice device = context.getDevice();
144 const VkQueue queue = context.getUniversalQueue();
145 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
146 Allocator &allocator = context.getDefaultAllocator();
147
148 const std::vector<TessLevels> tessLevelCases = genTessLevelCases(caseDef.spacingMode);
149 const std::vector<tcu::Vec2> vertexData = genVertexPositions(caseDef.primitiveType);
150 const uint32_t inPatchSize = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
151
152 // Vertex input: positions
153
154 const VkFormat vertexFormat = VK_FORMAT_R32G32_SFLOAT;
155 const uint32_t vertexStride = tcu::getPixelSize(mapVkFormat(vertexFormat));
156 const VkDeviceSize vertexDataSizeBytes = sizeInBytes(vertexData);
157
158 const BufferWithMemory vertexBuffer(vk, device, allocator,
159 makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
160 MemoryRequirement::HostVisible);
161
162 DE_ASSERT(inPatchSize == vertexData.size());
163 DE_ASSERT(sizeof(vertexData[0]) == vertexStride);
164
165 {
166 const Allocation &alloc = vertexBuffer.getAllocation();
167
168 deMemcpy(alloc.getHostPtr(), &vertexData[0], static_cast<std::size_t>(vertexDataSizeBytes));
169 flushAlloc(vk, device, alloc);
170 // No barrier needed, flushed memory is automatically visible
171 }
172
173 // Indirect buffer
174
175 const VkDrawIndirectCommand drawIndirectArgs{
176 inPatchSize, // uint32_t vertexCount;
177 1u, // uint32_t instanceCount;
178 0u, // uint32_t firstVertex;
179 0u, // uint32_t firstInstance;
180 };
181
182 const BufferWithMemory indirectBuffer(
183 vk, device, allocator, makeBufferCreateInfo(sizeof(drawIndirectArgs), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
184 MemoryRequirement::HostVisible);
185
186 {
187 const Allocation &alloc = indirectBuffer.getAllocation();
188
189 deMemcpy(alloc.getHostPtr(), &drawIndirectArgs, sizeof(drawIndirectArgs));
190 flushAlloc(vk, device, alloc);
191 // No barrier needed, flushed memory is automatically visible
192 }
193
194 // Color attachment
195
196 const tcu::IVec2 renderSize = tcu::IVec2(256, 256);
197 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
198 const VkImageSubresourceRange colorImageSubresourceRange =
199 makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
200 const ImageWithMemory colorAttachmentImage(
201 vk, device, allocator,
202 makeImageCreateInfo(renderSize, colorFormat,
203 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
204 MemoryRequirement::Any);
205
206 // Color output buffer: image will be copied here for verification
207
208 const VkDeviceSize colorBufferSizeBytes =
209 renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
210 const BufferWithMemory colorBuffer(vk, device, allocator,
211 makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT),
212 MemoryRequirement::HostVisible);
213
214 // Input buffer: tessellation levels. Data is filled in later.
215
216 const BufferWithMemory tessLevelsBuffer(
217 vk, device, allocator, makeBufferCreateInfo(sizeof(TessLevels), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
218 MemoryRequirement::HostVisible);
219
220 // Descriptors
221
222 const Unique<VkDescriptorSetLayout> descriptorSetLayout(
223 DescriptorSetLayoutBuilder()
224 .addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
225 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
226 .build(vk, device));
227
228 const Unique<VkDescriptorPool> descriptorPool(
229 DescriptorPoolBuilder()
230 .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
231 .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
232
233 const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
234
235 const VkDescriptorBufferInfo tessLevelsBufferInfo =
236 makeDescriptorBufferInfo(tessLevelsBuffer.get(), 0ull, sizeof(TessLevels));
237
238 DescriptorSetUpdateBuilder()
239 .writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u),
240 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &tessLevelsBufferInfo)
241 .update(vk, device);
242
243 // Pipeline
244
245 const Unique<VkImageView> colorAttachmentView(makeImageView(
246 vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
247 const Unique<VkRenderPass> renderPass(makeRenderPass(vk, device, colorFormat));
248 const Unique<VkFramebuffer> framebuffer(
249 makeFramebuffer(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y()));
250 const Unique<VkPipelineLayout> pipelineLayout(makePipelineLayout(vk, device, *descriptorSetLayout));
251 const Unique<VkCommandPool> cmdPool(makeCommandPool(vk, device, queueFamilyIndex));
252 const Unique<VkCommandBuffer> cmdBuffer(
253 allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
254
255 const Unique<VkPipeline> pipeline(
256 GraphicsPipelineBuilder()
257 .setRenderSize(renderSize)
258 .setVertexInputSingleAttribute(vertexFormat, vertexStride)
259 .setPatchControlPoints(inPatchSize)
260 .setShader(vk, device, VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"), nullptr)
261 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, context.getBinaryCollection().get("tesc"),
262 nullptr)
263 .setShader(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
264 context.getBinaryCollection().get("tese"), nullptr)
265 .setShader(vk, device, VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"), nullptr)
266 .build(vk, device, *pipelineLayout, *renderPass));
267
268 // Draw commands
269
270 uint32_t numPassedCases = 0;
271
272 for (uint32_t tessLevelCaseNdx = 0; tessLevelCaseNdx < tessLevelCases.size(); ++tessLevelCaseNdx)
273 {
274 context.getTestContext().getLog()
275 << tcu::TestLog::Message << "Tessellation levels: "
276 << getTessellationLevelsString(tessLevelCases[tessLevelCaseNdx], caseDef.primitiveType)
277 << tcu::TestLog::EndMessage;
278
279 // Upload tessellation levels data to the input buffer
280 {
281 const Allocation &alloc = tessLevelsBuffer.getAllocation();
282 TessLevels *const bufferTessLevels = static_cast<TessLevels *>(alloc.getHostPtr());
283
284 *bufferTessLevels = tessLevelCases[tessLevelCaseNdx];
285 flushAlloc(vk, device, alloc);
286 }
287
288 // Reset the command buffer and begin recording.
289 beginCommandBuffer(vk, *cmdBuffer);
290
291 // Change color attachment image layout
292 {
293 // State is slightly different on the first iteration.
294 const VkImageLayout currentLayout =
295 (tessLevelCaseNdx == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
296 const VkAccessFlags srcFlags =
297 (tessLevelCaseNdx == 0 ? (VkAccessFlags)0 : (VkAccessFlags)VK_ACCESS_TRANSFER_READ_BIT);
298
299 const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
300 srcFlags, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, currentLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
301 *colorAttachmentImage, colorImageSubresourceRange);
302
303 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
304 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u,
305 &colorAttachmentLayoutBarrier);
306 }
307
308 // Begin render pass
309 {
310 const VkRect2D renderArea = makeRect2D(renderSize);
311 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
312
313 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
314 }
315
316 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
317 vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u,
318 &descriptorSet.get(), 0u, nullptr);
319 {
320 const VkDeviceSize vertexBufferOffset = 0ull;
321 vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
322 }
323
324 // Process enough vertices to make a patch.
325 if (caseDef.drawType == DRAWTYPE_DRAW)
326 vk.cmdDraw(*cmdBuffer, inPatchSize, 1u, 0u, 0u);
327 else // DRAWTYPE_DRAW_INDIRECT
328 vk.cmdDrawIndirect(*cmdBuffer, indirectBuffer.get(), 0u, 1u, 0u); // Stride is ignored
329 endRenderPass(vk, *cmdBuffer);
330
331 // Copy render result to a host-visible buffer
332 copyImageToBuffer(vk, *cmdBuffer, *colorAttachmentImage, *colorBuffer, renderSize);
333
334 endCommandBuffer(vk, *cmdBuffer);
335 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
336
337 {
338 const Allocation &colorBufferAlloc = colorBuffer.getAllocation();
339
340 invalidateAlloc(vk, device, colorBufferAlloc);
341
342 // Verify case result
343 const tcu::ConstPixelBufferAccess resultImageAccess(mapVkFormat(colorFormat), renderSize.x(),
344 renderSize.y(), 1, colorBufferAlloc.getHostPtr());
345
346 // Load reference image
347 const std::string referenceImagePath =
348 caseDef.referenceImagePathPrefix + "_" + de::toString(tessLevelCaseNdx) + ".png";
349
350 tcu::TextureLevel referenceImage;
351 tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), referenceImagePath.c_str());
352
353 if (tcu::fuzzyCompare(context.getTestContext().getLog(), "ImageComparison", "Image Comparison",
354 referenceImage.getAccess(), resultImageAccess, 0.002f, tcu::COMPARE_LOG_RESULT))
355 ++numPassedCases;
356 }
357 } // tessLevelCaseNdx
358
359 return (numPassedCases == tessLevelCases.size() ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
360 }
361
getTessLevelsSSBODeclaration(void)362 inline const char *getTessLevelsSSBODeclaration(void)
363 {
364 return "layout(set = 0, binding = 0, std430) readonly restrict buffer TessLevels {\n"
365 " float inner0;\n"
366 " float inner1;\n"
367 " float outer0;\n"
368 " float outer1;\n"
369 " float outer2;\n"
370 " float outer3;\n"
371 "} sb_levels;\n";
372 }
373
374 //! Add vertex, fragment, and tessellation control shaders.
initCommonPrograms(vk::SourceCollections & programCollection,const CaseDefinition caseDef)375 void initCommonPrograms(vk::SourceCollections &programCollection, const CaseDefinition caseDef)
376 {
377 DE_ASSERT(!programCollection.glslSources.contains("vert"));
378 DE_ASSERT(!programCollection.glslSources.contains("tesc"));
379 DE_ASSERT(!programCollection.glslSources.contains("frag"));
380
381 // Vertex shader
382 {
383 std::ostringstream src;
384 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
385 << "\n"
386 << "layout(location = 0) in highp vec2 in_v_position;\n"
387 << "layout(location = 0) out highp vec2 in_tc_position;\n"
388 << "\n"
389 << "void main (void)\n"
390 << "{\n"
391 << " in_tc_position = in_v_position;\n"
392 << "}\n";
393
394 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
395 }
396
397 // Tessellation control shader
398 {
399 const int numVertices = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
400
401 std::ostringstream src;
402 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
403 << "#extension GL_EXT_tessellation_shader : require\n"
404 << "\n"
405 << "layout(vertices = " << numVertices << ") out;\n"
406 << "\n"
407 << getTessLevelsSSBODeclaration() << "\n"
408 << "layout(location = 0) in highp vec2 in_tc_position[];\n"
409 << "layout(location = 0) out highp vec2 in_te_position[];\n"
410 << "\n"
411 << "void main (void)\n"
412 << "{\n"
413 << " in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
414 << "\n"
415 << " gl_TessLevelInner[0] = sb_levels.inner0;\n"
416 << " gl_TessLevelInner[1] = sb_levels.inner1;\n"
417 << "\n"
418 << " gl_TessLevelOuter[0] = sb_levels.outer0;\n"
419 << " gl_TessLevelOuter[1] = sb_levels.outer1;\n"
420 << " gl_TessLevelOuter[2] = sb_levels.outer2;\n"
421 << " gl_TessLevelOuter[3] = sb_levels.outer3;\n"
422 << "}\n";
423
424 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
425 }
426
427 // Fragment shader
428 {
429 std::ostringstream src;
430 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
431 << "\n"
432 << "layout(location = 0) in highp vec4 in_f_color;\n"
433 << "layout(location = 0) out mediump vec4 o_color;\n"
434 << "\n"
435 << "void main (void)\n"
436 << "{\n"
437 << " o_color = in_f_color;\n"
438 << "}\n";
439
440 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
441 }
442 }
443
initProgramsFillCoverCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)444 void initProgramsFillCoverCase(vk::SourceCollections &programCollection, const CaseDefinition caseDef)
445 {
446 DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
447
448 initCommonPrograms(programCollection, caseDef);
449
450 // Tessellation evaluation shader
451 {
452 std::ostringstream src;
453 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
454 << "#extension GL_EXT_tessellation_shader : require\n"
455 << "\n"
456 << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
457 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
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 float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
466 " highp vec2 corner0 = in_te_position[0];\n"
467 " highp vec2 corner1 = in_te_position[1];\n"
468 " highp vec2 corner2 = in_te_position[2];\n"
469 " highp vec2 pos = corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
470 " highp vec2 fromCenter = pos - (corner0 + corner1 + corner2) / 3.0;\n"
471 " highp float f = (1.0 - length(fromCenter)) * (1.5 - d);\n"
472 " pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
473 " gl_Position = vec4(pos, 0.0, 1.0);\n" :
474 caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
475 " highp vec2 corner0 = in_te_position[0];\n"
476 " highp vec2 corner1 = in_te_position[1];\n"
477 " highp vec2 corner2 = in_te_position[2];\n"
478 " highp vec2 corner3 = in_te_position[3];\n"
479 " highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
480 " + ( gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
481 " + (1.0-gl_TessCoord.x)*( gl_TessCoord.y)*corner2\n"
482 " + ( gl_TessCoord.x)*( gl_TessCoord.y)*corner3;\n"
483 " highp float d = 2.0 * min(abs(gl_TessCoord.x-0.5), abs(gl_TessCoord.y-0.5));\n"
484 " highp vec2 fromCenter = pos - (corner0 + corner1 + corner2 + corner3) / 4.0;\n"
485 " highp float f = (1.0 - length(fromCenter)) * sqrt(1.7 - d);\n"
486 " pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
487 " gl_Position = vec4(pos, 0.0, 1.0);\n" :
488 "")
489 << " in_f_color = vec4(1.0);\n"
490 << "}\n";
491
492 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
493 }
494 }
495
initProgramsFillNonOverlapCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)496 void initProgramsFillNonOverlapCase(vk::SourceCollections &programCollection, const CaseDefinition caseDef)
497 {
498 DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
499
500 initCommonPrograms(programCollection, caseDef);
501
502 // Tessellation evaluation shader
503 {
504 std::ostringstream src;
505 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
506 << "#extension GL_EXT_tessellation_shader : require\n"
507 << "\n"
508 << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
509 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
510 << "\n"
511 << getTessLevelsSSBODeclaration() << "\n"
512 << "layout(location = 0) in highp vec2 in_te_position[];\n"
513 << "layout(location = 0) out highp vec4 in_f_color;\n"
514 << "\n"
515 << "void main (void)\n"
516 << "{\n"
517 << (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
518 " highp vec2 corner0 = in_te_position[0];\n"
519 " highp vec2 corner1 = in_te_position[1];\n"
520 " highp vec2 corner2 = in_te_position[2];\n"
521 " highp vec2 pos = corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
522 " gl_Position = vec4(pos, 0.0, 1.0);\n"
523 " highp int numConcentricTriangles = int(round(sb_levels.inner0)) / 2 + 1;\n"
524 " highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
525 " highp int phase = int(d*float(numConcentricTriangles)) % 3;\n"
526 " in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
527 " : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
528 " : vec4(0.0, 0.0, 1.0, 1.0);\n" :
529 caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
530 " highp vec2 corner0 = in_te_position[0];\n"
531 " highp vec2 corner1 = in_te_position[1];\n"
532 " highp vec2 corner2 = in_te_position[2];\n"
533 " highp vec2 corner3 = in_te_position[3];\n"
534 " highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
535 " + ( gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
536 " + (1.0-gl_TessCoord.x)*( gl_TessCoord.y)*corner2\n"
537 " + ( gl_TessCoord.x)*( gl_TessCoord.y)*corner3;\n"
538 " gl_Position = vec4(pos, 0.0, 1.0);\n"
539 " highp int phaseX = int(round((0.5 - abs(gl_TessCoord.x-0.5)) * sb_levels.inner0));\n"
540 " highp int phaseY = int(round((0.5 - abs(gl_TessCoord.y-0.5)) * sb_levels.inner1));\n"
541 " highp int phase = min(phaseX, phaseY) % 3;\n"
542 " in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
543 " : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
544 " : vec4(0.0, 0.0, 1.0, 1.0);\n" :
545 "")
546 << "}\n";
547
548 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
549 }
550 }
551
initProgramsIsolinesCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)552 void initProgramsIsolinesCase(vk::SourceCollections &programCollection, const CaseDefinition caseDef)
553 {
554 DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_ISOLINES);
555
556 initCommonPrograms(programCollection, caseDef);
557
558 // Tessellation evaluation shader
559 {
560 std::ostringstream src;
561 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
562 << "#extension GL_EXT_tessellation_shader : require\n"
563 << "\n"
564 << "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
565 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
566 << "\n"
567 << getTessLevelsSSBODeclaration() << "\n"
568 << "layout(location = 0) in highp vec2 in_te_position[];\n"
569 << "layout(location = 0) out highp vec4 in_f_color;\n"
570 << "\n"
571 << "void main (void)\n"
572 << "{\n"
573 << " highp vec2 corner0 = in_te_position[0];\n"
574 << " highp vec2 corner1 = in_te_position[1];\n"
575 << " highp vec2 corner2 = in_te_position[2];\n"
576 << " highp vec2 corner3 = in_te_position[3];\n"
577 << " highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
578 << " + ( gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
579 << " + (1.0-gl_TessCoord.x)*( gl_TessCoord.y)*corner2\n"
580 << " + ( gl_TessCoord.x)*( gl_TessCoord.y)*corner3;\n"
581 << " pos.y += 0.15*sin(gl_TessCoord.x*10.0);\n"
582 << " gl_Position = vec4(pos, 0.0, 1.0);\n"
583 << " highp int phaseX = int(round(gl_TessCoord.x*sb_levels.outer1));\n"
584 << " highp int phaseY = int(round(gl_TessCoord.y*sb_levels.outer0));\n"
585 << " highp int phase = (phaseX + phaseY) % 3;\n"
586 << " in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
587 << " : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
588 << " : vec4(0.0, 0.0, 1.0, 1.0);\n"
589 << "}\n";
590
591 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
592 }
593 }
594
getReferenceImagePathPrefix(const std::string & caseName)595 inline std::string getReferenceImagePathPrefix(const std::string &caseName)
596 {
597 return "vulkan/data/tessellation/" + caseName + "_ref";
598 }
599
600 struct TessStateSwitchParams
601 {
602 const std::pair<TessPrimitiveType, TessPrimitiveType> patchTypes;
603 const std::pair<SpacingMode, SpacingMode> spacing;
604 const std::pair<VkTessellationDomainOrigin, VkTessellationDomainOrigin> domainOrigin;
605 const bool geometryShader;
606
nonDefaultDomainOriginvkt::tessellation::__anonbc6b7a940111::TessStateSwitchParams607 bool nonDefaultDomainOrigin(void) const
608 {
609 return (domainOrigin.first != VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT ||
610 domainOrigin.second != VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT);
611 }
612 };
613
614 class TessStateSwitchInstance : public vkt::TestInstance
615 {
616 public:
TessStateSwitchInstance(Context & context,const TessStateSwitchParams & params)617 TessStateSwitchInstance(Context &context, const TessStateSwitchParams ¶ms)
618 : vkt::TestInstance(context)
619 , m_params(params)
620 {
621 }
622
~TessStateSwitchInstance(void)623 virtual ~TessStateSwitchInstance(void)
624 {
625 }
626
627 tcu::TestStatus iterate(void);
628
629 protected:
630 const TessStateSwitchParams m_params;
631 };
632
633 class TessStateSwitchCase : public vkt::TestCase
634 {
635 public:
TessStateSwitchCase(tcu::TestContext & testCtx,const std::string & name,const TessStateSwitchParams & params)636 TessStateSwitchCase(tcu::TestContext &testCtx, const std::string &name, const TessStateSwitchParams ¶ms)
637 : vkt::TestCase(testCtx, name)
638 , m_params(params)
639 {
640 }
641
~TessStateSwitchCase(void)642 virtual ~TessStateSwitchCase(void)
643 {
644 }
645
646 void checkSupport(Context &context) const;
647 void initPrograms(vk::SourceCollections &programCollection) const;
createInstance(Context & context) const648 TestInstance *createInstance(Context &context) const
649 {
650 return new TessStateSwitchInstance(context, m_params);
651 }
652
653 protected:
654 const TessStateSwitchParams m_params;
655 };
656
checkSupport(Context & context) const657 void TessStateSwitchCase::checkSupport(Context &context) const
658 {
659 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
660
661 if (m_params.geometryShader)
662 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
663
664 if (m_params.nonDefaultDomainOrigin())
665 context.requireDeviceFunctionality("VK_KHR_maintenance2");
666 }
667
initPrograms(vk::SourceCollections & programCollection) const668 void TessStateSwitchCase::initPrograms(vk::SourceCollections &programCollection) const
669 {
670 std::ostringstream vert;
671 vert << "#version 460\n"
672 << "layout (location=0) in vec4 inPos;\n"
673 << "layout (push_constant, std430) uniform PushConstantBlock { vec2 offset; } pc;\n"
674 << "out gl_PerVertex\n"
675 << "{\n"
676 << " vec4 gl_Position;\n"
677 << "};\n"
678 << "void main() {\n"
679 << " gl_Position = inPos + vec4(pc.offset, 0.0, 0.0);\n"
680 << "}\n";
681 programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
682
683 if (m_params.geometryShader)
684 {
685 std::ostringstream geom;
686 geom << "#version 460\n"
687 << "layout (triangles) in;\n"
688 << "layout (triangle_strip, max_vertices=3) out;\n"
689 << "in gl_PerVertex\n"
690 << "{\n"
691 << " vec4 gl_Position;\n"
692 << "} gl_in[3];\n"
693 << "out gl_PerVertex\n"
694 << "{\n"
695 << " vec4 gl_Position;\n"
696 << "};\n"
697 << "void main() {\n"
698 << " gl_Position = gl_in[0].gl_Position; EmitVertex();\n"
699 << " gl_Position = gl_in[1].gl_Position; EmitVertex();\n"
700 << " gl_Position = gl_in[2].gl_Position; EmitVertex();\n"
701 << " gl_PrimitiveID = gl_PrimitiveIDIn; EndPrimitive();\n"
702 << "}\n";
703 programCollection.glslSources.add("geom") << glu::GeometrySource(geom.str());
704 }
705
706 const auto even = (m_params.spacing.second == SPACINGMODE_FRACTIONAL_EVEN);
707 const auto extraLevel = (even ? "1.0" : "0.0");
708
709 std::ostringstream tesc;
710 tesc << "#version 460\n"
711 << "layout (vertices=4) out;\n"
712 << "in gl_PerVertex\n"
713 << "{\n"
714 << " vec4 gl_Position;\n"
715 << "} gl_in[gl_MaxPatchVertices];\n"
716 << "out gl_PerVertex\n"
717 << "{\n"
718 << " vec4 gl_Position;\n"
719 << "} gl_out[];\n"
720 << "void main() {\n"
721 << " const float extraLevel = " << extraLevel << ";\n"
722 << " gl_TessLevelInner[0] = 10.0 + extraLevel;\n"
723 << " gl_TessLevelInner[1] = 10.0 + extraLevel;\n"
724 << " gl_TessLevelOuter[0] = 50.0 + extraLevel;\n"
725 << " gl_TessLevelOuter[1] = 40.0 + extraLevel;\n"
726 << " gl_TessLevelOuter[2] = 30.0 + extraLevel;\n"
727 << " gl_TessLevelOuter[3] = 20.0 + extraLevel;\n"
728 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
729 << "}\n";
730 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tesc.str());
731
732 for (uint32_t i = 0u; i < 2u; ++i)
733 {
734 const auto &primType = ((i == 0u) ? m_params.patchTypes.first : m_params.patchTypes.second);
735 const auto &spacing = ((i == 0u) ? m_params.spacing.first : m_params.spacing.second);
736
737 std::ostringstream tese;
738 tese << "#version 460\n"
739 << "layout (" << getTessPrimitiveTypeShaderName(primType) << ", " << getSpacingModeShaderName(spacing)
740 << ", ccw) in;\n"
741 << "in gl_PerVertex\n"
742 << "{\n"
743 << " vec4 gl_Position;\n"
744 << "} gl_in[gl_MaxPatchVertices];\n"
745 << "out gl_PerVertex\n"
746 << "{\n"
747 << " vec4 gl_Position;\n"
748 << "};\n"
749 << "\n"
750 << "// This assumes 2D, calculates barycentrics for point p inside triangle (a, b, c)\n"
751 << "vec3 calcBaryCoords(vec2 p, vec2 a, vec2 b, vec2 c)\n"
752 << "{\n"
753 << " const vec2 v0 = b - a;\n"
754 << " const vec2 v1 = c - a;\n"
755 << " const vec2 v2 = p - a;\n"
756 << "\n"
757 << " const float den = v0.x * v1.y - v1.x * v0.y;\n"
758 << " const float v = (v2.x * v1.y - v1.x * v2.y) / den;\n"
759 << " const float w = (v0.x * v2.y - v2.x * v0.y) / den;\n"
760 << " const float u = 1.0 - v - w;\n"
761 << "\n"
762 << " return vec3(u, v, w);\n"
763 << "}\n"
764 << "\n"
765 << "void main() {\n"
766 << ((primType == TESSPRIMITIVETYPE_QUADS)
767 // For quads.
768 ?
769 " const float u = gl_TessCoord.x;\n"
770 " const float v = gl_TessCoord.y;\n"
771 " gl_Position = (1 - u) * (1 - v) * gl_in[0].gl_Position + (1 - u) * v * gl_in[1].gl_Position "
772 "+ u * (1 - v) * gl_in[2].gl_Position + u * v * gl_in[3].gl_Position;\n"
773 // For triangles.
774 :
775 " // We have a patch with 4 corners (v0,v1,v2,v3), but triangle-based tessellation.\n"
776 " // Lets suppose the triangle covers half the patch (triangle v0,v2,v1).\n"
777 " // Expand the triangle by virtually grabbing it from the midpoint between v1 and v2 (which "
778 "should fall in the middle of the patch) and stretching that point to the fourth corner (v3).\n"
779 " const vec4 origpoint = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
780 " (gl_TessCoord.y * gl_in[2].gl_Position) +\n"
781 " (gl_TessCoord.z * gl_in[1].gl_Position);\n"
782 " const vec4 midpoint = 0.5 * gl_in[1].gl_Position + 0.5 * gl_in[2].gl_Position;\n"
783 "\n"
784 " // Find out if it falls on left or right side of the triangle.\n"
785 " vec4 halfTriangle[3];\n"
786 " vec4 stretchedHalf[3];\n"
787 "\n"
788 " if (gl_TessCoord.z >= gl_TessCoord.y)\n"
789 " {\n"
790 " halfTriangle[0] = gl_in[0].gl_Position;\n"
791 " halfTriangle[1] = midpoint;\n"
792 " halfTriangle[2] = gl_in[1].gl_Position;\n"
793 "\n"
794 " stretchedHalf[0] = gl_in[0].gl_Position;\n"
795 " stretchedHalf[1] = gl_in[3].gl_Position;\n"
796 " stretchedHalf[2] = gl_in[1].gl_Position;\n"
797 " }\n"
798 " else\n"
799 " {\n"
800 " halfTriangle[0] = gl_in[0].gl_Position;\n"
801 " halfTriangle[1] = gl_in[2].gl_Position;\n"
802 " halfTriangle[2] = midpoint;\n"
803 "\n"
804 " stretchedHalf[0] = gl_in[0].gl_Position;\n"
805 " stretchedHalf[1] = gl_in[2].gl_Position;\n"
806 " stretchedHalf[2] = gl_in[3].gl_Position;\n"
807 " }\n"
808 "\n"
809 " // Calculate the barycentric coordinates for the left or right sides.\n"
810 " vec3 sideBaryCoord = calcBaryCoords(origpoint.xy, halfTriangle[0].xy, halfTriangle[1].xy, "
811 "halfTriangle[2].xy);\n"
812 "\n"
813 " // Move the point by stretching the half triangle and dragging the midpoint vertex to v3.\n"
814 " gl_Position = sideBaryCoord.x * stretchedHalf[0] + sideBaryCoord.y * stretchedHalf[1] + "
815 "sideBaryCoord.z * stretchedHalf[2];\n")
816 << "}\n";
817 programCollection.glslSources.add("tese" + std::to_string(i)) << glu::TessellationEvaluationSource(tese.str());
818 }
819
820 std::ostringstream frag;
821 frag << "#version 460\n"
822 << "layout (location=0) out vec4 outColor;\n"
823 << "void main() {\n"
824 << " outColor = vec4(0.5, 0.5, 0.5, 1.0);\n"
825 << "}\n";
826 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
827 }
828
iterate(void)829 tcu::TestStatus TessStateSwitchInstance::iterate(void)
830 {
831 const auto &ctx = m_context.getContextCommonData();
832 const tcu::IVec3 fbExtent(128, 128, 1);
833 const auto vkExtent = makeExtent3D(fbExtent);
834 const auto colorFormat = VK_FORMAT_R8G8B8A8_UNORM;
835 const auto tcuFormat = mapVkFormat(colorFormat);
836 const auto colorUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
837 const auto imageType = VK_IMAGE_TYPE_2D;
838 const auto colorSRR = makeDefaultImageSubresourceRange();
839 const auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
840
841 ImageWithBuffer referenceBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, imageType,
842 colorSRR);
843 ImageWithBuffer resultBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, imageType,
844 colorSRR);
845
846 // Vertex buffer containing a single full-screen patch.
847 const std::vector<tcu::Vec4> vertices{
848 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
849 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
850 tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f),
851 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f),
852 };
853 const auto vertexCount = de::sizeU32(vertices);
854 const auto patchControlPoints = vertexCount;
855
856 const auto vertexBufferSize = static_cast<VkDeviceSize>(de::dataSize(vertices));
857 const auto vertexBufferInfo = makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
858 BufferWithMemory vertexBuffer(ctx.vkd, ctx.device, ctx.allocator, vertexBufferInfo, MemoryRequirement::HostVisible);
859 auto &vertexBufferAlloc = vertexBuffer.getAllocation();
860 void *vertexBufferData = vertexBufferAlloc.getHostPtr();
861 const auto vertexBufferOffset = static_cast<VkDeviceSize>(0);
862
863 deMemcpy(vertexBufferData, de::dataOrNull(vertices), de::dataSize(vertices));
864 flushAlloc(ctx.vkd, ctx.device, vertexBufferAlloc);
865
866 const auto pcSize = static_cast<uint32_t>(sizeof(tcu::Vec2));
867 const auto pcStages = static_cast<VkShaderStageFlags>(VK_SHADER_STAGE_VERTEX_BIT);
868 const auto pcRange = makePushConstantRange(pcStages, 0u, pcSize);
869
870 const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device, VK_NULL_HANDLE, &pcRange);
871
872 const auto renderPass = makeRenderPass(ctx.vkd, ctx.device, colorFormat);
873
874 // Framebuffers.
875 const auto framebuffer0 = makeFramebuffer(ctx.vkd, ctx.device, *renderPass, referenceBuffer.getImageView(),
876 vkExtent.width, vkExtent.height);
877 const auto framebuffer1 =
878 makeFramebuffer(ctx.vkd, ctx.device, *renderPass, resultBuffer.getImageView(), vkExtent.width, vkExtent.height);
879
880 // Viewport and scissor.
881 const std::vector<VkViewport> viewports(1u, makeViewport(fbExtent));
882 const std::vector<VkRect2D> scissors(1u, makeRect2D(fbExtent));
883
884 // Shaders.
885 const auto &binaries = m_context.getBinaryCollection();
886 const auto vertModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
887 const auto tescModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("tesc"));
888 const auto teseModule0 = createShaderModule(ctx.vkd, ctx.device, binaries.get("tese0"));
889 const auto teseModule1 = createShaderModule(ctx.vkd, ctx.device, binaries.get("tese1"));
890 const auto geomModule = (m_params.geometryShader ? createShaderModule(ctx.vkd, ctx.device, binaries.get("geom")) :
891 Move<VkShaderModule>());
892 const auto fragModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
893
894 const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
895 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
896 nullptr, // const void* pNext;
897 0u, // VkPipelineInputAssemblyStateCreateFlags flags;
898 VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, // VkPrimitiveTopology topology;
899 VK_FALSE, // VkBool32 primitiveRestartEnable;
900 };
901
902 VkPipelineTessellationDomainOriginStateCreateInfo domainOriginStateCreateInfo = {
903 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO, // VkStructureType sType;
904 nullptr, // const void* pNext;
905 m_params.domainOrigin.first, // VkTessellationDomainOrigin domainOrigin;
906 };
907
908 const auto tessPNext = (m_params.nonDefaultDomainOrigin() ? &domainOriginStateCreateInfo : nullptr);
909 const VkPipelineTessellationStateCreateInfo tessellationStateCreateInfo = {
910 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType;
911 tessPNext, // const void* pNext;
912 0u, // VkPipelineTessellationStateCreateFlags flags;
913 patchControlPoints, // uint32_t patchControlPoints;
914 };
915
916 const VkPipelineViewportStateCreateInfo viewportStateCreateInfo = {
917 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
918 nullptr, // const void* pNext;
919 0u, // VkPipelineViewportStateCreateFlags flags;
920 de::sizeU32(viewports), // uint32_t viewportCount;
921 de::dataOrNull(viewports), // const VkViewport* pViewports;
922 de::sizeU32(scissors), // uint32_t scissorCount;
923 de::dataOrNull(scissors), // const VkRect2D* pScissors;
924 };
925
926 // In the rasterization parameters, use wireframe mode to see each triangle if possible.
927 // This makes the test harder to pass by mistake.
928 // We also cull back faces, which will help test domain origin.
929 // The front face changes with the domain origin.
930 const auto frontFace =
931 ((m_params.domainOrigin.second == VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT) ?
932 VK_FRONT_FACE_COUNTER_CLOCKWISE // With the default value it's as specified in the shader.
933 :
934 VK_FRONT_FACE_CLOCKWISE); // Otherwise the winding order changes.
935 const auto polygonMode =
936 ((m_context.getDeviceFeatures().fillModeNonSolid) ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL);
937 const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
938 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
939 nullptr, // const void* pNext;
940 0u, // VkPipelineRasterizationStateCreateFlags flags;
941 VK_FALSE, // VkBool32 depthClampEnable;
942 VK_FALSE, // VkBool32 rasterizerDiscardEnable;
943 polygonMode, // VkPolygonMode polygonMode;
944 VK_CULL_MODE_BACK_BIT, // VkCullModeFlags cullMode;
945 frontFace, // VkFrontFace frontFace;
946 VK_FALSE, // VkBool32 depthBiasEnable;
947 0.0f, // float depthBiasConstantFactor;
948 0.0f, // float depthBiasClamp;
949 0.0f, // float depthBiasSlopeFactor;
950 1.0f, // float lineWidth;
951 };
952
953 // Create two pipelines varying the tessellation evaluation module.
954 const auto pipeline0 =
955 makeGraphicsPipeline(ctx.vkd, ctx.device, *pipelineLayout, *vertModule, *tescModule, *teseModule0, *geomModule,
956 *fragModule, *renderPass, 0u, nullptr, &inputAssemblyStateCreateInfo,
957 &tessellationStateCreateInfo, &viewportStateCreateInfo, &rasterizationStateCreateInfo);
958
959 domainOriginStateCreateInfo.domainOrigin = m_params.domainOrigin.second;
960
961 const auto pipeline1 =
962 makeGraphicsPipeline(ctx.vkd, ctx.device, *pipelineLayout, *vertModule, *tescModule, *teseModule1, *geomModule,
963 *fragModule, *renderPass, 0u, nullptr, &inputAssemblyStateCreateInfo,
964 &tessellationStateCreateInfo, &viewportStateCreateInfo, &rasterizationStateCreateInfo);
965
966 const auto cmdPool = makeCommandPool(ctx.vkd, ctx.device, ctx.qfIndex);
967 const auto cmdBufferRef = allocateCommandBuffer(ctx.vkd, ctx.device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
968 const auto cmdBufferRes = allocateCommandBuffer(ctx.vkd, ctx.device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
969
970 const tcu::Vec2 noOffset(0.0f, 0.0f);
971 const tcu::Vec2 offscreenOffset(50.0f, 50.0f);
972 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
973
974 // Reference image.
975 beginCommandBuffer(ctx.vkd, *cmdBufferRef);
976 beginRenderPass(ctx.vkd, *cmdBufferRef, *renderPass, *framebuffer0, scissors.at(0u), clearColor);
977 ctx.vkd.cmdBindVertexBuffers(*cmdBufferRef, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
978 ctx.vkd.cmdBindPipeline(*cmdBufferRef, bindPoint, *pipeline1);
979 ctx.vkd.cmdPushConstants(*cmdBufferRef, *pipelineLayout, pcStages, 0u, pcSize, &noOffset);
980 ctx.vkd.cmdDraw(*cmdBufferRef, vertexCount, 1u, 0u, 0u);
981 endRenderPass(ctx.vkd, *cmdBufferRef);
982 copyImageToBuffer(ctx.vkd, *cmdBufferRef, referenceBuffer.getImage(), referenceBuffer.getBuffer(),
983 fbExtent.swizzle(0, 1), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
984 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u, VK_IMAGE_ASPECT_COLOR_BIT,
985 VK_IMAGE_ASPECT_COLOR_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
986 endCommandBuffer(ctx.vkd, *cmdBufferRef);
987 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, *cmdBufferRef);
988
989 // Result image.
990 beginCommandBuffer(ctx.vkd, *cmdBufferRes);
991 beginRenderPass(ctx.vkd, *cmdBufferRes, *renderPass, *framebuffer1, scissors.at(0u), clearColor);
992 ctx.vkd.cmdBindVertexBuffers(*cmdBufferRes, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
993 // Draw offscreen first to force tessellation state emission.
994 ctx.vkd.cmdBindPipeline(*cmdBufferRes, bindPoint, *pipeline0);
995 ctx.vkd.cmdPushConstants(*cmdBufferRes, *pipelineLayout, pcStages, 0u, pcSize, &offscreenOffset);
996 ctx.vkd.cmdDraw(*cmdBufferRes, vertexCount, 1u, 0u, 0u);
997 // Draw on screen second changing some tessellation state.
998 ctx.vkd.cmdBindPipeline(*cmdBufferRes, bindPoint, *pipeline1);
999 ctx.vkd.cmdPushConstants(*cmdBufferRes, *pipelineLayout, pcStages, 0u, pcSize, &noOffset);
1000 ctx.vkd.cmdDraw(*cmdBufferRes, vertexCount, 1u, 0u, 0u);
1001 endRenderPass(ctx.vkd, *cmdBufferRes);
1002 copyImageToBuffer(ctx.vkd, *cmdBufferRes, resultBuffer.getImage(), resultBuffer.getBuffer(), fbExtent.swizzle(0, 1),
1003 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
1004 VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
1005 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
1006 endCommandBuffer(ctx.vkd, *cmdBufferRes);
1007 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, *cmdBufferRes);
1008
1009 invalidateAlloc(ctx.vkd, ctx.device, referenceBuffer.getBufferAllocation());
1010 invalidateAlloc(ctx.vkd, ctx.device, resultBuffer.getBufferAllocation());
1011
1012 tcu::ConstPixelBufferAccess referenceAccess(tcuFormat, fbExtent,
1013 referenceBuffer.getBufferAllocation().getHostPtr());
1014 tcu::ConstPixelBufferAccess resultAccess(tcuFormat, fbExtent, resultBuffer.getBufferAllocation().getHostPtr());
1015
1016 auto &log = m_context.getTestContext().getLog();
1017 const float threshold = 0.005f; // 1/255 < 0.005 < 2/255
1018 const tcu::Vec4 thresholdVec(threshold, threshold, threshold, 0.0f);
1019
1020 if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, thresholdVec,
1021 tcu::COMPARE_LOG_ON_ERROR))
1022 return tcu::TestStatus::fail("Color result does not match reference image -- check log for details");
1023
1024 // Render pass and framebuffers.const DeviceCoreFeature requiredDeviceCoreFeature
1025 return tcu::TestStatus::pass("Pass");
1026 }
1027
getDomainOriginName(VkTessellationDomainOrigin value)1028 std::string getDomainOriginName(VkTessellationDomainOrigin value)
1029 {
1030 static const size_t prefixLen = strlen("VK_TESSELLATION_DOMAIN_ORIGIN_");
1031 std::string nameStr = getTessellationDomainOriginName(value);
1032
1033 return de::toLower(nameStr.substr(prefixLen));
1034 }
1035
1036 enum TessInstancedType
1037 {
1038 TESSINSTANCEDTYPE_NO_PATCHES = 0,
1039 TESSINSTANCEDTYPE_INSTANCED,
1040
1041 TESSINSTANCEDTYPE_LAST,
1042 };
1043
1044 struct TessInstancedDrawTestParams
1045 {
1046 TessInstancedType testType;
1047 TessPrimitiveType primitiveType;
1048 };
1049
getInstancedDrawTestName(const TessInstancedType type)1050 static inline const char *getInstancedDrawTestName(const TessInstancedType type)
1051 {
1052 static std::string primitiveName[] = {
1053 "no_patches", // TESSINSTANCEDTYPE_NO_PATCHES
1054 "instances", // TESSINSTANCEDTYPE_INSTANCED
1055 };
1056
1057 if (type >= TESSINSTANCEDTYPE_LAST)
1058 {
1059 DE_FATAL("Unexpected test type.");
1060 return nullptr;
1061 }
1062
1063 return primitiveName[type].c_str();
1064 }
1065
1066 class TessInstancedDrawTestInstance : public vkt::TestInstance
1067 {
1068 public:
TessInstancedDrawTestInstance(Context & context,const TessInstancedDrawTestParams & testParams)1069 TessInstancedDrawTestInstance(Context &context, const TessInstancedDrawTestParams &testParams)
1070 : vkt::TestInstance(context)
1071 , m_params(testParams)
1072 {
1073 }
1074
~TessInstancedDrawTestInstance()1075 ~TessInstancedDrawTestInstance()
1076 {
1077 }
1078
1079 tcu::TestStatus iterate(void);
1080
1081 protected:
1082 Move<VkBuffer> createBufferAndBindMemory(uint32_t bufferSize, VkBufferUsageFlags usageFlags,
1083 AllocationMp *outMemory);
1084 Move<VkImage> createImageAndBindMemory(tcu::IVec3 imgSize, VkFormat format, VkImageUsageFlags usageFlags,
1085 AllocationMp *outMemory);
1086 Move<VkImageView> createImageView(VkFormat format, VkImage image);
1087 Move<VkPipelineLayout> createPipelineLayout();
1088 Move<VkPipeline> createGraphicsPipeline(uint32_t patchCnt, VkPipelineLayout layout, VkRenderPass renderpass);
1089
1090 std::vector<tcu::Vec4> genPerVertexVertexData();
1091 std::vector<tcu::Vec4> genPerInstanceVertexData();
1092 std::vector<uint16_t> genIndexData();
1093
1094 protected:
1095 const TessInstancedDrawTestParams m_params;
1096 };
1097
1098 class InstancedVertexShader : public rr::VertexShader
1099 {
1100 public:
InstancedVertexShader(void)1101 InstancedVertexShader(void) : rr::VertexShader(2, 0)
1102 {
1103 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT;
1104 m_inputs[1].type = rr::GENERICVECTYPE_FLOAT;
1105 }
1106
~InstancedVertexShader()1107 virtual ~InstancedVertexShader()
1108 {
1109 }
1110
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const1111 void shadeVertices(const rr::VertexAttrib *inputs, rr::VertexPacket *const *packets, const int numPackets) const
1112 {
1113 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1114 {
1115 const tcu::Vec4 position =
1116 rr::readVertexAttribFloat(inputs[0], packets[packetNdx]->instanceNdx, packets[packetNdx]->vertexNdx);
1117 const tcu::Vec4 instancePosition =
1118 rr::readVertexAttribFloat(inputs[1], packets[packetNdx]->instanceNdx, packets[packetNdx]->vertexNdx);
1119
1120 packets[packetNdx]->position = position + instancePosition;
1121 }
1122 }
1123 };
1124
1125 class InstancedFragmentShader : public rr::FragmentShader
1126 {
1127 public:
InstancedFragmentShader(void)1128 InstancedFragmentShader(void) : rr::FragmentShader(0, 1)
1129 {
1130 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT;
1131 }
1132
~InstancedFragmentShader()1133 virtual ~InstancedFragmentShader()
1134 {
1135 }
1136
shadeFragments(rr::FragmentPacket *,const int numPackets,const rr::FragmentShadingContext & context) const1137 void shadeFragments(rr::FragmentPacket *, const int numPackets, const rr::FragmentShadingContext &context) const
1138 {
1139 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
1140 {
1141 for (int fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx)
1142 {
1143 const tcu::Vec4 color(1.0f, 0.0f, 1.0f, 1.0f);
1144 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color);
1145 }
1146 }
1147 }
1148 };
1149
1150 class TessInstancedDrawTestCase : public vkt::TestCase
1151 {
1152 public:
TessInstancedDrawTestCase(tcu::TestContext & testCtx,const std::string & name,const TessInstancedDrawTestParams & testParams)1153 TessInstancedDrawTestCase(tcu::TestContext &testCtx, const std::string &name,
1154 const TessInstancedDrawTestParams &testParams)
1155 : vkt::TestCase(testCtx, name)
1156 , m_params(testParams)
1157 {
1158 }
1159
~TessInstancedDrawTestCase()1160 ~TessInstancedDrawTestCase()
1161 {
1162 }
1163
1164 void checkSupport(Context &context) const;
1165 void initPrograms(vk::SourceCollections &programCollection) const;
createInstance(Context & context) const1166 TestInstance *createInstance(Context &context) const
1167 {
1168 return new TessInstancedDrawTestInstance(context, m_params);
1169 }
1170
1171 protected:
1172 const TessInstancedDrawTestParams m_params;
1173 };
1174
checkSupport(Context & context) const1175 void TessInstancedDrawTestCase::checkSupport(Context &context) const
1176 {
1177 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
1178 }
1179
initPrograms(vk::SourceCollections & programCollection) const1180 void TessInstancedDrawTestCase::initPrograms(vk::SourceCollections &programCollection) const
1181 {
1182 std::ostringstream vert;
1183 vert << "#version 460\n"
1184 << "\n"
1185 << "layout (location = 0) in vec4 inPos;\n"
1186 << "layout (location = 1) in vec4 instancePos;\n"
1187 << "\n"
1188 << "void main()\n"
1189 << "{\n"
1190 << " vec4 pos = inPos + instancePos;\n"
1191 << "\n"
1192 << " gl_Position = pos;\n"
1193 << "}\n";
1194 programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
1195
1196 std::ostringstream frag;
1197 frag << "#version 460\n"
1198 << "\n"
1199 << "layout (location = 0) out vec4 fragColor;\n"
1200 << "\n"
1201 << "void main()\n"
1202 << "{\n"
1203 << " fragColor = vec4(1.0f, 0.0f, 1.0f, 1.0f);\n"
1204 << "}\n";
1205 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
1206
1207 const int numVertices = m_params.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4;
1208
1209 std::ostringstream tessCntrl;
1210 tessCntrl << "#version 460\n"
1211 << "\n"
1212 << "layout (vertices = " << numVertices << ") out;\n"
1213 << "\n"
1214 << "void main()\n"
1215 << "{\n"
1216 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1217 << " \n"
1218 << " gl_TessLevelInner[0] = 1.0f;\n"
1219 << " gl_TessLevelInner[1] = 1.0f;\n"
1220 << " gl_TessLevelOuter[0] = 1.0f;\n"
1221 << " gl_TessLevelOuter[1] = 1.0f;\n"
1222 << " gl_TessLevelOuter[2] = 1.0f;\n"
1223 << " gl_TessLevelOuter[3] = 1.0f;\n"
1224 << " \n"
1225 << "}\n";
1226 programCollection.glslSources.add("tess_ctrl") << glu::TessellationControlSource(tessCntrl.str());
1227
1228 std::ostringstream tessEvel;
1229 tessEvel << "#version 460\n"
1230 << "\n"
1231 << "layout ( " << getTessPrimitiveTypeShaderName(m_params.primitiveType) << " ) in;\n"
1232 << "\n"
1233 << "void main()\n"
1234 << "{\n"
1235 << " const float u = gl_TessCoord.x;\n"
1236 << " const float v = gl_TessCoord.y;\n";
1237 if (m_params.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
1238 {
1239 tessEvel << " gl_Position = (1 - u) * (1 - v) * gl_in[0].gl_Position + (1 - u) * v * gl_in[1].gl_Position "
1240 << "+ u * (1 - v) * gl_in[2].gl_Position + u * v * gl_in[3].gl_Position;\n";
1241 }
1242 else // m_params.primitiveType == TESSPRIMITIVETYPE_QUADS
1243 {
1244 tessEvel << " gl_Position = (1 - u) * (1 - v) * gl_in[0].gl_Position + u * (1 - v) * gl_in[1].gl_Position "
1245 << "+ u * v * gl_in[2].gl_Position + (1 - u) * v * gl_in[3].gl_Position;\n";
1246 }
1247 tessEvel << "}\n";
1248 programCollection.glslSources.add("tess_eval") << glu::TessellationEvaluationSource(tessEvel.str());
1249 }
1250
iterate(void)1251 tcu::TestStatus TessInstancedDrawTestInstance::iterate(void)
1252 {
1253 const DeviceInterface &devInterface = m_context.getDeviceInterface();
1254 VkDevice dev = m_context.getDevice();
1255 VkQueue queue = m_context.getUniversalQueue();
1256
1257 // Command buffer
1258 Move<VkCommandPool> cmdPool(makeCommandPool(devInterface, dev, m_context.getUniversalQueueFamilyIndex()));
1259 Move<VkCommandBuffer> cmdBuffer(
1260 allocateCommandBuffer(devInterface, dev, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1261
1262 // Per vertex vertex buffer
1263 const std::vector<tcu::Vec4> perVertexVertices = genPerVertexVertexData();
1264 const uint32_t perVertexVBSize = static_cast<uint32_t>(perVertexVertices.size() * sizeof(tcu::Vec4));
1265
1266 AllocationMp perVertexVBMemory;
1267 Move<VkBuffer> perVertexVB(
1268 createBufferAndBindMemory(perVertexVBSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &perVertexVBMemory));
1269
1270 {
1271 deMemcpy(perVertexVBMemory->getHostPtr(), perVertexVertices.data(), perVertexVBSize);
1272 flushAlloc(devInterface, dev, *perVertexVBMemory);
1273 // No barrier needed, flushed memory is automatically visible
1274 }
1275
1276 const uint32_t patchCnt = static_cast<uint32_t>(perVertexVertices.size());
1277
1278 // Per instance vertex buffer
1279 const std::vector<tcu::Vec4> perInstanceVertices = genPerInstanceVertexData();
1280 const uint32_t perInstanceVBSize = static_cast<uint32_t>(perInstanceVertices.size() * sizeof(tcu::Vec4));
1281
1282 AllocationMp perInstanceVBMemory;
1283 Move<VkBuffer> perInstanceVB(
1284 createBufferAndBindMemory(perInstanceVBSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &perInstanceVBMemory));
1285
1286 {
1287 deMemcpy(perInstanceVBMemory->getHostPtr(), perInstanceVertices.data(), perInstanceVBSize);
1288 flushAlloc(devInterface, dev, *perInstanceVBMemory);
1289 // No barrier needed, flushed memory is automatically visible
1290 }
1291
1292 // Render target
1293 const tcu::IVec3 renderSize(256, 256, 1);
1294 const vk::VkFormat rtFormat = VK_FORMAT_R8G8B8A8_UNORM;
1295
1296 AllocationMp rtMemory;
1297 Move<VkImage> renderTargetImage(createImageAndBindMemory(
1298 renderSize, rtFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, &rtMemory));
1299
1300 // Render target view
1301 Move<VkImageView> rtView(createImageView(rtFormat, *renderTargetImage));
1302
1303 // Pixel buffer
1304 const uint32_t pixelBufferSize = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(rtFormat));
1305
1306 AllocationMp pixelBufferMemory;
1307 Move<VkBuffer> pixelBuffer(
1308 createBufferAndBindMemory(pixelBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, &pixelBufferMemory));
1309
1310 // Pipeline layout
1311 Move<VkPipelineLayout> pipelineLayout(createPipelineLayout());
1312
1313 // Renderpass
1314 Move<VkRenderPass> renderPass(makeRenderPass(devInterface, dev, rtFormat));
1315
1316 // Framebuffer
1317 Move<VkFramebuffer> framebuffer(
1318 makeFramebuffer(devInterface, dev, *renderPass, *rtView, renderSize.x(), renderSize.y()));
1319
1320 // Pipeline
1321 Move<VkPipeline> pipeline(createGraphicsPipeline(patchCnt, *pipelineLayout, *renderPass));
1322
1323 // Rendering
1324 beginCommandBuffer(devInterface, *cmdBuffer);
1325
1326 const vk::VkBuffer vertexBuffers[] = {*perVertexVB, *perInstanceVB};
1327 const vk::VkDeviceSize vertexBufferOffsets[] = {0, 0};
1328
1329 devInterface.cmdBindVertexBuffers(*cmdBuffer, 0, DE_LENGTH_OF_ARRAY(vertexBuffers), vertexBuffers,
1330 vertexBufferOffsets);
1331
1332 devInterface.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1333
1334 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
1335 beginRenderPass(devInterface, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(renderSize), clearColor);
1336
1337 if (m_params.testType == TESSINSTANCEDTYPE_INSTANCED)
1338 devInterface.cmdDraw(*cmdBuffer, patchCnt, static_cast<uint32_t>(perInstanceVertices.size()), 0u, 0u);
1339 else // m_params.testType == TESSINSTANCEDTYPE_NO_PATCHES
1340 devInterface.cmdDraw(*cmdBuffer, 2u, 1u, 0u, 0u);
1341
1342 endRenderPass(devInterface, *cmdBuffer);
1343
1344 copyImageToBuffer(devInterface, *cmdBuffer, *renderTargetImage, *pixelBuffer, {renderSize.x(), renderSize.y()});
1345
1346 endCommandBuffer(devInterface, *cmdBuffer);
1347
1348 submitCommandsAndWait(devInterface, dev, queue, cmdBuffer.get());
1349
1350 // Reference rendering
1351 tcu::TextureFormat tcuFormat = mapVkFormat(rtFormat);
1352 tcu::TextureLevel refImage(tcuFormat, renderSize.x(), renderSize.y());
1353
1354 tcu::clear(refImage.getAccess(), clearColor);
1355
1356 if (m_params.testType == TESSINSTANCEDTYPE_INSTANCED)
1357 {
1358 const InstancedVertexShader vertShader;
1359 const InstancedFragmentShader fragShader;
1360 const rr::Program program(&vertShader, &fragShader);
1361 const rr::MultisamplePixelBufferAccess colorBuffer =
1362 rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(refImage.getAccess());
1363 const rr::RenderTarget renderTarget(colorBuffer);
1364 const rr::RenderState renderState((rr::ViewportState(colorBuffer)),
1365 m_context.getDeviceProperties().limits.subPixelPrecisionBits);
1366 const rr::Renderer renderer;
1367
1368 const rr::VertexAttrib vertexAttribs[] = {
1369 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0,
1370 perVertexVertices.data()), // 0 means per vertex attribute
1371 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 1,
1372 perInstanceVertices.data()) // 1 means per instance attribute
1373 };
1374
1375 if (m_params.primitiveType == TESSPRIMITIVETYPE_QUADS)
1376 {
1377 const std::vector<uint16_t> indices = genIndexData();
1378
1379 const rr::DrawIndices drawIndices(indices.data());
1380 const rr::PrimitiveList primitives =
1381 rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, static_cast<int>(indices.size()), drawIndices);
1382 const rr::DrawCommand command(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs),
1383 &vertexAttribs[0], primitives);
1384
1385 renderer.drawInstanced(command, 4);
1386 }
1387 else
1388 {
1389 const rr::PrimitiveList primitives =
1390 rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, static_cast<int>(perVertexVertices.size()), 0);
1391 const rr::DrawCommand command(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs),
1392 &vertexAttribs[0], primitives);
1393
1394 renderer.drawInstanced(command, 4);
1395 }
1396 }
1397
1398 // Compare result
1399 tcu::TestLog &log = m_context.getTestContext().getLog();
1400 qpTestResult res = QP_TEST_RESULT_FAIL;
1401 const tcu::ConstPixelBufferAccess resultAccess(tcuFormat, renderSize, pixelBufferMemory->getHostPtr());
1402 const tcu::ConstPixelBufferAccess refAccess = refImage.getAccess();
1403
1404 if (tcu::fuzzyCompare(log, "Result", "", refAccess, resultAccess, 0.05f, tcu::COMPARE_LOG_RESULT))
1405 res = QP_TEST_RESULT_PASS;
1406
1407 return tcu::TestStatus(res, qpGetTestResultName(res));
1408 }
1409
createBufferAndBindMemory(uint32_t bufferSize,VkBufferUsageFlags usageFlags,AllocationMp * outMemory)1410 Move<VkBuffer> TessInstancedDrawTestInstance::createBufferAndBindMemory(uint32_t bufferSize,
1411 VkBufferUsageFlags usageFlags,
1412 AllocationMp *outMemory)
1413 {
1414 const VkDevice &device = m_context.getDevice();
1415 const DeviceInterface &vkdi = m_context.getDeviceInterface();
1416 Allocator &allocator = m_context.getDefaultAllocator();
1417
1418 const VkBufferCreateInfo bufferCreateInfo = {
1419 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType
1420 nullptr, // const void* pNext
1421 0, // VkBufferCreateFlags flags
1422 bufferSize, // VkDeviceSize size
1423 usageFlags, // VkBufferUsageFlags usage
1424 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
1425 0, // uint32_t queueFamilyIndexCount
1426 nullptr, // const uint32_t* pQueueFamilyIndices
1427 };
1428
1429 Move<VkBuffer> buffer(vk::createBuffer(vkdi, device, &bufferCreateInfo));
1430 const VkMemoryRequirements requirements = getBufferMemoryRequirements(vkdi, device, *buffer);
1431 AllocationMp bufferMemory = allocator.allocate(requirements, MemoryRequirement::HostVisible);
1432
1433 VK_CHECK(vkdi.bindBufferMemory(device, *buffer, bufferMemory->getMemory(), bufferMemory->getOffset()));
1434 *outMemory = bufferMemory;
1435
1436 return buffer;
1437 }
1438
createImageAndBindMemory(tcu::IVec3 imgSize,VkFormat format,VkImageUsageFlags usageFlags,AllocationMp * outMemory)1439 Move<VkImage> TessInstancedDrawTestInstance::createImageAndBindMemory(tcu::IVec3 imgSize, VkFormat format,
1440 VkImageUsageFlags usageFlags,
1441 AllocationMp *outMemory)
1442 {
1443 const VkDevice &device = m_context.getDevice();
1444 const DeviceInterface &vkdi = m_context.getDeviceInterface();
1445 Allocator &allocator = m_context.getDefaultAllocator();
1446
1447 const VkImageCreateInfo imageCreateInfo = {
1448 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType
1449 nullptr, // const void* pNext
1450 0u, // VkImageCreateFlags flags
1451 VK_IMAGE_TYPE_2D, // VkImageType imageType
1452 format, // VkFormat format
1453 makeExtent3D(imgSize), // VkExtent3D extent
1454 1u, // uint32_t mipLevels
1455 1u, // uint32_t arrayLayers
1456 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples
1457 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling
1458 usageFlags, // VkImageUsageFlags usage
1459 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
1460 0u, // uint32_t queueFamilyIndexCount
1461 nullptr, // const uint32_t* pQueueFamilyIndices
1462 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout
1463 };
1464
1465 Move<VkImage> image(vk::createImage(vkdi, device, &imageCreateInfo));
1466 const VkMemoryRequirements requirements = getImageMemoryRequirements(vkdi, device, *image);
1467 AllocationMp imageMemory = allocator.allocate(requirements, MemoryRequirement::Any);
1468
1469 VK_CHECK(vkdi.bindImageMemory(device, *image, imageMemory->getMemory(), imageMemory->getOffset()));
1470 *outMemory = imageMemory;
1471
1472 return image;
1473 }
1474
createImageView(VkFormat format,VkImage image)1475 Move<VkImageView> TessInstancedDrawTestInstance::createImageView(VkFormat format, VkImage image)
1476 {
1477 const VkDevice &device = m_context.getDevice();
1478 const DeviceInterface &vkdi = m_context.getDeviceInterface();
1479
1480 VkImageSubresourceRange range = {
1481 VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask
1482 0u, // uint32_t baseMipLevel
1483 1u, // uint32_t levelCount
1484 0u, // uint32_t baseArrayLayer
1485 1u, // uint32_t layerCount
1486 };
1487
1488 return makeImageView(vkdi, device, image, VK_IMAGE_VIEW_TYPE_2D, format, range);
1489 }
1490
createPipelineLayout()1491 Move<VkPipelineLayout> TessInstancedDrawTestInstance::createPipelineLayout()
1492 {
1493 const VkDevice &device = m_context.getDevice();
1494 const DeviceInterface &vkdi = m_context.getDeviceInterface();
1495
1496 const VkPipelineLayoutCreateInfo createInfo = {
1497 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType
1498 nullptr, // const void* pNext
1499 (VkPipelineLayoutCreateFlags)0, // VkPipelineLayoutCreateFlags flags
1500 0u, // uint32_t setLayoutCount
1501 nullptr, // const VkDescriptorSetLayout* pSetLayouts
1502 0u, // uint32_t pushConstantRangeCount
1503 nullptr, // const VkPushConstantRange* pPushConstantRanges
1504 };
1505
1506 return vk::createPipelineLayout(vkdi, device, &createInfo);
1507 }
1508
createGraphicsPipeline(uint32_t patchCnt,VkPipelineLayout layout,VkRenderPass renderpass)1509 Move<VkPipeline> TessInstancedDrawTestInstance::createGraphicsPipeline(uint32_t patchCnt, VkPipelineLayout layout,
1510 VkRenderPass renderpass)
1511 {
1512 const VkDevice &device = m_context.getDevice();
1513 const DeviceInterface &vkdi = m_context.getDeviceInterface();
1514
1515 vk::BinaryCollection &binCollection = m_context.getBinaryCollection();
1516 Move<VkShaderModule> vertModule(createShaderModule(vkdi, device, binCollection.get("vert")));
1517 Move<VkShaderModule> tessCtrlModule(createShaderModule(vkdi, device, binCollection.get("tess_ctrl")));
1518 Move<VkShaderModule> tessEvalModule(createShaderModule(vkdi, device, binCollection.get("tess_eval")));
1519 Move<VkShaderModule> fragModule(createShaderModule(vkdi, device, binCollection.get("frag")));
1520
1521 VkPipelineShaderStageCreateInfo stageInfos[4];
1522 uint32_t stageNdx = 0;
1523
1524 {
1525 const VkPipelineShaderStageCreateInfo pipelineShaderStageParam = {
1526 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1527 nullptr, // const void* pNext;
1528 0, // VkPipelineShaderStageCreateFlags flags;
1529 VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
1530 *vertModule, // VkShaderModule module;
1531 "main", // const char* pName;
1532 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
1533 };
1534 stageInfos[stageNdx++] = pipelineShaderStageParam;
1535 }
1536
1537 {
1538 const VkPipelineShaderStageCreateInfo pipelineShaderStageParam = {
1539 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1540 nullptr, // const void* pNext;
1541 0, // VkPipelineShaderStageCreateFlags flags;
1542 VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, // VkShaderStageFlagBits stage;
1543 *tessCtrlModule, // VkShaderModule module;
1544 "main", // const char* pName;
1545 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
1546 };
1547 stageInfos[stageNdx++] = pipelineShaderStageParam;
1548 }
1549
1550 {
1551 const VkPipelineShaderStageCreateInfo pipelineShaderStageParam = {
1552 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1553 nullptr, // const void* pNext;
1554 0, // VkPipelineShaderStageCreateFlags flags;
1555 VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, // VkShaderStageFlagBits stage;
1556 *tessEvalModule, // VkShaderModule module;
1557 "main", // const char* pName;
1558 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
1559 };
1560 stageInfos[stageNdx++] = pipelineShaderStageParam;
1561 }
1562
1563 {
1564 const VkPipelineShaderStageCreateInfo pipelineShaderStageParam = {
1565 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1566 nullptr, // const void* pNext;
1567 0, // VkPipelineShaderStageCreateFlags flags;
1568 VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
1569 *fragModule, // VkShaderModule module;
1570 "main", // const char* pName;
1571 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
1572 };
1573 stageInfos[stageNdx++] = pipelineShaderStageParam;
1574 }
1575
1576 const VkVertexInputBindingDescription vertexInputBindingDescriptions[] = {
1577 {
1578 0u, // uint32_t binding
1579 sizeof(tcu::Vec4), // uint32_t stride
1580 VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate
1581 },
1582 {
1583 1u, // uint32_t binding
1584 sizeof(tcu::Vec4), // uint32_t stride
1585 VK_VERTEX_INPUT_RATE_INSTANCE // VkVertexInputRate inputRate
1586 }};
1587
1588 const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = {
1589 {
1590 0u, // uint32_t location
1591 0u, // uint32_t binding
1592 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format
1593 0u // uint32_t offset
1594 },
1595 {
1596 1u, // uint32_t location
1597 1u, // uint32_t binding
1598 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format
1599 0u, // uint32_t offset
1600 }};
1601
1602 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfoDefault = {
1603 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType
1604 nullptr, // const void* pNext
1605 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags
1606 2u, // uint32_t vertexBindingDescriptionCount
1607 vertexInputBindingDescriptions, // const VkVertexInputBindingDescription* pVertexBindingDescriptions
1608 2u, // uint32_t vertexAttributeDescriptionCount
1609 vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions
1610 };
1611
1612 const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfoDefault = {
1613 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType
1614 nullptr, // const void* pNext
1615 0u, // VkPipelineInputAssemblyStateCreateFlags flags
1616 VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, // VkPrimitiveTopology topology
1617 VK_FALSE // VkBool32 primitiveRestartEnable
1618 };
1619
1620 const VkPipelineTessellationStateCreateInfo tessStateCreateInfo = {
1621 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType
1622 nullptr, // const void* pNext
1623 0u, // VkPipelineTessellationStateCreateFlags flags
1624 patchCnt // uint32_t patchControlPoints
1625 };
1626
1627 const VkViewport viewport = {
1628 0.0f, // float x
1629 0.0f, // float y
1630 256.0f, // float width
1631 256.0f, // float height
1632 0.0f, // float minDepth
1633 1.0f // float maxDepth
1634 };
1635
1636 const VkRect2D scissor = {
1637 {0, 0}, // VkOffset2D offset
1638 {256u, 256u} // VkExtent2D extent
1639 };
1640
1641 const VkPipelineViewportStateCreateInfo viewportStateCreateInfoDefault = {
1642 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType
1643 nullptr, // const void* pNext
1644 (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags
1645 1u, // uint32_t viewportCount
1646 &viewport, // const VkViewport* pViewports
1647 1u, // uint32_t scissorCount
1648 &scissor // const VkRect2D* pScissors
1649 };
1650
1651 const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfoDefault = {
1652 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType
1653 nullptr, // const void* pNext
1654 0u, // VkPipelineRasterizationStateCreateFlags flags
1655 VK_FALSE, // VkBool32 depthClampEnable
1656 VK_FALSE, // VkBool32 rasterizerDiscardEnable
1657 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode
1658 VK_CULL_MODE_NONE, // VkCullModeFlags cullMode
1659 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace
1660 VK_FALSE, // VkBool32 depthBiasEnable
1661 0.0f, // float depthBiasConstantFactor
1662 0.0f, // float depthBiasClamp
1663 0.0f, // float depthBiasSlopeFactor
1664 1.0f // float lineWidth
1665 };
1666
1667 const VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfoDefault = {
1668 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType
1669 nullptr, // const void* pNext
1670 0u, // VkPipelineMultisampleStateCreateFlags flags
1671 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples
1672 VK_FALSE, // VkBool32 sampleShadingEnable
1673 1.0f, // float minSampleShading
1674 nullptr, // const VkSampleMask* pSampleMask
1675 VK_FALSE, // VkBool32 alphaToCoverageEnable
1676 VK_FALSE // VkBool32 alphaToOneEnable
1677 };
1678
1679 const VkStencilOpState stencilOpState = {
1680 VK_STENCIL_OP_KEEP, // VkStencilOp failOp
1681 VK_STENCIL_OP_KEEP, // VkStencilOp passOp
1682 VK_STENCIL_OP_KEEP, // VkStencilOp depthFailOp
1683 VK_COMPARE_OP_NEVER, // VkCompareOp compareOp
1684 0, // uint32_t compareMask
1685 0, // uint32_t writeMask
1686 0 // uint32_t reference
1687 };
1688
1689 const VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfoDefault = {
1690 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType
1691 nullptr, // const void* pNext
1692 0u, // VkPipelineDepthStencilStateCreateFlags flags
1693 VK_FALSE, // VkBool32 depthTestEnable
1694 VK_FALSE, // VkBool32 depthWriteEnable
1695 VK_COMPARE_OP_LESS_OR_EQUAL, // VkCompareOp depthCompareOp
1696 VK_FALSE, // VkBool32 depthBoundsTestEnable
1697 VK_FALSE, // VkBool32 stencilTestEnable
1698 stencilOpState, // VkStencilOpState front
1699 stencilOpState, // VkStencilOpState back
1700 0.0f, // float minDepthBounds
1701 1.0f, // float maxDepthBounds
1702 };
1703
1704 const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
1705 VK_FALSE, // VkBool32 blendEnable
1706 VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcColorBlendFactor
1707 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor
1708 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp
1709 VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcAlphaBlendFactor
1710 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor
1711 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp
1712 VK_COLOR_COMPONENT_R_BIT // VkColorComponentFlags colorWriteMask
1713 | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
1714
1715 const VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfoDefault = {
1716 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType
1717 nullptr, // const void* pNext
1718 0u, // VkPipelineColorBlendStateCreateFlags flags
1719 VK_FALSE, // VkBool32 logicOpEnable
1720 VK_LOGIC_OP_CLEAR, // VkLogicOp logicOp
1721 1u, // uint32_t attachmentCount
1722 &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments
1723 {0.0f, 0.0f, 0.0f, 0.0f} // float blendConstants[4]
1724 };
1725
1726 const VkGraphicsPipelineCreateInfo pipelineCreateInfo = {
1727 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType
1728 nullptr, // const void* pNext
1729 0, // VkPipelineCreateFlags flags
1730 stageNdx, // uint32_t stageCount
1731 stageInfos, // const VkPipelineShaderStageCreateInfo* pStages
1732 &vertexInputStateCreateInfoDefault, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState
1733 &inputAssemblyStateCreateInfoDefault, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState
1734 &tessStateCreateInfo, // const VkPipelineTessellationStateCreateInfo* pTessellationState
1735 &viewportStateCreateInfoDefault, // const VkPipelineViewportStateCreateInfo* pViewportState
1736 &rasterizationStateCreateInfoDefault, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState
1737 &multisampleStateCreateInfoDefault, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState
1738 &depthStencilStateCreateInfoDefault, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState
1739 &colorBlendStateCreateInfoDefault, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState
1740 nullptr, // const VkPipelineDynamicStateCreateInfo* pDynamicState
1741 layout, // VkPipelineLayout layout
1742 renderpass, // VkRenderPass renderPass
1743 0, // uint32_t subpass
1744 VK_NULL_HANDLE, // VkPipeline basePipelineHandle
1745 0 // int32_t basePipelineIndex;
1746 };
1747
1748 return vk::createGraphicsPipeline(vkdi, device, VK_NULL_HANDLE, &pipelineCreateInfo);
1749 }
1750
genPerVertexVertexData()1751 std::vector<tcu::Vec4> TessInstancedDrawTestInstance::genPerVertexVertexData()
1752 {
1753 std::vector<tcu::Vec4> vertices = {
1754 {-0.1f, -0.1f, 0.0f, 1.0f},
1755 {0.1f, -0.1f, 0.0f, 1.0f},
1756 {0.1f, 0.1f, 0.0f, 1.0f},
1757 {-0.1f, 0.1f, 0.0f, 1.0f},
1758 };
1759
1760 return vertices;
1761 }
1762
genPerInstanceVertexData()1763 std::vector<tcu::Vec4> TessInstancedDrawTestInstance::genPerInstanceVertexData()
1764 {
1765 std::vector<tcu::Vec4> vertices = {
1766 {-0.5f, -0.5f, 0.0f, 1.0f},
1767 {0.5f, -0.5f, 0.0f, 1.0f},
1768 {0.5f, 0.5f, 0.0f, 1.0f},
1769 {-0.5f, 0.5f, 0.0f, 1.0f},
1770 };
1771
1772 return vertices;
1773 }
1774
genIndexData()1775 std::vector<uint16_t> TessInstancedDrawTestInstance::genIndexData()
1776 {
1777 std::vector<uint16_t> indices = {0, 1, 2, 2, 3, 0};
1778
1779 return indices;
1780 }
1781
1782 } // namespace
1783
1784 //! These tests correspond to dEQP-GLES31.functional.tessellation.misc_draw.*
createMiscDrawTests(tcu::TestContext & testCtx)1785 tcu::TestCaseGroup *createMiscDrawTests(tcu::TestContext &testCtx)
1786 {
1787 // Miscellaneous draw-result-verifying cases
1788 de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "misc_draw"));
1789
1790 static const TessPrimitiveType primitivesNoIsolines[] = {
1791 TESSPRIMITIVETYPE_TRIANGLES,
1792 TESSPRIMITIVETYPE_QUADS,
1793 };
1794
1795 static const DrawType drawTypes[] = {
1796 DRAWTYPE_DRAW,
1797 DRAWTYPE_DRAW_INDIRECT,
1798 };
1799
1800 // Triangle fill case
1801 for (int drawTypeNdx = 0; drawTypeNdx < DE_LENGTH_OF_ARRAY(drawTypes); ++drawTypeNdx)
1802 for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
1803 for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
1804 {
1805 const TessPrimitiveType primitiveType = primitivesNoIsolines[primitiveTypeNdx];
1806 const SpacingMode spacingMode = static_cast<SpacingMode>(spacingModeNdx);
1807 const DrawType drawType = static_cast<DrawType>(drawTypeNdx);
1808 const std::string caseName = std::string() + "fill_cover_" +
1809 getTessPrimitiveTypeShaderName(primitiveType) + "_" +
1810 getSpacingModeShaderName(spacingMode) + "_" + getDrawName(drawType);
1811 const std::string refName = std::string() + "fill_cover_" +
1812 getTessPrimitiveTypeShaderName(primitiveType) + "_" +
1813 getSpacingModeShaderName(spacingMode);
1814
1815 // Check that there are no obvious gaps in the triangle-filled area of a tessellated shape
1816 addFunctionCaseWithPrograms(
1817 group.get(), caseName, initProgramsFillCoverCase, runTest,
1818 makeCaseDefinition(primitiveType, spacingMode, drawType, getReferenceImagePathPrefix(refName)));
1819 }
1820
1821 // Triangle non-overlap case
1822 for (int drawTypeNdx = 0; drawTypeNdx < DE_LENGTH_OF_ARRAY(drawTypes); ++drawTypeNdx)
1823 for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
1824 for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
1825 {
1826 const TessPrimitiveType primitiveType = primitivesNoIsolines[primitiveTypeNdx];
1827 const SpacingMode spacingMode = static_cast<SpacingMode>(spacingModeNdx);
1828 const DrawType drawType = static_cast<DrawType>(drawTypeNdx);
1829 const std::string caseName = std::string() + "fill_overlap_" +
1830 getTessPrimitiveTypeShaderName(primitiveType) + "_" +
1831 getSpacingModeShaderName(spacingMode) + "_" + getDrawName(drawType);
1832 const std::string refName = std::string() + "fill_overlap_" +
1833 getTessPrimitiveTypeShaderName(primitiveType) + "_" +
1834 getSpacingModeShaderName(spacingMode);
1835
1836 // Check that there are no obvious triangle overlaps in the triangle-filled area of a tessellated shape
1837 addFunctionCaseWithPrograms(
1838 group.get(), caseName, initProgramsFillNonOverlapCase, runTest,
1839 makeCaseDefinition(primitiveType, spacingMode, drawType, getReferenceImagePathPrefix(refName)));
1840 }
1841
1842 // Isolines
1843 for (int drawTypeNdx = 0; drawTypeNdx < DE_LENGTH_OF_ARRAY(drawTypes); ++drawTypeNdx)
1844 for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
1845 {
1846 const SpacingMode spacingMode = static_cast<SpacingMode>(spacingModeNdx);
1847 const DrawType drawType = static_cast<DrawType>(drawTypeNdx);
1848 const std::string caseName =
1849 std::string() + "isolines_" + getSpacingModeShaderName(spacingMode) + "_" + getDrawName(drawType);
1850 const std::string refName = std::string() + "isolines_" + getSpacingModeShaderName(spacingMode);
1851
1852 // Basic isolines render test
1853 addFunctionCaseWithPrograms(group.get(), caseName, checkSupportCase, initProgramsIsolinesCase, runTest,
1854 makeCaseDefinition(TESSPRIMITIVETYPE_ISOLINES, spacingMode, drawType,
1855 getReferenceImagePathPrefix(refName)));
1856 }
1857
1858 static const TessInstancedType tessInstancedTypes[] = {
1859 TESSINSTANCEDTYPE_NO_PATCHES,
1860 TESSINSTANCEDTYPE_INSTANCED,
1861 };
1862
1863 // Instanced
1864 for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
1865 for (int testTypeNdx = 0; testTypeNdx < DE_LENGTH_OF_ARRAY(tessInstancedTypes); ++testTypeNdx)
1866 {
1867 const TessPrimitiveType primitiveType = primitivesNoIsolines[primitiveTypeNdx];
1868 const TessInstancedType testType = tessInstancedTypes[testTypeNdx];
1869 const std::string caseName = std::string() + getTessPrimitiveTypeShaderName(primitiveType) + "_" +
1870 getInstancedDrawTestName(testType);
1871
1872 const TessInstancedDrawTestParams testParams = {
1873 testType,
1874 primitiveType,
1875 };
1876
1877 group->addChild(new TessInstancedDrawTestCase(testCtx, caseName.c_str(), testParams));
1878 }
1879
1880 // Test switching tessellation parameters on the fly.
1881 for (const auto &geometryShader : {false, true})
1882 {
1883 const auto nameSuffix = (geometryShader ? "_with_geom_shader" : "");
1884
1885 static const VkTessellationDomainOrigin domainOrigins[] = {
1886 VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT,
1887 VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT,
1888 };
1889
1890 for (const auto &firstPrimitiveType : primitivesNoIsolines)
1891 for (const auto &secondPrimitiveType : primitivesNoIsolines)
1892 {
1893 if (firstPrimitiveType == secondPrimitiveType)
1894 continue;
1895
1896 const TessStateSwitchParams params{
1897 std::make_pair(firstPrimitiveType, secondPrimitiveType),
1898 std::make_pair(SPACINGMODE_EQUAL, SPACINGMODE_EQUAL),
1899 std::make_pair(VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT),
1900 geometryShader,
1901 };
1902
1903 const auto testName = std::string("switch_primitive_") +
1904 getTessPrimitiveTypeShaderName(params.patchTypes.first) + "_to_" +
1905 getTessPrimitiveTypeShaderName(params.patchTypes.second) + nameSuffix;
1906 group->addChild(new TessStateSwitchCase(testCtx, testName, params));
1907 }
1908
1909 for (const auto &firstDomainOrigin : domainOrigins)
1910 for (const auto &secondDomainOrigin : domainOrigins)
1911 {
1912 if (firstDomainOrigin == secondDomainOrigin)
1913 continue;
1914
1915 const TessStateSwitchParams params{
1916 std::make_pair(TESSPRIMITIVETYPE_QUADS, TESSPRIMITIVETYPE_QUADS),
1917 std::make_pair(SPACINGMODE_EQUAL, SPACINGMODE_EQUAL),
1918 std::make_pair(firstDomainOrigin, secondDomainOrigin),
1919 geometryShader,
1920 };
1921
1922 const auto testName = std::string("switch_domain_origin_") +
1923 getDomainOriginName(params.domainOrigin.first) + "_to_" +
1924 getDomainOriginName(params.domainOrigin.second) + nameSuffix;
1925 group->addChild(new TessStateSwitchCase(testCtx, testName, params));
1926 }
1927
1928 for (int firstSpacingModeNdx = 0; firstSpacingModeNdx < SPACINGMODE_LAST; ++firstSpacingModeNdx)
1929 for (int secondSpacingModeNdx = 0; secondSpacingModeNdx < SPACINGMODE_LAST; ++secondSpacingModeNdx)
1930 {
1931 if (firstSpacingModeNdx == secondSpacingModeNdx)
1932 continue;
1933
1934 const SpacingMode firstSpacingMode = static_cast<SpacingMode>(firstSpacingModeNdx);
1935 const SpacingMode secondSpacingMode = static_cast<SpacingMode>(secondSpacingModeNdx);
1936
1937 const TessStateSwitchParams params{
1938 std::make_pair(TESSPRIMITIVETYPE_QUADS, TESSPRIMITIVETYPE_QUADS),
1939 std::make_pair(firstSpacingMode, secondSpacingMode),
1940 std::make_pair(VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT),
1941 geometryShader,
1942 };
1943
1944 const auto testName = std::string("switch_spacing_mode_") +
1945 getSpacingModeShaderName(params.spacing.first) + "_to_" +
1946 getSpacingModeShaderName(params.spacing.second) + nameSuffix;
1947 group->addChild(new TessStateSwitchCase(testCtx, testName, params));
1948 }
1949 }
1950
1951 return group.release();
1952 }
1953
1954 } // namespace tessellation
1955 } // namespace vkt
1956