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