1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2023 LunarG, Inc.
6  * Copyright (c) 2023 Nintendo
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 Shader Object Performance Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktShaderObjectPerformanceTests.hpp"
26 #include "deUniquePtr.hpp"
27 #include "tcuTestCase.hpp"
28 #include "vktTestCase.hpp"
29 #include "vkShaderObjectUtil.hpp"
30 #include "vktShaderObjectCreateUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkBuilderUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include <chrono>
37 
38 namespace vkt
39 {
40 namespace ShaderObject
41 {
42 
43 namespace
44 {
45 
46 enum TestType
47 {
48     DRAW_STATIC_PIPELINE,
49     DRAW_DYNAMIC_PIPELINE,
50     DRAW_LINKED_SHADERS,
51     DRAW_BINARY,
52     DRAW_BINARY_BIND,
53 };
54 
55 enum BinaryType
56 {
57     BINARY_SHADER_CREATE,
58     BINARY_MEMCPY,
59 };
60 
61 enum DrawType
62 {
63     DRAW,
64     DRAW_INDEXED,
65     DRAW_INDEXED_INDIRECT,
66     DRAW_INDEXED_INDIRECT_COUNT,
67     DRAW_INDIRECT,
68     DRAW_INDIRECT_COUNT,
69 };
70 
71 enum DispatchType
72 {
73     DISPATCH,
74     DISPATCH_BASE,
75     DISPATCH_INDIRECT,
76 };
77 
78 class ShaderObjectPerformanceInstance : public vkt::TestInstance
79 {
80 public:
ShaderObjectPerformanceInstance(Context & context,const DrawType drawType,const TestType & type)81     ShaderObjectPerformanceInstance(Context &context, const DrawType drawType, const TestType &type)
82         : vkt::TestInstance(context)
83         , m_drawType(drawType)
84         , m_type(type)
85     {
86     }
~ShaderObjectPerformanceInstance(void)87     virtual ~ShaderObjectPerformanceInstance(void)
88     {
89     }
90 
91     tcu::TestStatus iterate(void) override;
92 
93 private:
94     std::chrono::nanoseconds draw(const vk::DeviceInterface &vk, vk::VkCommandBuffer cmdBuffer,
95                                   vk::VkBuffer indexBuffer, vk::VkBuffer indirectBuffer,
96                                   vk::VkBuffer countBuffer) const;
97 
98     const DrawType m_drawType;
99     const TestType m_type;
100 };
101 
extensionEnabled(const std::vector<std::string> & deviceExtensions,const std::string & ext)102 bool extensionEnabled(const std::vector<std::string> &deviceExtensions, const std::string &ext)
103 {
104     return std::find(deviceExtensions.begin(), deviceExtensions.end(), ext) != deviceExtensions.end();
105 }
106 
getDynamicStates(Context & context)107 std::vector<vk::VkDynamicState> getDynamicStates(Context &context)
108 {
109     const auto deviceExtensions = vk::removeUnsupportedShaderObjectExtensions(
110         context.getInstanceInterface(), context.getPhysicalDevice(), context.getDeviceExtensions());
111     const auto &edsFeatures  = context.getExtendedDynamicStateFeaturesEXT();
112     const auto &eds2Features = context.getExtendedDynamicState2FeaturesEXT();
113     const auto &eds3Features = context.getExtendedDynamicState3FeaturesEXT();
114     const auto &viFeatures   = context.getVertexInputDynamicStateFeaturesEXT();
115 
116     std::vector<vk::VkDynamicState> dynamicStates = {
117         vk::VK_DYNAMIC_STATE_LINE_WIDTH,           vk::VK_DYNAMIC_STATE_DEPTH_BIAS,
118         vk::VK_DYNAMIC_STATE_BLEND_CONSTANTS,      vk::VK_DYNAMIC_STATE_DEPTH_BOUNDS,
119         vk::VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, vk::VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
120         vk::VK_DYNAMIC_STATE_STENCIL_REFERENCE,
121     };
122 
123     if (edsFeatures.extendedDynamicState)
124     {
125         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_CULL_MODE_EXT);
126         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_FRONT_FACE_EXT);
127         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT);
128         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT);
129         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT);
130         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT);
131         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT);
132         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT);
133         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT);
134         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT);
135         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT);
136         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_OP_EXT);
137     }
138     else
139     {
140         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT);
141         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SCISSOR);
142     }
143     if (eds2Features.extendedDynamicState2)
144     {
145         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE);
146         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE);
147         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE);
148     }
149     if (eds2Features.extendedDynamicState2LogicOp)
150         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LOGIC_OP_EXT);
151     if (eds2Features.extendedDynamicState2PatchControlPoints)
152         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT);
153 
154     if (eds3Features.extendedDynamicState3TessellationDomainOrigin)
155         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT);
156     if (eds3Features.extendedDynamicState3DepthClampEnable)
157         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT);
158     if (eds3Features.extendedDynamicState3PolygonMode)
159         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_POLYGON_MODE_EXT);
160     if (eds3Features.extendedDynamicState3RasterizationSamples)
161         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT);
162     if (eds3Features.extendedDynamicState3SampleMask)
163         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SAMPLE_MASK_EXT);
164     if (eds3Features.extendedDynamicState3AlphaToCoverageEnable)
165         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT);
166     if (eds3Features.extendedDynamicState3AlphaToOneEnable)
167         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT);
168     if (eds3Features.extendedDynamicState3LogicOpEnable)
169         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT);
170     if (eds3Features.extendedDynamicState3ColorBlendEnable)
171         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT);
172     if (eds3Features.extendedDynamicState3ColorBlendEquation)
173         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT);
174     if (eds3Features.extendedDynamicState3ColorWriteMask)
175         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT);
176     if (viFeatures.vertexInputDynamicState)
177         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
178 
179     if (extensionEnabled(deviceExtensions, "VK_EXT_transform_feedback") &&
180         eds3Features.extendedDynamicState3RasterizationStream)
181         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_RASTERIZATION_STREAM_EXT);
182     if (extensionEnabled(deviceExtensions, "VK_EXT_blend_operation_advanced") &&
183         eds3Features.extendedDynamicState3ColorBlendAdvanced)
184         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT);
185     if (extensionEnabled(deviceExtensions, "VK_EXT_conservative_rasterization") &&
186         eds3Features.extendedDynamicState3ConservativeRasterizationMode)
187         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT);
188     if (extensionEnabled(deviceExtensions, "VK_NV_framebuffer_mixed_samples") &&
189         eds3Features.extendedDynamicState3CoverageModulationMode)
190         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_MODULATION_MODE_NV);
191     if (extensionEnabled(deviceExtensions, "VK_NV_framebuffer_mixed_samples") &&
192         eds3Features.extendedDynamicState3CoverageModulationTableEnable)
193         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_ENABLE_NV);
194     if (extensionEnabled(deviceExtensions, "VK_NV_framebuffer_mixed_samples") &&
195         eds3Features.extendedDynamicState3CoverageModulationTable)
196         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_NV);
197     if (extensionEnabled(deviceExtensions, "VK_NV_coverage_reduction_mode") &&
198         eds3Features.extendedDynamicState3CoverageReductionMode)
199         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_REDUCTION_MODE_NV);
200     if (extensionEnabled(deviceExtensions, "VK_NV_fragment_coverage_to_color") &&
201         eds3Features.extendedDynamicState3CoverageToColorEnable)
202         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_ENABLE_NV);
203     if (extensionEnabled(deviceExtensions, "VK_NV_fragment_coverage_to_color") &&
204         eds3Features.extendedDynamicState3CoverageToColorLocation)
205         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_LOCATION_NV);
206     if (extensionEnabled(deviceExtensions, "VK_EXT_depth_clip_enable") &&
207         eds3Features.extendedDynamicState3DepthClipEnable)
208         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT);
209     if (extensionEnabled(deviceExtensions, "VK_EXT_depth_clip_control") &&
210         eds3Features.extendedDynamicState3DepthClipNegativeOneToOne)
211         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT);
212     if (extensionEnabled(deviceExtensions, "VK_EXT_color_write_enable"))
213         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT);
214     if (extensionEnabled(deviceExtensions, "VK_EXT_conservative_rasterization") &&
215         eds3Features.extendedDynamicState3ExtraPrimitiveOverestimationSize)
216         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_EXTRA_PRIMITIVE_OVERESTIMATION_SIZE_EXT);
217     if ((extensionEnabled(deviceExtensions, "VK_KHR_line_rasterization") ||
218          extensionEnabled(deviceExtensions, "VK_EXT_line_rasterization")) &&
219         eds3Features.extendedDynamicState3LineRasterizationMode)
220         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT);
221     if ((extensionEnabled(deviceExtensions, "VK_KHR_line_rasterization") ||
222          extensionEnabled(deviceExtensions, "VK_EXT_line_rasterization")) &&
223         eds3Features.extendedDynamicState3LineStippleEnable)
224         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT);
225     if ((extensionEnabled(deviceExtensions, "VK_KHR_line_rasterization") ||
226          extensionEnabled(deviceExtensions, "VK_EXT_line_rasterization")))
227         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LINE_STIPPLE_EXT);
228     if (extensionEnabled(deviceExtensions, "VK_EXT_provoking_vertex") &&
229         eds3Features.extendedDynamicState3ProvokingVertexMode)
230         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PROVOKING_VERTEX_MODE_EXT);
231     if (extensionEnabled(deviceExtensions, "VK_KHR_fragment_shading_rate"))
232         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR);
233     if (extensionEnabled(deviceExtensions, "VK_NV_representative_fragment_test") &&
234         eds3Features.extendedDynamicState3RepresentativeFragmentTestEnable)
235         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_REPRESENTATIVE_FRAGMENT_TEST_ENABLE_NV);
236     if (extensionEnabled(deviceExtensions, "VK_EXT_sample_locations") &&
237         eds3Features.extendedDynamicState3SampleLocationsEnable)
238         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_ENABLE_EXT);
239     if (extensionEnabled(deviceExtensions, "VK_EXT_sample_locations"))
240         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT);
241     if (extensionEnabled(deviceExtensions, "VK_NV_shading_rate_image") &&
242         eds3Features.extendedDynamicState3ShadingRateImageEnable)
243         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SHADING_RATE_IMAGE_ENABLE_NV);
244     if (extensionEnabled(deviceExtensions, "VK_NV_shading_rate_image"))
245         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV);
246     if (extensionEnabled(deviceExtensions, "VK_NV_shading_rate_image"))
247         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV);
248     if (extensionEnabled(deviceExtensions, "VK_NV_viewport_swizzle") &&
249         eds3Features.extendedDynamicState3ViewportSwizzle)
250         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_SWIZZLE_NV);
251     if (extensionEnabled(deviceExtensions, "VK_NV_clip_space_w_scaling") &&
252         eds3Features.extendedDynamicState3ViewportWScalingEnable)
253         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_ENABLE_NV);
254     if (extensionEnabled(deviceExtensions, "VK_NV_clip_space_w_scaling"))
255         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV);
256     if (extensionEnabled(deviceExtensions, "VK_NV_scissor_exclusive"))
257         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV);
258     if (extensionEnabled(deviceExtensions, "VK_EXT_discard_rectangles"))
259         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DISCARD_RECTANGLE_ENABLE_EXT);
260     if (extensionEnabled(deviceExtensions, "VK_EXT_discard_rectangles"))
261         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT);
262     if (extensionEnabled(deviceExtensions, "VK_EXT_discard_rectangles"))
263         dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DISCARD_RECTANGLE_MODE_EXT);
264 
265     return dynamicStates;
266 }
267 
createShaderFromBinary(const vk::DeviceInterface & vk,const vk::VkDevice device,const vk::Move<vk::VkShaderEXT> & shader,vk::VkShaderStageFlagBits stage)268 vk::VkShaderEXT createShaderFromBinary(const vk::DeviceInterface &vk, const vk::VkDevice device,
269                                        const vk::Move<vk::VkShaderEXT> &shader, vk::VkShaderStageFlagBits stage)
270 {
271     size_t dataSize = 0;
272     vk.getShaderBinaryDataEXT(device, *shader, &dataSize, DE_NULL);
273     std::vector<uint8_t> data(dataSize);
274     vk.getShaderBinaryDataEXT(device, *shader, &dataSize, data.data());
275 
276     const vk::VkShaderCreateInfoEXT binaryShaderCreateInfo = {
277         vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, // VkStructureType sType;
278         DE_NULL,                                      // const void* pNext;
279         0u,                                           // VkShaderCreateFlagsEXT flags;
280         stage,                                        // VkShaderStageFlagBits stage;
281         0u,                                           // VkShaderStageFlags nextStage;
282         vk::VK_SHADER_CODE_TYPE_BINARY_EXT,           // VkShaderCodeTypeEXT codeType;
283         dataSize,                                     // size_t codeSize;
284         data.data(),                                  // const void* pCode;
285         "main",                                       // const char* pName;
286         0u,                                           // uint32_t setLayoutCount;
287         DE_NULL,                                      // VkDescriptorSetLayout* pSetLayouts;
288         0u,                                           // uint32_t pushConstantRangeCount;
289         DE_NULL,                                      // const VkPushConstantRange* pPushConstantRanges;
290         DE_NULL,                                      // const VkSpecializationInfo* pSpecializationInfo;
291     };
292 
293     vk::VkShaderEXT binaryShader;
294     vk.createShadersEXT(device, 1, &binaryShaderCreateInfo, DE_NULL, &binaryShader);
295     return binaryShader;
296 }
297 
draw(const vk::DeviceInterface & vk,vk::VkCommandBuffer cmdBuffer,vk::VkBuffer indexBuffer,vk::VkBuffer indirectBuffer,vk::VkBuffer countBuffer) const298 std::chrono::nanoseconds ShaderObjectPerformanceInstance::draw(const vk::DeviceInterface &vk,
299                                                                vk::VkCommandBuffer cmdBuffer, vk::VkBuffer indexBuffer,
300                                                                vk::VkBuffer indirectBuffer,
301                                                                vk::VkBuffer countBuffer) const
302 {
303     if (m_drawType == DRAW)
304     {
305         const auto shaderObjectStart = std::chrono::high_resolution_clock::now();
306         vk.cmdDraw(cmdBuffer, 4, 1, 0, 0);
307         return std::chrono::high_resolution_clock::now() - shaderObjectStart;
308     }
309     else if (m_drawType == DRAW_INDEXED)
310     {
311         vk.cmdBindIndexBuffer(cmdBuffer, indexBuffer, 0u, vk::VK_INDEX_TYPE_UINT16);
312         const auto shaderObjectStart = std::chrono::high_resolution_clock::now();
313         vk.cmdDrawIndexed(cmdBuffer, 4, 1, 0, 0, 0);
314         return std::chrono::high_resolution_clock::now() - shaderObjectStart;
315     }
316     else if (m_drawType == DRAW_INDEXED_INDIRECT)
317     {
318         vk.cmdBindIndexBuffer(cmdBuffer, indexBuffer, 0u, vk::VK_INDEX_TYPE_UINT16);
319         const auto shaderObjectStart = std::chrono::high_resolution_clock::now();
320         vk.cmdDrawIndexedIndirect(cmdBuffer, indirectBuffer, 0u, 1u, sizeof(vk::VkDrawIndexedIndirectCommand));
321         return std::chrono::high_resolution_clock::now() - shaderObjectStart;
322     }
323     else if (m_drawType == DRAW_INDEXED_INDIRECT_COUNT)
324     {
325         vk.cmdBindIndexBuffer(cmdBuffer, indexBuffer, 0u, vk::VK_INDEX_TYPE_UINT16);
326         const auto shaderObjectStart = std::chrono::high_resolution_clock::now();
327         vk.cmdDrawIndexedIndirectCount(cmdBuffer, indirectBuffer, 0u, countBuffer, 0u, 1u,
328                                        sizeof(vk::VkDrawIndexedIndirectCommand));
329         return std::chrono::high_resolution_clock::now() - shaderObjectStart;
330     }
331     else if (m_drawType == DRAW_INDIRECT)
332     {
333         const auto shaderObjectStart = std::chrono::high_resolution_clock::now();
334         vk.cmdDrawIndirect(cmdBuffer, indirectBuffer, 0u, 1u, sizeof(vk::VkDrawIndirectCommand));
335         return std::chrono::high_resolution_clock::now() - shaderObjectStart;
336     }
337     else if (m_drawType == DRAW_INDIRECT_COUNT)
338     {
339         const auto shaderObjectStart = std::chrono::high_resolution_clock::now();
340         vk.cmdDrawIndirectCount(cmdBuffer, indirectBuffer, 0u, countBuffer, 0u, 1u, sizeof(vk::VkDrawIndirectCommand));
341         return std::chrono::high_resolution_clock::now() - shaderObjectStart;
342     }
343     return std::chrono::nanoseconds(0);
344 }
345 
iterate(void)346 tcu::TestStatus ShaderObjectPerformanceInstance::iterate(void)
347 {
348     const vk::VkInstance instance = m_context.getInstance();
349     const vk::InstanceDriver instanceDriver(m_context.getPlatformInterface(), instance);
350     const vk::DeviceInterface &vk   = m_context.getDeviceInterface();
351     const vk::VkDevice device       = m_context.getDevice();
352     const vk::VkQueue queue         = m_context.getUniversalQueue();
353     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
354     auto &alloc                     = m_context.getDefaultAllocator();
355     const auto deviceExtensions     = vk::removeUnsupportedShaderObjectExtensions(
356         m_context.getInstanceInterface(), m_context.getPhysicalDevice(), m_context.getDeviceExtensions());
357     const bool tessellationSupported = m_context.getDeviceFeatures().tessellationShader;
358     const bool geometrySupported     = m_context.getDeviceFeatures().geometryShader;
359     const bool taskSupported         = m_context.getMeshShaderFeaturesEXT().taskShader;
360     const bool meshSupported         = m_context.getMeshShaderFeaturesEXT().meshShader;
361 
362     vk::VkFormat colorAttachmentFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
363     const auto subresourceRange        = makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
364 
365     const vk::Move<vk::VkCommandPool> cmdPool(
366         createCommandPool(vk, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
367     const vk::Move<vk::VkCommandBuffer> cmdBuffer(
368         allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
369 
370     const vk::VkPrimitiveTopology topology =
371         tessellationSupported ? vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
372 
373     const uint32_t geomIndex = tessellationSupported ? 4u : 2u;
374 
375     const vk::VkImageCreateInfo createInfo = {
376         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType            sType
377         DE_NULL,                                 // const void*                pNext
378         0u,                                      // VkImageCreateFlags        flags
379         vk::VK_IMAGE_TYPE_2D,                    // VkImageType                imageType
380         colorAttachmentFormat,                   // VkFormat                    format
381         {32, 32, 1},                             // VkExtent3D                extent
382         1u,                                      // uint32_t                    mipLevels
383         1u,                                      // uint32_t                    arrayLayers
384         vk::VK_SAMPLE_COUNT_1_BIT,               // VkSampleCountFlagBits    samples
385         vk::VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling            tiling
386         vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags        usage
387         vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode            sharingMode
388         0,                             // uint32_t                    queueFamilyIndexCount
389         DE_NULL,                       // const uint32_t*            pQueueFamilyIndices
390         vk::VK_IMAGE_LAYOUT_UNDEFINED  // VkImageLayout            initialLayout
391     };
392 
393     de::MovePtr<vk::ImageWithMemory> image = de::MovePtr<vk::ImageWithMemory>(
394         new vk::ImageWithMemory(vk, device, alloc, createInfo, vk::MemoryRequirement::Any));
395     const auto imageView =
396         vk::makeImageView(vk, device, **image, vk::VK_IMAGE_VIEW_TYPE_2D, colorAttachmentFormat, subresourceRange);
397     const vk::VkRect2D renderArea = vk::makeRect2D(0, 0, 32, 32);
398 
399     const vk::VkDeviceSize colorOutputBufferSize =
400         renderArea.extent.width * renderArea.extent.height * tcu::getPixelSize(vk::mapVkFormat(colorAttachmentFormat));
401     de::MovePtr<vk::BufferWithMemory> colorOutputBuffer = de::MovePtr<vk::BufferWithMemory>(new vk::BufferWithMemory(
402         vk, device, alloc, makeBufferCreateInfo(colorOutputBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT),
403         vk::MemoryRequirement::HostVisible));
404 
405     const auto &binaries = m_context.getBinaryCollection();
406 
407     std::vector<vk::VkShaderCreateInfoEXT> createInfos = {
408         vk::makeShaderCreateInfo(vk::VK_SHADER_STAGE_VERTEX_BIT, binaries.get("vert"), tessellationSupported,
409                                  geometrySupported),
410         vk::makeShaderCreateInfo(vk::VK_SHADER_STAGE_FRAGMENT_BIT, binaries.get("frag"), tessellationSupported,
411                                  geometrySupported),
412     };
413 
414     if (tessellationSupported)
415     {
416         createInfos.push_back(vk::makeShaderCreateInfo(vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
417                                                        binaries.get("tesc"), tessellationSupported, geometrySupported));
418         createInfos.push_back(vk::makeShaderCreateInfo(vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
419                                                        binaries.get("tese"), tessellationSupported, geometrySupported));
420     }
421     if (geometrySupported)
422     {
423         createInfos.push_back(vk::makeShaderCreateInfo(vk::VK_SHADER_STAGE_GEOMETRY_BIT, binaries.get("geom"),
424                                                        tessellationSupported, geometrySupported));
425     }
426 
427     if (tessellationSupported)
428     {
429         createInfos[0].nextStage = vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
430         createInfos[2].nextStage = vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
431         if (geometrySupported)
432             createInfos[3].nextStage = vk::VK_SHADER_STAGE_GEOMETRY_BIT;
433         else
434             createInfos[3].nextStage = vk::VK_SHADER_STAGE_FRAGMENT_BIT;
435     }
436     else if (geometrySupported)
437     {
438         createInfos[0].nextStage         = vk::VK_SHADER_STAGE_GEOMETRY_BIT;
439         createInfos[geomIndex].nextStage = vk::VK_SHADER_STAGE_FRAGMENT_BIT;
440     }
441     else
442     {
443         createInfos[0].nextStage = vk::VK_SHADER_STAGE_FRAGMENT_BIT;
444     }
445 
446     vk::Move<vk::VkShaderEXT> vertShader = vk::createShader(vk, device, createInfos[0]);
447     vk::Move<vk::VkShaderEXT> fragShader = vk::createShader(vk, device, createInfos[1]);
448     vk::Move<vk::VkShaderEXT> tescShader;
449     vk::Move<vk::VkShaderEXT> teseShader;
450     vk::Move<vk::VkShaderEXT> geomShader;
451 
452     if (tessellationSupported)
453     {
454         tescShader = vk::createShader(vk, device, createInfos[2]);
455         teseShader = vk::createShader(vk, device, createInfos[3]);
456     }
457     if (geometrySupported)
458     {
459         geomShader = vk::createShader(vk, device, createInfos[geomIndex]);
460     }
461 
462     std::vector<vk::VkShaderEXT> refShaders;
463 
464     if (m_type == DRAW_LINKED_SHADERS)
465     {
466         refShaders.resize(5, VK_NULL_HANDLE);
467         for (auto &info : createInfos)
468             info.flags = vk::VK_SHADER_CREATE_LINK_STAGE_BIT_EXT;
469 
470         vk.createShadersEXT(device, (uint32_t)createInfos.size(), createInfos.data(), DE_NULL, refShaders.data());
471     }
472     else if (m_type == DRAW_BINARY || m_type == DRAW_BINARY_BIND)
473     {
474         refShaders.resize(5, VK_NULL_HANDLE);
475         refShaders[0] = createShaderFromBinary(vk, device, vertShader, vk::VK_SHADER_STAGE_VERTEX_BIT);
476         refShaders[1] = createShaderFromBinary(vk, device, fragShader, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
477         if (tessellationSupported)
478         {
479             refShaders[2] =
480                 createShaderFromBinary(vk, device, tescShader, vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
481             refShaders[3] =
482                 createShaderFromBinary(vk, device, teseShader, vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
483         }
484         if (geometrySupported)
485         {
486             refShaders[geomIndex] = createShaderFromBinary(vk, device, geomShader, vk::VK_SHADER_STAGE_GEOMETRY_BIT);
487         }
488     }
489 
490     vk::VkShaderEXT linkedShaders[5];
491     vk.createShadersEXT(device, static_cast<uint32_t>(createInfos.size()), createInfos.data(), nullptr, linkedShaders);
492 
493     vk::Move<vk::VkShaderEXT> linkedVertShader = vk::Move<vk::VkShaderEXT>(
494         vk::check<vk::VkShaderEXT>(linkedShaders[0]), vk::Deleter<vk::VkShaderEXT>(vk, device, DE_NULL));
495     vk::Move<vk::VkShaderEXT> linkedFragShader = vk::Move<vk::VkShaderEXT>(
496         vk::check<vk::VkShaderEXT>(linkedShaders[1]), vk::Deleter<vk::VkShaderEXT>(vk, device, DE_NULL));
497     vk::Move<vk::VkShaderEXT> linkedTescShader;
498     vk::Move<vk::VkShaderEXT> linkedTeseShader;
499     vk::Move<vk::VkShaderEXT> linkedGeomShader;
500     if (tessellationSupported)
501     {
502         linkedTescShader = vk::Move<vk::VkShaderEXT>(vk::check<vk::VkShaderEXT>(linkedShaders[2]),
503                                                      vk::Deleter<vk::VkShaderEXT>(vk, device, DE_NULL));
504         linkedTeseShader = vk::Move<vk::VkShaderEXT>(vk::check<vk::VkShaderEXT>(linkedShaders[3]),
505                                                      vk::Deleter<vk::VkShaderEXT>(vk, device, DE_NULL));
506     }
507     if (geometrySupported)
508     {
509         linkedGeomShader = vk::Move<vk::VkShaderEXT>(vk::check<vk::VkShaderEXT>(linkedShaders[geomIndex]),
510                                                      vk::Deleter<vk::VkShaderEXT>(vk, device, DE_NULL));
511     }
512 
513     vk::Move<vk::VkShaderModule> vertShaderModule      = createShaderModule(vk, device, binaries.get("vert"));
514     vk::Move<vk::VkShaderModule> fragShaderModule      = createShaderModule(vk, device, binaries.get("frag"));
515     vk::Move<vk::VkShaderModule> dummyVertShaderModule = createShaderModule(vk, device, binaries.get("dummyVert"));
516     vk::Move<vk::VkShaderModule> dummyFragShaderModule = createShaderModule(vk, device, binaries.get("dummyFrag"));
517     vk::Move<vk::VkShaderModule> tescShaderModule;
518     vk::Move<vk::VkShaderModule> teseShaderModule;
519     vk::Move<vk::VkShaderModule> geomShaderModule;
520     if (tessellationSupported)
521     {
522         tescShaderModule = createShaderModule(vk, device, binaries.get("tesc"));
523         teseShaderModule = createShaderModule(vk, device, binaries.get("tese"));
524     }
525     if (geometrySupported)
526     {
527         geomShaderModule = createShaderModule(vk, device, binaries.get("geom"));
528     }
529 
530     const auto emptyPipelineLayout = makePipelineLayout(vk, device);
531 
532     const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateParams = {
533         vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
534         DE_NULL,                                                       // const void* pNext;
535         0u,                                                            // VkPipelineVertexInputStateCreateFlags flags;
536         0u,                                                            // uint32_t vertexBindingDescriptionCount;
537         DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
538         0u,      // uint32_t vertexAttributeDescriptionCount;
539         DE_NULL  // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
540     };
541 
542     const vk::VkPipelineTessellationStateCreateInfo tessStateCreateInfo = {
543         vk::VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType;
544         DE_NULL,                                                       // const void* pNext;
545         0u,                                                            // VkPipelineTessellationStateCreateFlags flags;
546         4u,                                                            // uint32_t patchControlPoints;
547     };
548 
549     vk::VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = {
550         vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType                             sType;
551         DE_NULL,                                         // const void*                                 pNext;
552         (vk::VkPipelineInputAssemblyStateCreateFlags)0u, // VkPipelineInputAssemblyStateCreateFlags     flags;
553         topology,                                        // VkPrimitiveTopology                         topology;
554         VK_FALSE, // VkBool32                                    primitiveRestartEnable;
555     };
556 
557     vk::VkPipelineRenderingCreateInfo pipelineRenderingCreateInfo = {
558         vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, // VkStructureType    sType
559         DE_NULL,                                              // const void*        pNext
560         0u,                                                   // uint32_t            viewMask
561         1u,                                                   // uint32_t            colorAttachmentCount
562         &colorAttachmentFormat,                               // const VkFormat*    pColorAttachmentFormats
563         vk::VK_FORMAT_UNDEFINED,                              // VkFormat            depthAttachmentFormat
564         vk::VK_FORMAT_UNDEFINED,                              // VkFormat            stencilAttachmentFormat
565     };
566 
567     const vk::VkViewport viewport =
568         vk::makeViewport((float)renderArea.extent.width, 0.0f, (float)renderArea.extent.width,
569                          (float)renderArea.extent.height, 0.0f, 1.0f);
570     const vk::VkRect2D scissor = vk::makeRect2D(renderArea.extent);
571 
572     vk::VkPipelineViewportStateCreateInfo viewportStateCreateInfo = {
573         vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType                             sType
574         DE_NULL,                                                   // const void*                                 pNext
575         (vk::VkPipelineViewportStateCreateFlags)0u,                // VkPipelineViewportStateCreateFlags          flags
576         (m_type == DRAW_DYNAMIC_PIPELINE) ? 0u : 1u, // uint32_t                                    viewportCount
577         &viewport,                                   // const VkViewport*                           pViewports
578         (m_type == DRAW_DYNAMIC_PIPELINE) ? 0u : 1u, // uint32_t                                    scissorCount
579         &scissor                                     // const VkRect2D*                             pScissors
580     };
581 
582     const auto dynamicStates = getDynamicStates(m_context);
583 
584     const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
585         vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
586         DE_NULL,                                                  // const void* pNext;
587         (vk::VkPipelineDynamicStateCreateFlags)0u,                // VkPipelineDynamicStateCreateFlags flags;
588         static_cast<uint32_t>(dynamicStates.size()),              // uint32_t dynamicStateCount;
589         dynamicStates.data(),                                     // const VkDynamicState* pDynamicStates;
590     };
591 
592     const vk::VkPipelineDynamicStateCreateInfo *pDynamicStateCreateInfo =
593         (m_type == DRAW_DYNAMIC_PIPELINE) ? &dynamicStateCreateInfo : DE_NULL;
594 
595     const auto pipeline = makeGraphicsPipeline(
596         vk, device, emptyPipelineLayout.get(), vertShaderModule.get(), tescShaderModule.get(), teseShaderModule.get(),
597         geomShaderModule.get(), fragShaderModule.get(), VK_NULL_HANDLE, 0u, &vertexInputStateParams,
598         &pipelineInputAssemblyStateInfo, &tessStateCreateInfo, &viewportStateCreateInfo, DE_NULL, DE_NULL, DE_NULL,
599         DE_NULL, pDynamicStateCreateInfo, &pipelineRenderingCreateInfo);
600     pipelineInputAssemblyStateInfo.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
601     viewportStateCreateInfo.viewportCount   = 1u;
602     viewportStateCreateInfo.scissorCount    = 1u;
603     const auto dummyPipeline                = makeGraphicsPipeline(
604         vk, device, emptyPipelineLayout.get(), dummyVertShaderModule.get(), VK_NULL_HANDLE, VK_NULL_HANDLE,
605         VK_NULL_HANDLE, dummyFragShaderModule.get(), VK_NULL_HANDLE, 0u, &vertexInputStateParams,
606         &pipelineInputAssemblyStateInfo, &tessStateCreateInfo, &viewportStateCreateInfo, DE_NULL, DE_NULL, DE_NULL,
607         DE_NULL, DE_NULL, &pipelineRenderingCreateInfo);
608 
609     const vk::VkClearValue clearValue = vk::makeClearValueColor({0.0f, 0.0f, 0.0f, 1.0f});
610 
611     vk::BufferWithMemory indirectBuffer(
612         vk, device, alloc,
613         vk::makeBufferCreateInfo(sizeof(vk::VkDrawIndirectCommand) + sizeof(vk::VkDrawIndexedIndirectCommand),
614                                  vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
615         vk::MemoryRequirement::HostVisible);
616 
617     if (m_drawType == DRAW_INDEXED_INDIRECT || m_drawType == DRAW_INDEXED_INDIRECT_COUNT)
618     {
619         vk::VkDrawIndexedIndirectCommand *indirectDataPtr =
620             reinterpret_cast<vk::VkDrawIndexedIndirectCommand *>(indirectBuffer.getAllocation().getHostPtr());
621         indirectDataPtr->indexCount    = 4;
622         indirectDataPtr->instanceCount = 1;
623         indirectDataPtr->firstIndex    = 0;
624         indirectDataPtr->vertexOffset  = 0;
625         indirectDataPtr->firstInstance = 0;
626     }
627     else
628     {
629         vk::VkDrawIndirectCommand *indirectDataPtr =
630             reinterpret_cast<vk::VkDrawIndirectCommand *>(indirectBuffer.getAllocation().getHostPtr());
631         indirectDataPtr->vertexCount   = 4;
632         indirectDataPtr->instanceCount = 1;
633         indirectDataPtr->firstVertex   = 0;
634         indirectDataPtr->firstInstance = 0;
635     }
636 
637     vk::BufferWithMemory countBuffer(
638         vk, device, alloc, vk::makeBufferCreateInfo(sizeof(uint32_t), vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
639         vk::MemoryRequirement::HostVisible);
640     uint32_t *countDataPtr = reinterpret_cast<uint32_t *>(countBuffer.getAllocation().getHostPtr());
641     countDataPtr[0]        = 1u;
642 
643     vk::BufferWithMemory indexBuffer(
644         vk, device, alloc, vk::makeBufferCreateInfo(sizeof(uint32_t) * 4, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT),
645         vk::MemoryRequirement::HostVisible);
646     uint32_t *indexDataPtr = reinterpret_cast<uint32_t *>(indexBuffer.getAllocation().getHostPtr());
647     indexDataPtr[0]        = 0u;
648     indexDataPtr[1]        = 1u;
649     indexDataPtr[2]        = 2u;
650     indexDataPtr[3]        = 3u;
651 
652     const vk::VkDeviceSize bufferSize        = 64;
653     de::MovePtr<vk::BufferWithMemory> buffer = de::MovePtr<vk::BufferWithMemory>(new vk::BufferWithMemory(
654         vk, device, alloc, vk::makeBufferCreateInfo(bufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT),
655         vk::MemoryRequirement::HostVisible));
656 
657     // Do a dummy run, to ensure memory allocations are done with before performance testing
658     {
659         vk::beginCommandBuffer(vk, *cmdBuffer, 0u);
660         vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *dummyPipeline);
661         vk::beginRendering(vk, *cmdBuffer, *imageView, renderArea, clearValue, vk::VK_IMAGE_LAYOUT_GENERAL,
662                            vk::VK_ATTACHMENT_LOAD_OP_CLEAR);
663         vk.cmdDraw(*cmdBuffer, 4, 1, 0, 0);
664         vk::endRendering(vk, *cmdBuffer);
665         vk::endCommandBuffer(vk, *cmdBuffer);
666         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
667     }
668 
669     std::chrono::nanoseconds time       = std::chrono::nanoseconds(0);
670     std::chrono::nanoseconds refTime    = std::chrono::nanoseconds(0);
671     std::chrono::nanoseconds maxTime    = std::chrono::nanoseconds(0);
672     std::chrono::nanoseconds maxRefTime = std::chrono::nanoseconds(0);
673 
674     for (uint32_t i = 0; i < 100; ++i)
675     {
676         std::chrono::nanoseconds currentTime;
677         std::chrono::nanoseconds currentRefTime;
678 
679         if (m_type == DRAW_BINARY_BIND)
680         {
681             vk::beginCommandBuffer(vk, *cmdBuffer, 0u);
682             const auto shaderObjectStart = std::chrono::high_resolution_clock::now();
683             vk::bindGraphicsShaders(vk, *cmdBuffer, *vertShader, *tescShader, *teseShader, *geomShader, *fragShader,
684                                     taskSupported, meshSupported);
685             currentTime = std::chrono::high_resolution_clock::now() - shaderObjectStart;
686             vk::endCommandBuffer(vk, *cmdBuffer);
687 
688             vk::beginCommandBuffer(vk, *cmdBuffer, 0u);
689             const auto refShaderObjectStart = std::chrono::high_resolution_clock::now();
690             vk::bindGraphicsShaders(vk, *cmdBuffer, refShaders[0], refShaders[2], refShaders[3], refShaders[4],
691                                     refShaders[1], taskSupported, meshSupported);
692             currentRefTime = std::chrono::high_resolution_clock::now() - refShaderObjectStart;
693             vk::endCommandBuffer(vk, *cmdBuffer);
694         }
695         else
696         {
697             vk::beginCommandBuffer(vk, *cmdBuffer, 0u);
698             vk::bindGraphicsShaders(vk, *cmdBuffer, *vertShader, *tescShader, *teseShader, *geomShader, *fragShader,
699                                     taskSupported, meshSupported);
700             vk::setDefaultShaderObjectDynamicStates(
701                 vk, *cmdBuffer, deviceExtensions, topology, false,
702                 !m_context.getExtendedDynamicStateFeaturesEXT().extendedDynamicState);
703             vk::beginRendering(vk, *cmdBuffer, *imageView, renderArea, clearValue, vk::VK_IMAGE_LAYOUT_GENERAL,
704                                vk::VK_ATTACHMENT_LOAD_OP_CLEAR);
705             currentTime = draw(vk, *cmdBuffer, *indexBuffer, *indirectBuffer, *countBuffer);
706             vk::endRendering(vk, *cmdBuffer);
707             vk::endCommandBuffer(vk, *cmdBuffer);
708             submitCommandsAndWait(vk, device, queue, *cmdBuffer);
709 
710             if (m_type == DRAW_LINKED_SHADERS || m_type == DRAW_BINARY)
711             {
712                 vk::beginCommandBuffer(vk, *cmdBuffer, 0u);
713                 vk::bindGraphicsShaders(vk, *cmdBuffer, refShaders[0], refShaders[2], refShaders[3], refShaders[4],
714                                         refShaders[1], taskSupported, meshSupported);
715                 vk::setDefaultShaderObjectDynamicStates(
716                     vk, *cmdBuffer, deviceExtensions, topology, false,
717                     !m_context.getExtendedDynamicStateFeaturesEXT().extendedDynamicState);
718                 vk::beginRendering(vk, *cmdBuffer, *imageView, renderArea, clearValue, vk::VK_IMAGE_LAYOUT_GENERAL,
719                                    vk::VK_ATTACHMENT_LOAD_OP_CLEAR);
720                 currentRefTime = draw(vk, *cmdBuffer, *indexBuffer, *indirectBuffer, *countBuffer);
721                 vk::endRendering(vk, *cmdBuffer);
722                 vk::endCommandBuffer(vk, *cmdBuffer);
723                 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
724             }
725             else
726             {
727                 vk::beginCommandBuffer(vk, *cmdBuffer, 0u);
728                 vk::VkDeviceSize offset = 0u;
729                 vk::VkDeviceSize stride = 16u;
730                 vk.cmdBindVertexBuffers2(*cmdBuffer, 0u, 1u, &**buffer, &offset, &bufferSize, &stride);
731                 vk::setDefaultShaderObjectDynamicStates(
732                     vk, *cmdBuffer, deviceExtensions, topology, false,
733                     !m_context.getExtendedDynamicStateFeaturesEXT().extendedDynamicState);
734                 vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
735                 vk::beginRendering(vk, *cmdBuffer, *imageView, renderArea, clearValue, vk::VK_IMAGE_LAYOUT_GENERAL,
736                                    vk::VK_ATTACHMENT_LOAD_OP_CLEAR);
737                 currentRefTime = draw(vk, *cmdBuffer, *indexBuffer, *indirectBuffer, *countBuffer);
738                 vk::endRendering(vk, *cmdBuffer);
739                 vk::endCommandBuffer(vk, *cmdBuffer);
740                 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
741             }
742         }
743 
744         time += currentTime;
745         if (currentTime > maxTime)
746             maxTime = currentTime;
747 
748         refTime += currentRefTime;
749         if (currentRefTime > maxRefTime)
750             maxRefTime = currentRefTime;
751     }
752 
753     for (const auto &shader : refShaders)
754         vk.destroyShaderEXT(device, shader, DE_NULL);
755 
756     if (m_type == DRAW_STATIC_PIPELINE)
757     {
758         if (maxTime > maxRefTime * 1.5f)
759             return tcu::TestStatus::fail("Maximum shader object rendering iteration was more than 50% slower than "
760                                          "maximum static pipeline iteration rendering");
761         if (time > refTime * 1.25f)
762             return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING,
763                                    "Shader object rendering was more than 25% slower than static pipeline rendering");
764         if (maxTime > maxRefTime * 1.25f)
765             return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING,
766                                    "Maximum shader object iteration rendering was more than 25% slower than maximum "
767                                    "static pipeline iteration rendering");
768     }
769     else if (m_type == DRAW_DYNAMIC_PIPELINE)
770     {
771         if (maxTime > maxRefTime * 1.2f)
772             return tcu::TestStatus::fail("Maximum shader object iteration rendering was more than 20% slower than "
773                                          "maximum dynamic pipeline iteration rendering");
774         if (time > refTime * 1.1f)
775             return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING,
776                                    "Shader object rendering was more than 10% slower than dynamic pipeline rendering");
777         if (maxTime > maxRefTime * 1.1f)
778             return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING,
779                                    "Maximum shader object iteration rendering was more than 10% slower than maximum "
780                                    "dynamic pipeline iteration rendering");
781     }
782     else if (m_type == DRAW_LINKED_SHADERS)
783     {
784         if (maxTime > maxRefTime * 1.05f)
785             return tcu::TestStatus::fail("Maximum unlinked shader object iteration rendering was more than 5% slower "
786                                          "than maximum linked shader object iteration rendering");
787         if (time * 1.05f < refTime)
788             return tcu::TestStatus::fail(
789                 "Linked shader object rendering was more than 5% slower than unlinked shader object rendering");
790         if (maxTime * 1.05f < maxRefTime)
791             return tcu::TestStatus::fail("Maximum linked shader object iteration rendering was more than 5% slower "
792                                          "than maximum unlinked shader object iteratino rendering");
793     }
794     else if (m_type == DRAW_BINARY)
795     {
796         if (maxTime > maxRefTime * 1.05f)
797             return tcu::TestStatus::fail("Maximum shader object iteration rendering was more than 5% slower than "
798                                          "maximum binary shader object iteration rendering");
799         if (time * 1.05f < refTime)
800             return tcu::TestStatus::fail(
801                 "Binary shader object rendering was more than 5% slower than shader object rendering");
802         if (maxTime * 1.05f < maxRefTime)
803             return tcu::TestStatus::fail("Maximum binary shader object iteration rendering was more than 5% slower "
804                                          "than maximum shader object iteration rendering");
805     }
806     else if (m_type == DRAW_BINARY_BIND)
807     {
808         if (maxTime > maxRefTime * 1.05f)
809             return tcu::TestStatus::fail("Maximum shader object iteration binding was more than 5% slower than maximum "
810                                          "binary shader object iteration binding");
811         if (time * 1.05f < refTime)
812             return tcu::TestStatus::fail(
813                 "Binary shader object binding was more than 5% slower than shader object binding");
814         if (maxTime * 1.05f < maxRefTime)
815             return tcu::TestStatus::fail("Maximum binary shader object iteration binding was more than 5% slower than "
816                                          "maximum shader object iteration binding");
817     }
818 
819     return tcu::TestStatus::pass("Pass");
820 }
821 
822 class ShaderObjectPerformanceCase : public vkt::TestCase
823 {
824 public:
ShaderObjectPerformanceCase(tcu::TestContext & testCtx,const std::string & name,const DrawType drawType,const TestType & type)825     ShaderObjectPerformanceCase(tcu::TestContext &testCtx, const std::string &name, const DrawType drawType,
826                                 const TestType &type)
827         : vkt::TestCase(testCtx, name)
828         , m_drawType(drawType)
829         , m_type(type)
830     {
831     }
~ShaderObjectPerformanceCase(void)832     virtual ~ShaderObjectPerformanceCase(void)
833     {
834     }
835 
836     void checkSupport(vkt::Context &context) const override;
837     virtual void initPrograms(vk::SourceCollections &programCollection) const override;
createInstance(Context & context) const838     TestInstance *createInstance(Context &context) const override
839     {
840         return new ShaderObjectPerformanceInstance(context, m_drawType, m_type);
841     }
842 
843 private:
844     DrawType m_drawType;
845     TestType m_type;
846 };
847 
checkSupport(Context & context) const848 void ShaderObjectPerformanceCase::checkSupport(Context &context) const
849 {
850     context.requireDeviceFunctionality("VK_EXT_shader_object");
851 }
852 
initPrograms(vk::SourceCollections & programCollection) const853 void ShaderObjectPerformanceCase::initPrograms(vk::SourceCollections &programCollection) const
854 {
855     vk::addBasicShaderObjectShaders(programCollection);
856 
857     std::stringstream dummyVert;
858     std::stringstream dummyFrag;
859 
860     dummyVert << "#version 450\n"
861               << "layout(location = 0) out vec4 rgba;\n"
862               << "void main() {\n"
863               << "    vec2 pos2 = vec2(float(gl_VertexIndex & 1), float((gl_VertexIndex >> 1) & 1));\n"
864               << "    vec3 pos3 = vec3(pos2, 0.0f) * gl_InstanceIndex;\n"
865               << "    gl_Position = vec4(pos3, 1.0f);\n"
866               << "    rgba = vec4(0.0f, pos3.zyx);\n"
867               << "}\n";
868 
869     dummyFrag << "#version 450\n"
870               << "layout(location = 0) in vec4 rgba;\n"
871               << "layout(location = 0) out vec4 color;\n"
872               << "void main() {\n"
873               << "    color = rgba * rgba;\n"
874               << "}\n";
875 
876     programCollection.glslSources.add("dummyVert") << glu::VertexSource(dummyVert.str());
877     programCollection.glslSources.add("dummyFrag") << glu::FragmentSource(dummyFrag.str());
878 }
879 
880 class ShaderObjectDispatchPerformanceInstance : public vkt::TestInstance
881 {
882 public:
ShaderObjectDispatchPerformanceInstance(Context & context,const DispatchType dispatchType)883     ShaderObjectDispatchPerformanceInstance(Context &context, const DispatchType dispatchType)
884         : vkt::TestInstance(context)
885         , m_dispatchType(dispatchType)
886     {
887     }
~ShaderObjectDispatchPerformanceInstance(void)888     virtual ~ShaderObjectDispatchPerformanceInstance(void)
889     {
890     }
891 
892     tcu::TestStatus iterate(void) override;
893 
894 private:
895     const DispatchType m_dispatchType;
896 };
897 
iterate(void)898 tcu::TestStatus ShaderObjectDispatchPerformanceInstance::iterate(void)
899 {
900     const vk::DeviceInterface &vk   = m_context.getDeviceInterface();
901     const vk::VkDevice device       = m_context.getDevice();
902     const vk::VkQueue queue         = m_context.getUniversalQueue();
903     const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
904     auto &alloc                     = m_context.getDefaultAllocator();
905 
906     const vk::VkDeviceSize bufferSizeBytes = sizeof(uint32_t) * 16;
907     const vk::BufferWithMemory outputBuffer(
908         vk, device, alloc, vk::makeBufferCreateInfo(bufferSizeBytes, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT),
909         vk::MemoryRequirement::HostVisible);
910     const bool tessellationSupported = m_context.getDeviceFeatures().tessellationShader;
911     const bool geometrySupported     = m_context.getDeviceFeatures().geometryShader;
912 
913     const auto &binaries = m_context.getBinaryCollection();
914 
915     const auto &comp            = binaries.get("comp");
916     const auto compShaderModule = createShaderModule(vk, device, comp);
917 
918     const vk::Unique<vk::VkDescriptorSetLayout> descriptorSetLayout(
919         vk::DescriptorSetLayoutBuilder()
920             .addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT)
921             .build(vk, device));
922 
923     const vk::Unique<vk::VkDescriptorPool> descriptorPool(
924         vk::DescriptorPoolBuilder()
925             .addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
926             .build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
927     const auto pipelineLayout = makePipelineLayout(vk, device, descriptorSetLayout.get());
928 
929     const vk::Unique<vk::VkDescriptorSet> descriptorSet(
930         makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
931     const vk::VkDescriptorBufferInfo descriptorInfo =
932         vk::makeDescriptorBufferInfo(*outputBuffer, 0ull, bufferSizeBytes);
933     vk::DescriptorSetUpdateBuilder()
934         .writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u),
935                      vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descriptorInfo)
936         .update(vk, device);
937 
938     vk::VkShaderCreateInfoEXT shaderCreateInfo =
939         vk::makeShaderCreateInfo(vk::VK_SHADER_STAGE_COMPUTE_BIT, binaries.get("comp"), tessellationSupported,
940                                  geometrySupported, &*descriptorSetLayout);
941     if (m_dispatchType == DISPATCH_BASE)
942         shaderCreateInfo.flags |= vk::VK_SHADER_CREATE_DISPATCH_BASE_BIT_EXT;
943 
944     const auto compShader = vk::createShader(vk, device, shaderCreateInfo);
945     const vk::VkPipelineCreateFlags pipelineFlags =
946         (m_dispatchType == DISPATCH) ? (vk::VkPipelineCreateFlags)0u :
947                                        (vk::VkPipelineCreateFlags)vk::VK_PIPELINE_CREATE_DISPATCH_BASE_BIT;
948     const auto computePipeline =
949         vk::makeComputePipeline(vk, device, pipelineLayout.get(), pipelineFlags, nullptr, compShaderModule.get(),
950                                 (vk::VkPipelineShaderStageCreateFlags)0u);
951 
952     const vk::Move<vk::VkCommandPool> cmdPool(
953         createCommandPool(vk, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
954     const vk::Move<vk::VkCommandBuffer> cmdBuffer(
955         allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
956 
957     vk::BufferWithMemory indirectBuffer(
958         vk, device, alloc,
959         vk::makeBufferCreateInfo(sizeof(vk::VkDispatchIndirectCommand), vk::VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT),
960         vk::MemoryRequirement::HostVisible);
961 
962     vk::VkDispatchIndirectCommand *indirectDataPtr =
963         reinterpret_cast<vk::VkDispatchIndirectCommand *>(indirectBuffer.getAllocation().getHostPtr());
964     indirectDataPtr->x = 1;
965     indirectDataPtr->y = 1;
966     indirectDataPtr->z = 1;
967 
968     std::chrono::nanoseconds time    = std::chrono::nanoseconds(0);
969     std::chrono::nanoseconds refTime = std::chrono::nanoseconds(0);
970 
971     for (uint32_t i = 0; i < 100; ++i)
972     {
973         vk::beginCommandBuffer(vk, *cmdBuffer, 0u);
974         vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout.get(), 0, 1,
975                                  &descriptorSet.get(), 0, DE_NULL);
976         vk::bindComputeShader(vk, *cmdBuffer, *compShader);
977         if (m_dispatchType == DISPATCH)
978         {
979             const auto shaderObjectStart = std::chrono::high_resolution_clock::now();
980             vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
981             time += std::chrono::high_resolution_clock::now() - shaderObjectStart;
982         }
983         else if (m_dispatchType == DISPATCH_BASE)
984         {
985             const auto shaderObjectStart = std::chrono::high_resolution_clock::now();
986             vk.cmdDispatchBase(*cmdBuffer, 1, 1, 1, 0, 0, 0);
987             time += std::chrono::high_resolution_clock::now() - shaderObjectStart;
988         }
989         else if (m_dispatchType == DISPATCH_INDIRECT)
990         {
991             const auto shaderObjectStart = std::chrono::high_resolution_clock::now();
992             vk.cmdDispatchIndirect(*cmdBuffer, *indirectBuffer, 0u);
993             time += std::chrono::high_resolution_clock::now() - shaderObjectStart;
994         }
995         vk::endCommandBuffer(vk, *cmdBuffer);
996         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
997 
998         vk::beginCommandBuffer(vk, *cmdBuffer, 0u);
999         vk.cmdBindDescriptorSets(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout.get(), 0, 1,
1000                                  &descriptorSet.get(), 0, DE_NULL);
1001         vk.cmdBindPipeline(*cmdBuffer, vk::VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
1002         if (m_dispatchType == DISPATCH)
1003         {
1004             const auto pipelineStart = std::chrono::high_resolution_clock::now();
1005             vk.cmdDispatch(*cmdBuffer, 1, 1, 1);
1006             refTime += std::chrono::high_resolution_clock::now() - pipelineStart;
1007         }
1008         else if (m_dispatchType == DISPATCH_BASE)
1009         {
1010             const auto pipelineStart = std::chrono::high_resolution_clock::now();
1011             vk.cmdDispatchBase(*cmdBuffer, 1, 1, 1, 0, 0, 0);
1012             refTime += std::chrono::high_resolution_clock::now() - pipelineStart;
1013         }
1014         else if (m_dispatchType == DISPATCH_INDIRECT)
1015         {
1016             const auto pipelineStart = std::chrono::high_resolution_clock::now();
1017             vk.cmdDispatchIndirect(*cmdBuffer, *indirectBuffer, 0u);
1018             refTime += std::chrono::high_resolution_clock::now() - pipelineStart;
1019         }
1020         vk::endCommandBuffer(vk, *cmdBuffer);
1021         submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1022 
1023         // Ignore first iteration, there is a penalty on the first call
1024         if (i == 0)
1025         {
1026             time    = std::chrono::nanoseconds(0);
1027             refTime = std::chrono::nanoseconds(0);
1028         }
1029     }
1030 
1031     if (time > refTime * 1.05f)
1032         return tcu::TestStatus::fail("Shader object dispatch was more than 5% slower than compute pipeline dispatch");
1033     return tcu::TestStatus::pass("Pass");
1034 }
1035 
1036 class ShaderObjectDispatchPerformanceCase : public vkt::TestCase
1037 {
1038 public:
ShaderObjectDispatchPerformanceCase(tcu::TestContext & testCtx,const std::string & name,const DispatchType dispatchType)1039     ShaderObjectDispatchPerformanceCase(tcu::TestContext &testCtx, const std::string &name,
1040                                         const DispatchType dispatchType)
1041         : vkt::TestCase(testCtx, name)
1042         , m_dispatchType(dispatchType)
1043     {
1044     }
~ShaderObjectDispatchPerformanceCase(void)1045     virtual ~ShaderObjectDispatchPerformanceCase(void)
1046     {
1047     }
1048 
1049     void checkSupport(vkt::Context &context) const override;
1050     virtual void initPrograms(vk::SourceCollections &programCollection) const override;
createInstance(Context & context) const1051     TestInstance *createInstance(Context &context) const override
1052     {
1053         return new ShaderObjectDispatchPerformanceInstance(context, m_dispatchType);
1054     }
1055 
1056 private:
1057     const DispatchType m_dispatchType;
1058 };
1059 
checkSupport(Context & context) const1060 void ShaderObjectDispatchPerformanceCase::checkSupport(Context &context) const
1061 {
1062     context.requireDeviceFunctionality("VK_EXT_shader_object");
1063 }
1064 
initPrograms(vk::SourceCollections & programCollection) const1065 void ShaderObjectDispatchPerformanceCase::initPrograms(vk::SourceCollections &programCollection) const
1066 {
1067     vk::addBasicShaderObjectShaders(programCollection);
1068 }
1069 
1070 class ShaderObjectBinaryPerformanceInstance : public vkt::TestInstance
1071 {
1072 public:
ShaderObjectBinaryPerformanceInstance(Context & context,BinaryType type)1073     ShaderObjectBinaryPerformanceInstance(Context &context, BinaryType type) : vkt::TestInstance(context), m_type(type)
1074     {
1075     }
~ShaderObjectBinaryPerformanceInstance(void)1076     virtual ~ShaderObjectBinaryPerformanceInstance(void)
1077     {
1078     }
1079 
1080     tcu::TestStatus iterate(void) override;
1081 
1082 private:
1083     const BinaryType m_type;
1084 };
1085 
iterate(void)1086 tcu::TestStatus ShaderObjectBinaryPerformanceInstance::iterate(void)
1087 {
1088     const vk::DeviceInterface &vk    = m_context.getDeviceInterface();
1089     const vk::VkDevice device        = m_context.getDevice();
1090     auto &alloc                      = m_context.getDefaultAllocator();
1091     const bool tessellationSupported = m_context.getDeviceFeatures().tessellationShader;
1092     const bool geometrySupported     = m_context.getDeviceFeatures().geometryShader;
1093 
1094     const auto &binaries = m_context.getBinaryCollection();
1095 
1096     std::chrono::nanoseconds time    = std::chrono::nanoseconds(0);
1097     std::chrono::nanoseconds refTime = std::chrono::nanoseconds(0);
1098 
1099     for (uint32_t i = 0; i < 100; ++i)
1100     {
1101         const auto spirvCreateInfo = vk::makeShaderCreateInfo(vk::VK_SHADER_STAGE_VERTEX_BIT, binaries.get("vert"),
1102                                                               tessellationSupported, geometrySupported);
1103         vk::VkShaderEXT spirvShader;
1104         const auto spirvStart = std::chrono::high_resolution_clock::now();
1105         vk.createShadersEXT(device, 1u, &spirvCreateInfo, DE_NULL, &spirvShader);
1106         const auto spirvEnd = std::chrono::high_resolution_clock::now();
1107         if (m_type == BINARY_SHADER_CREATE)
1108             refTime += spirvEnd - spirvStart;
1109 
1110         size_t dataSize = 0;
1111         vk.getShaderBinaryDataEXT(device, spirvShader, &dataSize, DE_NULL);
1112         std::vector<uint8_t> data(dataSize);
1113         vk.getShaderBinaryDataEXT(device, spirvShader, &dataSize, data.data());
1114 
1115         const vk::VkShaderCreateInfoEXT binaryShaderCreateInfo = {
1116             vk::VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT, // VkStructureType sType;
1117             DE_NULL,                                      // const void* pNext;
1118             0u,                                           // VkShaderCreateFlagsEXT flags;
1119             vk::VK_SHADER_STAGE_VERTEX_BIT,               // VkShaderStageFlagBits stage;
1120             0u,                                           // VkShaderStageFlags nextStage;
1121             vk::VK_SHADER_CODE_TYPE_BINARY_EXT,           // VkShaderCodeTypeEXT codeType;
1122             dataSize,                                     // size_t codeSize;
1123             data.data(),                                  // const void* pCode;
1124             "main",                                       // const char* pName;
1125             0u,                                           // uint32_t setLayoutCount;
1126             DE_NULL,                                      // VkDescriptorSetLayout* pSetLayouts;
1127             0u,                                           // uint32_t pushConstantRangeCount;
1128             DE_NULL,                                      // const VkPushConstantRange* pPushConstantRanges;
1129             DE_NULL,                                      // const VkSpecializationInfo* pSpecializationInfo;
1130         };
1131 
1132         vk::VkShaderEXT binaryShader;
1133         const auto binaryStart = std::chrono::high_resolution_clock::now();
1134         vk.createShadersEXT(device, 1, &binaryShaderCreateInfo, DE_NULL, &binaryShader);
1135         time += std::chrono::high_resolution_clock::now() - binaryStart;
1136 
1137         const auto bufferCreateInfo   = vk::makeBufferCreateInfo(dataSize, vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
1138         vk::Move<vk::VkBuffer> buffer = vk::createBuffer(vk, device, &bufferCreateInfo);
1139         const auto bufferMemReqs      = vk::getBufferMemoryRequirements(vk, device, *buffer);
1140         const auto memoryProperties =
1141             vk::getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice());
1142         const auto hostCachedDeviceLocal =
1143             bufferMemReqs.memoryTypeBits &
1144             vk::getCompatibleMemoryTypes(memoryProperties, vk::MemoryRequirement::Cached |
1145                                                                vk::MemoryRequirement::Local |
1146                                                                vk::MemoryRequirement::HostVisible);
1147 
1148         vk::MemoryRequirement memoryRequirements =
1149             (hostCachedDeviceLocal != 0) ?
1150                 vk::MemoryRequirement::Cached | vk::MemoryRequirement::Local | vk::MemoryRequirement::HostVisible :
1151                 vk::MemoryRequirement::Coherent | vk::MemoryRequirement::Local | vk::MemoryRequirement::HostVisible;
1152         vk::BufferWithMemory bufferWithMemory(vk, device, alloc, bufferCreateInfo, memoryRequirements);
1153         const vk::Allocation &bufferAlloc = bufferWithMemory.getAllocation();
1154         const auto memcpyStart            = std::chrono::high_resolution_clock::now();
1155         memcpy(bufferAlloc.getHostPtr(), data.data(), dataSize);
1156         flushAlloc(vk, device, bufferAlloc);
1157         const auto memcpyEnd = std::chrono::high_resolution_clock::now();
1158         if (m_type == BINARY_MEMCPY)
1159             refTime += memcpyEnd - memcpyStart;
1160 
1161         vk.destroyShaderEXT(device, spirvShader, DE_NULL);
1162         vk.destroyShaderEXT(device, binaryShader, DE_NULL);
1163     }
1164 
1165     if (m_type == BINARY_SHADER_CREATE)
1166     {
1167         if (time > refTime * 1.05f)
1168             return tcu::TestStatus::fail(
1169                 "Binary shader object create time is more than 5% slower than spirv shader object create time");
1170     }
1171     else if (m_type == BINARY_MEMCPY)
1172     {
1173         if (time > refTime * 1.5f)
1174             return tcu::TestStatus::fail(
1175                 "Binary shader object create time is more than 50% slower than memcpy of an equal amount of data");
1176     }
1177 
1178     return tcu::TestStatus::pass("Pass");
1179 }
1180 
1181 class ShaderObjectBinaryPerformanceCase : public vkt::TestCase
1182 {
1183 public:
ShaderObjectBinaryPerformanceCase(tcu::TestContext & testCtx,const std::string & name,BinaryType type)1184     ShaderObjectBinaryPerformanceCase(tcu::TestContext &testCtx, const std::string &name, BinaryType type)
1185         : vkt::TestCase(testCtx, name)
1186         , m_type(type)
1187     {
1188     }
~ShaderObjectBinaryPerformanceCase(void)1189     virtual ~ShaderObjectBinaryPerformanceCase(void)
1190     {
1191     }
1192 
1193     void checkSupport(vkt::Context &context) const override;
1194     virtual void initPrograms(vk::SourceCollections &programCollection) const override;
createInstance(Context & context) const1195     TestInstance *createInstance(Context &context) const override
1196     {
1197         return new ShaderObjectBinaryPerformanceInstance(context, m_type);
1198     }
1199 
1200 private:
1201     const BinaryType m_type;
1202 };
1203 
checkSupport(Context & context) const1204 void ShaderObjectBinaryPerformanceCase::checkSupport(Context &context) const
1205 {
1206     context.requireDeviceFunctionality("VK_EXT_shader_object");
1207 }
1208 
initPrograms(vk::SourceCollections & programCollection) const1209 void ShaderObjectBinaryPerformanceCase::initPrograms(vk::SourceCollections &programCollection) const
1210 {
1211     vk::addBasicShaderObjectShaders(programCollection);
1212 }
1213 
1214 } // namespace
1215 
createShaderObjectPerformanceTests(tcu::TestContext & testCtx)1216 tcu::TestCaseGroup *createShaderObjectPerformanceTests(tcu::TestContext &testCtx)
1217 {
1218     de::MovePtr<tcu::TestCaseGroup> performanceGroup(new tcu::TestCaseGroup(testCtx, "performance"));
1219 
1220     const struct
1221     {
1222         DrawType drawType;
1223         const char *name;
1224     } drawTypeTests[] = {
1225         {DRAW, "draw"},
1226         {DRAW_INDEXED, "draw_indexed"},
1227         {DRAW_INDEXED_INDIRECT, "draw_indexed_indirect"},
1228         {DRAW_INDEXED_INDIRECT_COUNT, "draw_indexed_indirect_count"},
1229         {DRAW_INDIRECT, "draw_indirect"},
1230         {DRAW_INDIRECT_COUNT, "draw_indirect_count"},
1231     };
1232 
1233     const struct
1234     {
1235         TestType testTpye;
1236         const char *name;
1237     } typeTests[] = {
1238         {DRAW_STATIC_PIPELINE, "static_pipeline"},
1239         {DRAW_DYNAMIC_PIPELINE, "dynamic_pipeline"},
1240         {DRAW_LINKED_SHADERS, "linked_shaders"},
1241         {DRAW_BINARY, "binary_shaders"},
1242     };
1243 
1244     for (const auto &drawType : drawTypeTests)
1245     {
1246         for (const auto &typeTest : typeTests)
1247         {
1248             performanceGroup->addChild(
1249                 new ShaderObjectPerformanceCase(testCtx, std::string(drawType.name) + "_" + std::string(typeTest.name),
1250                                                 drawType.drawType, typeTest.testTpye));
1251         }
1252     }
1253     performanceGroup->addChild(new ShaderObjectPerformanceCase(testCtx, "binary_bind_shaders", DRAW, DRAW_BINARY_BIND));
1254 
1255     performanceGroup->addChild(new ShaderObjectDispatchPerformanceCase(testCtx, "dispatch", DISPATCH));
1256     performanceGroup->addChild(new ShaderObjectDispatchPerformanceCase(testCtx, "dispatch_base", DISPATCH_BASE));
1257     performanceGroup->addChild(
1258         new ShaderObjectDispatchPerformanceCase(testCtx, "dispatch_indirect", DISPATCH_INDIRECT));
1259 
1260     performanceGroup->addChild(
1261         new ShaderObjectBinaryPerformanceCase(testCtx, "binary_shader_create", BINARY_SHADER_CREATE));
1262     performanceGroup->addChild(new ShaderObjectBinaryPerformanceCase(testCtx, "binary_memcpy", BINARY_MEMCPY));
1263 
1264     return performanceGroup.release();
1265 }
1266 
1267 } // namespace ShaderObject
1268 } // namespace vkt
1269