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