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