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