1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Negative viewport height (part of VK_KHR_maintenance1)
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktDrawNegativeViewportHeightTests.hpp"
25 #include "vktDrawCreateInfoUtil.hpp"
26 #include "vktDrawImageObjectUtil.hpp"
27 #include "vktDrawBufferObjectUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktTestCaseUtil.hpp"
30
31 #include "vkPrograms.hpp"
32 #include "vkTypeUtil.hpp"
33 #include "vkImageUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkCmdUtil.hpp"
36
37 #include "tcuVector.hpp"
38 #include "tcuTextureUtil.hpp"
39 #include "tcuImageCompare.hpp"
40 #include "tcuTestLog.hpp"
41
42 #include "deSharedPtr.hpp"
43
44 namespace vkt
45 {
46 namespace Draw
47 {
48 namespace
49 {
50 using namespace vk;
51 using tcu::Vec4;
52 using de::SharedPtr;
53 using de::MovePtr;
54
55 enum Constants
56 {
57 WIDTH = 256,
58 HEIGHT = WIDTH/2,
59 };
60
61 struct TestParams
62 {
63 VkFrontFace frontFace;
64 VkCullModeFlagBits cullMode;
65 bool zeroViewportHeight;
66 };
67
68 class NegativeViewportHeightTestInstance : public TestInstance
69 {
70 public:
71 NegativeViewportHeightTestInstance (Context& context, const TestParams& params);
72 tcu::TestStatus iterate (void);
73 tcu::ConstPixelBufferAccess draw (const VkViewport viewport);
74 MovePtr<tcu::TextureLevel> generateReferenceImage (void) const;
75 bool isCulled (const VkFrontFace triangleFace) const;
76
77 private:
78 const TestParams m_params;
79 const VkFormat m_colorAttachmentFormat;
80 SharedPtr<Image> m_colorTargetImage;
81 Move<VkImageView> m_colorTargetView;
82 SharedPtr<Buffer> m_vertexBuffer;
83 Move<VkRenderPass> m_renderPass;
84 Move<VkFramebuffer> m_framebuffer;
85 Move<VkPipelineLayout> m_pipelineLayout;
86 Move<VkPipeline> m_pipeline;
87 };
88
NegativeViewportHeightTestInstance(Context & context,const TestParams & params)89 NegativeViewportHeightTestInstance::NegativeViewportHeightTestInstance (Context& context, const TestParams& params)
90 : TestInstance (context)
91 , m_params (params)
92 , m_colorAttachmentFormat (VK_FORMAT_R8G8B8A8_UNORM)
93 {
94 const DeviceInterface& vk = m_context.getDeviceInterface();
95 const VkDevice device = m_context.getDevice();
96
97 // Vertex data
98 {
99 std::vector<Vec4> vertexData;
100
101 // CCW triangle
102 vertexData.push_back(Vec4(-0.8f, -0.6f, 0.0f, 1.0f)); // 0-----2
103 vertexData.push_back(Vec4(-0.8f, 0.6f, 0.0f, 1.0f)); // | /
104 vertexData.push_back(Vec4(-0.2f, -0.6f, 0.0f, 1.0f)); // 1|/
105
106 // CW triangle
107 vertexData.push_back(Vec4( 0.2f, -0.6f, 0.0f, 1.0f)); // 0-----1
108 vertexData.push_back(Vec4( 0.8f, -0.6f, 0.0f, 1.0f)); // \ |
109 vertexData.push_back(Vec4( 0.8f, 0.6f, 0.0f, 1.0f)); // \|2
110
111 const VkDeviceSize dataSize = vertexData.size() * sizeof(Vec4);
112 m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
113 m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
114
115 deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), &vertexData[0], static_cast<std::size_t>(dataSize));
116 flushMappedMemoryRange(vk, device, m_vertexBuffer->getBoundMemory().getMemory(), m_vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
117 }
118
119 // Render pass
120 {
121 const VkExtent3D targetImageExtent = { WIDTH, HEIGHT, 1 };
122 const VkImageUsageFlags targetImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
123
124 const ImageCreateInfo targetImageCreateInfo(
125 VK_IMAGE_TYPE_2D, // imageType,
126 m_colorAttachmentFormat, // format,
127 targetImageExtent, // extent,
128 1u, // mipLevels,
129 1u, // arrayLayers,
130 VK_SAMPLE_COUNT_1_BIT, // samples,
131 VK_IMAGE_TILING_OPTIMAL, // tiling,
132 targetImageUsageFlags); // usage,
133
134 m_colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
135
136 RenderPassCreateInfo renderPassCreateInfo;
137 renderPassCreateInfo.addAttachment(AttachmentDescription(
138 m_colorAttachmentFormat, // format
139 VK_SAMPLE_COUNT_1_BIT, // samples
140 VK_ATTACHMENT_LOAD_OP_LOAD, // loadOp
141 VK_ATTACHMENT_STORE_OP_STORE, // storeOp
142 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp
143 VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp
144 VK_IMAGE_LAYOUT_GENERAL, // initialLayout
145 VK_IMAGE_LAYOUT_GENERAL)); // finalLayout
146
147 const VkAttachmentReference colorAttachmentReference =
148 {
149 0u,
150 VK_IMAGE_LAYOUT_GENERAL
151 };
152
153 renderPassCreateInfo.addSubpass(SubpassDescription(
154 VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
155 (VkSubpassDescriptionFlags)0, // flags
156 0u, // inputAttachmentCount
157 DE_NULL, // inputAttachments
158 1u, // colorAttachmentCount
159 &colorAttachmentReference, // colorAttachments
160 DE_NULL, // resolveAttachments
161 AttachmentReference(), // depthStencilAttachment
162 0u, // preserveAttachmentCount
163 DE_NULL)); // preserveAttachments
164
165 m_renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
166 }
167
168 // Framebuffer
169 {
170 const ImageViewCreateInfo colorTargetViewInfo (m_colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
171 m_colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
172
173 std::vector<VkImageView> colorAttachments(1);
174 colorAttachments[0] = *m_colorTargetView;
175
176 const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
177 m_framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
178 }
179
180 // Vertex input
181
182 const VkVertexInputBindingDescription vertexInputBindingDescription =
183 {
184 0u, // uint32_t binding;
185 sizeof(Vec4), // uint32_t stride;
186 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
187 };
188
189 const VkVertexInputAttributeDescription vertexInputAttributeDescription =
190 {
191 0u, // uint32_t location;
192 0u, // uint32_t binding;
193 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
194 0u // uint32_t offset;
195 };
196
197 const PipelineCreateInfo::VertexInputState vertexInputState = PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription,
198 1, &vertexInputAttributeDescription);
199
200 // Graphics pipeline
201
202 const VkRect2D scissor = makeRect2D(WIDTH, HEIGHT);
203
204 std::vector<VkDynamicState> dynamicStates;
205 dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT);
206
207 const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
208 const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
209
210 const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
211 m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
212
213 const PipelineCreateInfo::ColorBlendState::Attachment colorBlendAttachmentState;
214
215 PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, (VkPipelineCreateFlags)0);
216 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vertexModule, "main", VK_SHADER_STAGE_VERTEX_BIT));
217 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fragmentModule, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
218 pipelineCreateInfo.addState (PipelineCreateInfo::VertexInputState (vertexInputState));
219 pipelineCreateInfo.addState (PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
220 pipelineCreateInfo.addState (PipelineCreateInfo::ColorBlendState (1, &colorBlendAttachmentState));
221 pipelineCreateInfo.addState (PipelineCreateInfo::ViewportState (1, std::vector<VkViewport>(), std::vector<VkRect2D>(1, scissor)));
222 pipelineCreateInfo.addState (PipelineCreateInfo::DepthStencilState ());
223 pipelineCreateInfo.addState (PipelineCreateInfo::RasterizerState (
224 VK_FALSE, // depthClampEnable
225 VK_FALSE, // rasterizerDiscardEnable
226 VK_POLYGON_MODE_FILL, // polygonMode
227 m_params.cullMode, // cullMode
228 m_params.frontFace, // frontFace
229 VK_FALSE, // depthBiasEnable
230 0.0f, // depthBiasConstantFactor
231 0.0f, // depthBiasClamp
232 0.0f, // depthBiasSlopeFactor
233 1.0f)); // lineWidth
234 pipelineCreateInfo.addState (PipelineCreateInfo::MultiSampleState ());
235 pipelineCreateInfo.addState (PipelineCreateInfo::DynamicState (dynamicStates));
236
237 m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
238 }
239
draw(const VkViewport viewport)240 tcu::ConstPixelBufferAccess NegativeViewportHeightTestInstance::draw (const VkViewport viewport)
241 {
242 const DeviceInterface& vk = m_context.getDeviceInterface();
243 const VkDevice device = m_context.getDevice();
244 const VkQueue queue = m_context.getUniversalQueue();
245 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
246
247 // Command buffer
248
249 const CmdPoolCreateInfo cmdPoolCreateInfo (queueFamilyIndex);
250 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, &cmdPoolCreateInfo));
251 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
252
253 // Draw
254
255 beginCommandBuffer(vk, *cmdBuffer);
256
257 vk.cmdSetViewport(*cmdBuffer, 0u, 1u, &viewport);
258
259 {
260 const VkClearColorValue clearColor = makeClearValueColorF32(0.125f, 0.25f, 0.5f, 1.0f).color;
261 const ImageSubresourceRange subresourceRange (VK_IMAGE_ASPECT_COLOR_BIT);
262
263 initialTransitionColor2DImage(vk, *cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL,
264 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
265 vk.cmdClearColorImage(*cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &subresourceRange);
266 }
267
268 if (m_params.zeroViewportHeight)
269 {
270 // Set zero viewport height
271 const VkViewport zeroViewportHeight =
272 {
273 viewport.x, // float x;
274 viewport.y / 2.0f, // float y;
275 viewport.width, // float width;
276 0.0f, // float height;
277 viewport.minDepth, // float minDepth;
278 viewport.maxDepth // float maxDepth;
279 };
280
281 vk.cmdSetViewport(*cmdBuffer, 0u, 1u, &zeroViewportHeight);
282 }
283
284 {
285 const VkMemoryBarrier memBarrier =
286 {
287 VK_STRUCTURE_TYPE_MEMORY_BARRIER, // VkStructureType sType;
288 DE_NULL, // const void* pNext;
289 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
290 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT // VkAccessFlags dstAccessMask;
291 };
292
293 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
294 }
295
296 beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, WIDTH, HEIGHT));
297
298 {
299 const VkDeviceSize offset = 0;
300 const VkBuffer buffer = m_vertexBuffer->object();
301
302 vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &buffer, &offset);
303 }
304
305 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
306 vk.cmdDraw(*cmdBuffer, 6, 1, 0, 0);
307 endRenderPass(vk, *cmdBuffer);
308 endCommandBuffer(vk, *cmdBuffer);
309
310 // Submit
311 submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
312
313 // Get result
314 {
315 const VkOffset3D zeroOffset = { 0, 0, 0 };
316 return m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, VK_IMAGE_ASPECT_COLOR_BIT);
317 }
318 }
319
320 //! Determine if a triangle with triangleFace orientation will be culled or not
isCulled(const VkFrontFace triangleFace) const321 bool NegativeViewportHeightTestInstance::isCulled (const VkFrontFace triangleFace) const
322 {
323 const bool isFrontFacing = (triangleFace == m_params.frontFace);
324
325 if (m_params.cullMode == VK_CULL_MODE_FRONT_BIT && isFrontFacing)
326 return true;
327 if (m_params.cullMode == VK_CULL_MODE_BACK_BIT && !isFrontFacing)
328 return true;
329
330 return m_params.cullMode == VK_CULL_MODE_FRONT_AND_BACK;
331 }
332
generateReferenceImage(void) const333 MovePtr<tcu::TextureLevel> NegativeViewportHeightTestInstance::generateReferenceImage (void) const
334 {
335 DE_ASSERT(HEIGHT == WIDTH/2);
336
337 MovePtr<tcu::TextureLevel> image (new tcu::TextureLevel(mapVkFormat(m_colorAttachmentFormat), WIDTH, HEIGHT));
338 const tcu::PixelBufferAccess access (image->getAccess());
339 const Vec4 blue (0.125f, 0.25f, 0.5f, 1.0f);
340 const Vec4 white (1.0f);
341 const Vec4 gray (0.5f, 0.5f, 0.5f, 1.0f);
342
343 tcu::clear(access, blue);
344
345 // Zero viewport height
346 if (m_params.zeroViewportHeight)
347 {
348 return image;
349 }
350 // Negative viewport height
351 else
352 {
353 const int p1 = static_cast<int>(static_cast<float>(HEIGHT) * (1.0f - 0.6f) / 2.0f);
354 const int p2 = p1 + static_cast<int>(static_cast<float>(HEIGHT) * (2.0f * 0.6f) / 2.0f);
355
356 // left triangle (CCW -> CW after y-flip)
357 if (!isCulled(VK_FRONT_FACE_CLOCKWISE))
358 {
359 const Vec4& color = (m_params.frontFace == VK_FRONT_FACE_CLOCKWISE ? white : gray);
360
361 for (int y = p1; y <= p2; ++y)
362 for (int x = p1; x < y; ++x)
363 access.setPixel(color, x, y);
364 }
365
366 // right triangle (CW -> CCW after y-flip)
367 if (!isCulled(VK_FRONT_FACE_COUNTER_CLOCKWISE))
368 {
369 const Vec4& color = (m_params.frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE ? white : gray);
370
371 for (int y = p1; y <= p2; ++y)
372 for (int x = WIDTH - y; x < p2 + HEIGHT; ++x)
373 access.setPixel(color, x, y);
374 }
375
376 return image;
377 }
378 }
379
getCullModeStr(const VkCullModeFlagBits cullMode)380 std::string getCullModeStr (const VkCullModeFlagBits cullMode)
381 {
382 // Cull mode flags are a bit special, because there's a meaning to 0 and or'ed flags.
383 // The function getCullModeFlagsStr() doesn't work too well in this case.
384
385 switch (cullMode)
386 {
387 case VK_CULL_MODE_NONE: return "VK_CULL_MODE_NONE";
388 case VK_CULL_MODE_FRONT_BIT: return "VK_CULL_MODE_FRONT_BIT";
389 case VK_CULL_MODE_BACK_BIT: return "VK_CULL_MODE_BACK_BIT";
390 case VK_CULL_MODE_FRONT_AND_BACK: return "VK_CULL_MODE_FRONT_AND_BACK";
391
392 default:
393 DE_ASSERT(0);
394 return std::string();
395 }
396 }
397
iterate(void)398 tcu::TestStatus NegativeViewportHeightTestInstance::iterate (void)
399 {
400 // Check requirements
401
402 if(!isDeviceExtensionSupported(m_context.getUsedApiVersion(), m_context.getDeviceExtensions(), "VK_KHR_maintenance1"))
403 TCU_THROW(NotSupportedError, "Missing extension: VK_KHR_maintenance1");
404
405 // Set up the viewport and draw
406
407 const VkViewport viewport =
408 {
409 0.0f, // float x;
410 static_cast<float>(HEIGHT), // float y;
411 static_cast<float>(WIDTH), // float width;
412 -static_cast<float>(HEIGHT), // float height;
413 0.0f, // float minDepth;
414 1.0f, // float maxDepth;
415 };
416
417 const tcu::ConstPixelBufferAccess resultImage = draw(viewport);
418
419 // Verify the results
420
421 tcu::TestLog& log = m_context.getTestContext().getLog();
422 MovePtr<tcu::TextureLevel> referenceImage = generateReferenceImage();
423
424 // Zero viewport height
425 if (m_params.zeroViewportHeight)
426 {
427 log << tcu::TestLog::Message
428 << "Drawing two triangles with zero viewport height."
429 << tcu::TestLog::EndMessage;
430 log << tcu::TestLog::Message
431 << "Result image should be empty."
432 << tcu::TestLog::EndMessage;
433 }
434 // Negative viewport height
435 else
436 {
437 log << tcu::TestLog::Message
438 << "Drawing two triangles with negative viewport height, which will cause a y-flip. This changes the sign of the triangle's area."
439 << tcu::TestLog::EndMessage;
440 log << tcu::TestLog::Message
441 << "After the flip, the triangle on the left is CW and the triangle on the right is CCW. Right angles of the both triangles should be at the bottom of the image."
442 << " Front face is white, back face is gray."
443 << tcu::TestLog::EndMessage;
444 }
445
446 log << tcu::TestLog::Message
447 << "Front face: " << getFrontFaceName(m_params.frontFace) << "\n"
448 << "Cull mode: " << getCullModeStr (m_params.cullMode) << "\n"
449 << tcu::TestLog::EndMessage;
450
451 if (!tcu::fuzzyCompare(log, "Image compare", "Image compare", referenceImage->getAccess(), resultImage, 0.02f, tcu::COMPARE_LOG_RESULT))
452 return tcu::TestStatus::fail("Rendered image is incorrect");
453 else
454 return tcu::TestStatus::pass("Pass");
455 }
456
457 class NegativeViewportHeightTest : public TestCase
458 {
459 public:
NegativeViewportHeightTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)460 NegativeViewportHeightTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
461 : TestCase (testCtx, name, description)
462 , m_params (params)
463 {
464 }
465
initPrograms(SourceCollections & programCollection) const466 void initPrograms (SourceCollections& programCollection) const
467 {
468 // Vertex shader
469 {
470 std::ostringstream src;
471 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
472 << "\n"
473 << "layout(location = 0) in vec4 in_position;\n"
474 << "\n"
475 << "out gl_PerVertex {\n"
476 << " vec4 gl_Position;\n"
477 << "};\n"
478 << "\n"
479 << "void main(void)\n"
480 << "{\n"
481 << " gl_Position = in_position;\n"
482 << "}\n";
483
484 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
485 }
486
487 // Fragment shader
488 {
489 std::ostringstream src;
490 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
491 << "\n"
492 << "layout(location = 0) out vec4 out_color;\n"
493 << "\n"
494 << "void main(void)\n"
495 << "{\n"
496 << " if (gl_FrontFacing)\n"
497 << " out_color = vec4(1.0);\n"
498 << " else\n"
499 << " out_color = vec4(vec3(0.5), 1.0);\n"
500 << "}\n";
501
502 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
503 }
504 }
505
createInstance(Context & context) const506 virtual TestInstance* createInstance (Context& context) const
507 {
508 return new NegativeViewportHeightTestInstance(context, m_params);
509 }
510
511 private:
512 const TestParams m_params;
513 };
514
populateTestGroup(tcu::TestCaseGroup * testGroup,bool zeroViewportHeight)515 void populateTestGroup (tcu::TestCaseGroup* testGroup, bool zeroViewportHeight)
516 {
517 const struct
518 {
519 const char* const name;
520 VkFrontFace frontFace;
521 } frontFace[] =
522 {
523 { "front_ccw", VK_FRONT_FACE_COUNTER_CLOCKWISE },
524 { "front_cw", VK_FRONT_FACE_CLOCKWISE },
525 };
526
527 const struct
528 {
529 const char* const name;
530 VkCullModeFlagBits cullMode;
531 } cullMode[] =
532 {
533 { "cull_none", VK_CULL_MODE_NONE },
534 { "cull_front", VK_CULL_MODE_FRONT_BIT },
535 { "cull_back", VK_CULL_MODE_BACK_BIT },
536 { "cull_both", VK_CULL_MODE_FRONT_AND_BACK },
537 };
538
539 for (int ndxFrontFace = 0; ndxFrontFace < DE_LENGTH_OF_ARRAY(frontFace); ++ndxFrontFace)
540 for (int ndxCullMode = 0; ndxCullMode < DE_LENGTH_OF_ARRAY(cullMode); ++ndxCullMode)
541 {
542 const TestParams params =
543 {
544 frontFace[ndxFrontFace].frontFace,
545 cullMode[ndxCullMode].cullMode,
546 zeroViewportHeight
547 };
548 std::ostringstream name;
549 name << frontFace[ndxFrontFace].name << "_" << cullMode[ndxCullMode].name;
550
551 testGroup->addChild(new NegativeViewportHeightTest(testGroup->getTestContext(), name.str(), "", params));
552 }
553 }
554
555 } // anonymous
556
createNegativeViewportHeightTests(tcu::TestContext & testCtx)557 tcu::TestCaseGroup* createNegativeViewportHeightTests (tcu::TestContext& testCtx)
558 {
559 return createTestGroup(testCtx, "negative_viewport_height", "Negative viewport height (VK_KHR_maintenance1)", populateTestGroup, false);
560 }
561
createZeroViewportHeightTests(tcu::TestContext & testCtx)562 tcu::TestCaseGroup* createZeroViewportHeightTests (tcu::TestContext& testCtx)
563 {
564 return createTestGroup(testCtx, "zero_viewport_height", "Zero viewport height (VK_KHR_maintenance1)", populateTestGroup, true);
565 }
566
567 } // Draw
568 } // vkt
569