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 #include "vkObjUtil.hpp"
37 #include "vkBarrierUtil.hpp"
38
39 #include "tcuVector.hpp"
40 #include "tcuTextureUtil.hpp"
41 #include "tcuImageCompare.hpp"
42 #include "tcuTestLog.hpp"
43
44 #include "deSharedPtr.hpp"
45 #include "deRandom.hpp"
46
47 namespace vkt
48 {
49 namespace Draw
50 {
51 namespace
52 {
53 using namespace vk;
54 using tcu::Vec4;
55 using de::SharedPtr;
56 using de::MovePtr;
57
58 class DynRenderHelper
59 {
60 public:
DynRenderHelper(const SharedGroupParams params)61 DynRenderHelper (const SharedGroupParams params)
62 : m_params(params)
63 {}
64
beginSecondaryCmdBuffer(const DeviceInterface & vkd,VkCommandBuffer cmdBuffer,const VkFormat & colorAttachmentFormat) const65 void beginSecondaryCmdBuffer (const DeviceInterface& vkd, VkCommandBuffer cmdBuffer, const VkFormat& colorAttachmentFormat) const
66 {
67 #ifndef CTS_USES_VULKANSC
68 VkRenderingFlags renderingFlags = 0u;
69 if (m_params->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
70 renderingFlags |= VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT;
71
72 VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo
73 {
74 VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, // VkStructureType sType;
75 DE_NULL, // const void* pNext;
76 renderingFlags, // VkRenderingFlagsKHR flags;
77 0u, // uint32_t viewMask;
78 1u, // uint32_t colorAttachmentCount;
79 &colorAttachmentFormat, // const VkFormat* pColorAttachmentFormats;
80 VK_FORMAT_UNDEFINED, // VkFormat depthAttachmentFormat;
81 VK_FORMAT_UNDEFINED, // VkFormat stencilAttachmentFormat;
82 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
83 };
84 const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo);
85
86 VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
87 if (!m_params->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
88 usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
89
90 const VkCommandBufferBeginInfo commandBufBeginParams
91 {
92 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType;
93 DE_NULL, // const void* pNext;
94 usageFlags, // VkCommandBufferUsageFlags flags;
95 &bufferInheritanceInfo
96 };
97
98 VK_CHECK(vkd.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
99 #else
100 DE_UNREF(vkd);
101 DE_UNREF(cmdBuffer);
102 DE_UNREF(colorAttachmentFormat);
103 DE_ASSERT(false);
104 #endif // CTS_USES_VULKANSC
105 }
106
beginRendering(const DeviceInterface & vkd,const VkCommandBuffer cmdBuffer,const bool isPrimaryCmdBuffer,const VkImageView colorImageView,const VkRect2D & renderArea,const VkClearValue & clearValue,const VkImageLayout imageLayout) const107 void beginRendering(const DeviceInterface& vkd,
108 const VkCommandBuffer cmdBuffer,
109 const bool isPrimaryCmdBuffer,
110 const VkImageView colorImageView,
111 const VkRect2D& renderArea,
112 const VkClearValue& clearValue,
113 const VkImageLayout imageLayout) const
114 {
115 #ifndef CTS_USES_VULKANSC
116 VkRenderingFlagsKHR renderingFlags = 0u;
117 if (isPrimaryCmdBuffer && m_params->useSecondaryCmdBuffer && !m_params->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
118 renderingFlags |= VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT;
119
120 vk::beginRendering(vkd, cmdBuffer, colorImageView, renderArea, clearValue, imageLayout, VK_ATTACHMENT_LOAD_OP_LOAD, renderingFlags);
121 #else
122 DE_UNREF(vkd);
123 DE_UNREF(cmdBuffer);
124 DE_UNREF(isPrimaryCmdBuffer);
125 DE_UNREF(colorImageView);
126 DE_UNREF(renderArea);
127 DE_UNREF(clearValue);
128 DE_UNREF(imageLayout);
129 DE_ASSERT(false);
130 #endif // CTS_USES_VULKANSC
131 }
132
133 protected:
134 SharedGroupParams m_params;
135 };
136
137 enum Constants
138 {
139 WIDTH = 256,
140 HEIGHT = WIDTH/2,
141 };
142
143 struct TestParams
144 {
145 VkFrontFace frontFace;
146 VkCullModeFlagBits cullMode;
147 bool zeroViewportHeight;
148 const SharedGroupParams groupParams;
149 };
150
151 class NegativeViewportHeightTestInstance : public TestInstance
152 {
153 public:
154 NegativeViewportHeightTestInstance (Context& context, const TestParams& params);
155 tcu::TestStatus iterate (void);
156 void preRenderCommands (VkCommandBuffer cmdBuffer, const VkClearValue& clearColor);
157 void draw (VkCommandBuffer cmdBuffer, const VkViewport& viewport);
158
159 MovePtr<tcu::TextureLevel> generateReferenceImage (void) const;
160 bool isCulled (const VkFrontFace triangleFace) const;
161
162 private:
163 const TestParams m_params;
164 const DynRenderHelper m_dynRenderHelper;
165 const VkFormat m_colorAttachmentFormat;
166 SharedPtr<Image> m_colorTargetImage;
167 Move<VkImageView> m_colorTargetView;
168 SharedPtr<Buffer> m_vertexBuffer;
169 Move<VkRenderPass> m_renderPass;
170 Move<VkFramebuffer> m_framebuffer;
171 Move<VkPipelineLayout> m_pipelineLayout;
172 Move<VkPipeline> m_pipeline;
173 };
174
NegativeViewportHeightTestInstance(Context & context,const TestParams & params)175 NegativeViewportHeightTestInstance::NegativeViewportHeightTestInstance (Context& context, const TestParams& params)
176 : TestInstance (context)
177 , m_params (params)
178 , m_dynRenderHelper (params.groupParams)
179 , m_colorAttachmentFormat (VK_FORMAT_R8G8B8A8_UNORM)
180 {
181 const DeviceInterface& vk = m_context.getDeviceInterface();
182 const VkDevice device = m_context.getDevice();
183
184 // Vertex data
185 {
186 std::vector<Vec4> vertexData;
187
188 // CCW triangle
189 vertexData.push_back(Vec4(-0.8f, -0.6f, 0.0f, 1.0f)); // 0-----2
190 vertexData.push_back(Vec4(-0.8f, 0.6f, 0.0f, 1.0f)); // | /
191 vertexData.push_back(Vec4(-0.2f, -0.6f, 0.0f, 1.0f)); // 1|/
192
193 // CW triangle
194 vertexData.push_back(Vec4( 0.2f, -0.6f, 0.0f, 1.0f)); // 0-----1
195 vertexData.push_back(Vec4( 0.8f, -0.6f, 0.0f, 1.0f)); // \ |
196 vertexData.push_back(Vec4( 0.8f, 0.6f, 0.0f, 1.0f)); // \|2
197
198 const VkDeviceSize dataSize = vertexData.size() * sizeof(Vec4);
199 m_vertexBuffer = Buffer::createAndAlloc(vk, device, BufferCreateInfo(dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
200 m_context.getDefaultAllocator(), MemoryRequirement::HostVisible);
201
202 deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), &vertexData[0], static_cast<std::size_t>(dataSize));
203 flushMappedMemoryRange(vk, device, m_vertexBuffer->getBoundMemory().getMemory(), m_vertexBuffer->getBoundMemory().getOffset(), VK_WHOLE_SIZE);
204 }
205
206 const VkExtent3D targetImageExtent = { WIDTH, HEIGHT, 1 };
207 const VkImageUsageFlags targetImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
208
209 const ImageCreateInfo targetImageCreateInfo(
210 VK_IMAGE_TYPE_2D, // imageType,
211 m_colorAttachmentFormat, // format,
212 targetImageExtent, // extent,
213 1u, // mipLevels,
214 1u, // arrayLayers,
215 VK_SAMPLE_COUNT_1_BIT, // samples,
216 VK_IMAGE_TILING_OPTIMAL, // tiling,
217 targetImageUsageFlags); // usage,
218
219 m_colorTargetImage = Image::createAndAlloc(vk, device, targetImageCreateInfo, m_context.getDefaultAllocator(), m_context.getUniversalQueueFamilyIndex());
220
221 const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat);
222 m_colorTargetView = createImageView(vk, device, &colorTargetViewInfo);
223
224 // Render pass and framebuffer
225 if (!m_params.groupParams->useDynamicRendering)
226 {
227 RenderPassCreateInfo renderPassCreateInfo;
228 renderPassCreateInfo.addAttachment(AttachmentDescription(
229 m_colorAttachmentFormat, // format
230 VK_SAMPLE_COUNT_1_BIT, // samples
231 VK_ATTACHMENT_LOAD_OP_LOAD, // loadOp
232 VK_ATTACHMENT_STORE_OP_STORE, // storeOp
233 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // stencilLoadOp
234 VK_ATTACHMENT_STORE_OP_DONT_CARE, // stencilStoreOp
235 VK_IMAGE_LAYOUT_GENERAL, // initialLayout
236 VK_IMAGE_LAYOUT_GENERAL)); // finalLayout
237
238 const VkAttachmentReference colorAttachmentReference =
239 {
240 0u,
241 VK_IMAGE_LAYOUT_GENERAL
242 };
243
244 renderPassCreateInfo.addSubpass(SubpassDescription(
245 VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
246 (VkSubpassDescriptionFlags)0, // flags
247 0u, // inputAttachmentCount
248 DE_NULL, // inputAttachments
249 1u, // colorAttachmentCount
250 &colorAttachmentReference, // colorAttachments
251 DE_NULL, // resolveAttachments
252 AttachmentReference(), // depthStencilAttachment
253 0u, // preserveAttachmentCount
254 DE_NULL)); // preserveAttachments
255
256 m_renderPass = createRenderPass(vk, device, &renderPassCreateInfo);
257
258 std::vector<VkImageView> colorAttachments { *m_colorTargetView };
259 const FramebufferCreateInfo framebufferCreateInfo (*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1);
260 m_framebuffer = createFramebuffer(vk, device, &framebufferCreateInfo);
261 }
262
263 // Vertex input
264
265 const VkVertexInputBindingDescription vertexInputBindingDescription =
266 {
267 0u, // uint32_t binding;
268 sizeof(Vec4), // uint32_t stride;
269 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
270 };
271
272 const VkVertexInputAttributeDescription vertexInputAttributeDescription =
273 {
274 0u, // uint32_t location;
275 0u, // uint32_t binding;
276 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
277 0u // uint32_t offset;
278 };
279
280 const PipelineCreateInfo::VertexInputState vertexInputState = PipelineCreateInfo::VertexInputState(1, &vertexInputBindingDescription,
281 1, &vertexInputAttributeDescription);
282
283 // Graphics pipeline
284
285 const VkRect2D scissor = makeRect2D(WIDTH, HEIGHT);
286
287 std::vector<VkDynamicState> dynamicStates;
288 dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT);
289
290 const Unique<VkShaderModule> vertexModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
291 const Unique<VkShaderModule> fragmentModule (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
292
293 const PipelineLayoutCreateInfo pipelineLayoutCreateInfo;
294 m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
295
296 const PipelineCreateInfo::ColorBlendState::Attachment colorBlendAttachmentState;
297
298 PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, (VkPipelineCreateFlags)0);
299 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vertexModule, "main", VK_SHADER_STAGE_VERTEX_BIT));
300 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fragmentModule, "main", VK_SHADER_STAGE_FRAGMENT_BIT));
301 pipelineCreateInfo.addState (PipelineCreateInfo::VertexInputState (vertexInputState));
302 pipelineCreateInfo.addState (PipelineCreateInfo::InputAssemblerState(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
303 pipelineCreateInfo.addState (PipelineCreateInfo::ColorBlendState (1, &colorBlendAttachmentState));
304 pipelineCreateInfo.addState (PipelineCreateInfo::ViewportState (1, std::vector<VkViewport>(), std::vector<VkRect2D>(1, scissor)));
305 pipelineCreateInfo.addState (PipelineCreateInfo::DepthStencilState ());
306 pipelineCreateInfo.addState (PipelineCreateInfo::RasterizerState (
307 VK_FALSE, // depthClampEnable
308 VK_FALSE, // rasterizerDiscardEnable
309 VK_POLYGON_MODE_FILL, // polygonMode
310 m_params.cullMode, // cullMode
311 m_params.frontFace, // frontFace
312 VK_FALSE, // depthBiasEnable
313 0.0f, // depthBiasConstantFactor
314 0.0f, // depthBiasClamp
315 0.0f, // depthBiasSlopeFactor
316 1.0f)); // lineWidth
317 pipelineCreateInfo.addState (PipelineCreateInfo::MultiSampleState ());
318 pipelineCreateInfo.addState (PipelineCreateInfo::DynamicState (dynamicStates));
319
320 #ifndef CTS_USES_VULKANSC
321 vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo
322 {
323 vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
324 DE_NULL,
325 0u,
326 1u,
327 &m_colorAttachmentFormat,
328 vk::VK_FORMAT_UNDEFINED,
329 vk::VK_FORMAT_UNDEFINED
330 };
331
332 if (m_params.groupParams->useDynamicRendering)
333 pipelineCreateInfo.pNext = &renderingCreateInfo;
334 #endif // CTS_USES_VULKANSC
335
336 m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &pipelineCreateInfo);
337 }
338
preRenderCommands(VkCommandBuffer cmdBuffer,const VkClearValue & clearColor)339 void NegativeViewportHeightTestInstance::preRenderCommands(VkCommandBuffer cmdBuffer, const VkClearValue& clearColor)
340 {
341 const DeviceInterface& vk = m_context.getDeviceInterface();
342 const ImageSubresourceRange subresourceRange (VK_IMAGE_ASPECT_COLOR_BIT);
343
344 initialTransitionColor2DImage(vk, cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL,
345 VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
346 vk.cmdClearColorImage(cmdBuffer, m_colorTargetImage->object(), VK_IMAGE_LAYOUT_GENERAL, &clearColor.color, 1, &subresourceRange);
347
348 const VkMemoryBarrier memBarrier
349 {
350 VK_STRUCTURE_TYPE_MEMORY_BARRIER, // VkStructureType sType;
351 DE_NULL, // const void* pNext;
352 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask;
353 VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT // VkAccessFlags dstAccessMask;
354 };
355
356 vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
357 }
358
draw(VkCommandBuffer cmdBuffer,const VkViewport & viewport)359 void NegativeViewportHeightTestInstance::draw (VkCommandBuffer cmdBuffer, const VkViewport& viewport)
360 {
361 const DeviceInterface& vk = m_context.getDeviceInterface();
362 const VkBuffer buffer = m_vertexBuffer->object();
363 const VkDeviceSize offset = 0;
364
365 if (m_params.zeroViewportHeight)
366 {
367 // Set zero viewport height
368 const VkViewport zeroViewportHeight
369 {
370 viewport.x, // float x;
371 viewport.y / 2.0f, // float y;
372 viewport.width, // float width;
373 0.0f, // float height;
374 viewport.minDepth, // float minDepth;
375 viewport.maxDepth // float maxDepth;
376 };
377
378 vk.cmdSetViewport(cmdBuffer, 0u, 1u, &zeroViewportHeight);
379 }
380 else
381 vk.cmdSetViewport(cmdBuffer, 0u, 1u, &viewport);
382
383 vk.cmdBindVertexBuffers(cmdBuffer, 0, 1, &buffer, &offset);
384 vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
385 vk.cmdDraw(cmdBuffer, 6, 1, 0, 0);
386 }
387
388 //! Determine if a triangle with triangleFace orientation will be culled or not
isCulled(const VkFrontFace triangleFace) const389 bool NegativeViewportHeightTestInstance::isCulled (const VkFrontFace triangleFace) const
390 {
391 const bool isFrontFacing = (triangleFace == m_params.frontFace);
392
393 if (m_params.cullMode == VK_CULL_MODE_FRONT_BIT && isFrontFacing)
394 return true;
395 if (m_params.cullMode == VK_CULL_MODE_BACK_BIT && !isFrontFacing)
396 return true;
397
398 return m_params.cullMode == VK_CULL_MODE_FRONT_AND_BACK;
399 }
400
generateReferenceImage(void) const401 MovePtr<tcu::TextureLevel> NegativeViewportHeightTestInstance::generateReferenceImage (void) const
402 {
403 DE_ASSERT(HEIGHT == WIDTH/2);
404
405 MovePtr<tcu::TextureLevel> image (new tcu::TextureLevel(mapVkFormat(m_colorAttachmentFormat), WIDTH, HEIGHT));
406 const tcu::PixelBufferAccess access (image->getAccess());
407 const Vec4 blue (0.125f, 0.25f, 0.5f, 1.0f);
408 const Vec4 white (1.0f);
409 const Vec4 gray (0.5f, 0.5f, 0.5f, 1.0f);
410
411 tcu::clear(access, blue);
412
413 // Zero viewport height
414 if (m_params.zeroViewportHeight)
415 {
416 return image;
417 }
418 // Negative viewport height
419 else
420 {
421 const int p1 = static_cast<int>(static_cast<float>(HEIGHT) * (1.0f - 0.6f) / 2.0f);
422 const int p2 = p1 + static_cast<int>(static_cast<float>(HEIGHT) * (2.0f * 0.6f) / 2.0f);
423
424 // left triangle (CCW -> CW after y-flip)
425 if (!isCulled(VK_FRONT_FACE_CLOCKWISE))
426 {
427 const Vec4& color = (m_params.frontFace == VK_FRONT_FACE_CLOCKWISE ? white : gray);
428
429 for (int y = p1; y <= p2; ++y)
430 for (int x = p1; x < y; ++x)
431 access.setPixel(color, x, y);
432 }
433
434 // right triangle (CW -> CCW after y-flip)
435 if (!isCulled(VK_FRONT_FACE_COUNTER_CLOCKWISE))
436 {
437 const Vec4& color = (m_params.frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE ? white : gray);
438
439 for (int y = p1; y <= p2; ++y)
440 for (int x = WIDTH - y; x < p2 + HEIGHT; ++x)
441 access.setPixel(color, x, y);
442 }
443
444 return image;
445 }
446 }
447
getCullModeStr(const VkCullModeFlagBits cullMode)448 std::string getCullModeStr (const VkCullModeFlagBits cullMode)
449 {
450 // Cull mode flags are a bit special, because there's a meaning to 0 and or'ed flags.
451 // The function getCullModeFlagsStr() doesn't work too well in this case.
452
453 switch (cullMode)
454 {
455 case VK_CULL_MODE_NONE: return "VK_CULL_MODE_NONE";
456 case VK_CULL_MODE_FRONT_BIT: return "VK_CULL_MODE_FRONT_BIT";
457 case VK_CULL_MODE_BACK_BIT: return "VK_CULL_MODE_BACK_BIT";
458 case VK_CULL_MODE_FRONT_AND_BACK: return "VK_CULL_MODE_FRONT_AND_BACK";
459
460 default:
461 DE_ASSERT(0);
462 return std::string();
463 }
464 }
465
iterate(void)466 tcu::TestStatus NegativeViewportHeightTestInstance::iterate (void)
467 {
468 // Set up the viewport and draw
469
470 const VkViewport viewport
471 {
472 0.0f, // float x;
473 static_cast<float>(HEIGHT), // float y;
474 static_cast<float>(WIDTH), // float width;
475 -static_cast<float>(HEIGHT), // float height;
476 0.0f, // float minDepth;
477 1.0f, // float maxDepth;
478 };
479 VkRect2D rect = makeRect2D(0, 0, WIDTH, HEIGHT);
480
481 const DeviceInterface& vk = m_context.getDeviceInterface();
482 const VkDevice device = m_context.getDevice();
483 const VkQueue queue = m_context.getUniversalQueue();
484 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
485 const VkClearValue clearColor = makeClearValueColorF32(0.125f, 0.25f, 0.5f, 1.0f);
486 const CmdPoolCreateInfo cmdPoolCreateInfo (queueFamilyIndex);
487 const Unique<VkCommandPool> cmdPool (createCommandPool(vk, device, &cmdPoolCreateInfo));
488 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
489 Move<VkCommandBuffer> secCmdBuffer;
490
491 #ifndef CTS_USES_VULKANSC
492 if (m_params.groupParams->useSecondaryCmdBuffer)
493 {
494 secCmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
495
496 // record secondary command buffer
497 m_dynRenderHelper.beginSecondaryCmdBuffer(vk, *secCmdBuffer, m_colorAttachmentFormat);
498
499 if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
500 m_dynRenderHelper.beginRendering(vk, *secCmdBuffer, false/*isPrimary*/, *m_colorTargetView, rect, clearColor, VK_IMAGE_LAYOUT_GENERAL);
501
502 draw(*secCmdBuffer, viewport);
503
504 if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
505 endRendering(vk, *secCmdBuffer);
506
507 endCommandBuffer(vk, *secCmdBuffer);
508
509 // record primary command buffer
510 beginCommandBuffer(vk, *cmdBuffer, 0u);
511
512 preRenderCommands(*cmdBuffer, clearColor);
513
514 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
515 m_dynRenderHelper.beginRendering(vk, *cmdBuffer, true/*isPrimary*/, *m_colorTargetView, rect, clearColor, VK_IMAGE_LAYOUT_GENERAL);
516
517 vk.cmdExecuteCommands(*cmdBuffer, 1u, &*secCmdBuffer);
518
519 if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
520 endRendering(vk, *cmdBuffer);
521
522 endCommandBuffer(vk, *cmdBuffer);
523 }
524 else if (m_params.groupParams->useDynamicRendering)
525 {
526 beginCommandBuffer(vk, *cmdBuffer);
527
528 preRenderCommands(*cmdBuffer, clearColor);
529 m_dynRenderHelper.beginRendering(vk, *cmdBuffer, true/*isPrimary*/, *m_colorTargetView, rect, clearColor, VK_IMAGE_LAYOUT_GENERAL);
530 draw(*cmdBuffer, viewport);
531 endRendering(vk, *cmdBuffer);
532
533 endCommandBuffer(vk, *cmdBuffer);
534 }
535 #endif // CTS_USES_VULKANSC
536
537 if (!m_params.groupParams->useDynamicRendering)
538 {
539 beginCommandBuffer(vk, *cmdBuffer);
540
541 preRenderCommands(*cmdBuffer, clearColor);
542 beginRenderPass(vk, *cmdBuffer, *m_renderPass, *m_framebuffer, rect);
543 draw(*cmdBuffer, viewport);
544 endRenderPass(vk, *cmdBuffer);
545
546 endCommandBuffer(vk, *cmdBuffer);
547 }
548
549 // Submit
550 submitCommandsAndWait(vk, device, queue, cmdBuffer.get());
551
552 // Get result
553 const VkOffset3D zeroOffset = { 0, 0, 0 };
554 const tcu::ConstPixelBufferAccess resultImage = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, VK_IMAGE_ASPECT_COLOR_BIT);
555
556 // Verify the results
557
558 tcu::TestLog& log = m_context.getTestContext().getLog();
559 MovePtr<tcu::TextureLevel> referenceImage = generateReferenceImage();
560
561 // Zero viewport height
562 if (m_params.zeroViewportHeight)
563 {
564 log << tcu::TestLog::Message
565 << "Drawing two triangles with zero viewport height."
566 << tcu::TestLog::EndMessage;
567 log << tcu::TestLog::Message
568 << "Result image should be empty."
569 << tcu::TestLog::EndMessage;
570 }
571 // Negative viewport height
572 else
573 {
574 log << tcu::TestLog::Message
575 << "Drawing two triangles with negative viewport height, which will cause a y-flip. This changes the sign of the triangle's area."
576 << tcu::TestLog::EndMessage;
577 log << tcu::TestLog::Message
578 << "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."
579 << " Front face is white, back face is gray."
580 << tcu::TestLog::EndMessage;
581 }
582
583 log << tcu::TestLog::Message
584 << "Front face: " << getFrontFaceName(m_params.frontFace) << "\n"
585 << "Cull mode: " << getCullModeStr (m_params.cullMode) << "\n"
586 << tcu::TestLog::EndMessage;
587
588 if (!tcu::fuzzyCompare(log, "Image compare", "Image compare", referenceImage->getAccess(), resultImage, 0.02f, tcu::COMPARE_LOG_RESULT))
589 return tcu::TestStatus::fail("Rendered image is incorrect");
590 else
591 return tcu::TestStatus::pass("Pass");
592 }
593
594 class NegativeViewportHeightTest : public TestCase
595 {
596 public:
NegativeViewportHeightTest(tcu::TestContext & testCtx,const std::string & name,const TestParams & params)597 NegativeViewportHeightTest (tcu::TestContext& testCtx, const std::string& name, const TestParams& params)
598 : TestCase (testCtx, name)
599 , m_params (params)
600 {
601 }
602
initPrograms(SourceCollections & programCollection) const603 void initPrograms (SourceCollections& programCollection) const
604 {
605 // Vertex shader
606 {
607 std::ostringstream src;
608 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
609 << "\n"
610 << "layout(location = 0) in vec4 in_position;\n"
611 << "\n"
612 << "out gl_PerVertex {\n"
613 << " vec4 gl_Position;\n"
614 << "};\n"
615 << "\n"
616 << "void main(void)\n"
617 << "{\n"
618 << " gl_Position = in_position;\n"
619 << "}\n";
620
621 programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
622 }
623
624 // Fragment shader
625 {
626 std::ostringstream src;
627 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
628 << "\n"
629 << "layout(location = 0) out vec4 out_color;\n"
630 << "\n"
631 << "void main(void)\n"
632 << "{\n"
633 << " if (gl_FrontFacing)\n"
634 << " out_color = vec4(1.0);\n"
635 << " else\n"
636 << " out_color = vec4(vec3(0.5), 1.0);\n"
637 << "}\n";
638
639 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
640 }
641 }
642
checkSupport(Context & context) const643 virtual void checkSupport (Context& context) const
644 {
645 if (m_params.groupParams->useDynamicRendering)
646 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
647
648 context.requireDeviceFunctionality("VK_KHR_maintenance1");
649 }
650
createInstance(Context & context) const651 virtual TestInstance* createInstance (Context& context) const
652 {
653 return new NegativeViewportHeightTestInstance(context, m_params);
654 }
655
656 private:
657 const TestParams m_params;
658 };
659
660 struct SubGroupParams
661 {
662 bool zeroViewportHeight;
663 const SharedGroupParams groupParams;
664 };
665
populateTestGroup(tcu::TestCaseGroup * testGroup,SubGroupParams subGroupParams)666 void populateTestGroup (tcu::TestCaseGroup* testGroup, SubGroupParams subGroupParams)
667 {
668 const struct
669 {
670 const char* const name;
671 VkFrontFace frontFace;
672 } frontFace[] =
673 {
674 { "front_ccw", VK_FRONT_FACE_COUNTER_CLOCKWISE },
675 { "front_cw", VK_FRONT_FACE_CLOCKWISE },
676 };
677
678 const struct
679 {
680 const char* const name;
681 VkCullModeFlagBits cullMode;
682 } cullMode[] =
683 {
684 { "cull_none", VK_CULL_MODE_NONE },
685 { "cull_front", VK_CULL_MODE_FRONT_BIT },
686 { "cull_back", VK_CULL_MODE_BACK_BIT },
687 { "cull_both", VK_CULL_MODE_FRONT_AND_BACK },
688 };
689
690 for (int ndxFrontFace = 0; ndxFrontFace < DE_LENGTH_OF_ARRAY(frontFace); ++ndxFrontFace)
691 for (int ndxCullMode = 0; ndxCullMode < DE_LENGTH_OF_ARRAY(cullMode); ++ndxCullMode)
692 {
693 const TestParams params =
694 {
695 frontFace[ndxFrontFace].frontFace,
696 cullMode[ndxCullMode].cullMode,
697 subGroupParams.zeroViewportHeight,
698 subGroupParams.groupParams
699 };
700 std::ostringstream name;
701 name << frontFace[ndxFrontFace].name << "_" << cullMode[ndxCullMode].name;
702
703 testGroup->addChild(new NegativeViewportHeightTest(testGroup->getTestContext(), name.str(), params));
704 }
705 }
706
707 enum class OffScreenAxisCase
708 {
709 ONSCREEN = 0,
710 NEGATIVE_SIDE = 1,
711 POSITIVE_SIDE = 2,
712 };
713
714 struct OffScreenParams
715 {
716 const uint32_t randomSeed;
717 const OffScreenAxisCase xAxis;
718 const OffScreenAxisCase yAxis;
719 const bool negativeHeight;
720 const SharedGroupParams groupParams;
721
OffScreenParamsvkt::Draw::__anon89b8d6ff0111::OffScreenParams722 OffScreenParams (uint32_t seed, OffScreenAxisCase x, OffScreenAxisCase y, bool negH, const SharedGroupParams gp)
723 : randomSeed (seed)
724 , xAxis (x)
725 , yAxis (y)
726 , negativeHeight (negH)
727 , groupParams (gp)
728 {
729 // At least one of them must be offscreen.
730 DE_ASSERT(xAxis != OffScreenAxisCase::ONSCREEN || yAxis != OffScreenAxisCase::ONSCREEN);
731 }
732 };
733
734 class OffScreenViewportCase : public vkt::TestCase
735 {
736 public:
737 static constexpr int32_t kFramebufferSize = 32; // Width and Height of framebuffer.
738 static constexpr int32_t kViewportMaxDim = 1024; // When generating offscreen coords, use this limit as the negative or positive max coord for X/Y.
739 static constexpr uint32_t kVertexCount = 4u;
740
741 // Choose a couple of values for the Axis range (X or Y) according to the chosen Axis case.
genAxis(de::Random & rnd,OffScreenAxisCase axisCase)742 static tcu::IVec2 genAxis (de::Random& rnd, OffScreenAxisCase axisCase)
743 {
744 int32_t minVal = 0;
745 int32_t maxVal = 0;
746
747 if (axisCase == OffScreenAxisCase::ONSCREEN)
748 maxVal = kFramebufferSize - 1;
749 else if (axisCase == OffScreenAxisCase::NEGATIVE_SIDE)
750 {
751 minVal = -kViewportMaxDim;
752 maxVal = -1;
753 }
754 else if (axisCase == OffScreenAxisCase::POSITIVE_SIDE)
755 {
756 minVal = kFramebufferSize + 1;
757 maxVal = kViewportMaxDim;
758 }
759
760 const auto a = rnd.getInt(minVal, maxVal);
761 const auto b = rnd.getInt(minVal, maxVal);
762
763 const tcu::IVec2 axisRange (de::min(a, b), de::max(a, b));
764 return axisRange;
765 }
766
OffScreenViewportCase(tcu::TestContext & testCtx,const std::string & name,const OffScreenParams & params)767 OffScreenViewportCase (tcu::TestContext& testCtx, const std::string& name, const OffScreenParams& params)
768 : vkt::TestCase (testCtx, name)
769 , m_params (params)
770 {}
771
~OffScreenViewportCase(void)772 virtual ~OffScreenViewportCase (void) {}
773
774 void initPrograms (vk::SourceCollections& programCollection) const override;
775 TestInstance* createInstance (Context& context) const override;
776 void checkSupport (Context& context) const override;
777
778 protected:
779 const OffScreenParams m_params;
780 };
781
782 class OffScreenViewportInstance : public vkt::TestInstance
783 {
784 public:
OffScreenViewportInstance(Context & context,const OffScreenParams & params)785 OffScreenViewportInstance (Context& context, const OffScreenParams& params)
786 : vkt::TestInstance (context)
787 , m_params (params)
788 , m_dynRenderHelper (params.groupParams)
789 {}
790
~OffScreenViewportInstance(void)791 virtual ~OffScreenViewportInstance (void) {}
792
793 tcu::TestStatus iterate (void) override;
794
795 protected:
796 const OffScreenParams m_params;
797 const DynRenderHelper m_dynRenderHelper;
798 };
799
createInstance(Context & context) const800 TestInstance* OffScreenViewportCase::createInstance (Context &context) const
801 {
802 return new OffScreenViewportInstance(context, m_params);
803 }
804
checkSupport(Context & context) const805 void OffScreenViewportCase::checkSupport (Context &context) const
806 {
807 if (m_params.groupParams->useDynamicRendering)
808 context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
809
810 if (m_params.negativeHeight)
811 context.requireDeviceFunctionality("VK_KHR_maintenance1");
812 }
813
initPrograms(vk::SourceCollections & programCollection) const814 void OffScreenViewportCase::initPrograms (vk::SourceCollections &programCollection) const
815 {
816 std::ostringstream vert;
817 vert
818 << "#version 460\n"
819 << "const int vertexCount = " << kVertexCount << ";\n"
820 << "vec2 positions[vertexCount] = vec2[](\n"
821 << " vec2(-1.0, -1.0),\n"
822 << " vec2(-1.0, 1.0),\n"
823 << " vec2( 1.0, -1.0),\n"
824 << " vec2( 1.0, 1.0)\n"
825 << ");\n"
826 << "void main (void) { gl_Position = vec4(positions[gl_VertexIndex % vertexCount], 0.0, 1.0); }\n"
827 ;
828 programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
829
830 std::ostringstream frag;
831 frag
832 << "#version 460\n"
833 << "layout (location=0) out vec4 outColor;\n"
834 << "void main (void) { outColor = vec4(0.0, 0.0, 1.0, 1.0); }\n"
835 ;
836 programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
837 }
838
iterate(void)839 tcu::TestStatus OffScreenViewportInstance::iterate (void)
840 {
841 de::Random rnd(m_params.randomSeed);
842
843 // Pseudorandomly generate viewport data.
844 const auto xAxis = OffScreenViewportCase::genAxis(rnd, m_params.xAxis);
845 auto yAxis = OffScreenViewportCase::genAxis(rnd, m_params.yAxis);
846 const auto width = xAxis.y() - xAxis.x() + 1;
847 auto height = yAxis.y() - yAxis.x() + 1;
848
849 if (m_params.negativeHeight)
850 {
851 height = -height;
852 std::swap(yAxis[0], yAxis[1]);
853 }
854
855 const VkViewport testViewport =
856 {
857 static_cast<float>(xAxis.x()), // float x;
858 static_cast<float>(yAxis.x()), // float y;
859 static_cast<float>(width), // float width;
860 static_cast<float>(height), // float height;
861 0.0f, // float minDepth;
862 1.0f, // float maxDepth;
863 };
864
865 // Framebuffer parameters.
866 const auto kIFbSize = OffScreenViewportCase::kFramebufferSize;
867 const auto fbSize = static_cast<uint32_t>(kIFbSize);
868 const auto fbExtent = makeExtent3D(fbSize, fbSize, 1u);
869 const auto fbFormat = VK_FORMAT_R8G8B8A8_UNORM;
870 const auto fbUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
871
872 const auto& ctx = m_context.getContextCommonData();
873 CommandPoolWithBuffer cmd (ctx.vkd, ctx.device, ctx.qfIndex);
874 ImageWithBuffer colorRes (ctx.vkd, ctx.device, ctx.allocator, fbExtent, fbFormat, fbUsage, VK_IMAGE_TYPE_2D);
875
876 const auto& binaries = m_context.getBinaryCollection();
877 const auto vertModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
878 const auto fragModule = createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
879
880 // Render pass and framebuffer.
881 const auto renderPass = makeRenderPass(ctx.vkd, ctx.device, fbFormat, VK_FORMAT_UNDEFINED /* DS format */, VK_ATTACHMENT_LOAD_OP_LOAD);
882 const auto framebuffer = makeFramebuffer(ctx.vkd, ctx.device, renderPass.get(), colorRes.getImageView(), fbExtent.width, fbExtent.height);
883
884 // Pipeline.
885 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = initVulkanStructure();
886
887 const std::vector<VkViewport> viewports(1u, testViewport);
888 const std::vector<VkRect2D> scissors (1u, makeRect2D(fbExtent));
889
890 const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device);
891 const auto pipelineRP = (m_params.groupParams->useDynamicRendering ? VK_NULL_HANDLE : renderPass.get());
892 const auto pipeline = makeGraphicsPipeline(ctx.vkd, ctx.device, pipelineLayout.get(),
893 vertModule.get(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, fragModule.get(),
894 pipelineRP, viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 0u, 0u, &vertexInputStateCreateInfo);
895
896 const auto cmdBuffer = cmd.cmdBuffer.get();
897 const auto secCmdBufferPtr = (m_params.groupParams->useSecondaryCmdBuffer
898 ? allocateCommandBuffer(ctx.vkd, ctx.device, cmd.cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_SECONDARY)
899 : Move<VkCommandBuffer>());
900 const auto secCmdBuffer = secCmdBufferPtr.get();
901 const auto clearColor = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
902 const auto clearColorVal = makeClearValueColorVec4(clearColor);
903 const auto colorSRR = makeDefaultImageSubresourceRange();
904
905 // Draw (offscreen due to the viewport).
906 beginCommandBuffer(ctx.vkd, cmdBuffer);
907
908 // Clear color image outside render pass.
909 const auto preClearBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_TRANSFER_WRITE_BIT,
910 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
911 colorRes.getImage(), colorSRR);
912 cmdPipelineImageMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, &preClearBarrier);
913
914 ctx.vkd.cmdClearColorImage(cmdBuffer, colorRes.getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColorVal.color, 1u, &colorSRR);
915
916 const auto postClearBarrier = makeImageMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT),
917 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
918 colorRes.getImage(), colorSRR);
919 cmdPipelineImageMemoryBarrier(ctx.vkd, cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, &postClearBarrier);
920
921 // Render pass.
922 if (!m_params.groupParams->useDynamicRendering)
923 {
924 beginRenderPass(ctx.vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.at(0u));
925 ctx.vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
926 ctx.vkd.cmdDraw(cmdBuffer, OffScreenViewportCase::kVertexCount, 1u, 0u, 0u);
927 endRenderPass(ctx.vkd, cmdBuffer);
928 }
929 else
930 {
931 #ifndef CTS_USES_VULKANSC
932 const bool secondary = m_params.groupParams->useSecondaryCmdBuffer;
933 const bool allInSecondary = m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass;
934 const auto beginEndCmdBuffer = (allInSecondary ? secCmdBuffer : cmdBuffer);
935 const auto rpContentsCmdBuffer = (secondary ? secCmdBuffer : cmdBuffer);
936 const auto endAndExecuteSecondary = [&cmdBuffer, &secCmdBuffer, &ctx](void)
937 {
938 endCommandBuffer(ctx.vkd, secCmdBuffer);
939 ctx.vkd.cmdExecuteCommands(cmdBuffer, 1u, &secCmdBuffer);
940 };
941
942 if (secondary)
943 m_dynRenderHelper.beginSecondaryCmdBuffer(ctx.vkd, secCmdBuffer, fbFormat);
944
945 m_dynRenderHelper.beginRendering(ctx.vkd, beginEndCmdBuffer, !allInSecondary/*isPrimary*/, colorRes.getImageView(), scissors.at(0), clearColorVal, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
946 ctx.vkd.cmdBindPipeline(rpContentsCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
947 ctx.vkd.cmdDraw(rpContentsCmdBuffer, OffScreenViewportCase::kVertexCount, 1u, 0u, 0u);
948 if (secondary && !allInSecondary)
949 endAndExecuteSecondary();
950 endRendering(ctx.vkd, beginEndCmdBuffer);
951
952 if (secondary && allInSecondary)
953 endAndExecuteSecondary();
954 #else
955 DE_UNREF(secCmdBuffer);
956 DE_ASSERT(false);
957 #endif // CTS_USES_VULKANSC
958 }
959
960 // Copy to results buffer.
961 copyImageToBuffer(ctx.vkd, cmdBuffer, colorRes.getImage(), colorRes.getBuffer(), tcu::IVec2(kIFbSize, kIFbSize),
962 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
963 1u, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
964 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
965
966 endCommandBuffer(ctx.vkd, cmdBuffer);
967 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
968
969 // Verify color buffer.
970 invalidateAlloc(ctx.vkd, ctx.device, colorRes.getBufferAllocation());
971
972 const tcu::ConstPixelBufferAccess resultAccess (mapVkFormat(fbFormat), tcu::IVec3(kIFbSize, kIFbSize, 1), colorRes.getBufferAllocation().getHostPtr());
973 auto& log = m_context.getTestContext().getLog();
974 const tcu::Vec4 threshold (0.0f, 0.0f, 0.0f, 0.0f);
975
976 if (!tcu::floatThresholdCompare(log, "Result", "", clearColor, resultAccess, threshold, tcu::COMPARE_LOG_ON_ERROR))
977 return tcu::TestStatus::fail("Unexpected color result; check log for details");
978
979 return tcu::TestStatus::pass("Pass");
980 }
981
982 } // anonymous
983
createNegativeViewportHeightTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)984 tcu::TestCaseGroup* createNegativeViewportHeightTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
985 {
986 SubGroupParams subGroupParams { false, groupParams };
987 // Negative viewport height (VK_KHR_maintenance1)
988 return createTestGroup(testCtx, "negative_viewport_height", populateTestGroup, subGroupParams);
989 }
990
createZeroViewportHeightTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)991 tcu::TestCaseGroup* createZeroViewportHeightTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
992 {
993 SubGroupParams subGroupParams{ false, groupParams };
994 // Zero viewport height (VK_KHR_maintenance1)
995 return createTestGroup(testCtx, "zero_viewport_height", populateTestGroup, subGroupParams);
996 }
997
createOffScreenViewportTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)998 tcu::TestCaseGroup* createOffScreenViewportTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
999 {
1000 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
1001
1002 const struct
1003 {
1004 const OffScreenAxisCase axisCase;
1005 const char* suffix;
1006 } axisCases[] =
1007 {
1008 { OffScreenAxisCase::ONSCREEN, "_on_screen" },
1009 { OffScreenAxisCase::NEGATIVE_SIDE, "_off_screen_negative" },
1010 { OffScreenAxisCase::POSITIVE_SIDE, "_off_screen_positive" },
1011 };
1012
1013 const struct
1014 {
1015 const bool negativeHeight;
1016 const char* suffix;
1017 } negativeHeightCases[] =
1018 {
1019 { false, "" },
1020 { true, "_negative_height" },
1021 };
1022
1023 uint32_t seed = 1674229780;
1024 // Test using off-screen viewports
1025 GroupPtr group (new tcu::TestCaseGroup(testCtx, "offscreen_viewport"));
1026
1027 for (const auto& xCase : axisCases)
1028 for (const auto& yCase : axisCases)
1029 {
1030 // At least one of the axis has to be offscreen for the framebuffer to remain clear.
1031 if (xCase.axisCase == OffScreenAxisCase::ONSCREEN && yCase.axisCase == OffScreenAxisCase::ONSCREEN)
1032 continue;
1033
1034 for (const auto& negHeightCase : negativeHeightCases)
1035 {
1036 OffScreenParams params(seed, xCase.axisCase, yCase.axisCase, negHeightCase.negativeHeight, groupParams);
1037 ++seed;
1038
1039 const auto testName = std::string("x") + xCase.suffix + "_y" + yCase.suffix + negHeightCase.suffix;
1040 group->addChild(new OffScreenViewportCase(testCtx, testName, params));
1041 }
1042 }
1043 return group.release();
1044 }
1045
1046 } // Draw
1047 } // vkt
1048