1/*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2016 The Khronos Group Inc. 6 * Copyright (c) 2014 The Android Open Source Project 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 *//*! 21 * \file 22 * \brief Scissor multi viewport tests 23 *//*--------------------------------------------------------------------*/ 24 25#include "vktFragmentOperationsScissorMultiViewportTests.hpp" 26#include "vktTestCaseUtil.hpp" 27#include "vktFragmentOperationsMakeUtil.hpp" 28 29#include "vkDefs.hpp" 30#include "vkRefUtil.hpp" 31#include "vkTypeUtil.hpp" 32#include "vkMemUtil.hpp" 33#include "vkPrograms.hpp" 34#include "vkImageUtil.hpp" 35#include "vkQueryUtil.hpp" 36 37#include "tcuTestLog.hpp" 38#include "tcuVector.hpp" 39#include "tcuImageCompare.hpp" 40#include "tcuTextureUtil.hpp" 41 42#include "deUniquePtr.hpp" 43#include "deMath.h" 44 45namespace vkt 46{ 47namespace FragmentOperations 48{ 49using namespace vk; 50using de::UniquePtr; 51using de::MovePtr; 52using tcu::Vec4; 53using tcu::Vec2; 54using tcu::IVec2; 55using tcu::IVec4; 56 57namespace 58{ 59 60enum Constants 61{ 62 MIN_MAX_VIEWPORTS = 16, //!< Minimum number of viewports for an implementation supporting multiViewport. 63}; 64 65template<typename T> 66inline VkDeviceSize sizeInBytes(const std::vector<T>& vec) 67{ 68 return vec.size() * sizeof(vec[0]); 69} 70 71VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const IVec2& size, VkImageUsageFlags usage) 72{ 73 const VkImageCreateInfo imageParams = 74 { 75 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; 76 DE_NULL, // const void* pNext; 77 (VkImageCreateFlags)0, // VkImageCreateFlags flags; 78 VK_IMAGE_TYPE_2D, // VkImageType imageType; 79 format, // VkFormat format; 80 makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent; 81 1u, // deUint32 mipLevels; 82 1u, // deUint32 arrayLayers; 83 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; 84 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; 85 usage, // VkImageUsageFlags usage; 86 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 87 0u, // deUint32 queueFamilyIndexCount; 88 DE_NULL, // const deUint32* pQueueFamilyIndices; 89 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; 90 }; 91 return imageParams; 92} 93 94//! A single-attachment, single-subpass render pass. 95Move<VkRenderPass> makeRenderPass (const DeviceInterface& vk, 96 const VkDevice device, 97 const VkFormat colorFormat) 98{ 99 const VkAttachmentDescription colorAttachmentDescription = 100 { 101 (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; 102 colorFormat, // VkFormat format; 103 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; 104 VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; 105 VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; 106 VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; 107 VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; 108 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; 109 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout; 110 }; 111 112 const VkAttachmentReference colorAttachmentRef = 113 { 114 0u, // deUint32 attachment; 115 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout; 116 }; 117 118 const VkSubpassDescription subpassDescription = 119 { 120 (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags; 121 VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; 122 0u, // deUint32 inputAttachmentCount; 123 DE_NULL, // const VkAttachmentReference* pInputAttachments; 124 1u, // deUint32 colorAttachmentCount; 125 &colorAttachmentRef, // const VkAttachmentReference* pColorAttachments; 126 DE_NULL, // const VkAttachmentReference* pResolveAttachments; 127 DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment; 128 0u, // deUint32 preserveAttachmentCount; 129 DE_NULL // const deUint32* pPreserveAttachments; 130 }; 131 132 const VkRenderPassCreateInfo renderPassInfo = 133 { 134 VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; 135 DE_NULL, // const void* pNext; 136 (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags; 137 1u, // deUint32 attachmentCount; 138 &colorAttachmentDescription, // const VkAttachmentDescription* pAttachments; 139 1u, // deUint32 subpassCount; 140 &subpassDescription, // const VkSubpassDescription* pSubpasses; 141 0u, // deUint32 dependencyCount; 142 DE_NULL // const VkSubpassDependency* pDependencies; 143 }; 144 145 return createRenderPass(vk, device, &renderPassInfo); 146} 147 148Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface& vk, 149 const VkDevice device, 150 const VkPipelineLayout pipelineLayout, 151 const VkRenderPass renderPass, 152 const VkShaderModule vertexModule, 153 const VkShaderModule geometryModule, 154 const VkShaderModule fragmentModule, 155 const IVec2 renderSize, 156 const int numViewports, 157 const std::vector<IVec4> scissors) 158{ 159 const VkVertexInputBindingDescription vertexInputBindingDescription = 160 { 161 0u, // uint32_t binding; 162 sizeof(Vec4), // uint32_t stride; 163 VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate; 164 }; 165 166 const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = 167 { 168 { 169 0u, // uint32_t location; 170 0u, // uint32_t binding; 171 VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; 172 0u, // uint32_t offset; 173 }, 174 }; 175 176 const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = 177 { 178 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; 179 DE_NULL, // const void* pNext; 180 (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags; 181 1u, // uint32_t vertexBindingDescriptionCount; 182 &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; 183 DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions), // uint32_t vertexAttributeDescriptionCount; 184 vertexInputAttributeDescriptions, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; 185 }; 186 187 const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = 188 { 189 VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; 190 DE_NULL, // const void* pNext; 191 (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags; 192 VK_PRIMITIVE_TOPOLOGY_POINT_LIST, // VkPrimitiveTopology topology; 193 VK_FALSE, // VkBool32 primitiveRestartEnable; 194 }; 195 196 const VkViewport defaultViewport = makeViewport( 197 0.0f, 0.0f, 198 static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()), 199 0.0f, 1.0f); 200 const std::vector<VkViewport> viewports(numViewports, defaultViewport); 201 202 DE_ASSERT(numViewports == static_cast<int>(scissors.size())); 203 204 std::vector<VkRect2D> rectScissors; 205 rectScissors.reserve(numViewports); 206 207 for (std::vector<IVec4>::const_iterator it = scissors.begin(); it != scissors.end(); ++it) 208 { 209 const VkRect2D rect = 210 { 211 makeOffset2D(it->x(), it->y()), 212 makeExtent2D(static_cast<deUint32>(it->z()), static_cast<deUint32>(it->w())), 213 }; 214 rectScissors.push_back(rect); 215 } 216 217 const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = 218 { 219 VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; 220 DE_NULL, // const void* pNext; 221 (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags; 222 static_cast<deUint32>(numViewports), // uint32_t viewportCount; 223 &viewports[0], // const VkViewport* pViewports; 224 static_cast<deUint32>(numViewports), // uint32_t scissorCount; 225 &rectScissors[0], // const VkRect2D* pScissors; 226 }; 227 228 const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = 229 { 230 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; 231 DE_NULL, // const void* pNext; 232 (VkPipelineRasterizationStateCreateFlags)0, // VkPipelineRasterizationStateCreateFlags flags; 233 VK_FALSE, // VkBool32 depthClampEnable; 234 VK_FALSE, // VkBool32 rasterizerDiscardEnable; 235 VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode; 236 VK_CULL_MODE_NONE, // VkCullModeFlags cullMode; 237 VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace; 238 VK_FALSE, // VkBool32 depthBiasEnable; 239 0.0f, // float depthBiasConstantFactor; 240 0.0f, // float depthBiasClamp; 241 0.0f, // float depthBiasSlopeFactor; 242 1.0f, // float lineWidth; 243 }; 244 245 const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = 246 { 247 VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; 248 DE_NULL, // const void* pNext; 249 (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags; 250 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples; 251 VK_FALSE, // VkBool32 sampleShadingEnable; 252 0.0f, // float minSampleShading; 253 DE_NULL, // const VkSampleMask* pSampleMask; 254 VK_FALSE, // VkBool32 alphaToCoverageEnable; 255 VK_FALSE // VkBool32 alphaToOneEnable; 256 }; 257 258 const VkStencilOpState stencilOpState = makeStencilOpState( 259 VK_STENCIL_OP_KEEP, // stencil fail 260 VK_STENCIL_OP_KEEP, // depth & stencil pass 261 VK_STENCIL_OP_KEEP, // depth only fail 262 VK_COMPARE_OP_ALWAYS, // compare op 263 0u, // compare mask 264 0u, // write mask 265 0u); // reference 266 267 VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo = 268 { 269 VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; 270 DE_NULL, // const void* pNext; 271 (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags; 272 VK_FALSE, // VkBool32 depthTestEnable; 273 VK_FALSE, // VkBool32 depthWriteEnable; 274 VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp; 275 VK_FALSE, // VkBool32 depthBoundsTestEnable; 276 VK_FALSE, // VkBool32 stencilTestEnable; 277 stencilOpState, // VkStencilOpState front; 278 stencilOpState, // VkStencilOpState back; 279 0.0f, // float minDepthBounds; 280 1.0f, // float maxDepthBounds; 281 }; 282 283 const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; 284 const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = 285 { 286 VK_FALSE, // VkBool32 blendEnable; 287 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor; 288 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor; 289 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp; 290 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor; 291 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor; 292 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp; 293 colorComponentsAll, // VkColorComponentFlags colorWriteMask; 294 }; 295 296 const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = 297 { 298 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; 299 DE_NULL, // const void* pNext; 300 (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags; 301 VK_FALSE, // VkBool32 logicOpEnable; 302 VK_LOGIC_OP_COPY, // VkLogicOp logicOp; 303 1u, // deUint32 attachmentCount; 304 &pipelineColorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments; 305 { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4]; 306 }; 307 308 const VkPipelineShaderStageCreateInfo pShaderStages[] = 309 { 310 { 311 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; 312 DE_NULL, // const void* pNext; 313 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; 314 VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage; 315 vertexModule, // VkShaderModule module; 316 "main", // const char* pName; 317 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo; 318 }, 319 { 320 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; 321 DE_NULL, // const void* pNext; 322 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; 323 VK_SHADER_STAGE_GEOMETRY_BIT, // VkShaderStageFlagBits stage; 324 geometryModule, // VkShaderModule module; 325 "main", // const char* pName; 326 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo; 327 }, 328 { 329 VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; 330 DE_NULL, // const void* pNext; 331 (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; 332 VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage; 333 fragmentModule, // VkShaderModule module; 334 "main", // const char* pName; 335 DE_NULL, // const VkSpecializationInfo* pSpecializationInfo; 336 }, 337 }; 338 339 const VkGraphicsPipelineCreateInfo graphicsPipelineInfo = 340 { 341 VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; 342 DE_NULL, // const void* pNext; 343 (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags; 344 DE_LENGTH_OF_ARRAY(pShaderStages), // deUint32 stageCount; 345 pShaderStages, // const VkPipelineShaderStageCreateInfo* pStages; 346 &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; 347 &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; 348 DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState; 349 &pipelineViewportStateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState; 350 &pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState; 351 &pipelineMultisampleStateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; 352 &pipelineDepthStencilStateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; 353 &pipelineColorBlendStateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; 354 DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState; 355 pipelineLayout, // VkPipelineLayout layout; 356 renderPass, // VkRenderPass renderPass; 357 0u, // deUint32 subpass; 358 DE_NULL, // VkPipeline basePipelineHandle; 359 0, // deInt32 basePipelineIndex; 360 }; 361 362 return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo); 363} 364 365void zeroBuffer (const DeviceInterface& vk, const VkDevice device, const Allocation& alloc, const VkDeviceSize size) 366{ 367 deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(size)); 368 flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), size); 369} 370 371void requireFeatureMultiViewport (const InstanceInterface& vki, const VkPhysicalDevice physDevice) 372{ 373 const VkPhysicalDeviceFeatures features = getPhysicalDeviceFeatures(vki, physDevice); 374 const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(vki, physDevice).limits; 375 376 if (!features.geometryShader) 377 TCU_THROW(NotSupportedError, "Required feature is not supported: geometryShader"); 378 379 if (!features.multiViewport) 380 TCU_THROW(NotSupportedError, "Required feature is not supported: multiViewport"); 381 382 if (limits.maxViewports < MIN_MAX_VIEWPORTS) 383 TCU_THROW(NotSupportedError, "Implementation doesn't support minimum required number of viewports"); 384} 385 386std::vector<IVec4> generateScissors (const int numScissors, const IVec2& renderSize) 387{ 388 // Scissor rects will be arranged in a grid-like fashion. 389 390 const int numCols = deCeilFloatToInt32(deFloatSqrt(static_cast<float>(numScissors))); 391 const int numRows = deCeilFloatToInt32(static_cast<float>(numScissors) / static_cast<float>(numCols)); 392 const int rectWidth = renderSize.x() / numCols; 393 const int rectHeight = renderSize.y() / numRows; 394 395 std::vector<IVec4> scissors; 396 scissors.reserve(numScissors); 397 398 int x = 0; 399 int y = 0; 400 401 for (int scissorNdx = 0; scissorNdx < numScissors; ++scissorNdx) 402 { 403 const bool nextRow = (scissorNdx != 0) && (scissorNdx % numCols == 0); 404 if (nextRow) 405 { 406 x = 0; 407 y += rectHeight; 408 } 409 410 scissors.push_back(IVec4(x, y, rectWidth, rectHeight)); 411 412 x += rectWidth; 413 } 414 415 return scissors; 416} 417 418std::vector<Vec4> generateColors (const int numColors) 419{ 420 const Vec4 colors[] = 421 { 422 Vec4(0.18f, 0.42f, 0.17f, 1.0f), 423 Vec4(0.29f, 0.62f, 0.28f, 1.0f), 424 Vec4(0.59f, 0.84f, 0.44f, 1.0f), 425 Vec4(0.96f, 0.95f, 0.72f, 1.0f), 426 Vec4(0.94f, 0.55f, 0.39f, 1.0f), 427 Vec4(0.82f, 0.19f, 0.12f, 1.0f), 428 Vec4(0.46f, 0.15f, 0.26f, 1.0f), 429 Vec4(0.24f, 0.14f, 0.24f, 1.0f), 430 Vec4(0.49f, 0.31f, 0.26f, 1.0f), 431 Vec4(0.78f, 0.52f, 0.33f, 1.0f), 432 Vec4(0.94f, 0.82f, 0.31f, 1.0f), 433 Vec4(0.98f, 0.65f, 0.30f, 1.0f), 434 Vec4(0.22f, 0.65f, 0.53f, 1.0f), 435 Vec4(0.67f, 0.81f, 0.91f, 1.0f), 436 Vec4(0.43f, 0.44f, 0.75f, 1.0f), 437 Vec4(0.26f, 0.24f, 0.48f, 1.0f), 438 }; 439 440 DE_ASSERT(numColors <= DE_LENGTH_OF_ARRAY(colors)); 441 442 return std::vector<Vec4>(colors, colors + numColors); 443} 444 445//! Renders a colorful grid of rectangles. 446tcu::TextureLevel generateReferenceImage (const tcu::TextureFormat format, 447 const IVec2& renderSize, 448 const Vec4& clearColor, 449 const std::vector<IVec4>& scissors, 450 const std::vector<Vec4>& scissorColors) 451{ 452 DE_ASSERT(scissors.size() == scissorColors.size()); 453 454 tcu::TextureLevel image(format, renderSize.x(), renderSize.y()); 455 tcu::clear(image.getAccess(), clearColor); 456 457 for (std::size_t i = 0; i < scissors.size(); ++i) 458 { 459 tcu::clear( 460 tcu::getSubregion(image.getAccess(), scissors[i].x(), scissors[i].y(), scissors[i].z(), scissors[i].w()), 461 scissorColors[i]); 462 } 463 464 return image; 465} 466 467void initPrograms (SourceCollections& programCollection, const int numViewports) 468{ 469 DE_UNREF(numViewports); 470 471 // Vertex shader 472 { 473 std::ostringstream src; 474 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 475 << "\n" 476 << "layout(location = 0) in vec4 in_color;\n" 477 << "layout(location = 0) out vec4 out_color;\n" 478 << "\n" 479 << "void main(void)\n" 480 << "{\n" 481 << " out_color = in_color;\n" 482 << "}\n"; 483 484 programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); 485 } 486 487 // Geometry shader 488 { 489 // Each input point generates a fullscreen quad. 490 491 std::ostringstream src; 492 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 493 << "\n" 494 << "layout(points) in;\n" 495 << "layout(triangle_strip, max_vertices=4) out;\n" 496 << "\n" 497 << "out gl_PerVertex {\n" 498 << " vec4 gl_Position;\n" 499 << "};\n" 500 << "\n" 501 << "layout(location = 0) in vec4 in_color[];\n" 502 << "layout(location = 0) out vec4 out_color;\n" 503 << "\n" 504 << "void main(void)\n" 505 << "{\n" 506 << " gl_ViewportIndex = gl_PrimitiveIDIn;\n" 507 << " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n" 508 << " out_color = in_color[0];\n" 509 << " EmitVertex();" 510 << "\n" 511 << " gl_ViewportIndex = gl_PrimitiveIDIn;\n" 512 << " gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n" 513 << " out_color = in_color[0];\n" 514 << " EmitVertex();" 515 << "\n" 516 << " gl_ViewportIndex = gl_PrimitiveIDIn;\n" 517 << " gl_Position = vec4(1.0, -1.0, 0.0, 1.0);\n" 518 << " out_color = in_color[0];\n" 519 << " EmitVertex();" 520 << "\n" 521 << " gl_ViewportIndex = gl_PrimitiveIDIn;\n" 522 << " gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n" 523 << " out_color = in_color[0];\n" 524 << " EmitVertex();" 525 << "}\n"; 526 527 programCollection.glslSources.add("geom") << glu::GeometrySource(src.str()); 528 } 529 530 // Fragment shader 531 { 532 std::ostringstream src; 533 src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" 534 << "\n" 535 << "layout(location = 0) in vec4 in_color;\n" 536 << "layout(location = 0) out vec4 out_color;\n" 537 << "\n" 538 << "void main(void)\n" 539 << "{\n" 540 << " out_color = in_color;\n" 541 << "}\n"; 542 543 programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); 544 } 545} 546 547class ScissorRenderer 548{ 549public: 550 ScissorRenderer (Context& context, 551 const IVec2& renderSize, 552 const int numViewports, 553 const std::vector<IVec4>& scissors, 554 const VkFormat colorFormat, 555 const Vec4& clearColor, 556 const std::vector<Vec4>& vertices) 557 : m_renderSize (renderSize) 558 , m_colorFormat (colorFormat) 559 , m_colorSubresourceRange (makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)) 560 , m_clearColor (clearColor) 561 , m_numViewports (numViewports) 562 , m_vertexBufferSize (sizeInBytes(vertices)) 563 { 564 const DeviceInterface& vk = context.getDeviceInterface(); 565 const VkDevice device = context.getDevice(); 566 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); 567 Allocator& allocator = context.getDefaultAllocator(); 568 569 m_colorImage = makeImage (vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT)); 570 m_colorImageAlloc = bindImage (vk, device, allocator, *m_colorImage, MemoryRequirement::Any); 571 m_colorAttachment = makeImageView (vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange); 572 573 m_vertexBuffer = makeBuffer (vk, device, makeBufferCreateInfo(m_vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)); 574 m_vertexBufferAlloc = bindBuffer (vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible); 575 576 { 577 deMemcpy(m_vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(m_vertexBufferSize)); 578 flushMappedMemoryRange(vk, device, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), m_vertexBufferSize); 579 } 580 581 m_vertexModule = createShaderModule (vk, device, context.getBinaryCollection().get("vert"), 0u); 582 m_geometryModule = createShaderModule (vk, device, context.getBinaryCollection().get("geom"), 0u); 583 m_fragmentModule = createShaderModule (vk, device, context.getBinaryCollection().get("frag"), 0u); 584 m_renderPass = makeRenderPass (vk, device, m_colorFormat); 585 m_framebuffer = makeFramebuffer (vk, device, *m_renderPass, 1u, &m_colorAttachment.get(), 586 static_cast<deUint32>(m_renderSize.x()), static_cast<deUint32>(m_renderSize.y())); 587 m_pipelineLayout = makePipelineLayout (vk, device); 588 m_pipeline = makeGraphicsPipeline (vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_geometryModule, *m_fragmentModule, 589 m_renderSize, m_numViewports, scissors); 590 m_cmdPool = createCommandPool (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex); 591 m_cmdBuffer = allocateCommandBuffer (vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); 592 } 593 594 void draw (Context& context, const VkBuffer colorBuffer) const 595 { 596 const DeviceInterface& vk = context.getDeviceInterface(); 597 const VkDevice device = context.getDevice(); 598 const VkQueue queue = context.getUniversalQueue(); 599 600 beginCommandBuffer(vk, *m_cmdBuffer); 601 602 const VkClearValue clearValue = makeClearValueColor(m_clearColor); 603 const VkRect2D renderArea = 604 { 605 makeOffset2D(0, 0), 606 makeExtent2D(m_renderSize.x(), m_renderSize.y()), 607 }; 608 const VkRenderPassBeginInfo renderPassBeginInfo = 609 { 610 VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType; 611 DE_NULL, // const void* pNext; 612 *m_renderPass, // VkRenderPass renderPass; 613 *m_framebuffer, // VkFramebuffer framebuffer; 614 renderArea, // VkRect2D renderArea; 615 1u, // uint32_t clearValueCount; 616 &clearValue, // const VkClearValue* pClearValues; 617 }; 618 vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); 619 620 vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); 621 { 622 const VkDeviceSize vertexBufferOffset = 0ull; 623 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexBufferOffset); 624 } 625 vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_numViewports), 1u, 0u, 0u); // one vertex per viewport 626 vk.cmdEndRenderPass(*m_cmdBuffer); 627 628 // Prepare color image for copy 629 { 630 const VkImageMemoryBarrier barriers[] = 631 { 632 { 633 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; 634 DE_NULL, // const void* pNext; 635 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags outputMask; 636 VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags inputMask; 637 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout oldLayout; 638 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout; 639 VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; 640 VK_QUEUE_FAMILY_IGNORED, // deUint32 destQueueFamilyIndex; 641 *m_colorImage, // VkImage image; 642 m_colorSubresourceRange, // VkImageSubresourceRange subresourceRange; 643 }, 644 }; 645 646 vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 647 0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers); 648 } 649 // Color image -> host buffer 650 { 651 const VkBufferImageCopy region = 652 { 653 0ull, // VkDeviceSize bufferOffset; 654 0u, // uint32_t bufferRowLength; 655 0u, // uint32_t bufferImageHeight; 656 makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u), // VkImageSubresourceLayers imageSubresource; 657 makeOffset3D(0, 0, 0), // VkOffset3D imageOffset; 658 makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u), // VkExtent3D imageExtent; 659 }; 660 661 vk.cmdCopyImageToBuffer(*m_cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer, 1u, ®ion); 662 } 663 // Buffer write barrier 664 { 665 const VkBufferMemoryBarrier barriers[] = 666 { 667 { 668 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType; 669 DE_NULL, // const void* pNext; 670 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; 671 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask; 672 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex; 673 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex; 674 colorBuffer, // VkBuffer buffer; 675 0ull, // VkDeviceSize offset; 676 VK_WHOLE_SIZE, // VkDeviceSize size; 677 }, 678 }; 679 680 vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 681 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, DE_NULL, 0u); 682 } 683 684 VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer)); 685 submitCommandsAndWait(vk, device, queue, *m_cmdBuffer); 686 } 687 688private: 689 const IVec2 m_renderSize; 690 const VkFormat m_colorFormat; 691 const VkImageSubresourceRange m_colorSubresourceRange; 692 const Vec4 m_clearColor; 693 const int m_numViewports; 694 const VkDeviceSize m_vertexBufferSize; 695 696 Move<VkImage> m_colorImage; 697 MovePtr<Allocation> m_colorImageAlloc; 698 Move<VkImageView> m_colorAttachment; 699 Move<VkBuffer> m_vertexBuffer; 700 MovePtr<Allocation> m_vertexBufferAlloc; 701 Move<VkShaderModule> m_vertexModule; 702 Move<VkShaderModule> m_geometryModule; 703 Move<VkShaderModule> m_fragmentModule; 704 Move<VkRenderPass> m_renderPass; 705 Move<VkFramebuffer> m_framebuffer; 706 Move<VkPipelineLayout> m_pipelineLayout; 707 Move<VkPipeline> m_pipeline; 708 Move<VkCommandPool> m_cmdPool; 709 Move<VkCommandBuffer> m_cmdBuffer; 710 711 // "deleted" 712 ScissorRenderer (const ScissorRenderer&); 713 ScissorRenderer& operator= (const ScissorRenderer&); 714}; 715 716tcu::TestStatus test (Context& context, const int numViewports) 717{ 718 requireFeatureMultiViewport(context.getInstanceInterface(), context.getPhysicalDevice()); 719 720 const DeviceInterface& vk = context.getDeviceInterface(); 721 const VkDevice device = context.getDevice(); 722 Allocator& allocator = context.getDefaultAllocator(); 723 724 const IVec2 renderSize (128, 128); 725 const VkFormat colorFormat = VK_FORMAT_R8G8B8A8_UNORM; 726 const Vec4 clearColor (0.5f, 0.5f, 0.5f, 1.0f); 727 const std::vector<Vec4> vertexColors = generateColors(numViewports); 728 const std::vector<IVec4> scissors = generateScissors(numViewports, renderSize); 729 730 const VkDeviceSize colorBufferSize = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat)); 731 const Unique<VkBuffer> colorBuffer (makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT))); 732 const UniquePtr<Allocation> colorBufferAlloc (bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible)); 733 734 zeroBuffer(vk, device, *colorBufferAlloc, colorBufferSize); 735 736 { 737 context.getTestContext().getLog() 738 << tcu::TestLog::Message << "Rendering a colorful grid of " << numViewports << " rectangle(s)." << tcu::TestLog::EndMessage 739 << tcu::TestLog::Message << "Not covered area will be filled with a gray color." << tcu::TestLog::EndMessage; 740 } 741 742 // Draw 743 { 744 const ScissorRenderer renderer (context, renderSize, numViewports, scissors, colorFormat, clearColor, vertexColors); 745 renderer.draw(context, *colorBuffer); 746 } 747 748 // Log image 749 { 750 invalidateMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), 0ull, colorBufferSize); 751 752 const tcu::ConstPixelBufferAccess resultImage (mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferAlloc->getHostPtr()); 753 const tcu::TextureLevel referenceImage = generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, scissors, vertexColors); 754 755 // Images should now match. 756 if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT)) 757 return tcu::TestStatus::fail("Rendered image is not correct"); 758 } 759 760 return tcu::TestStatus::pass("OK"); 761} 762 763} // anonymous 764 765tcu::TestCaseGroup* createScissorMultiViewportTests (tcu::TestContext& testCtx) 766{ 767 MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "multi_viewport", "")); 768 769 for (int numViewports = 1; numViewports <= MIN_MAX_VIEWPORTS; ++numViewports) 770 addFunctionCaseWithPrograms(group.get(), "scissor_" + de::toString(numViewports), "", initPrograms, test, numViewports); 771 772 return group.release(); 773} 774 775} // FragmentOperations 776} // vkt 777