Commit 180c2b67 authored by Bas Nieuwenhuizen's avatar Bas Nieuwenhuizen
Browse files

Add a recording bench using a dynamic uniform buffer.

For recording CPU performance.
parent c4b04481
......@@ -27,3 +27,5 @@ executable('buffer_copy_bench', ['src/buffer_copy_bench.cpp', 'src/framework.cpp
executable('image_store_bench', ['src/image_store_bench.cpp', 'src/framework.cpp'], dependencies: [vulkan])
executable('bg3_image_test', ['src/bg3_image_test.cpp', 'src/framework.cpp'], dependencies: [vulkan])
executable('recording_bench', ['src/recording_bench.cpp', 'src/framework.cpp'], dependencies: [vulkan])
/*
* Copyright © 2020 Bas Nieuwenhuizen
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "framework.h"
#include <stdio.h>
#include <time.h>
static double gettime() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec + ts.tv_nsec/1e9;
}
int main() {
Device dev;
VkResult result;
const VkDescriptorSetLayoutBinding bindings[] = {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
.stageFlags =
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
},
{
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
.descriptorCount = 1,
.stageFlags =
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
}};
const VkDescriptorSetLayoutCreateInfo ds_layout_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 2,
.pBindings = bindings};
VkDescriptorSetLayout ds_layout;
result =
vkCreateDescriptorSetLayout(dev.dev(), &ds_layout_info, NULL, &ds_layout);
if (result != VK_SUCCESS)
throw -1;
VkPipelineLayout pl;
const VkPipelineLayoutCreateInfo pl_create_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 1,
.pSetLayouts = &ds_layout,
.pushConstantRangeCount = 0,
};
result = vkCreatePipelineLayout(dev.dev(), &pl_create_info, nullptr, &pl);
if (result != VK_SUCCESS)
throw -1;
VkDescriptorPoolSize ds_pool_sizes[] = {
{VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 128},
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 128},
{VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 128},
{VK_DESCRIPTOR_TYPE_SAMPLER, 128},
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 128},
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 128},
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 128},
};
VkDescriptorPoolCreateInfo ds_pool_create_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.maxSets = 128,
.poolSizeCount = 6,
.pPoolSizes = ds_pool_sizes};
VkDescriptorPool ds_pool;
result =
vkCreateDescriptorPool(dev.dev(), &ds_pool_create_info, NULL, &ds_pool);
if (result != VK_SUCCESS)
throw -1;
const VkAttachmentDescription attachment_info = {
.format = VK_FORMAT_R8G8B8A8_UNORM,
.samples = VK_SAMPLE_COUNT_1_BIT,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
};
const VkAttachmentReference color_attach_info = {
.attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
const VkSubpassDescription subpass_info = {
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.colorAttachmentCount = 1,
.pColorAttachments = &color_attach_info,
};
const VkRenderPassCreateInfo rp_info = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.attachmentCount = 1,
.pAttachments = &attachment_info,
.subpassCount = 1,
.pSubpasses = &subpass_info,
};
VkRenderPass rp = VK_NULL_HANDLE;
result = vkCreateRenderPass(dev.dev(), &rp_info, nullptr, &rp);
if (result != VK_SUCCESS)
throw -1;
const int width = 1920;
const int height = 1020;
const VkImageCreateInfo img_create_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
.format = VK_FORMAT_R8G8B8A8_UNORM,
.extent = {width, height, 1},
.mipLevels = 1,
.arrayLayers = 1,
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
};
Image image1(dev, img_create_info, Access::gpu);
Image image2(dev, img_create_info, Access::gpu);
auto view = image1.view();
const VkFramebufferCreateInfo framebuffer_info = {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.renderPass = rp,
.attachmentCount = 1,
.pAttachments = &view,
.width = width,
.height = height,
.layers = 1,
};
VkFramebuffer fb1, fb2;
result = vkCreateFramebuffer(dev.dev(), &framebuffer_info, nullptr, &fb1);
if (result != VK_SUCCESS)
throw -1;
view = image2.view();
result = vkCreateFramebuffer(dev.dev(), &framebuffer_info, nullptr, &fb2);
if (result != VK_SUCCESS)
throw -1;
auto vs = dev.compile_shader(VK_SHADER_STAGE_VERTEX_BIT, R"(
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (location = 0) in vec4 vin;
layout (binding = 0) uniform UBO0
{
vec4 pos;
} ubo0;
layout (binding = 1) uniform UBO1
{
vec4 pos;
} ubo1;
out gl_PerVertex {
vec4 gl_Position;
};
void main()
{
gl_Position = vin + ubo0.pos + ubo1.pos;
}
)");
auto fs_initial = dev.compile_shader(VK_SHADER_STAGE_FRAGMENT_BIT, R"(
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (location = 0) out vec4 outFragColor;
void main()
{
outFragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
)");
VkPipelineShaderStageCreateInfo stages[2] = {
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.module = vs,
.pName = "main",
},
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.module = fs_initial,
.pName = "main",
},
};
const VkVertexInputBindingDescription binding_info = {
.binding = 0,
.stride = 8,
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
};
const VkVertexInputAttributeDescription attrib_info = {
.location = 0,
.binding = 0,
.format = VK_FORMAT_R16G16B16A16_SFLOAT,
.offset = 0,
};
const VkPipelineVertexInputStateCreateInfo vertex_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = &binding_info,
.vertexAttributeDescriptionCount= 1,
.pVertexAttributeDescriptions = &attrib_info,
};
const VkPipelineInputAssemblyStateCreateInfo assembly_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
};
VkViewport viewport = {0, 0, width, height, 0.0, 1.0};
VkRect2D scissor = {{0, 0}, {width, height}};
const VkPipelineViewportStateCreateInfo viewport_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 1,
.pViewports = &viewport,
.scissorCount = 1,
.pScissors = &scissor,
};
const VkPipelineRasterizationStateCreateInfo rasterization_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.polygonMode = VK_POLYGON_MODE_FILL,
.cullMode = VK_CULL_MODE_NONE,
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
};
const VkPipelineDynamicStateCreateInfo dynamic_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
};
const VkPipelineColorBlendAttachmentState attachment_blend_info = {};
const VkPipelineColorBlendStateCreateInfo blend_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.attachmentCount = 1,
.pAttachments = &attachment_blend_info,
};
VkGraphicsPipelineCreateInfo pipeline_info = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.stageCount = 2,
.pStages = stages,
.pVertexInputState = &vertex_info,
.pInputAssemblyState = &assembly_info,
.pViewportState = &viewport_info,
.pRasterizationState = &rasterization_info,
.pColorBlendState = &blend_info,
.pDynamicState = &dynamic_info,
.layout = pl,
.renderPass = rp,
.subpass = 0,
};
VkPipeline pipeline;
result = vkCreateGraphicsPipelines(dev.dev(), VK_NULL_HANDLE, 1,
&pipeline_info, nullptr, &pipeline);
if (result != VK_SUCCESS)
throw -1;
Buffer fixed_buf(dev, 2 * 1024 * 1024, Access::gpu);
Buffer dynamic_buf(dev, 2 * 1024 * 1024, Access::gpu);
Buffer index_buf(dev, 2 * 1024 * 1024, Access::gpu);
Buffer vertex_buf(dev, 2 * 1024 * 1024, Access::gpu);
VkDescriptorSetAllocateInfo ds_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.descriptorPool = ds_pool,
.descriptorSetCount = 1,
.pSetLayouts = &ds_layout,
};
VkDescriptorSet ds;
result = vkAllocateDescriptorSets(dev.dev(), &ds_info, &ds);
if (result != VK_SUCCESS)
throw -1;
VkDescriptorBufferInfo buffer_info[] = {
{.buffer = fixed_buf.buffer(), .offset = 0, .range = 2 * 1024 * 1024},
{.buffer = dynamic_buf.buffer(), .offset = 0, .range = 4096},
};
VkWriteDescriptorSet ds_writes[] = {
{.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = ds,
.dstBinding = 1,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.pBufferInfo = &buffer_info[0]},
{.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = ds,
.dstBinding = 1,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
.pBufferInfo = &buffer_info[1]}};
vkUpdateDescriptorSets(dev.dev(), 2, ds_writes, 0, NULL);
VkCommandBuffer cmd_buf = create_cmdbuf(dev, dev.gfx_pool());
const unsigned num_iters = 5000;
double ta = gettime();
for (unsigned i = 0; i < num_iters; ++i) {
const unsigned num_passes = 20;
const unsigned num_draws_per_pass[4] = {100, 1000, 10, 1};
const VkCommandBufferBeginInfo begin_info = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
vkBeginCommandBuffer(cmd_buf, &begin_info);
vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
unsigned didx = 0;
for (unsigned p = 0; p < num_passes; ++p) {
VkClearValue clear_value = {{{0.0, 0.0, 0.0, 1.0}}};
const VkRenderPassBeginInfo rp_begin_info = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = rp,
.framebuffer = (p & 1) ? fb2 : fb1,
.clearValueCount = 1,
.pClearValues = &clear_value};
vkCmdBeginRenderPass(cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE);
const unsigned num_draws = num_draws_per_pass[p & 3];
for (unsigned d = 0; d < num_draws; ++d, ++didx) {
uint32_t ubo_offset = 4096 * didx;
vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, pl, 0, 1, &ds, 1, &ubo_offset);
if ((d & 1) == 0) {
auto buf = vertex_buf.buffer();
VkDeviceSize vbo_size = d * 4096;
vkCmdBindIndexBuffer(cmd_buf, index_buf.buffer(), 4096 * d, VK_INDEX_TYPE_UINT32);
vkCmdBindVertexBuffers(cmd_buf, 0, 1, &buf, &vbo_size);
}
vkCmdDrawIndexed(cmd_buf, 120, 1, 0, 0, 0);
}
vkCmdEndRenderPass(cmd_buf);
}
if (vkEndCommandBuffer(cmd_buf) != VK_SUCCESS)
throw -1;
}
double tb = gettime();
fprintf(stdout, "time/cmdbuffers: %f us\n",(tb - ta) * 1e6 / num_iters);
return 0;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment