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 Clipping tests 22 *//*--------------------------------------------------------------------*/ 23 24 #include "vktClippingTests.hpp" 25 #include "vktTestCase.hpp" 26 #include "vktTestGroupUtil.hpp" 27 #include "vktTestCaseUtil.hpp" 28 #include "vktClippingUtil.hpp" 29 #include "vkRefUtil.hpp" 30 #include "vkTypeUtil.hpp" 31 #include "vkImageUtil.hpp" 32 #include "deUniquePtr.hpp" 33 #include "deStringUtil.hpp" 34 #include "deRandom.hpp" 35 36 namespace vkt 37 { 38 namespace clipping 39 { 40 namespace 41 { 42 using namespace vk; 43 using de::MovePtr; 44 using tcu::UVec2; 45 using tcu::Vec4; 46 using tcu::IVec2; 47 48 enum Constants 49 { 50 RENDER_SIZE = 16, 51 RENDER_SIZE_LARGE = 128, 52 NUM_RENDER_PIXELS = RENDER_SIZE * RENDER_SIZE, 53 NUM_PATCH_CONTROL_POINTS = 3, 54 MAX_NUM_SHADER_MODULES = 5, 55 MAX_CLIP_DISTANCES = 8, 56 MAX_CULL_DISTANCES = 8, 57 MAX_COMBINED_CLIP_AND_CULL_DISTANCES = 8, 58 }; 59 60 struct Shader 61 { 62 VkShaderStageFlagBits stage; 63 const ProgramBinary* binary; 64 65 Shader (const VkShaderStageFlagBits stage_, const ProgramBinary& binary_) 66 : stage (stage_) 67 , binary (&binary_) 68 { 69 } 70 }; 71 72 //! Sets up a graphics pipeline and enables simple draw calls to predefined attachments. 73 //! Clip volume uses wc = 1.0, which gives clip coord ranges: x = [-1, 1], y = [-1, 1], z = [0, 1] 74 //! Clip coords (-1,-1) map to viewport coords (0, 0). 75 class DrawContext 76 { 77 public: 78 DrawContext (Context& context, 79 const std::vector<Shader>& shaders, 80 const std::vector<Vec4>& vertices, 81 const VkPrimitiveTopology primitiveTopology, 82 const deUint32 renderSize = static_cast<deUint32>(RENDER_SIZE), 83 const bool depthClampEnable = false, 84 const bool blendEnable = false, 85 const float lineWidth = 1.0f); 86 87 void draw (void); 88 tcu::ConstPixelBufferAccess getColorPixels (void) const; 89 90 private: 91 Context& m_context; 92 const VkFormat m_colorFormat; 93 const VkImageSubresourceRange m_colorSubresourceRange; 94 const UVec2 m_renderSize; 95 const VkExtent3D m_imageExtent; 96 const VkPrimitiveTopology m_primitiveTopology; 97 const bool m_depthClampEnable; 98 const bool m_blendEnable; 99 const deUint32 m_numVertices; 100 const float m_lineWidth; 101 const deUint32 m_numPatchControlPoints; 102 MovePtr<Buffer> m_vertexBuffer; 103 MovePtr<Image> m_colorImage; 104 MovePtr<Buffer> m_colorAttachmentBuffer; 105 Move<VkImageView> m_colorImageView; 106 Move<VkRenderPass> m_renderPass; 107 Move<VkFramebuffer> m_framebuffer; 108 Move<VkPipelineLayout> m_pipelineLayout; 109 Move<VkPipeline> m_pipeline; 110 Move<VkCommandPool> m_cmdPool; 111 Move<VkCommandBuffer> m_cmdBuffer; 112 Move<VkShaderModule> m_shaderModules[MAX_NUM_SHADER_MODULES]; 113 114 DrawContext (const DrawContext&); // "deleted" 115 DrawContext& operator= (const DrawContext&); // "deleted" 116 }; 117 118 DrawContext::DrawContext (Context& context, 119 const std::vector<Shader>& shaders, 120 const std::vector<Vec4>& vertices, 121 const VkPrimitiveTopology primitiveTopology, 122 const deUint32 renderSize, 123 const bool depthClampEnable, 124 const bool blendEnable, 125 const float lineWidth) 126 : m_context (context) 127 , m_colorFormat (VK_FORMAT_R8G8B8A8_UNORM) 128 , m_colorSubresourceRange (makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)) 129 , m_renderSize (renderSize, renderSize) 130 , m_imageExtent (makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u)) 131 , m_primitiveTopology (primitiveTopology) 132 , m_depthClampEnable (depthClampEnable) 133 , m_blendEnable (blendEnable) 134 , m_numVertices (static_cast<deUint32>(vertices.size())) 135 , m_lineWidth (lineWidth) 136 , m_numPatchControlPoints (NUM_PATCH_CONTROL_POINTS) // we're treating patches as triangles 137 { 138 const DeviceInterface& vk = m_context.getDeviceInterface(); 139 const VkDevice device = m_context.getDevice(); 140 Allocator& allocator = m_context.getDefaultAllocator(); 141 142 // Command buffer 143 { 144 m_cmdPool = makeCommandPool(vk, device, m_context.getUniversalQueueFamilyIndex()); 145 m_cmdBuffer = makeCommandBuffer(vk, device, *m_cmdPool); 146 } 147 148 // Color attachment image 149 { 150 const VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 151 const VkImageCreateInfo imageCreateInfo = 152 { 153 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; 154 DE_NULL, // const void* pNext; 155 (VkImageCreateFlags)0, // VkImageCreateFlags flags; 156 VK_IMAGE_TYPE_2D, // VkImageType imageType; 157 m_colorFormat, // VkFormat format; 158 m_imageExtent, // VkExtent3D extent; 159 1u, // uint32_t mipLevels; 160 1u, // uint32_t arrayLayers; 161 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; 162 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; 163 usage, // VkImageUsageFlags usage; 164 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 165 VK_QUEUE_FAMILY_IGNORED, // uint32_t queueFamilyIndexCount; 166 DE_NULL, // const uint32_t* pQueueFamilyIndices; 167 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; 168 }; 169 170 m_colorImage = MovePtr<Image>(new Image(vk, device, allocator, imageCreateInfo, MemoryRequirement::Any)); 171 m_colorImageView = makeImageView(vk, device, **m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange); 172 173 // Buffer to copy attachment data after rendering 174 175 const VkDeviceSize bitmapSize = tcu::getPixelSize(mapVkFormat(m_colorFormat)) * m_renderSize.x() * m_renderSize.y(); 176 m_colorAttachmentBuffer = MovePtr<Buffer>(new Buffer( 177 vk, device, allocator, makeBufferCreateInfo(bitmapSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible)); 178 179 { 180 const Allocation& alloc = m_colorAttachmentBuffer->getAllocation(); 181 deMemset(alloc.getHostPtr(), 0, (size_t)bitmapSize); 182 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), bitmapSize); 183 } 184 } 185 186 // Vertex buffer 187 { 188 const VkDeviceSize bufferSize = vertices.size() * sizeof(vertices[0]); 189 m_vertexBuffer = MovePtr<Buffer>(new Buffer( 190 vk, device, allocator, makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible)); 191 192 const Allocation& alloc = m_vertexBuffer->getAllocation(); 193 deMemcpy(alloc.getHostPtr(), &vertices[0], (size_t)bufferSize); 194 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), bufferSize); 195 } 196 197 // Pipeline layout 198 { 199 m_pipelineLayout = makePipelineLayoutWithoutDescriptors(vk, device); 200 } 201 202 // Renderpass 203 { 204 const VkAttachmentDescription colorAttachmentDescription = 205 { 206 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; 207 m_colorFormat, // VkFormat format; 208 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; 209 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; 210 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; 211 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; 212 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; 213 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; 214 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout; 215 }; 216 217 const VkAttachmentReference colorAttachmentReference = 218 { 219 0u, // deUint32 attachment; 220 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout; 221 }; 222 223 const VkAttachmentReference depthAttachmentReference = 224 { 225 VK_ATTACHMENT_UNUSED, // deUint32 attachment; 226 VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout layout; 227 }; 228 229 const VkSubpassDescription subpassDescription = 230 { 231 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags; 232 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; 233 0u, // deUint32 inputAttachmentCount; 234 DE_NULL, // const VkAttachmentReference* pInputAttachments; 235 1u, // deUint32 colorAttachmentCount; 236 &colorAttachmentReference, // const VkAttachmentReference* pColorAttachments; 237 DE_NULL, // const VkAttachmentReference* pResolveAttachments; 238 &depthAttachmentReference, // const VkAttachmentReference* pDepthStencilAttachment; 239 0u, // deUint32 preserveAttachmentCount; 240 DE_NULL // const deUint32* pPreserveAttachments; 241 }; 242 243 const VkRenderPassCreateInfo renderPassInfo = 244 { 245 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; 246 DE_NULL, // const void* pNext; 247 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags; 248 1u, // deUint32 attachmentCount; 249 &colorAttachmentDescription, // const VkAttachmentDescription* pAttachments; 250 1u, // deUint32 subpassCount; 251 &subpassDescription, // const VkSubpassDescription* pSubpasses; 252 0u, // deUint32 dependencyCount; 253 DE_NULL // const VkSubpassDependency* pDependencies; 254 }; 255 256 m_renderPass = createRenderPass(vk, device, &renderPassInfo); 257 } 258 259 // Framebuffer 260 { 261 const VkFramebufferCreateInfo framebufferInfo = { 262 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; 263 DE_NULL, // const void* pNext; 264 (VkFramebufferCreateFlags)0, // VkFramebufferCreateFlags flags; 265 *m_renderPass, // VkRenderPass renderPass; 266 1u, // uint32_t attachmentCount; 267 &m_colorImageView.get(), // const VkImageView* pAttachments; 268 m_renderSize.x(), // uint32_t width; 269 m_renderSize.y(), // uint32_t height; 270 1u, // uint32_t layers; 271 }; 272 273 m_framebuffer = createFramebuffer(vk, device, &framebufferInfo); 274 } 275 276 // Graphics pipeline 277 { 278 const deUint32 vertexStride = sizeof(Vec4); 279 const VkFormat vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT; 280 281 const VkVertexInputBindingDescription bindingDesc = 282 { 283 0u, // uint32_t binding; 284 vertexStride, // uint32_t stride; 285 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate; 286 }; 287 const VkVertexInputAttributeDescription attributeDesc = 288 { 289 0u, // uint32_t location; 290 0u, // uint32_t binding; 291 vertexFormat, // VkFormat format; 292 0u, // uint32_t offset; 293 }; 294 295 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = 296 { 297 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; 298 DE_NULL, // const void* pNext; 299 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags; 300 1u, // uint32_t vertexBindingDescriptionCount; 301 &bindingDesc, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; 302 1u, // uint32_t vertexAttributeDescriptionCount; 303 &attributeDesc, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; 304 }; 305 306 const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = 307 { 308 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; 309 DE_NULL, // const void* pNext; 310 (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags; 311 m_primitiveTopology, // VkPrimitiveTopology topology; 312 VK_FALSE, // VkBool32 primitiveRestartEnable; 313 }; 314 315 const VkPipelineTessellationStateCreateInfo pipelineTessellationStateInfo = 316 { 317 VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType; 318 DE_NULL, // const void* pNext; 319 (VkPipelineTessellationStateCreateFlags)0, // VkPipelineTessellationStateCreateFlags flags; 320 m_numPatchControlPoints, // uint32_t patchControlPoints; 321 }; 322 323 const VkViewport viewport = makeViewport( 324 0.0f, 0.0f, 325 static_cast<float>(m_renderSize.x()), static_cast<float>(m_renderSize.y()), 326 0.0f, 1.0f); 327 328 const VkRect2D scissor = { 329 makeOffset2D(0, 0), 330 makeExtent2D(m_renderSize.x(), m_renderSize.y()), 331 }; 332 333 const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = 334 { 335 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; 336 DE_NULL, // const void* pNext; 337 (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags; 338 1u, // uint32_t viewportCount; 339 &viewport, // const VkViewport* pViewports; 340 1u, // uint32_t scissorCount; 341 &scissor, // const VkRect2D* pScissors; 342 }; 343 344 const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = 345 { 346 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; 347 DE_NULL, // const void* pNext; 348 (VkPipelineRasterizationStateCreateFlags)0, // VkPipelineRasterizationStateCreateFlags flags; 349 m_depthClampEnable, // VkBool32 depthClampEnable; 350 VK_FALSE, // VkBool32 rasterizerDiscardEnable; 351 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode; 352 VK_CULL_MODE_NONE, // VkCullModeFlags cullMode; 353 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; 354 VK_FALSE, // VkBool32 depthBiasEnable; 355 0.0f, // float depthBiasConstantFactor; 356 0.0f, // float depthBiasClamp; 357 0.0f, // float depthBiasSlopeFactor; 358 m_lineWidth, // float lineWidth; 359 }; 360 361 const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = 362 { 363 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; 364 DE_NULL, // const void* pNext; 365 (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags; 366 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; 367 VK_FALSE, // VkBool32 sampleShadingEnable; 368 0.0f, // float minSampleShading; 369 DE_NULL, // const VkSampleMask* pSampleMask; 370 VK_FALSE, // VkBool32 alphaToCoverageEnable; 371 VK_FALSE // VkBool32 alphaToOneEnable; 372 }; 373 374 const VkStencilOpState stencilOpState = makeStencilOpState( 375 VK_STENCIL_OP_KEEP, // stencil fail 376 VK_STENCIL_OP_KEEP, // depth & stencil pass 377 VK_STENCIL_OP_KEEP, // depth only fail 378 VK_COMPARE_OP_NEVER, // compare op 379 0u, // compare mask 380 0u, // write mask 381 0u); // reference 382 383 const VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo = 384 { 385 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; 386 DE_NULL, // const void* pNext; 387 (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags; 388 VK_FALSE, // VkBool32 depthTestEnable; 389 VK_FALSE, // VkBool32 depthWriteEnable; 390 VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp; 391 VK_FALSE, // VkBool32 depthBoundsTestEnable; 392 VK_FALSE, // VkBool32 stencilTestEnable; 393 stencilOpState, // VkStencilOpState front; 394 stencilOpState, // VkStencilOpState back; 395 0.0f, // float minDepthBounds; 396 1.0f, // float maxDepthBounds; 397 }; 398 399 const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; 400 const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = 401 { 402 m_blendEnable, // VkBool32 blendEnable; 403 VK_BLEND_FACTOR_SRC_ALPHA, // VkBlendFactor srcColorBlendFactor; 404 VK_BLEND_FACTOR_ONE, // VkBlendFactor dstColorBlendFactor; 405 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp; 406 VK_BLEND_FACTOR_SRC_ALPHA, // VkBlendFactor srcAlphaBlendFactor; 407 VK_BLEND_FACTOR_ONE, // VkBlendFactor dstAlphaBlendFactor; 408 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp; 409 colorComponentsAll, // VkColorComponentFlags colorWriteMask; 410 }; 411 412 const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = 413 { 414 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; 415 DE_NULL, // const void* pNext; 416 (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags; 417 VK_FALSE, // VkBool32 logicOpEnable; 418 VK_LOGIC_OP_COPY, // VkLogicOp logicOp; 419 1u, // deUint32 attachmentCount; 420 &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments; 421 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4]; 422 }; 423 424 // Create shader stages 425 426 std::vector<VkPipelineShaderStageCreateInfo> shaderStages; 427 VkShaderStageFlags stageFlags = (VkShaderStageFlags)0; 428 429 DE_ASSERT(shaders.size() <= MAX_NUM_SHADER_MODULES); 430 for (deUint32 shaderNdx = 0; shaderNdx < shaders.size(); ++shaderNdx) 431 { 432 m_shaderModules[shaderNdx] = createShaderModule(vk, device, *shaders[shaderNdx].binary, (VkShaderModuleCreateFlags)0); 433 434 const VkPipelineShaderStageCreateInfo pipelineShaderStageInfo = 435 { 436 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; 437 DE_NULL, // const void* pNext; 438 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; 439 shaders[shaderNdx].stage, // VkShaderStageFlagBits stage; 440 *m_shaderModules[shaderNdx], // VkShaderModule module; 441 "main", // const char* pName; 442 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo; 443 }; 444 445 shaderStages.push_back(pipelineShaderStageInfo); 446 stageFlags |= shaders[shaderNdx].stage; 447 } 448 449 DE_ASSERT( 450 (m_primitiveTopology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) || 451 (stageFlags & (VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT))); 452 453 const bool tessellationEnabled = (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST); 454 const VkGraphicsPipelineCreateInfo graphicsPipelineInfo = 455 { 456 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; 457 DE_NULL, // const void* pNext; 458 (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags; 459 static_cast<deUint32>(shaderStages.size()), // deUint32 stageCount; 460 &shaderStages[0], // const VkPipelineShaderStageCreateInfo* pStages; 461 &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; 462 &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; 463 (tessellationEnabled ? &pipelineTessellationStateInfo : DE_NULL), // const VkPipelineTessellationStateCreateInfo* pTessellationState; 464 &pipelineViewportStateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState; 465 &pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState; 466 &pipelineMultisampleStateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; 467 &pipelineDepthStencilStateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; 468 &pipelineColorBlendStateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; 469 DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState; 470 *m_pipelineLayout, // VkPipelineLayout layout; 471 *m_renderPass, // VkRenderPass renderPass; 472 0u, // deUint32 subpass; 473 DE_NULL, // VkPipeline basePipelineHandle; 474 0, // deInt32 basePipelineIndex; 475 }; 476 477 m_pipeline = createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo); 478 } 479 480 // Record commands 481 { 482 const VkDeviceSize zeroOffset = 0ull; 483 484 beginCommandBuffer(vk, *m_cmdBuffer); 485 486 // Begin render pass 487 { 488 const VkClearValue clearValue = makeClearValueColor(Vec4(0.0f, 0.0f, 0.0f, 1.0f)); 489 const VkRect2D renderArea = 490 { 491 makeOffset2D(0, 0), 492 makeExtent2D(m_renderSize.x(), m_renderSize.y()) 493 }; 494 495 const VkRenderPassBeginInfo renderPassBeginInfo = { 496 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType; 497 DE_NULL, // const void* pNext; 498 *m_renderPass, // VkRenderPass renderPass; 499 *m_framebuffer, // VkFramebuffer framebuffer; 500 renderArea, // VkRect2D renderArea; 501 1u, // uint32_t clearValueCount; 502 &clearValue, // const VkClearValue* pClearValues; 503 }; 504 505 vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); 506 } 507 508 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); 509 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &(**m_vertexBuffer), &zeroOffset); 510 511 vk.cmdDraw(*m_cmdBuffer, m_numVertices, 1u, 0u, 1u); 512 vk.cmdEndRenderPass(*m_cmdBuffer); 513 514 // Barrier: draw -> copy from image 515 { 516 const VkImageMemoryBarrier barrier = makeImageMemoryBarrier( 517 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, 518 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 519 **m_colorImage, m_colorSubresourceRange); 520 521 vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 522 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier); 523 } 524 525 { 526 const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u), m_imageExtent); 527 vk.cmdCopyImageToBuffer(*m_cmdBuffer, **m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **m_colorAttachmentBuffer, 1u, ©Region); 528 } 529 530 // Barrier: copy to buffer -> host read 531 { 532 const VkBufferMemoryBarrier barrier = makeBufferMemoryBarrier( 533 VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, 534 **m_colorAttachmentBuffer, 0ull, VK_WHOLE_SIZE); 535 536 vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 537 0u, DE_NULL, 1u, &barrier, 0u, DE_NULL); 538 } 539 540 endCommandBuffer(vk, *m_cmdBuffer); 541 } 542 } 543 544 void DrawContext::draw (void) 545 { 546 const DeviceInterface& vk = m_context.getDeviceInterface(); 547 const VkDevice device = m_context.getDevice(); 548 const VkQueue queue = m_context.getUniversalQueue(); 549 tcu::TestLog& log = m_context.getTestContext().getLog(); 550 551 submitCommandsAndWait(vk, device, queue, *m_cmdBuffer); 552 553 log << tcu::LogImageSet("attachments", "") << tcu::LogImage("color0", "", getColorPixels()) << tcu::TestLog::EndImageSet; 554 } 555 556 tcu::ConstPixelBufferAccess DrawContext::getColorPixels (void) const 557 { 558 const DeviceInterface& vk = m_context.getDeviceInterface(); 559 const VkDevice device = m_context.getDevice(); 560 561 const Allocation& alloc = m_colorAttachmentBuffer->getAllocation(); 562 invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), VK_WHOLE_SIZE); 563 564 return tcu::ConstPixelBufferAccess(mapVkFormat(m_colorFormat), m_imageExtent.width, m_imageExtent.height, m_imageExtent.depth, alloc.getHostPtr()); 565 } 566 567 std::vector<Vec4> genVertices (const VkPrimitiveTopology topology, const Vec4& offset, const float slope) 568 { 569 const float p = 1.0f; 570 const float hp = 0.5f; 571 const float z = 0.0f; 572 const float w = 1.0f; 573 574 std::vector<Vec4> vertices; 575 576 // We're setting adjacent vertices to zero where needed, as we don't use them in meaningful way. 577 578 switch (topology) 579 { 580 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: 581 vertices.push_back(offset + Vec4(0.0f, 0.0f, slope/2.0f + z, w)); 582 vertices.push_back(offset + Vec4( -hp, -hp, z, w)); 583 vertices.push_back(offset + Vec4( hp, -hp, slope + z, w)); 584 vertices.push_back(offset + Vec4( -hp, hp, z, w)); 585 vertices.push_back(offset + Vec4( hp, hp, slope + z, w)); 586 break; 587 588 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: 589 vertices.push_back(offset + Vec4(-p, -p, z, w)); 590 vertices.push_back(offset + Vec4( p, p, slope + z, w)); // line 0 591 vertices.push_back(offset + Vec4( p, p, slope + z, w)); 592 vertices.push_back(offset + Vec4( p, -p, slope + z, w)); // line 1 593 vertices.push_back(offset + Vec4( p, -p, slope + z, w)); 594 vertices.push_back(offset + Vec4(-p, p, z, w)); // line 2 595 break; 596 597 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: 598 vertices.push_back(Vec4()); 599 vertices.push_back(offset + Vec4(-p, -p, z, w)); 600 vertices.push_back(offset + Vec4( p, p, slope + z, w)); // line 0 601 vertices.push_back(Vec4()); 602 vertices.push_back(Vec4()); 603 vertices.push_back(offset + Vec4( p, p, slope + z, w)); 604 vertices.push_back(offset + Vec4( p, -p, slope + z, w)); // line 1 605 vertices.push_back(Vec4()); 606 vertices.push_back(Vec4()); 607 vertices.push_back(offset + Vec4( p, -p, slope + z, w)); 608 vertices.push_back(offset + Vec4(-p, p, z, w)); // line 2 609 vertices.push_back(Vec4()); 610 break; 611 612 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: 613 vertices.push_back(offset + Vec4(-p, -p, z, w)); 614 vertices.push_back(offset + Vec4( p, p, slope + z, w)); // line 0 615 vertices.push_back(offset + Vec4( p, -p, slope + z, w)); // line 1 616 vertices.push_back(offset + Vec4(-p, p, z, w)); // line 2 617 break; 618 619 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: 620 vertices.push_back(Vec4()); 621 vertices.push_back(offset + Vec4(-p, -p, z, w)); 622 vertices.push_back(offset + Vec4( p, p, slope + z, w)); // line 0 623 vertices.push_back(offset + Vec4( p, -p, slope + z, w)); // line 1 624 vertices.push_back(offset + Vec4(-p, p, z, w)); // line 2 625 vertices.push_back(Vec4()); 626 break; 627 628 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: 629 vertices.push_back(offset + Vec4( p, -p, slope + z, w)); 630 vertices.push_back(offset + Vec4(-p, -p, z, w)); 631 vertices.push_back(offset + Vec4(-p, p, z, w)); // triangle 0 632 vertices.push_back(offset + Vec4(-p, p, z, w)); 633 vertices.push_back(offset + Vec4( p, p, slope + z, w)); 634 vertices.push_back(offset + Vec4( p, -p, slope + z, w)); // triangle 1 635 break; 636 637 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: 638 vertices.push_back(offset + Vec4( p, -p, slope + z, w)); 639 vertices.push_back(Vec4()); 640 vertices.push_back(offset + Vec4(-p, -p, z, w)); 641 vertices.push_back(Vec4()); 642 vertices.push_back(offset + Vec4(-p, p, z, w)); // triangle 0 643 vertices.push_back(Vec4()); 644 vertices.push_back(offset + Vec4(-p, p, z, w)); 645 vertices.push_back(Vec4()); 646 vertices.push_back(offset + Vec4( p, p, slope + z, w)); 647 vertices.push_back(Vec4()); 648 vertices.push_back(offset + Vec4( p, -p, slope + z, w)); // triangle 1 649 vertices.push_back(Vec4()); 650 break; 651 652 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: 653 vertices.push_back(offset + Vec4(-p, -p, z, w)); 654 vertices.push_back(offset + Vec4(-p, p, z, w)); 655 vertices.push_back(offset + Vec4( p, -p, slope + z, w)); // triangle 0 656 vertices.push_back(offset + Vec4( p, p, slope + z, w)); // triangle 1 657 break; 658 659 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: 660 vertices.push_back(offset + Vec4(-p, -p, z, w)); 661 vertices.push_back(Vec4()); 662 vertices.push_back(offset + Vec4(-p, p, z, w)); 663 vertices.push_back(Vec4()); 664 vertices.push_back(offset + Vec4( p, -p, slope + z, w)); // triangle 0 665 vertices.push_back(Vec4()); 666 vertices.push_back(offset + Vec4( p, p, slope + z, w)); // triangle 1 667 vertices.push_back(Vec4()); 668 break; 669 670 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: 671 vertices.push_back(offset + Vec4( p, -p, slope + z, w)); 672 vertices.push_back(offset + Vec4(-p, -p, z, w)); 673 vertices.push_back(offset + Vec4(-p, p, z, w)); // triangle 0 674 vertices.push_back(offset + Vec4( p, p, slope + z, w)); // triangle 1 675 break; 676 677 case VK_PRIMITIVE_TOPOLOGY_PATCH_LIST: 678 DE_ASSERT(0); 679 break; 680 681 default: 682 DE_ASSERT(0); 683 break; 684 } 685 return vertices; 686 } 687 688 bool inline isColorInRange (const Vec4& color, const Vec4& minColor, const Vec4& maxColor) 689 { 690 return (minColor.x() <= color.x() && color.x() <= maxColor.x()) 691 && (minColor.y() <= color.y() && color.y() <= maxColor.y()) 692 && (minColor.z() <= color.z() && color.z() <= maxColor.z()) 693 && (minColor.w() <= color.w() && color.w() <= maxColor.w()); 694 } 695 696 //! Count pixels that match color within threshold, in the specified region. 697 int countPixels (const tcu::ConstPixelBufferAccess pixels, const IVec2& regionOffset, const IVec2& regionSize, const Vec4& color, const Vec4& colorThreshold) 698 { 699 const Vec4 minColor = color - colorThreshold; 700 const Vec4 maxColor = color + colorThreshold; 701 const int xEnd = regionOffset.x() + regionSize.x(); 702 const int yEnd = regionOffset.y() + regionSize.y(); 703 int numPixels = 0; 704 705 DE_ASSERT(xEnd <= pixels.getWidth()); 706 DE_ASSERT(yEnd <= pixels.getHeight()); 707 708 for (int y = regionOffset.y(); y < yEnd; ++y) 709 for (int x = regionOffset.x(); x < xEnd; ++x) 710 { 711 if (isColorInRange(pixels.getPixel(x, y), minColor, maxColor)) 712 ++numPixels; 713 } 714 715 return numPixels; 716 } 717 718 int countPixels (const tcu::ConstPixelBufferAccess pixels, const Vec4& color, const Vec4& colorThreshold) 719 { 720 return countPixels(pixels, IVec2(), IVec2(pixels.getWidth(), pixels.getHeight()), color, colorThreshold); 721 } 722 723 //! Clipping against the default clip volume. 724 namespace ClipVolume 725 { 726 727 //! Used by wide lines test. 728 enum LineOrientation 729 { 730 LINE_ORIENTATION_AXIS_ALIGNED, 731 LINE_ORIENTATION_DIAGONAL, 732 }; 733 734 void addSimplePrograms (SourceCollections& programCollection, const float pointSize = 0.0f) 735 { 736 // Vertex shader 737 { 738 const bool usePointSize = pointSize > 0.0f; 739 740 std::ostringstream src; 741 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 742 << "\n" 743 << "layout(location = 0) in vec4 v_position;\n" 744 << "\n" 745 << "out gl_PerVertex {\n" 746 << " vec4 gl_Position;\n" 747 << (usePointSize ? " float gl_PointSize;\n" : "") 748 << "};\n" 749 << "\n" 750 << "void main (void)\n" 751 << "{\n" 752 << " gl_Position = v_position;\n" 753 << (usePointSize ? " gl_PointSize = " + de::floatToString(pointSize, 1) + ";\n" : "") 754 << "}\n"; 755 756 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 757 } 758 759 // Fragment shader 760 { 761 std::ostringstream src; 762 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 763 << "\n" 764 << "layout(location = 0) out vec4 o_color;\n" 765 << "\n" 766 << "void main (void)\n" 767 << "{\n" 768 << " o_color = vec4(1.0, gl_FragCoord.z, 0.0, 1.0);\n" 769 << "}\n"; 770 771 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 772 } 773 } 774 775 void initPrograms (SourceCollections& programCollection, const VkPrimitiveTopology topology) 776 { 777 const float pointSize = (topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST ? 1.0f : 0.0f); 778 addSimplePrograms(programCollection, pointSize); 779 } 780 781 void initPrograms (SourceCollections& programCollection, const LineOrientation lineOrientation) 782 { 783 DE_UNREF(lineOrientation); 784 addSimplePrograms(programCollection); 785 } 786 787 void initProgramsPointSize (SourceCollections& programCollection) 788 { 789 addSimplePrograms(programCollection, 0.75f * RENDER_SIZE); 790 } 791 792 //! Primitives fully inside the clip volume. 793 tcu::TestStatus testPrimitivesInside (Context& context, const VkPrimitiveTopology topology) 794 { 795 int minExpectedBlackPixels = 0; 796 797 switch (topology) 798 { 799 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: 800 // We draw only 5 points. 801 minExpectedBlackPixels = NUM_RENDER_PIXELS - 5; 802 break; 803 804 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: 805 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: 806 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: 807 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: 808 // Allow for some error. 809 minExpectedBlackPixels = NUM_RENDER_PIXELS - 3 * RENDER_SIZE; 810 break; 811 812 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: 813 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: 814 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: 815 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: 816 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: 817 // All render area should be covered. 818 minExpectedBlackPixels = 0; 819 break; 820 821 default: 822 DE_ASSERT(0); 823 break; 824 } 825 826 std::vector<Shader> shaders; 827 shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"))); 828 shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"))); 829 830 tcu::TestLog& log = context.getTestContext().getLog(); 831 int numPassed = 0; 832 833 static const struct 834 { 835 const char* const desc; 836 float zPos; 837 } cases[] = 838 { 839 { "Draw primitives at near clipping plane, z = 0.0", 0.0f, }, 840 { "Draw primitives at z = 0.5", 0.5f, }, 841 { "Draw primitives at far clipping plane, z = 1.0", 1.0f, }, 842 }; 843 844 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx) 845 { 846 log << tcu::TestLog::Message << cases[caseNdx].desc << tcu::TestLog::EndMessage; 847 848 const std::vector<Vec4> vertices = genVertices(topology, Vec4(0.0f, 0.0f, cases[caseNdx].zPos, 0.0f), 0.0f); 849 DrawContext drawContext(context, shaders, vertices, topology); 850 drawContext.draw(); 851 852 const int numBlackPixels = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4()); 853 if (numBlackPixels >= minExpectedBlackPixels) 854 ++numPassed; 855 } 856 857 return (numPassed == DE_LENGTH_OF_ARRAY(cases) ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect")); 858 } 859 860 //! Primitives fully outside the clip volume. 861 tcu::TestStatus testPrimitivesOutside (Context& context, const VkPrimitiveTopology topology) 862 { 863 std::vector<Shader> shaders; 864 shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"))); 865 shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"))); 866 867 tcu::TestLog& log = context.getTestContext().getLog(); 868 int numPassed = 0; 869 870 static const struct 871 { 872 const char* const desc; 873 float zPos; 874 } cases[] = 875 { 876 { "Draw primitives in front of the near clipping plane, z < 0.0", -0.5f, }, 877 { "Draw primitives behind the far clipping plane, z > 1.0", 1.5f, }, 878 }; 879 880 log << tcu::TestLog::Message << "Drawing primitives outside the clip volume. Expecting an empty image." << tcu::TestLog::EndMessage; 881 882 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx) 883 { 884 log << tcu::TestLog::Message << cases[caseNdx].desc << tcu::TestLog::EndMessage; 885 886 const std::vector<Vec4> vertices = genVertices(topology, Vec4(0.0f, 0.0f, cases[caseNdx].zPos, 0.0f), 0.0f); 887 DrawContext drawContext(context, shaders, vertices, topology); 888 drawContext.draw(); 889 890 // All pixels must be black -- nothing is drawn. 891 const int numBlackPixels = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4()); 892 if (numBlackPixels == NUM_RENDER_PIXELS) 893 ++numPassed; 894 } 895 896 return (numPassed == DE_LENGTH_OF_ARRAY(cases) ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect")); 897 } 898 899 //! Primitives partially outside the clip volume, but depth clamped 900 tcu::TestStatus testPrimitivesDepthClamp (Context& context, const VkPrimitiveTopology topology) 901 { 902 requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_DEPTH_CLAMP); 903 904 std::vector<Shader> shaders; 905 shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"))); 906 shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"))); 907 908 const int numCases = 4; 909 const IVec2 regionSize = IVec2(RENDER_SIZE/2, RENDER_SIZE); //! size of the clamped region 910 const int regionPixels = regionSize.x() * regionSize.y(); 911 tcu::TestLog& log = context.getTestContext().getLog(); 912 int numPassed = 0; 913 914 static const struct 915 { 916 const char* const desc; 917 float zPos; 918 bool depthClampEnable; 919 IVec2 regionOffset; 920 Vec4 color; 921 } cases[numCases] = 922 { 923 { "Draw primitives intersecting the near clipping plane, depth clamp disabled", -0.5f, false, IVec2(0, 0), Vec4(0.0f, 0.0f, 0.0f, 1.0f) }, 924 { "Draw primitives intersecting the near clipping plane, depth clamp enabled", -0.5f, true, IVec2(0, 0), Vec4(1.0f, 0.0f, 0.0f, 1.0f) }, 925 { "Draw primitives intersecting the far clipping plane, depth clamp disabled", 0.5f, false, IVec2(RENDER_SIZE/2, 0), Vec4(0.0f, 0.0f, 0.0f, 1.0f) }, 926 { "Draw primitives intersecting the far clipping plane, depth clamp enabled", 0.5f, true, IVec2(RENDER_SIZE/2, 0), Vec4(1.0f, 1.0f, 0.0f, 1.0f) }, 927 }; 928 929 // Per case minimum number of colored pixels. 930 int caseMinPixels[numCases] = { 0, 0, 0, 0 }; 931 932 switch (topology) 933 { 934 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST: 935 caseMinPixels[0] = caseMinPixels[2] = regionPixels - 1; 936 caseMinPixels[1] = caseMinPixels[3] = 2; 937 break; 938 939 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: 940 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: 941 case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: 942 case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: 943 caseMinPixels[0] = regionPixels; 944 caseMinPixels[1] = RENDER_SIZE - 2; 945 caseMinPixels[2] = regionPixels; 946 caseMinPixels[3] = 2 * (RENDER_SIZE - 2); 947 break; 948 949 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: 950 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: 951 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: 952 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: 953 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: 954 caseMinPixels[0] = caseMinPixels[1] = caseMinPixels[2] = caseMinPixels[3] = regionPixels; 955 break; 956 957 default: 958 DE_ASSERT(0); 959 break; 960 } 961 962 for (int caseNdx = 0; caseNdx < numCases; ++caseNdx) 963 { 964 log << tcu::TestLog::Message << cases[caseNdx].desc << tcu::TestLog::EndMessage; 965 966 const std::vector<Vec4> vertices = genVertices(topology, Vec4(0.0f, 0.0f, cases[caseNdx].zPos, 0.0f), 1.0f); 967 DrawContext drawContext(context, shaders, vertices, topology, static_cast<deUint32>(RENDER_SIZE), cases[caseNdx].depthClampEnable); 968 drawContext.draw(); 969 970 const int numPixels = countPixels(drawContext.getColorPixels(), cases[caseNdx].regionOffset, regionSize, cases[caseNdx].color, Vec4()); 971 972 if (numPixels >= caseMinPixels[caseNdx]) 973 ++numPassed; 974 } 975 976 return (numPassed == numCases ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect")); 977 } 978 979 //! Large point clipping 980 //! Spec: If the primitive under consideration is a point, then clipping passes it unchanged if it lies within the clip volume; 981 //! otherwise, it is discarded. 982 tcu::TestStatus testLargePoints (Context& context) 983 { 984 requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_LARGE_POINTS); 985 986 std::vector<Shader> shaders; 987 shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"))); 988 shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"))); 989 990 std::vector<Vec4> vertices; 991 { 992 const float delta = 0.1f; // much smaller than the point size 993 const float p = 1.0f + delta; 994 995 vertices.push_back(Vec4( -p, -p, 0.1f, 1.0f)); 996 vertices.push_back(Vec4( -p, p, 0.2f, 1.0f)); 997 vertices.push_back(Vec4( p, p, 0.4f, 1.0f)); 998 vertices.push_back(Vec4( p, -p, 0.6f, 1.0f)); 999 vertices.push_back(Vec4(0.0f, -p, 0.8f, 1.0f)); 1000 vertices.push_back(Vec4( p, 0.0f, 0.9f, 1.0f)); 1001 vertices.push_back(Vec4(0.0f, p, 0.1f, 1.0f)); 1002 vertices.push_back(Vec4( -p, 0.0f, 0.2f, 1.0f)); 1003 } 1004 1005 tcu::TestLog& log = context.getTestContext().getLog(); 1006 1007 log << tcu::TestLog::Message << "Drawing several large points just outside the clip volume. Expecting an empty image." << tcu::TestLog::EndMessage; 1008 1009 DrawContext drawContext(context, shaders, vertices, VK_PRIMITIVE_TOPOLOGY_POINT_LIST); 1010 drawContext.draw(); 1011 1012 // All pixels must be black -- nothing is drawn. 1013 const int numBlackPixels = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4()); 1014 1015 return (numBlackPixels == NUM_RENDER_PIXELS ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect")); 1016 } 1017 1018 //! Wide line clipping 1019 //! Spec: If the primitive is a line segment, then clipping does nothing to it if it lies entirely within the clip volume, and discards it 1020 //! if it lies entirely outside the volume. 1021 tcu::TestStatus testWideLines (Context& context, const LineOrientation lineOrientation) 1022 { 1023 requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_WIDE_LINES); 1024 1025 std::vector<Shader> shaders; 1026 shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"))); 1027 shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"))); 1028 1029 const float delta = 0.1f; // much smaller than the line width 1030 1031 std::vector<Vec4> vertices; 1032 if (lineOrientation == LINE_ORIENTATION_AXIS_ALIGNED) 1033 { 1034 // Axis-aligned lines just outside the clip volume. 1035 const float p = 1.0f + delta; 1036 const float q = 0.9f; 1037 1038 vertices.push_back(Vec4(-p, -q, 0.1f, 1.0f)); 1039 vertices.push_back(Vec4(-p, q, 0.9f, 1.0f)); // line 0 1040 vertices.push_back(Vec4(-q, p, 0.1f, 1.0f)); 1041 vertices.push_back(Vec4( q, p, 0.9f, 1.0f)); // line 1 1042 vertices.push_back(Vec4( p, q, 0.1f, 1.0f)); 1043 vertices.push_back(Vec4( p, -q, 0.9f, 1.0f)); // line 2 1044 vertices.push_back(Vec4( q, -p, 0.1f, 1.0f)); 1045 vertices.push_back(Vec4(-q, -p, 0.9f, 1.0f)); // line 3 1046 } 1047 else if (lineOrientation == LINE_ORIENTATION_DIAGONAL) 1048 { 1049 // Diagonal lines just outside the clip volume. 1050 const float p = 2.0f + delta; 1051 1052 vertices.push_back(Vec4( -p, 0.0f, 0.1f, 1.0f)); 1053 vertices.push_back(Vec4(0.0f, -p, 0.9f, 1.0f)); // line 0 1054 vertices.push_back(Vec4(0.0f, -p, 0.1f, 1.0f)); 1055 vertices.push_back(Vec4( p, 0.0f, 0.9f, 1.0f)); // line 1 1056 vertices.push_back(Vec4( p, 0.0f, 0.1f, 1.0f)); 1057 vertices.push_back(Vec4(0.0f, p, 0.9f, 1.0f)); // line 2 1058 vertices.push_back(Vec4(0.0f, p, 0.1f, 1.0f)); 1059 vertices.push_back(Vec4( -p, 0.0f, 0.9f, 1.0f)); // line 3 1060 } 1061 else 1062 DE_ASSERT(0); 1063 1064 const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice()).limits; 1065 1066 const float lineWidth = std::min(static_cast<float>(RENDER_SIZE), limits.lineWidthRange[1]); 1067 tcu::TestLog& log = context.getTestContext().getLog(); 1068 1069 log << tcu::TestLog::Message << "Drawing several wide lines just outside the clip volume. Expecting an empty image." << tcu::TestLog::EndMessage 1070 << tcu::TestLog::Message << "Line width is " << lineWidth << "." << tcu::TestLog::EndMessage; 1071 1072 DrawContext drawContext(context, shaders, vertices, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, static_cast<deUint32>(RENDER_SIZE), false, false, lineWidth); 1073 drawContext.draw(); 1074 1075 // All pixels must be black -- nothing is drawn. 1076 const int numBlackPixels = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4()); 1077 1078 return (numBlackPixels == NUM_RENDER_PIXELS ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect")); 1079 } 1080 1081 } // ClipVolume ns 1082 1083 namespace ClipDistance 1084 { 1085 1086 struct CaseDefinition 1087 { 1088 const VkPrimitiveTopology topology; 1089 const bool dynamicIndexing; 1090 const bool enableTessellation; 1091 const bool enableGeometry; 1092 const int numClipDistances; 1093 const int numCullDistances; 1094 1095 CaseDefinition (const VkPrimitiveTopology topology_, 1096 const int numClipDistances_, 1097 const int numCullDistances_, 1098 const bool enableTessellation_, 1099 const bool enableGeometry_, 1100 const bool dynamicIndexing_) 1101 : topology (topology_) 1102 , dynamicIndexing (dynamicIndexing_) 1103 , enableTessellation (enableTessellation_) 1104 , enableGeometry (enableGeometry_) 1105 , numClipDistances (numClipDistances_) 1106 , numCullDistances (numCullDistances_) 1107 { 1108 } 1109 }; 1110 1111 void initPrograms (SourceCollections& programCollection, const CaseDefinition caseDef) 1112 { 1113 DE_ASSERT(caseDef.numClipDistances + caseDef.numCullDistances <= MAX_COMBINED_CLIP_AND_CULL_DISTANCES); 1114 1115 std::string perVertexBlock; 1116 { 1117 std::ostringstream str; 1118 str << "gl_PerVertex {\n" 1119 << " vec4 gl_Position;\n"; 1120 if (caseDef.numClipDistances > 0) 1121 str << " float gl_ClipDistance[" << caseDef.numClipDistances << "];\n"; 1122 if (caseDef.numCullDistances > 0) 1123 str << " float gl_CullDistance[" << caseDef.numCullDistances << "];\n"; 1124 str << "}"; 1125 perVertexBlock = str.str(); 1126 } 1127 1128 // Vertex shader 1129 { 1130 std::ostringstream src; 1131 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 1132 << "\n" 1133 << "layout(location = 0) in vec4 v_position;\n" 1134 << "layout(location = 0) out vec4 out_color;\n" 1135 << "\n" 1136 << "out " << perVertexBlock << ";\n" 1137 << "\n" 1138 << "void main (void)\n" 1139 << "{\n" 1140 << " gl_Position = v_position;\n" 1141 << " out_color = vec4(1.0, 0.5 * (v_position.x + 1.0), 0.0, 1.0);\n" 1142 << "\n" 1143 << " const int barNdx = gl_VertexIndex / 6;\n"; 1144 if (caseDef.dynamicIndexing) 1145 { 1146 if (caseDef.numClipDistances > 0) 1147 src << " for (int i = 0; i < " << caseDef.numClipDistances << "; ++i)\n" 1148 << " gl_ClipDistance[i] = (barNdx == i ? v_position.y : 0.0);\n"; 1149 if (caseDef.numCullDistances > 0) 1150 src << " for (int i = 0; i < " << caseDef.numCullDistances << "; ++i)\n" 1151 << " gl_CullDistance[i] = 0.0;\n"; 1152 } 1153 else 1154 { 1155 for (int i = 0; i < caseDef.numClipDistances; ++i) 1156 src << " gl_ClipDistance[" << i << "] = (barNdx == " << i << " ? v_position.y : 0.0);\n"; 1157 for (int i = 0; i < caseDef.numCullDistances; ++i) 1158 src << " gl_CullDistance[" << i << "] = 0.0;\n"; // don't cull anything 1159 } 1160 src << "}\n"; 1161 1162 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 1163 } 1164 1165 if (caseDef.enableTessellation) 1166 { 1167 std::ostringstream src; 1168 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 1169 << "\n" 1170 << "layout(vertices = " << NUM_PATCH_CONTROL_POINTS << ") out;\n" 1171 << "\n" 1172 << "layout(location = 0) in vec4 in_color[];\n" 1173 << "layout(location = 0) out vec4 out_color[];\n" 1174 << "\n" 1175 << "in " << perVertexBlock << " gl_in[gl_MaxPatchVertices];\n" 1176 << "\n" 1177 << "out " << perVertexBlock << " gl_out[];\n" 1178 << "\n" 1179 << "void main (void)\n" 1180 << "{\n" 1181 << " gl_TessLevelInner[0] = 1.0;\n" 1182 << " gl_TessLevelInner[1] = 1.0;\n" 1183 << "\n" 1184 << " gl_TessLevelOuter[0] = 1.0;\n" 1185 << " gl_TessLevelOuter[1] = 1.0;\n" 1186 << " gl_TessLevelOuter[2] = 1.0;\n" 1187 << " gl_TessLevelOuter[3] = 1.0;\n" 1188 << "\n" 1189 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" 1190 << " out_color[gl_InvocationID] = in_color[gl_InvocationID];\n" 1191 << "\n"; 1192 if (caseDef.dynamicIndexing) 1193 { 1194 if (caseDef.numClipDistances > 0) 1195 src << " for (int i = 0; i < " << caseDef.numClipDistances << "; ++i)\n" 1196 << " gl_out[gl_InvocationID].gl_ClipDistance[i] = gl_in[gl_InvocationID].gl_ClipDistance[i];\n"; 1197 if (caseDef.numCullDistances > 0) 1198 src << " for (int i = 0; i < " << caseDef.numCullDistances << "; ++i)\n" 1199 << " gl_out[gl_InvocationID].gl_CullDistance[i] = gl_in[gl_InvocationID].gl_CullDistance[i];\n"; 1200 } 1201 else 1202 { 1203 for (int i = 0; i < caseDef.numClipDistances; ++i) 1204 src << " gl_out[gl_InvocationID].gl_ClipDistance[" << i << "] = gl_in[gl_InvocationID].gl_ClipDistance[" << i << "];\n"; 1205 for (int i = 0; i < caseDef.numCullDistances; ++i) 1206 src << " gl_out[gl_InvocationID].gl_CullDistance[" << i << "] = gl_in[gl_InvocationID].gl_CullDistance[" << i << "];\n"; 1207 } 1208 src << "}\n"; 1209 1210 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str()); 1211 } 1212 1213 if (caseDef.enableTessellation) 1214 { 1215 DE_ASSERT(NUM_PATCH_CONTROL_POINTS == 3); // assumed in shader code 1216 1217 std::ostringstream src; 1218 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 1219 << "\n" 1220 << "layout(triangles, equal_spacing, ccw) in;\n" 1221 << "\n" 1222 << "layout(location = 0) in vec4 in_color[];\n" 1223 << "layout(location = 0) out vec4 out_color;\n" 1224 << "\n" 1225 << "in " << perVertexBlock << " gl_in[gl_MaxPatchVertices];\n" 1226 << "\n" 1227 << "out " << perVertexBlock << ";\n" 1228 << "\n" 1229 << "void main (void)\n" 1230 << "{\n" 1231 << " vec3 px = gl_TessCoord.x * gl_in[0].gl_Position.xyz;\n" 1232 << " vec3 py = gl_TessCoord.y * gl_in[1].gl_Position.xyz;\n" 1233 << " vec3 pz = gl_TessCoord.z * gl_in[2].gl_Position.xyz;\n" 1234 << " gl_Position = vec4(px + py + pz, 1.0);\n" 1235 << " out_color = (in_color[0] + in_color[1] + in_color[2]) / 3.0;\n" 1236 << "\n"; 1237 if (caseDef.dynamicIndexing) 1238 { 1239 if (caseDef.numClipDistances > 0) 1240 src << " for (int i = 0; i < " << caseDef.numClipDistances << "; ++i)\n" 1241 << " gl_ClipDistance[i] = gl_TessCoord.x * gl_in[0].gl_ClipDistance[i]\n" 1242 << " + gl_TessCoord.y * gl_in[1].gl_ClipDistance[i]\n" 1243 << " + gl_TessCoord.z * gl_in[2].gl_ClipDistance[i];\n"; 1244 if (caseDef.numCullDistances > 0) 1245 src << " for (int i = 0; i < " << caseDef.numCullDistances << "; ++i)\n" 1246 << " gl_CullDistance[i] = gl_TessCoord.x * gl_in[0].gl_CullDistance[i]\n" 1247 << " + gl_TessCoord.y * gl_in[1].gl_CullDistance[i]\n" 1248 << " + gl_TessCoord.z * gl_in[2].gl_CullDistance[i];\n"; 1249 } 1250 else 1251 { 1252 for (int i = 0; i < caseDef.numClipDistances; ++i) 1253 src << " gl_ClipDistance[" << i << "] = gl_TessCoord.x * gl_in[0].gl_ClipDistance[" << i << "]\n" 1254 << " + gl_TessCoord.y * gl_in[1].gl_ClipDistance[" << i << "]\n" 1255 << " + gl_TessCoord.z * gl_in[2].gl_ClipDistance[" << i << "];\n"; 1256 for (int i = 0; i < caseDef.numCullDistances; ++i) 1257 src << " gl_CullDistance[" << i << "] = gl_TessCoord.x * gl_in[0].gl_CullDistance[" << i << "]\n" 1258 << " + gl_TessCoord.y * gl_in[1].gl_CullDistance[" << i << "]\n" 1259 << " + gl_TessCoord.z * gl_in[2].gl_CullDistance[" << i << "];\n"; 1260 } 1261 src << "}\n"; 1262 1263 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str()); 1264 } 1265 1266 if (caseDef.enableGeometry) 1267 { 1268 std::ostringstream src; 1269 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 1270 << "\n" 1271 << "layout(triangles) in;\n" 1272 << "layout(triangle_strip, max_vertices = 3) out;\n" 1273 << "\n" 1274 << "layout(location = 0) in vec4 in_color[];\n" 1275 << "layout(location = 0) out vec4 out_color;\n" 1276 << "\n" 1277 << "in " << perVertexBlock << " gl_in[];\n" 1278 << "\n" 1279 << "out " << perVertexBlock << ";\n" 1280 << "\n" 1281 << "void main (void)\n" 1282 << "{\n"; 1283 for (int vertNdx = 0; vertNdx < 3; ++vertNdx) 1284 { 1285 if (vertNdx > 0) 1286 src << "\n"; 1287 src << " gl_Position = gl_in[" << vertNdx << "].gl_Position;\n" 1288 << " out_color = in_color[" << vertNdx << "];\n"; 1289 if (caseDef.dynamicIndexing) 1290 { 1291 if (caseDef.numClipDistances > 0) 1292 src << " for (int i = 0; i < " << caseDef.numClipDistances << "; ++i)\n" 1293 << " gl_ClipDistance[i] = gl_in[" << vertNdx << "].gl_ClipDistance[i];\n"; 1294 if (caseDef.numCullDistances > 0) 1295 src << " for (int i = 0; i < " << caseDef.numCullDistances << "; ++i)\n" 1296 << " gl_CullDistance[i] = gl_in[" << vertNdx << "].gl_CullDistance[i];\n"; 1297 } 1298 else 1299 { 1300 for (int i = 0; i < caseDef.numClipDistances; ++i) 1301 src << " gl_ClipDistance[" << i << "] = gl_in[" << vertNdx << "].gl_ClipDistance[" << i << "];\n"; 1302 for (int i = 0; i < caseDef.numCullDistances; ++i) 1303 src << " gl_CullDistance[" << i << "] = gl_in[" << vertNdx << "].gl_CullDistance[" << i << "];\n"; 1304 } 1305 src << " EmitVertex();\n"; 1306 } 1307 src << "}\n"; 1308 1309 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str()); 1310 } 1311 1312 // Fragment shader 1313 { 1314 std::ostringstream src; 1315 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 1316 << "\n" 1317 << "layout(location = 0) in flat vec4 in_color;\n" 1318 << "layout(location = 0) out vec4 o_color;\n" 1319 << "\n" 1320 << "void main (void)\n" 1321 << "{\n" 1322 << " o_color = vec4(in_color.rgb + vec3(0.0, 0.0, 0.5), 1.0);\n" // mix with a constant color in case variable wasn't passed correctly through stages 1323 << "}\n"; 1324 1325 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 1326 } 1327 } 1328 1329 tcu::TestStatus testClipDistance (Context& context, const CaseDefinition caseDef) 1330 { 1331 // Check test requirements 1332 { 1333 const InstanceInterface& vki = context.getInstanceInterface(); 1334 const VkPhysicalDevice physDevice = context.getPhysicalDevice(); 1335 const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(vki, physDevice).limits; 1336 1337 FeatureFlags requirements = (FeatureFlags)0; 1338 1339 if (caseDef.numClipDistances > 0) 1340 requirements |= FEATURE_SHADER_CLIP_DISTANCE; 1341 if (caseDef.numCullDistances > 0) 1342 requirements |= FEATURE_SHADER_CULL_DISTANCE; 1343 if (caseDef.enableTessellation) 1344 requirements |= FEATURE_TESSELLATION_SHADER; 1345 if (caseDef.enableGeometry) 1346 requirements |= FEATURE_GEOMETRY_SHADER; 1347 1348 requireFeatures(vki, physDevice, requirements); 1349 1350 // Check limits for supported features 1351 1352 if (caseDef.numClipDistances > 0 && limits.maxClipDistances < MAX_CLIP_DISTANCES) 1353 return tcu::TestStatus::fail("maxClipDistances smaller than the minimum required by the spec"); 1354 if (caseDef.numCullDistances > 0 && limits.maxCullDistances < MAX_CULL_DISTANCES) 1355 return tcu::TestStatus::fail("maxCullDistances smaller than the minimum required by the spec"); 1356 if (caseDef.numCullDistances > 0 && limits.maxCombinedClipAndCullDistances < MAX_COMBINED_CLIP_AND_CULL_DISTANCES) 1357 return tcu::TestStatus::fail("maxCombinedClipAndCullDistances smaller than the minimum required by the spec"); 1358 } 1359 1360 std::vector<Shader> shaders; 1361 shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"))); 1362 shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"))); 1363 if (caseDef.enableTessellation) 1364 { 1365 shaders.push_back(Shader(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, context.getBinaryCollection().get("tesc"))); 1366 shaders.push_back(Shader(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"))); 1367 } 1368 if (caseDef.enableGeometry) 1369 shaders.push_back(Shader(VK_SHADER_STAGE_GEOMETRY_BIT, context.getBinaryCollection().get("geom"))); 1370 1371 const int numBars = MAX_COMBINED_CLIP_AND_CULL_DISTANCES; 1372 1373 std::vector<Vec4> vertices; 1374 { 1375 const float dx = 2.0f / numBars; 1376 for (int i = 0; i < numBars; ++i) 1377 { 1378 const float x = -1.0f + dx * static_cast<float>(i); 1379 1380 vertices.push_back(Vec4(x, -1.0f, 0.0f, 1.0f)); 1381 vertices.push_back(Vec4(x, 1.0f, 0.0f, 1.0f)); 1382 vertices.push_back(Vec4(x + dx, -1.0f, 0.0f, 1.0f)); 1383 1384 vertices.push_back(Vec4(x, 1.0f, 0.0f, 1.0f)); 1385 vertices.push_back(Vec4(x + dx, 1.0f, 0.0f, 1.0f)); 1386 vertices.push_back(Vec4(x + dx, -1.0f, 0.0f, 1.0f)); 1387 } 1388 } 1389 1390 tcu::TestLog& log = context.getTestContext().getLog(); 1391 1392 log << tcu::TestLog::Message << "Drawing " << numBars << " colored bars, clipping the first " << caseDef.numClipDistances << tcu::TestLog::EndMessage 1393 << tcu::TestLog::Message << "Using " << caseDef.numClipDistances << " ClipDistance(s) and " << caseDef.numCullDistances << " CullDistance(s)" << tcu::TestLog::EndMessage 1394 << tcu::TestLog::Message << "Expecting upper half of the clipped bars to be black." << tcu::TestLog::EndMessage; 1395 1396 DrawContext drawContext(context, shaders, vertices, caseDef.topology); 1397 drawContext.draw(); 1398 1399 // Count black pixels in the whole image. 1400 const int numBlackPixels = countPixels(drawContext.getColorPixels(), Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4()); 1401 const IVec2 clipRegion = IVec2(caseDef.numClipDistances * RENDER_SIZE / numBars, RENDER_SIZE / 2); 1402 const int expectedClippedPixels = clipRegion.x() * clipRegion.y(); 1403 // Make sure the bottom half has no black pixels (possible if image became corrupted). 1404 const int guardPixels = countPixels(drawContext.getColorPixels(), IVec2(0, RENDER_SIZE/2), clipRegion, Vec4(0.0f, 0.0f, 0.0f, 1.0f), Vec4()); 1405 1406 return (numBlackPixels == expectedClippedPixels && guardPixels == 0 ? tcu::TestStatus::pass("OK") 1407 : tcu::TestStatus::fail("Rendered image(s) are incorrect")); 1408 } 1409 1410 } // ClipDistance ns 1411 1412 namespace ClipDistanceComplementarity 1413 { 1414 1415 void initPrograms (SourceCollections& programCollection, const int numClipDistances) 1416 { 1417 // Vertex shader 1418 { 1419 DE_ASSERT(numClipDistances > 0); 1420 const int clipDistanceLastNdx = numClipDistances - 1; 1421 1422 std::ostringstream src; 1423 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 1424 << "\n" 1425 << "layout(location = 0) in vec4 v_position; // we are passing ClipDistance in w component\n" 1426 << "\n" 1427 << "out gl_PerVertex {\n" 1428 << " vec4 gl_Position;\n" 1429 << " float gl_ClipDistance[" << numClipDistances << "];\n" 1430 << "};\n" 1431 << "\n" 1432 << "void main (void)\n" 1433 << "{\n" 1434 << " gl_Position = vec4(v_position.xyz, 1.0);\n"; 1435 for (int i = 0; i < clipDistanceLastNdx; ++i) 1436 src << " gl_ClipDistance[" << i << "] = 0.0;\n"; 1437 src << " gl_ClipDistance[" << clipDistanceLastNdx << "] = v_position.w;\n" 1438 << "}\n"; 1439 1440 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 1441 } 1442 1443 // Fragment shader 1444 { 1445 std::ostringstream src; 1446 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 1447 << "\n" 1448 << "layout(location = 0) out vec4 o_color;\n" 1449 << "\n" 1450 << "void main (void)\n" 1451 << "{\n" 1452 << " o_color = vec4(1.0, 1.0, 1.0, 0.5);\n" 1453 << "}\n"; 1454 1455 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 1456 } 1457 } 1458 1459 tcu::TestStatus testComplementarity (Context& context, const int numClipDistances) 1460 { 1461 // Check test requirements 1462 { 1463 const InstanceInterface& vki = context.getInstanceInterface(); 1464 const VkPhysicalDevice physDevice = context.getPhysicalDevice(); 1465 1466 requireFeatures(vki, physDevice, FEATURE_SHADER_CLIP_DISTANCE); 1467 } 1468 1469 std::vector<Shader> shaders; 1470 shaders.push_back(Shader(VK_SHADER_STAGE_VERTEX_BIT, context.getBinaryCollection().get("vert"))); 1471 shaders.push_back(Shader(VK_SHADER_STAGE_FRAGMENT_BIT, context.getBinaryCollection().get("frag"))); 1472 1473 std::vector<Vec4> vertices; 1474 { 1475 de::Random rnd (1234); 1476 const int numSections = 16; 1477 const int numVerticesPerSection = 4; // logical verticies, due to triangle list topology we actually use 6 per section 1478 1479 DE_ASSERT(RENDER_SIZE_LARGE % numSections == 0); 1480 1481 std::vector<float> clipDistances(numVerticesPerSection * numSections); 1482 for (int i = 0; i < static_cast<int>(clipDistances.size()); ++i) 1483 clipDistances[i] = rnd.getFloat(-1.0f, 1.0f); 1484 1485 // Two sets of identical primitives, but with a different ClipDistance sign. 1486 for (int setNdx = 0; setNdx < 2; ++setNdx) 1487 { 1488 const float sign = (setNdx == 0 ? 1.0f : -1.0f); 1489 const float dx = 2.0f / static_cast<float>(numSections); 1490 1491 for (int i = 0; i < numSections; ++i) 1492 { 1493 const int ndxBase = numVerticesPerSection * i; 1494 const float x = -1.0f + dx * static_cast<float>(i); 1495 const Vec4 p0 = Vec4(x, -1.0f, 0.0f, sign * clipDistances[ndxBase + 0]); 1496 const Vec4 p1 = Vec4(x, 1.0f, 0.0f, sign * clipDistances[ndxBase + 1]); 1497 const Vec4 p2 = Vec4(x + dx, 1.0f, 0.0f, sign * clipDistances[ndxBase + 2]); 1498 const Vec4 p3 = Vec4(x + dx, -1.0f, 0.0f, sign * clipDistances[ndxBase + 3]); 1499 1500 vertices.push_back(p0); 1501 vertices.push_back(p1); 1502 vertices.push_back(p2); 1503 1504 vertices.push_back(p2); 1505 vertices.push_back(p3); 1506 vertices.push_back(p0); 1507 } 1508 } 1509 } 1510 1511 tcu::TestLog& log = context.getTestContext().getLog(); 1512 1513 log << tcu::TestLog::Message << "Draw two sets of primitives with blending, differing only with ClipDistance sign." << tcu::TestLog::EndMessage 1514 << tcu::TestLog::Message << "Using " << numClipDistances << " clipping plane(s), one of them possibly having negative values." << tcu::TestLog::EndMessage 1515 << tcu::TestLog::Message << "Expecting a uniform gray area, no missing (black) nor overlapped (white) pixels." << tcu::TestLog::EndMessage; 1516 1517 DrawContext drawContext(context, shaders, vertices, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, static_cast<deUint32>(RENDER_SIZE_LARGE), false, true); 1518 drawContext.draw(); 1519 1520 const int numGrayPixels = countPixels(drawContext.getColorPixels(), Vec4(0.5f, 0.5f, 0.5f, 1.0f), Vec4(0.02f, 0.02f, 0.02f, 0.0f)); 1521 const int numExpectedPixels = RENDER_SIZE_LARGE * RENDER_SIZE_LARGE; 1522 1523 return (numGrayPixels == numExpectedPixels ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Rendered image(s) are incorrect")); 1524 } 1525 1526 } // ClipDistanceComplementarity ns 1527 1528 void addClippingTests (tcu::TestCaseGroup* clippingTestsGroup) 1529 { 1530 tcu::TestContext& testCtx = clippingTestsGroup->getTestContext(); 1531 1532 // Clipping against the clip volume 1533 { 1534 using namespace ClipVolume; 1535 1536 static const VkPrimitiveTopology cases[] = 1537 { 1538 VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 1539 VK_PRIMITIVE_TOPOLOGY_LINE_LIST, 1540 VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, 1541 VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 1542 VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, 1543 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 1544 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, 1545 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 1546 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, 1547 VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, 1548 }; 1549 1550 MovePtr<tcu::TestCaseGroup> clipVolumeGroup(new tcu::TestCaseGroup(testCtx, "clip_volume", "clipping with the clip volume")); 1551 1552 // Fully inside the clip volume 1553 { 1554 MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "inside", "")); 1555 1556 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx) 1557 addFunctionCaseWithPrograms<VkPrimitiveTopology>( 1558 group.get(), getPrimitiveTopologyShortName(cases[caseNdx]), "", initPrograms, testPrimitivesInside, cases[caseNdx]); 1559 1560 clipVolumeGroup->addChild(group.release()); 1561 } 1562 1563 // Fully outside the clip volume 1564 { 1565 MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "outside", "")); 1566 1567 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx) 1568 addFunctionCaseWithPrograms<VkPrimitiveTopology>( 1569 group.get(), getPrimitiveTopologyShortName(cases[caseNdx]), "", initPrograms, testPrimitivesOutside, cases[caseNdx]); 1570 1571 clipVolumeGroup->addChild(group.release()); 1572 } 1573 1574 // Depth clamping 1575 { 1576 MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "depth_clamp", "")); 1577 1578 for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx) 1579 addFunctionCaseWithPrograms<VkPrimitiveTopology>( 1580 group.get(), getPrimitiveTopologyShortName(cases[caseNdx]), "", initPrograms, testPrimitivesDepthClamp, cases[caseNdx]); 1581 1582 clipVolumeGroup->addChild(group.release()); 1583 } 1584 1585 // Large points and wide lines 1586 { 1587 // \note For both points and lines, if an unsupported size/width is selected, the nearest supported size will be chosen. 1588 // We do have to check for feature support though. 1589 1590 MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "clipped", "")); 1591 1592 addFunctionCaseWithPrograms(group.get(), "large_points", "", initProgramsPointSize, testLargePoints); 1593 1594 addFunctionCaseWithPrograms<LineOrientation>(group.get(), "wide_lines_axis_aligned", "", initPrograms, testWideLines, LINE_ORIENTATION_AXIS_ALIGNED); 1595 addFunctionCaseWithPrograms<LineOrientation>(group.get(), "wide_lines_diagonal", "", initPrograms, testWideLines, LINE_ORIENTATION_DIAGONAL); 1596 1597 clipVolumeGroup->addChild(group.release()); 1598 } 1599 1600 clippingTestsGroup->addChild(clipVolumeGroup.release()); 1601 } 1602 1603 // User-defined clip planes 1604 { 1605 MovePtr<tcu::TestCaseGroup> clipDistanceGroup(new tcu::TestCaseGroup(testCtx, "user_defined", "user-defined clip planes")); 1606 1607 // ClipDistance, CullDistance and maxCombinedClipAndCullDistances usage 1608 { 1609 using namespace ClipDistance; 1610 1611 static const struct 1612 { 1613 const char* const groupName; 1614 const char* const description; 1615 bool useCullDistance; 1616 } caseGroups[] = 1617 { 1618 { "clip_distance", "use ClipDistance", false }, 1619 { "clip_cull_distance", "use ClipDistance and CullDistance at the same time", true }, 1620 }; 1621 1622 const deUint32 flagTessellation = 1u << 0; 1623 const deUint32 flagGeometry = 1u << 1; 1624 1625 for (int groupNdx = 0; groupNdx < DE_LENGTH_OF_ARRAY(caseGroups); ++groupNdx) 1626 for (int indexingMode = 0; indexingMode < 2; ++indexingMode) 1627 { 1628 const bool dynamicIndexing = (indexingMode == 1); 1629 const std::string mainGroupName = de::toString(caseGroups[groupNdx].groupName) + (dynamicIndexing ? "_dynamic_index" : ""); 1630 1631 MovePtr<tcu::TestCaseGroup> mainGroup(new tcu::TestCaseGroup(testCtx, mainGroupName.c_str(), "")); 1632 1633 for (deUint32 shaderMask = 0u; shaderMask <= (flagTessellation | flagGeometry); ++shaderMask) 1634 { 1635 const bool useTessellation = (shaderMask & flagTessellation) != 0; 1636 const bool useGeometry = (shaderMask & flagGeometry) != 0; 1637 const std::string shaderGroupName = std::string("vert") + (useTessellation ? "_tess" : "") + (useGeometry ? "_geom" : ""); 1638 1639 MovePtr<tcu::TestCaseGroup> shaderGroup(new tcu::TestCaseGroup(testCtx, shaderGroupName.c_str(), "")); 1640 1641 for (int numClipPlanes = 1; numClipPlanes <= MAX_CLIP_DISTANCES; ++numClipPlanes) 1642 { 1643 const int numCullPlanes = (caseGroups[groupNdx].useCullDistance 1644 ? std::min(static_cast<int>(MAX_CULL_DISTANCES), MAX_COMBINED_CLIP_AND_CULL_DISTANCES - numClipPlanes) 1645 : 0); 1646 const std::string caseName = de::toString(numClipPlanes) + (numCullPlanes > 0 ? "_" + de::toString(numCullPlanes) : ""); 1647 const VkPrimitiveTopology topology = (useTessellation ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); 1648 1649 addFunctionCaseWithPrograms<CaseDefinition>( 1650 shaderGroup.get(), caseName, caseGroups[groupNdx].description, initPrograms, testClipDistance, 1651 CaseDefinition(topology, numClipPlanes, numCullPlanes, useTessellation, useGeometry, dynamicIndexing)); 1652 } 1653 mainGroup->addChild(shaderGroup.release()); 1654 } 1655 clipDistanceGroup->addChild(mainGroup.release()); 1656 } 1657 } 1658 1659 // Complementarity criterion (i.e. clipped and not clipped areas must add up to a complete primitive with no holes nor overlap) 1660 { 1661 using namespace ClipDistanceComplementarity; 1662 1663 MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "complementarity", "")); 1664 1665 for (int numClipDistances = 1; numClipDistances <= MAX_CLIP_DISTANCES; ++numClipDistances) 1666 addFunctionCaseWithPrograms<int>(group.get(), de::toString(numClipDistances).c_str(), "", initPrograms, testComplementarity, numClipDistances); 1667 1668 clippingTestsGroup->addChild(group.release()); 1669 } 1670 1671 clippingTestsGroup->addChild(clipDistanceGroup.release()); 1672 } 1673 } 1674 1675 } // anonymous 1676 1677 tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx) 1678 { 1679 return createTestGroup(testCtx, "clipping", "Clipping tests", addClippingTests); 1680 } 1681 1682 } // clipping 1683 } // vkt 1684