1/*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2016 The Khronos Group Inc. 6 * Copyright (c) 2016 Samsung Electronics Co., Ltd. 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 Instanced Draw Tests 23 *//*--------------------------------------------------------------------*/ 24 25#include "vktDrawInstancedTests.hpp" 26 27#include "deSharedPtr.hpp" 28#include "rrRenderer.hpp" 29#include "tcuImageCompare.hpp" 30#include "tcuRGBA.hpp" 31#include "tcuTextureUtil.hpp" 32#include "vkImageUtil.hpp" 33#include "vkPrograms.hpp" 34#include "vktDrawBufferObjectUtil.hpp" 35#include "vktDrawCreateInfoUtil.hpp" 36#include "vktDrawImageObjectUtil.hpp" 37#include "vktDrawTestCaseUtil.hpp" 38 39namespace vkt 40{ 41namespace Draw 42{ 43namespace 44{ 45 46static const int QUAD_GRID_SIZE = 8; 47static const int WIDTH = 128; 48static const int HEIGHT = 128; 49 50struct TestParams 51{ 52 enum DrawFunction 53 { 54 FUNCTION_DRAW = 0, 55 FUNCTION_DRAW_INDEXED, 56 FUNCTION_DRAW_INDIRECT, 57 FUNCTION_DRAW_INDEXED_INDIRECT, 58 59 FUNTION_LAST 60 }; 61 62 DrawFunction function; 63 vk::VkPrimitiveTopology topology; 64}; 65 66struct VertexPositionAndColor 67{ 68 VertexPositionAndColor (tcu::Vec4 position_, tcu::Vec4 color_) 69 : position (position_) 70 , color (color_) 71 { 72 } 73 74 tcu::Vec4 position; 75 tcu::Vec4 color; 76}; 77 78std::ostream & operator<<(std::ostream & str, TestParams const & v) 79{ 80 std::ostringstream string; 81 switch (v.function) 82 { 83 case TestParams::FUNCTION_DRAW: 84 string << "draw"; 85 break; 86 case TestParams::FUNCTION_DRAW_INDEXED: 87 string << "draw_indexed"; 88 break; 89 case TestParams::FUNCTION_DRAW_INDIRECT: 90 string << "draw_indirect"; 91 break; 92 case TestParams::FUNCTION_DRAW_INDEXED_INDIRECT: 93 string << "draw_indexed_indirect"; 94 break; 95 default: 96 DE_ASSERT(false); 97 } 98 99 string << "_" << de::toString(v.topology); 100 return str << string.str(); 101} 102 103rr::PrimitiveType mapVkPrimitiveTopology (vk::VkPrimitiveTopology primitiveTopology) 104{ 105 switch (primitiveTopology) 106 { 107 case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST: return rr::PRIMITIVETYPE_POINTS; 108 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST: return rr::PRIMITIVETYPE_LINES; 109 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: return rr::PRIMITIVETYPE_LINE_STRIP; 110 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: return rr::PRIMITIVETYPE_TRIANGLES; 111 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: return rr::PRIMITIVETYPE_TRIANGLE_FAN; 112 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: return rr::PRIMITIVETYPE_TRIANGLE_STRIP; 113 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: return rr::PRIMITIVETYPE_LINES_ADJACENCY; 114 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: return rr::PRIMITIVETYPE_LINE_STRIP_ADJACENCY; 115 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: return rr::PRIMITIVETYPE_TRIANGLES_ADJACENCY; 116 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: return rr::PRIMITIVETYPE_TRIANGLE_STRIP_ADJACENCY; 117 default: 118 DE_ASSERT(false); 119 } 120 return rr::PRIMITIVETYPE_LAST; 121} 122 123template<typename T> 124de::SharedPtr<Buffer> createAndUploadBuffer(const std::vector<T> data, const vk::DeviceInterface& vk, const Context& context, vk::VkBufferUsageFlags usage) 125{ 126 const vk::VkDeviceSize dataSize = data.size() * sizeof(T); 127 de::SharedPtr<Buffer> buffer = Buffer::createAndAlloc(vk, context.getDevice(), 128 BufferCreateInfo(dataSize, usage), 129 context.getDefaultAllocator(), 130 vk::MemoryRequirement::HostVisible); 131 132 deUint8* ptr = reinterpret_cast<deUint8*>(buffer->getBoundMemory().getHostPtr()); 133 134 deMemcpy(ptr, &data[0], static_cast<size_t>(dataSize)); 135 136 vk::flushMappedMemoryRange(vk, context.getDevice(), 137 buffer->getBoundMemory().getMemory(), 138 buffer->getBoundMemory().getOffset(), 139 VK_WHOLE_SIZE); 140 return buffer; 141} 142 143class TestVertShader : public rr::VertexShader 144{ 145public: 146 TestVertShader (int numInstances, int firstInstance) 147 : rr::VertexShader (3, 1) 148 , m_numInstances (numInstances) 149 , m_firstInstance (firstInstance) 150 { 151 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; 152 m_inputs[1].type = rr::GENERICVECTYPE_FLOAT; 153 m_inputs[2].type = rr::GENERICVECTYPE_FLOAT; 154 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; 155 } 156 157 void shadeVertices (const rr::VertexAttrib* inputs, 158 rr::VertexPacket* const* packets, 159 const int numPackets) const 160 { 161 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) 162 { 163 const int instanceNdx = packets[packetNdx]->instanceNdx + m_firstInstance; 164 const tcu::Vec4 position = rr::readVertexAttribFloat(inputs[0], instanceNdx, packets[packetNdx]->vertexNdx); 165 const tcu::Vec4 color = rr::readVertexAttribFloat(inputs[1], instanceNdx, packets[packetNdx]->vertexNdx); 166 const tcu::Vec4 color2 = rr::readVertexAttribFloat(inputs[2], instanceNdx, packets[packetNdx]->vertexNdx); 167 packets[packetNdx]->position = position + tcu::Vec4((float)(packets[packetNdx]->instanceNdx * 2.0 / m_numInstances), 0.0, 0.0, 0.0); 168 packets[packetNdx]->outputs[0] = color + tcu::Vec4((float)instanceNdx / (float)m_numInstances, 0.0, 0.0, 1.0) + color2; 169 } 170 } 171 172private: 173 const int m_numInstances; 174 const int m_firstInstance; 175}; 176 177class TestFragShader : public rr::FragmentShader 178{ 179public: 180 TestFragShader (void) 181 : rr::FragmentShader(1, 1) 182 { 183 m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; 184 m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; 185 } 186 187 void shadeFragments (rr::FragmentPacket* packets, 188 const int numPackets, 189 const rr::FragmentShadingContext& context) const 190 { 191 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) 192 { 193 rr::FragmentPacket& packet = packets[packetNdx]; 194 for (int fragNdx = 0; fragNdx < rr::NUM_FRAGMENTS_PER_PACKET; ++fragNdx) 195 { 196 const tcu::Vec4 color = rr::readVarying<float>(packet, context, 0, fragNdx); 197 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color); 198 } 199 } 200 } 201}; 202 203class InstancedDrawInstance : public TestInstance 204{ 205public: 206 InstancedDrawInstance (Context& context, TestParams params); 207 virtual tcu::TestStatus iterate (void); 208 209private: 210 void prepareVertexData (int instanceCount, int firstInstance); 211 212 const TestParams m_params; 213 const vk::DeviceInterface& m_vk; 214 215 vk::VkFormat m_colorAttachmentFormat; 216 217 vk::Move<vk::VkPipeline> m_pipeline; 218 vk::Move<vk::VkPipelineLayout> m_pipelineLayout; 219 220 de::SharedPtr<Image> m_colorTargetImage; 221 vk::Move<vk::VkImageView> m_colorTargetView; 222 223 PipelineCreateInfo::VertexInputState m_vertexInputState; 224 225 vk::Move<vk::VkCommandPool> m_cmdPool; 226 vk::Move<vk::VkCommandBuffer> m_cmdBuffer; 227 228 vk::Move<vk::VkFramebuffer> m_framebuffer; 229 vk::Move<vk::VkRenderPass> m_renderPass; 230 231 // Vertex data 232 std::vector<VertexPositionAndColor> m_data; 233 std::vector<deUint32> m_indexes; 234 std::vector<tcu::Vec4> m_instancedColor; 235}; 236 237class InstancedDrawCase : public TestCase 238{ 239public: 240 InstancedDrawCase (tcu::TestContext& testCtx, 241 const std::string& name, 242 const std::string& desc, 243 TestParams params) 244 : TestCase (testCtx, name, desc) 245 , m_params (params) 246 { 247 m_vertexShader = "#version 430\n" 248 "layout(location = 0) in vec4 in_position;\n" 249 "layout(location = 1) in vec4 in_color;\n" 250 "layout(location = 2) in vec4 in_color_2;\n" 251 "layout(push_constant) uniform TestParams {\n" 252 " float firstInstance;\n" 253 " float instanceCount;\n" 254 "} params;\n" 255 "layout(location = 0) out vec4 out_color;\n" 256 "out gl_PerVertex {\n" 257 " vec4 gl_Position;\n" 258 " float gl_PointSize;\n" 259 "};\n" 260 "void main() {\n" 261 " gl_PointSize = 1.0;\n" 262 " gl_Position = in_position + vec4(float(gl_InstanceIndex - params.firstInstance) * 2.0 / params.instanceCount, 0.0, 0.0, 0.0);\n" 263 " out_color = in_color + vec4(float(gl_InstanceIndex) / params.instanceCount, 0.0, 0.0, 1.0) + in_color_2;\n" 264 "}\n"; 265 266 m_fragmentShader = "#version 430\n" 267 "layout(location = 0) in vec4 in_color;\n" 268 "layout(location = 0) out vec4 out_color;\n" 269 "void main()\n" 270 "{\n" 271 " out_color = in_color;\n" 272 "}\n"; 273 } 274 275 TestInstance* createInstance (Context& context) const 276 { 277 return new InstancedDrawInstance(context, m_params); 278 } 279 280 virtual void initPrograms (vk::SourceCollections& programCollection) const 281 { 282 programCollection.glslSources.add("InstancedDrawVert") << glu::VertexSource(m_vertexShader); 283 programCollection.glslSources.add("InstancedDrawFrag") << glu::FragmentSource(m_fragmentShader); 284 } 285 286private: 287 const TestParams m_params; 288 std::string m_vertexShader; 289 std::string m_fragmentShader; 290}; 291 292InstancedDrawInstance::InstancedDrawInstance(Context &context, TestParams params) 293 : TestInstance (context) 294 , m_params (params) 295 , m_vk (context.getDeviceInterface()) 296 , m_colorAttachmentFormat (vk::VK_FORMAT_R8G8B8A8_UNORM) 297{ 298 const vk::VkDevice device = m_context.getDevice(); 299 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); 300 301 const vk::VkPushConstantRange pushConstantRange = { 302 vk::VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlags stageFlags; 303 0u, // uint32_t offset; 304 (deUint32)sizeof(float) * 2, // uint32_t size; 305 }; 306 307 const PipelineLayoutCreateInfo pipelineLayoutCreateInfo(0, DE_NULL, 1, &pushConstantRange); 308 m_pipelineLayout = vk::createPipelineLayout(m_vk, device, &pipelineLayoutCreateInfo); 309 310 const vk::VkExtent3D targetImageExtent = { WIDTH, HEIGHT, 1 }; 311 const ImageCreateInfo targetImageCreateInfo(vk::VK_IMAGE_TYPE_2D, m_colorAttachmentFormat, targetImageExtent, 1, 1, vk::VK_SAMPLE_COUNT_1_BIT, 312 vk::VK_IMAGE_TILING_OPTIMAL, vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT); 313 314 m_colorTargetImage = Image::createAndAlloc(m_vk, device, targetImageCreateInfo, m_context.getDefaultAllocator()); 315 316 const ImageViewCreateInfo colorTargetViewInfo(m_colorTargetImage->object(), vk::VK_IMAGE_VIEW_TYPE_2D, m_colorAttachmentFormat); 317 m_colorTargetView = vk::createImageView(m_vk, device, &colorTargetViewInfo); 318 319 RenderPassCreateInfo renderPassCreateInfo; 320 renderPassCreateInfo.addAttachment(AttachmentDescription(m_colorAttachmentFormat, 321 vk::VK_SAMPLE_COUNT_1_BIT, 322 vk::VK_ATTACHMENT_LOAD_OP_LOAD, 323 vk::VK_ATTACHMENT_STORE_OP_STORE, 324 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, 325 vk::VK_ATTACHMENT_STORE_OP_STORE, 326 vk::VK_IMAGE_LAYOUT_GENERAL, 327 vk::VK_IMAGE_LAYOUT_GENERAL)); 328 329 const vk::VkAttachmentReference colorAttachmentReference = 330 { 331 0, 332 vk::VK_IMAGE_LAYOUT_GENERAL 333 }; 334 335 renderPassCreateInfo.addSubpass(SubpassDescription(vk::VK_PIPELINE_BIND_POINT_GRAPHICS, 336 0, 337 0, 338 DE_NULL, 339 1, 340 &colorAttachmentReference, 341 DE_NULL, 342 AttachmentReference(), 343 0, 344 DE_NULL)); 345 346 m_renderPass = vk::createRenderPass(m_vk, device, &renderPassCreateInfo); 347 348 std::vector<vk::VkImageView> colorAttachments(1); 349 colorAttachments[0] = *m_colorTargetView; 350 351 const FramebufferCreateInfo framebufferCreateInfo(*m_renderPass, colorAttachments, WIDTH, HEIGHT, 1); 352 353 m_framebuffer = vk::createFramebuffer(m_vk, device, &framebufferCreateInfo); 354 355 const vk::VkVertexInputBindingDescription vertexInputBindingDescription[2] = 356 { 357 { 358 0u, 359 (deUint32)sizeof(VertexPositionAndColor), 360 vk::VK_VERTEX_INPUT_RATE_VERTEX, 361 }, 362 { 363 1u, 364 (deUint32)sizeof(tcu::Vec4), 365 vk::VK_VERTEX_INPUT_RATE_INSTANCE, 366 }, 367 }; 368 369 const vk::VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] = 370 { 371 { 372 0u, 373 0u, 374 vk::VK_FORMAT_R32G32B32A32_SFLOAT, 375 0u 376 }, 377 { 378 1u, 379 0u, 380 vk::VK_FORMAT_R32G32B32A32_SFLOAT, 381 (deUint32)sizeof(tcu::Vec4), 382 }, 383 { 384 2u, 385 1u, 386 vk::VK_FORMAT_R32G32B32A32_SFLOAT, 387 0, 388 } 389 }; 390 391 m_vertexInputState = PipelineCreateInfo::VertexInputState(2, 392 vertexInputBindingDescription, 393 DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions), 394 vertexInputAttributeDescriptions); 395 396 const CmdPoolCreateInfo cmdPoolCreateInfo(queueFamilyIndex); 397 m_cmdPool = vk::createCommandPool(m_vk, device, &cmdPoolCreateInfo); 398 399 m_cmdBuffer = vk::allocateCommandBuffer(m_vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY); 400 401 const vk::Unique<vk::VkShaderModule> vs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("InstancedDrawVert"), 0)); 402 const vk::Unique<vk::VkShaderModule> fs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("InstancedDrawFrag"), 0)); 403 404 const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState; 405 406 vk::VkViewport viewport; 407 viewport.x = 0; 408 viewport.y = 0; 409 viewport.width = static_cast<float>(WIDTH); 410 viewport.height = static_cast<float>(HEIGHT); 411 viewport.minDepth = 0.0f; 412 viewport.maxDepth = 1.0f; 413 414 vk::VkRect2D scissor; 415 scissor.offset.x = 0; 416 scissor.offset.y = 0; 417 scissor.extent.width = WIDTH; 418 scissor.extent.height = HEIGHT; 419 420 PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0); 421 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT)); 422 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT)); 423 pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState)); 424 pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(m_params.topology)); 425 pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState)); 426 pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor))); 427 pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState()); 428 pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState()); 429 pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState()); 430 431 m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo); 432} 433 434tcu::TestStatus InstancedDrawInstance::iterate() 435{ 436 const vk::VkQueue queue = m_context.getUniversalQueue(); 437 static const deUint32 instanceCounts[] = { 0, 1, 2, 4, 20 }; 438 static const deUint32 firstInstanceIndices[] = { 0, 1, 3, 4, 20 }; 439 440 qpTestResult res = QP_TEST_RESULT_PASS; 441 442 const vk::VkClearColorValue clearColor = { { 0.0f, 0.0f, 0.0f, 1.0f } }; 443 const CmdBufferBeginInfo beginInfo; 444 int firstInstanceIndicesCount = 1; 445 446 // Require 'drawIndirectFirstInstance' feature to run non-zero firstInstance indirect draw tests. 447 if (m_context.getDeviceFeatures().drawIndirectFirstInstance) 448 firstInstanceIndicesCount = DE_LENGTH_OF_ARRAY(firstInstanceIndices); 449 450 for (int instanceCountNdx = 0; instanceCountNdx < DE_LENGTH_OF_ARRAY(instanceCounts); instanceCountNdx++) 451 { 452 const deUint32 instanceCount = instanceCounts[instanceCountNdx]; 453 for (int firstInstanceIndexNdx = 0; firstInstanceIndexNdx < firstInstanceIndicesCount; firstInstanceIndexNdx++) 454 { 455 // Prepare vertex data for at least one instance 456 const deUint32 prepareCount = de::max(instanceCount, 1u); 457 const deUint32 firstInstance = firstInstanceIndices[firstInstanceIndexNdx]; 458 459 prepareVertexData(prepareCount, firstInstance); 460 const de::SharedPtr<Buffer> vertexBuffer = createAndUploadBuffer(m_data, m_vk, m_context, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); 461 const de::SharedPtr<Buffer> instancedVertexBuffer = createAndUploadBuffer(m_instancedColor, m_vk, m_context, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); 462 de::SharedPtr<Buffer> indexBuffer; 463 de::SharedPtr<Buffer> indirectBuffer; 464 m_vk.beginCommandBuffer(*m_cmdBuffer, &beginInfo); 465 466 initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL); 467 468 const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT); 469 m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(), 470 vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &subresourceRange); 471 472 const vk::VkMemoryBarrier memBarrier = 473 { 474 vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER, 475 DE_NULL, 476 vk::VK_ACCESS_TRANSFER_WRITE_BIT, 477 vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT 478 }; 479 480 m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 481 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 482 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL); 483 484 const vk::VkRect2D renderArea = { { 0, 0 }, { WIDTH, HEIGHT } }; 485 const RenderPassBeginInfo renderPassBegin(*m_renderPass, *m_framebuffer, renderArea); 486 487 m_vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBegin, vk::VK_SUBPASS_CONTENTS_INLINE); 488 489 if (m_params.function == TestParams::FUNCTION_DRAW_INDEXED || m_params.function == TestParams::FUNCTION_DRAW_INDEXED_INDIRECT) 490 { 491 indexBuffer = createAndUploadBuffer(m_indexes, m_vk, m_context, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT); 492 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, indexBuffer->object(), 0, vk::VK_INDEX_TYPE_UINT32); 493 } 494 495 const vk::VkBuffer vertexBuffers[] = 496 { 497 vertexBuffer->object(), 498 instancedVertexBuffer->object(), 499 }; 500 501 const vk::VkDeviceSize vertexBufferOffsets[] = 502 { 503 0, // vertexBufferOffset 504 0, // instancedVertexBufferOffset 505 }; 506 507 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, DE_LENGTH_OF_ARRAY(vertexBuffers), vertexBuffers, vertexBufferOffsets); 508 509 const float pushConstants[] = { (float)firstInstance, (float)instanceCount }; 510 m_vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(pushConstants), pushConstants); 511 512 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); 513 514 switch (m_params.function) 515 { 516 case TestParams::FUNCTION_DRAW: 517 m_vk.cmdDraw(*m_cmdBuffer, (deUint32)m_data.size(), instanceCount, 0u, firstInstance); 518 break; 519 520 case TestParams::FUNCTION_DRAW_INDEXED: 521 m_vk.cmdDrawIndexed(*m_cmdBuffer, (deUint32)m_indexes.size(), instanceCount, 0u, 0u, firstInstance); 522 break; 523 524 case TestParams::FUNCTION_DRAW_INDIRECT: 525 { 526 vk::VkDrawIndirectCommand drawCommand = 527 { 528 (deUint32)m_data.size(), // uint32_t vertexCount; 529 instanceCount, // uint32_t instanceCount; 530 0u, // uint32_t firstVertex; 531 firstInstance, // uint32_t firstInstance; 532 }; 533 std::vector<vk::VkDrawIndirectCommand> drawCommands; 534 drawCommands.push_back(drawCommand); 535 indirectBuffer = createAndUploadBuffer(drawCommands, m_vk, m_context, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT); 536 537 m_vk.cmdDrawIndirect(*m_cmdBuffer, indirectBuffer->object(), 0, 1u, 0u); 538 break; 539 } 540 case TestParams::FUNCTION_DRAW_INDEXED_INDIRECT: 541 { 542 vk::VkDrawIndexedIndirectCommand drawCommand = 543 { 544 (deUint32)m_indexes.size(), // uint32_t indexCount; 545 instanceCount, // uint32_t instanceCount; 546 0u, // uint32_t firstIndex; 547 0, // int32_t vertexOffset; 548 firstInstance, // uint32_t firstInstance; 549 }; 550 std::vector<vk::VkDrawIndexedIndirectCommand> drawCommands; 551 drawCommands.push_back(drawCommand); 552 indirectBuffer = createAndUploadBuffer(drawCommands, m_vk, m_context, vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT); 553 554 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, indirectBuffer->object(), 0, 1u, 0u); 555 break; 556 } 557 default: 558 DE_ASSERT(false); 559 } 560 561 m_vk.cmdEndRenderPass(*m_cmdBuffer); 562 m_vk.endCommandBuffer(*m_cmdBuffer); 563 564 vk::VkSubmitInfo submitInfo = 565 { 566 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType; 567 DE_NULL, // const void* pNext; 568 0, // deUint32 waitSemaphoreCount; 569 DE_NULL, // const VkSemaphore* pWaitSemaphores; 570 (const vk::VkPipelineStageFlags*)DE_NULL, // const VkPipelineStageFlags* pWaitDstStageMask; 571 1, // deUint32 commandBufferCount; 572 &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers; 573 0, // deUint32 signalSemaphoreCount; 574 DE_NULL // const VkSemaphore* pSignalSemaphores; 575 }; 576 VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL)); 577 578 VK_CHECK(m_vk.queueWaitIdle(queue)); 579 580 // Reference rendering 581 std::vector<tcu::Vec4> vetrices; 582 std::vector<tcu::Vec4> colors; 583 584 for (std::vector<VertexPositionAndColor>::const_iterator it = m_data.begin(); it != m_data.end(); ++it) 585 { 586 vetrices.push_back(it->position); 587 colors.push_back(it->color); 588 } 589 590 tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT)); 591 592 tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)); 593 594 const TestVertShader vertShader(instanceCount, firstInstance); 595 const TestFragShader fragShader; 596 const rr::Program program (&vertShader, &fragShader); 597 const rr::MultisamplePixelBufferAccess colorBuffer = rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(refImage.getAccess()); 598 const rr::RenderTarget renderTarget (colorBuffer); 599 const rr::RenderState renderState ((rr::ViewportState(colorBuffer))); 600 const rr::Renderer renderer; 601 602 const rr::VertexAttrib vertexAttribs[] = 603 { 604 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &vetrices[0]), 605 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &colors[0]), 606 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 1, &m_instancedColor[0]) 607 }; 608 609 if (m_params.function == TestParams::FUNCTION_DRAW || m_params.function == TestParams::FUNCTION_DRAW_INDIRECT) 610 { 611 const rr::PrimitiveList primitives = rr::PrimitiveList(mapVkPrimitiveTopology(m_params.topology), (int)vetrices.size(), 0); 612 const rr::DrawCommand command(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs), &vertexAttribs[0], 613 primitives); 614 renderer.drawInstanced(command, instanceCount); 615 } 616 else 617 { 618 const rr::DrawIndices indicies(m_indexes.data()); 619 620 const rr::PrimitiveList primitives = rr::PrimitiveList(mapVkPrimitiveTopology(m_params.topology), (int)m_indexes.size(), indicies); 621 const rr::DrawCommand command(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs), &vertexAttribs[0], 622 primitives); 623 renderer.drawInstanced(command, instanceCount); 624 } 625 626 const vk::VkOffset3D zeroOffset = { 0, 0, 0 }; 627 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(), 628 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT); 629 630 tcu::TestLog &log = m_context.getTestContext().getLog(); 631 632 std::ostringstream resultDesc; 633 resultDesc << "Image comparison result. Instance count: " << instanceCount << " first instance index: " << firstInstance; 634 635 if (m_params.topology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST) 636 { 637 const bool ok = tcu::intThresholdPositionDeviationCompare( 638 log, "Result", resultDesc.str().c_str(), refImage.getAccess(), renderedFrame, 639 tcu::UVec4(4u), // color threshold 640 tcu::IVec3(1, 1, 0), // position deviation tolerance 641 true, // don't check the pixels at the boundary 642 tcu::COMPARE_LOG_RESULT); 643 644 if (!ok) 645 res = QP_TEST_RESULT_FAIL; 646 } 647 else 648 { 649 if (!tcu::fuzzyCompare(log, "Result", resultDesc.str().c_str(), refImage.getAccess(), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT)) 650 res = QP_TEST_RESULT_FAIL; 651 } 652 } 653 } 654 return tcu::TestStatus(res, qpGetTestResultName(res)); 655} 656 657void InstancedDrawInstance::prepareVertexData(int instanceCount, int firstInstance) 658{ 659 m_data.clear(); 660 m_indexes.clear(); 661 m_instancedColor.clear(); 662 663 if (m_params.function == TestParams::FUNCTION_DRAW || m_params.function == TestParams::FUNCTION_DRAW_INDIRECT) 664 { 665 for (int y = 0; y < QUAD_GRID_SIZE; y++) 666 { 667 for (int x = 0; x < QUAD_GRID_SIZE; x++) 668 { 669 const float fx0 = -1.0f + (float)(x+0) / (float)QUAD_GRID_SIZE * 2.0f / (float)instanceCount; 670 const float fx1 = -1.0f + (float)(x+1) / (float)QUAD_GRID_SIZE * 2.0f / (float)instanceCount; 671 const float fy0 = -1.0f + (float)(y+0) / (float)QUAD_GRID_SIZE * 2.0f; 672 const float fy1 = -1.0f + (float)(y+1) / (float)QUAD_GRID_SIZE * 2.0f; 673 674 // Vertices of a quad's lower-left triangle: (fx0, fy0), (fx1, fy0) and (fx0, fy1) 675 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec())); 676 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec())); 677 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec())); 678 679 // Vertices of a quad's upper-right triangle: (fx1, fy1), (fx0, fy1) and (fx1, fy0) 680 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec())); 681 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec())); 682 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec())); 683 } 684 } 685 } 686 else 687 { 688 for (int y = 0; y < QUAD_GRID_SIZE + 1; y++) 689 { 690 for (int x = 0; x < QUAD_GRID_SIZE + 1; x++) 691 { 692 const float fx = -1.0f + (float)x / (float)QUAD_GRID_SIZE * 2.0f / (float)instanceCount; 693 const float fy = -1.0f + (float)y / (float)QUAD_GRID_SIZE * 2.0f; 694 695 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx, fy, 1.0f, 1.0f), 696 (y % 2 ? tcu::RGBA::blue().toVec() : tcu::RGBA::green().toVec()))); 697 } 698 } 699 700 for (int y = 0; y < QUAD_GRID_SIZE; y++) 701 { 702 for (int x = 0; x < QUAD_GRID_SIZE; x++) 703 { 704 const int ndx00 = y*(QUAD_GRID_SIZE + 1) + x; 705 const int ndx10 = y*(QUAD_GRID_SIZE + 1) + x + 1; 706 const int ndx01 = (y + 1)*(QUAD_GRID_SIZE + 1) + x; 707 const int ndx11 = (y + 1)*(QUAD_GRID_SIZE + 1) + x + 1; 708 709 // Lower-left triangle of a quad. 710 m_indexes.push_back((deUint16)ndx00); 711 m_indexes.push_back((deUint16)ndx10); 712 m_indexes.push_back((deUint16)ndx01); 713 714 // Upper-right triangle of a quad. 715 m_indexes.push_back((deUint16)ndx11); 716 m_indexes.push_back((deUint16)ndx01); 717 m_indexes.push_back((deUint16)ndx10); 718 } 719 } 720 } 721 722 for (int i = 0; i < instanceCount + firstInstance; i++) 723 { 724 m_instancedColor.push_back(tcu::Vec4(0.0, (float)(1.0 - i * 1.0 / (instanceCount + firstInstance)) / 2, 0.0, 1.0)); 725 } 726} 727 728} // anonymus 729 730InstancedTests::InstancedTests(tcu::TestContext& testCtx) 731 : TestCaseGroup (testCtx, "instanced", "Instanced drawing tests") 732{ 733 static const vk::VkPrimitiveTopology topologies[] = 734 { 735 vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 736 vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST, 737 vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, 738 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 739 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 740 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, 741 }; 742 static const TestParams::DrawFunction functions[] = 743 { 744 TestParams::FUNCTION_DRAW, 745 TestParams::FUNCTION_DRAW_INDEXED, 746 TestParams::FUNCTION_DRAW_INDIRECT, 747 TestParams::FUNCTION_DRAW_INDEXED_INDIRECT, 748 }; 749 750 for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(topologies); topologyNdx++) 751 { 752 for (int functionNdx = 0; functionNdx < DE_LENGTH_OF_ARRAY(functions); functionNdx++) 753 { 754 TestParams param; 755 param.function = functions[functionNdx]; 756 param.topology = topologies[topologyNdx]; 757 758 std::string testName = de::toString(param); 759 760 addChild(new InstancedDrawCase(m_testCtx, de::toLower(testName), "Instanced drawing test", param)); 761 } 762 } 763} 764 765InstancedTests::~InstancedTests() {} 766 767} // DrawTests 768} // vkt 769