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
39 namespace vkt
40 {
41 namespace Draw
42 {
43 namespace
44 {
45
46 static const int QUAD_GRID_SIZE = 8;
47 static const int WIDTH = 128;
48 static const int HEIGHT = 128;
49
50 struct 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
66 struct VertexPositionAndColor
67 {
VertexPositionAndColorvkt::Draw::__anon4eaeed6a0111::VertexPositionAndColor68 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
operator <<(std::ostream & str,TestParams const & v)78 std::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
mapVkPrimitiveTopology(vk::VkPrimitiveTopology primitiveTopology)103 rr::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
123 template<typename T>
createAndUploadBuffer(const std::vector<T> data,const vk::DeviceInterface & vk,const Context & context)124 de::SharedPtr<Buffer> createAndUploadBuffer(const std::vector<T> data, const vk::DeviceInterface& vk, const Context& context)
125 {
126 const vk::VkDeviceSize dataSize = data.size() * sizeof(T);
127 de::SharedPtr<Buffer> vertexBuffer = Buffer::createAndAlloc(vk, context.getDevice(),
128 BufferCreateInfo(dataSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
129 context.getDefaultAllocator(),
130 vk::MemoryRequirement::HostVisible);
131
132 deUint8* ptr = reinterpret_cast<deUint8*>(vertexBuffer->getBoundMemory().getHostPtr());
133
134 deMemcpy(ptr, &data[0], static_cast<size_t>(dataSize));
135
136 vk::flushMappedMemoryRange(vk, context.getDevice(),
137 vertexBuffer->getBoundMemory().getMemory(),
138 vertexBuffer->getBoundMemory().getOffset(),
139 VK_WHOLE_SIZE);
140 return vertexBuffer;
141 }
142
143 class TestVertShader : public rr::VertexShader
144 {
145 public:
TestVertShader(int numInstances,int firstInstance)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
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const157 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
172 private:
173 const int m_numInstances;
174 const int m_firstInstance;
175 };
176
177 class TestFragShader : public rr::FragmentShader
178 {
179 public:
TestFragShader(void)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
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const187 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
203 class InstancedDrawInstance : public TestInstance
204 {
205 public:
206 InstancedDrawInstance (Context& context, TestParams params);
207 virtual tcu::TestStatus iterate (void);
208
209 private:
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
237 class InstancedDrawCase : public TestCase
238 {
239 public:
InstancedDrawCase(tcu::TestContext & testCtx,const std::string & name,const std::string & desc,TestParams params)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
createInstance(Context & context) const275 TestInstance* createInstance (Context& context) const
276 {
277 return new InstancedDrawInstance(context, m_params);
278 }
279
initPrograms(vk::SourceCollections & programCollection) const280 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
286 private:
287 const TestParams m_params;
288 std::string m_vertexShader;
289 std::string m_fragmentShader;
290 };
291
InstancedDrawInstance(Context & context,TestParams params)292 InstancedDrawInstance::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 const vk::VkCommandBufferAllocateInfo cmdBufferAllocateInfo =
400 {
401 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType sType;
402 DE_NULL, // const void* pNext;
403 *m_cmdPool, // VkCommandPool commandPool;
404 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, // VkCommandBufferLevel level;
405 1u, // deUint32 bufferCount;
406 };
407 m_cmdBuffer = vk::allocateCommandBuffer(m_vk, device, &cmdBufferAllocateInfo);
408
409 const vk::Unique<vk::VkShaderModule> vs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("InstancedDrawVert"), 0));
410 const vk::Unique<vk::VkShaderModule> fs(createShaderModule(m_vk, device, m_context.getBinaryCollection().get("InstancedDrawFrag"), 0));
411
412 const PipelineCreateInfo::ColorBlendState::Attachment vkCbAttachmentState;
413
414 vk::VkViewport viewport;
415 viewport.x = 0;
416 viewport.y = 0;
417 viewport.width = static_cast<float>(WIDTH);
418 viewport.height = static_cast<float>(HEIGHT);
419 viewport.minDepth = 0.0f;
420 viewport.maxDepth = 1.0f;
421
422 vk::VkRect2D scissor;
423 scissor.offset.x = 0;
424 scissor.offset.y = 0;
425 scissor.extent.width = WIDTH;
426 scissor.extent.height = HEIGHT;
427
428 PipelineCreateInfo pipelineCreateInfo(*m_pipelineLayout, *m_renderPass, 0, 0);
429 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*vs, "main", vk::VK_SHADER_STAGE_VERTEX_BIT));
430 pipelineCreateInfo.addShader(PipelineCreateInfo::PipelineShaderStage(*fs, "main", vk::VK_SHADER_STAGE_FRAGMENT_BIT));
431 pipelineCreateInfo.addState(PipelineCreateInfo::VertexInputState(m_vertexInputState));
432 pipelineCreateInfo.addState(PipelineCreateInfo::InputAssemblerState(m_params.topology));
433 pipelineCreateInfo.addState(PipelineCreateInfo::ColorBlendState(1, &vkCbAttachmentState));
434 pipelineCreateInfo.addState(PipelineCreateInfo::ViewportState(1, std::vector<vk::VkViewport>(1, viewport), std::vector<vk::VkRect2D>(1, scissor)));
435 pipelineCreateInfo.addState(PipelineCreateInfo::DepthStencilState());
436 pipelineCreateInfo.addState(PipelineCreateInfo::RasterizerState());
437 pipelineCreateInfo.addState(PipelineCreateInfo::MultiSampleState());
438
439 m_pipeline = vk::createGraphicsPipeline(m_vk, device, DE_NULL, &pipelineCreateInfo);
440 }
441
iterate()442 tcu::TestStatus InstancedDrawInstance::iterate()
443 {
444 const vk::VkQueue queue = m_context.getUniversalQueue();
445 static const deUint32 instanceCounts[] = { 1, 2, 4, 20 };
446 static const deUint32 firstInstanceIndices[] = { 0, 1, 3, 4, 20 };
447
448 qpTestResult res = QP_TEST_RESULT_PASS;
449
450 const vk::VkClearColorValue clearColor = { { 0.0f, 0.0f, 0.0f, 1.0f } };
451 const CmdBufferBeginInfo beginInfo;
452
453 for (int instanceCountNdx = 0; instanceCountNdx < DE_LENGTH_OF_ARRAY(instanceCounts); instanceCountNdx++)
454 {
455 const deUint32 instanceCount = instanceCounts[instanceCountNdx];
456 for (int firstInstanceIndexNdx = 0; firstInstanceIndexNdx < DE_LENGTH_OF_ARRAY(firstInstanceIndices); firstInstanceIndexNdx++)
457 {
458 const deUint32 firstInstance = firstInstanceIndices[firstInstanceIndexNdx];
459
460 prepareVertexData(instanceCount, firstInstance);
461 const de::SharedPtr<Buffer> vertexBuffer = createAndUploadBuffer(m_data, m_vk, m_context);
462 const de::SharedPtr<Buffer> instancedVertexBuffer = createAndUploadBuffer(m_instancedColor, m_vk, m_context);
463 de::SharedPtr<Buffer> indexBuffer;
464 de::SharedPtr<Buffer> indirectBuffer;
465 m_vk.beginCommandBuffer(*m_cmdBuffer, &beginInfo);
466
467 initialTransitionColor2DImage(m_vk, *m_cmdBuffer, m_colorTargetImage->object(), vk::VK_IMAGE_LAYOUT_GENERAL);
468
469 const ImageSubresourceRange subresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT);
470 m_vk.cmdClearColorImage(*m_cmdBuffer, m_colorTargetImage->object(),
471 vk::VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &subresourceRange);
472
473 const vk::VkMemoryBarrier memBarrier =
474 {
475 vk::VK_STRUCTURE_TYPE_MEMORY_BARRIER,
476 DE_NULL,
477 vk::VK_ACCESS_TRANSFER_WRITE_BIT,
478 vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
479 };
480
481 m_vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT,
482 vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
483 0, 1, &memBarrier, 0, DE_NULL, 0, DE_NULL);
484
485 const vk::VkRect2D renderArea = { { 0, 0 }, { WIDTH, HEIGHT } };
486 const RenderPassBeginInfo renderPassBegin(*m_renderPass, *m_framebuffer, renderArea);
487
488 m_vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBegin, vk::VK_SUBPASS_CONTENTS_INLINE);
489
490 if (m_params.function == TestParams::FUNCTION_DRAW_INDEXED || m_params.function == TestParams::FUNCTION_DRAW_INDEXED_INDIRECT)
491 {
492 indexBuffer = createAndUploadBuffer(m_indexes, m_vk, m_context);
493 m_vk.cmdBindIndexBuffer(*m_cmdBuffer, indexBuffer->object(), 0, vk::VK_INDEX_TYPE_UINT32);
494 }
495
496 const vk::VkBuffer vertexBuffers[] =
497 {
498 vertexBuffer->object(),
499 instancedVertexBuffer->object(),
500 };
501
502 const vk::VkDeviceSize vertexBufferOffsets[] =
503 {
504 0, // vertexBufferOffset
505 0, // instancedVertexBufferOffset
506 };
507
508 m_vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, DE_LENGTH_OF_ARRAY(vertexBuffers), vertexBuffers, vertexBufferOffsets);
509
510 const float pushConstants[] = { (float)firstInstance, (float)instanceCount };
511 m_vk.cmdPushConstants(*m_cmdBuffer, *m_pipelineLayout, vk::VK_SHADER_STAGE_VERTEX_BIT, 0u, (deUint32)sizeof(pushConstants), pushConstants);
512
513 m_vk.cmdBindPipeline(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
514
515 switch (m_params.function)
516 {
517 case TestParams::FUNCTION_DRAW:
518 m_vk.cmdDraw(*m_cmdBuffer, (deUint32)m_data.size(), instanceCount, 0u, firstInstance);
519 break;
520
521 case TestParams::FUNCTION_DRAW_INDEXED:
522 m_vk.cmdDrawIndexed(*m_cmdBuffer, (deUint32)m_indexes.size(), instanceCount, 0u, 0u, firstInstance);
523 break;
524
525 case TestParams::FUNCTION_DRAW_INDIRECT:
526 {
527 vk::VkDrawIndirectCommand drawCommand =
528 {
529 (deUint32)m_data.size(), // uint32_t vertexCount;
530 instanceCount, // uint32_t instanceCount;
531 0u, // uint32_t firstVertex;
532 firstInstance, // uint32_t firstInstance;
533 };
534 std::vector<vk::VkDrawIndirectCommand> drawCommands;
535 drawCommands.push_back(drawCommand);
536 indirectBuffer = createAndUploadBuffer(drawCommands, m_vk, m_context);
537
538 m_vk.cmdDrawIndirect(*m_cmdBuffer, indirectBuffer->object(), 0, 1u, 0u);
539 break;
540 }
541 case TestParams::FUNCTION_DRAW_INDEXED_INDIRECT:
542 {
543 vk::VkDrawIndexedIndirectCommand drawCommand =
544 {
545 (deUint32)m_indexes.size(), // uint32_t indexCount;
546 instanceCount, // uint32_t instanceCount;
547 0u, // uint32_t firstIndex;
548 0, // int32_t vertexOffset;
549 firstInstance, // uint32_t firstInstance;
550 };
551 std::vector<vk::VkDrawIndexedIndirectCommand> drawCommands;
552 drawCommands.push_back(drawCommand);
553 indirectBuffer = createAndUploadBuffer(drawCommands, m_vk, m_context);
554
555 m_vk.cmdDrawIndexedIndirect(*m_cmdBuffer, indirectBuffer->object(), 0, 1u, 0u);
556 break;
557 }
558 default:
559 DE_ASSERT(false);
560 }
561
562 m_vk.cmdEndRenderPass(*m_cmdBuffer);
563 m_vk.endCommandBuffer(*m_cmdBuffer);
564
565 vk::VkSubmitInfo submitInfo =
566 {
567 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
568 DE_NULL, // const void* pNext;
569 0, // deUint32 waitSemaphoreCount;
570 DE_NULL, // const VkSemaphore* pWaitSemaphores;
571 (const vk::VkPipelineStageFlags*)DE_NULL, // const VkPipelineStageFlags* pWaitDstStageMask;
572 1, // deUint32 commandBufferCount;
573 &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers;
574 0, // deUint32 signalSemaphoreCount;
575 DE_NULL // const VkSemaphore* pSignalSemaphores;
576 };
577 VK_CHECK(m_vk.queueSubmit(queue, 1, &submitInfo, DE_NULL));
578
579 VK_CHECK(m_vk.queueWaitIdle(queue));
580
581 // Reference rendering
582 std::vector<tcu::Vec4> vetrices;
583 std::vector<tcu::Vec4> colors;
584
585 for (std::vector<VertexPositionAndColor>::const_iterator it = m_data.begin(); it != m_data.end(); ++it)
586 {
587 vetrices.push_back(it->position);
588 colors.push_back(it->color);
589 }
590
591 tcu::TextureLevel refImage (vk::mapVkFormat(m_colorAttachmentFormat), (int)(0.5 + WIDTH), (int)(0.5 + HEIGHT));
592
593 tcu::clear(refImage.getAccess(), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
594
595 const TestVertShader vertShader(instanceCount, firstInstance);
596 const TestFragShader fragShader;
597 const rr::Program program (&vertShader, &fragShader);
598 const rr::MultisamplePixelBufferAccess colorBuffer = rr::MultisamplePixelBufferAccess::fromSinglesampleAccess(refImage.getAccess());
599 const rr::RenderTarget renderTarget (colorBuffer);
600 const rr::RenderState renderState ((rr::ViewportState(colorBuffer)));
601 const rr::Renderer renderer;
602
603 const rr::VertexAttrib vertexAttribs[] =
604 {
605 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &vetrices[0]),
606 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 0, &colors[0]),
607 rr::VertexAttrib(rr::VERTEXATTRIBTYPE_FLOAT, 4, sizeof(tcu::Vec4), 1, &m_instancedColor[0])
608 };
609
610 if (m_params.function == TestParams::FUNCTION_DRAW || m_params.function == TestParams::FUNCTION_DRAW_INDIRECT)
611 {
612 const rr::PrimitiveList primitives = rr::PrimitiveList(mapVkPrimitiveTopology(m_params.topology), (int)vetrices.size(), 0);
613 const rr::DrawCommand command(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs), &vertexAttribs[0],
614 primitives);
615 renderer.drawInstanced(command, instanceCount);
616 }
617 else
618 {
619 const rr::DrawIndices indicies(m_indexes.data());
620
621 const rr::PrimitiveList primitives = rr::PrimitiveList(mapVkPrimitiveTopology(m_params.topology), (int)m_indexes.size(), indicies);
622 const rr::DrawCommand command(renderState, renderTarget, program, DE_LENGTH_OF_ARRAY(vertexAttribs), &vertexAttribs[0],
623 primitives);
624 renderer.drawInstanced(command, instanceCount);
625 }
626
627 const vk::VkOffset3D zeroOffset = { 0, 0, 0 };
628 const tcu::ConstPixelBufferAccess renderedFrame = m_colorTargetImage->readSurface(queue, m_context.getDefaultAllocator(),
629 vk::VK_IMAGE_LAYOUT_GENERAL, zeroOffset, WIDTH, HEIGHT, vk::VK_IMAGE_ASPECT_COLOR_BIT);
630
631 tcu::TestLog &log = m_context.getTestContext().getLog();
632
633 std::ostringstream resultDesc;
634 resultDesc << "Image comparison result. Instance count: " << instanceCount << " first instance index: " << firstInstance;
635
636 if (m_params.topology == vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
637 {
638 const bool ok = tcu::intThresholdPositionDeviationCompare(
639 log, "Result", resultDesc.str().c_str(), refImage.getAccess(), renderedFrame,
640 tcu::UVec4(4u), // color threshold
641 tcu::IVec3(1, 1, 0), // position deviation tolerance
642 true, // don't check the pixels at the boundary
643 tcu::COMPARE_LOG_RESULT);
644
645 if (!ok)
646 res = QP_TEST_RESULT_FAIL;
647 }
648 else
649 {
650 if (!tcu::fuzzyCompare(log, "Result", resultDesc.str().c_str(), refImage.getAccess(), renderedFrame, 0.05f, tcu::COMPARE_LOG_RESULT))
651 res = QP_TEST_RESULT_FAIL;
652 }
653 }
654 }
655 return tcu::TestStatus(res, qpGetTestResultName(res));
656 }
657
prepareVertexData(int instanceCount,int firstInstance)658 void InstancedDrawInstance::prepareVertexData(int instanceCount, int firstInstance)
659 {
660 m_data.clear();
661 m_indexes.clear();
662 m_instancedColor.clear();
663
664 if (m_params.function == TestParams::FUNCTION_DRAW || m_params.function == TestParams::FUNCTION_DRAW_INDIRECT)
665 {
666 for (int y = 0; y < QUAD_GRID_SIZE; y++)
667 {
668 for (int x = 0; x < QUAD_GRID_SIZE; x++)
669 {
670 const float fx0 = -1.0f + (float)(x+0) / (float)QUAD_GRID_SIZE * 2.0f / (float)instanceCount;
671 const float fx1 = -1.0f + (float)(x+1) / (float)QUAD_GRID_SIZE * 2.0f / (float)instanceCount;
672 const float fy0 = -1.0f + (float)(y+0) / (float)QUAD_GRID_SIZE * 2.0f;
673 const float fy1 = -1.0f + (float)(y+1) / (float)QUAD_GRID_SIZE * 2.0f;
674
675 // Vertices of a quad's lower-left triangle: (fx0, fy0), (fx1, fy0) and (fx0, fy1)
676 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
677 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
678 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
679
680 // Vertices of a quad's upper-right triangle: (fx1, fy1), (fx0, fy1) and (fx1, fy0)
681 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
682 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx0, fy1, 1.0f, 1.0f), tcu::RGBA::green().toVec()));
683 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx1, fy0, 1.0f, 1.0f), tcu::RGBA::blue().toVec()));
684 }
685 }
686 }
687 else
688 {
689 for (int y = 0; y < QUAD_GRID_SIZE + 1; y++)
690 {
691 for (int x = 0; x < QUAD_GRID_SIZE + 1; x++)
692 {
693 const float fx = -1.0f + (float)x / (float)QUAD_GRID_SIZE * 2.0f / (float)instanceCount;
694 const float fy = -1.0f + (float)y / (float)QUAD_GRID_SIZE * 2.0f;
695
696 m_data.push_back(VertexPositionAndColor(tcu::Vec4(fx, fy, 1.0f, 1.0f),
697 (y % 2 ? tcu::RGBA::blue().toVec() : tcu::RGBA::green().toVec())));
698 }
699 }
700
701 for (int y = 0; y < QUAD_GRID_SIZE; y++)
702 {
703 for (int x = 0; x < QUAD_GRID_SIZE; x++)
704 {
705 const int ndx00 = y*(QUAD_GRID_SIZE + 1) + x;
706 const int ndx10 = y*(QUAD_GRID_SIZE + 1) + x + 1;
707 const int ndx01 = (y + 1)*(QUAD_GRID_SIZE + 1) + x;
708 const int ndx11 = (y + 1)*(QUAD_GRID_SIZE + 1) + x + 1;
709
710 // Lower-left triangle of a quad.
711 m_indexes.push_back((deUint16)ndx00);
712 m_indexes.push_back((deUint16)ndx10);
713 m_indexes.push_back((deUint16)ndx01);
714
715 // Upper-right triangle of a quad.
716 m_indexes.push_back((deUint16)ndx11);
717 m_indexes.push_back((deUint16)ndx01);
718 m_indexes.push_back((deUint16)ndx10);
719 }
720 }
721 }
722
723 for (int i = 0; i < instanceCount + firstInstance; i++)
724 {
725 m_instancedColor.push_back(tcu::Vec4(0.0, (float)(1.0 - i * 1.0 / (instanceCount + firstInstance)) / 2, 0.0, 1.0));
726 }
727 }
728
729 } // anonymus
730
InstancedTests(tcu::TestContext & testCtx)731 InstancedTests::InstancedTests(tcu::TestContext& testCtx)
732 : TestCaseGroup (testCtx, "instanced", "Instanced drawing tests")
733 {
734 static const vk::VkPrimitiveTopology topologies[] =
735 {
736 vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
737 vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
738 vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
739 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
740 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
741 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
742 };
743 static const TestParams::DrawFunction functions[] =
744 {
745 TestParams::FUNCTION_DRAW,
746 TestParams::FUNCTION_DRAW_INDEXED,
747 TestParams::FUNCTION_DRAW_INDIRECT,
748 TestParams::FUNCTION_DRAW_INDEXED_INDIRECT,
749 };
750
751 for (int topologyNdx = 0; topologyNdx < DE_LENGTH_OF_ARRAY(topologies); topologyNdx++)
752 {
753 for (int functionNdx = 0; functionNdx < DE_LENGTH_OF_ARRAY(functions); functionNdx++)
754 {
755 TestParams param;
756 param.function = functions[functionNdx];
757 param.topology = topologies[topologyNdx];
758
759 std::string testName = de::toString(param);
760
761 addChild(new InstancedDrawCase(m_testCtx, de::toLower(testName), "Instanced drawing test", param));
762 }
763 }
764 }
765
~InstancedTests()766 InstancedTests::~InstancedTests() {}
767
768 } // DrawTests
769 } // vkt
770