| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <unistd.h> |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "src/graphics/examples/vkproto/common/command_buffers.h" |
| #include "src/graphics/examples/vkproto/common/command_pool.h" |
| #include "src/graphics/examples/vkproto/common/debug_utils_messenger.h" |
| #include "src/graphics/examples/vkproto/common/device.h" |
| #include "src/graphics/examples/vkproto/common/framebuffers.h" |
| #include "src/graphics/examples/vkproto/common/graphics_pipeline.h" |
| #include "src/graphics/examples/vkproto/common/image_view.h" |
| #include "src/graphics/examples/vkproto/common/instance.h" |
| #include "src/graphics/examples/vkproto/common/physical_device.h" |
| #include "src/graphics/examples/vkproto/common/render_pass.h" |
| #include "src/graphics/examples/vkproto/common/utils.h" |
| |
| #include <vulkan/vulkan.hpp> |
| |
| static bool DrawAllFrames(const vkp::Device& vkp_device, |
| const vkp::CommandBuffers& vkp_command_buffers); |
| |
| int main(int argc, char* argv[]) { |
| // INSTANCE |
| #ifndef NDEBUG |
| printf("Warning - benchmarking debug build.\n"); |
| const bool kEnableValidation = true; |
| #else |
| const bool kEnableValidation = false; |
| #endif |
| vkp::Instance vkp_instance(vkp::Instance::Builder() |
| .set_validation_layers_enabled(kEnableValidation) |
| .set_swapchain_enabled(false) |
| .Build()); |
| RTN_IF_MSG(1, !vkp_instance.initialized(), "Instance Initialization Failed.\n"); |
| |
| // DEBUG UTILS MESSENGER |
| if (kEnableValidation) { |
| vkp::DebugUtilsMessenger vkp_debug_messenger(vkp_instance.shared()); |
| RTN_IF_MSG(1, !vkp_debug_messenger.Init(), "Debug Messenger Initialization Failed.\n"); |
| } |
| |
| // PHYSICAL DEVICE |
| vkp::PhysicalDevice vkp_physical_device(vkp_instance.shared()); |
| vkp_physical_device.set_swapchain_enabled(false); |
| RTN_IF_MSG(1, !vkp_physical_device.Init(), "Phys Device Initialization Failed.\n"); |
| |
| // LOGICAL DEVICE |
| vkp::Device vkp_device(vkp_physical_device.get()); |
| vkp_device.set_swapchain_enabled(false); |
| RTN_IF_MSG(1, !vkp_device.Init(), "Logical Device Initialization Failed.\n"); |
| std::shared_ptr<vk::Device> device = vkp_device.shared(); |
| |
| vk::Format image_format; |
| vk::Extent2D extent; |
| |
| // The number of image views added in either the offscreen or onscreen logic blocks |
| // below controls the number of framebuffers, command buffers, fences and signalling |
| // semaphores created subsequently. |
| std::vector<std::shared_ptr<vkp::ImageView>> vkp_image_views; |
| std::vector<vk::ImageView> image_views; |
| constexpr uint32_t kCommandBufferCount = 100; |
| for (uint32_t i = 0; i < kCommandBufferCount; i++) { |
| // IMAGE VIEW |
| auto vkp_offscreen_image_view = |
| std::make_shared<vkp::ImageView>(device, vkp_physical_device.get(), vk::Extent2D{64, 64}); |
| |
| RTN_IF_MSG(1, !vkp_offscreen_image_view->Init(), "Image View Initialization Failed.\n"); |
| image_format = vkp_offscreen_image_view->format(); |
| extent = vkp_offscreen_image_view->extent(); |
| image_views.emplace_back(vkp_offscreen_image_view->get()); |
| vkp_image_views.emplace_back(std::move(vkp_offscreen_image_view)); |
| } |
| |
| // RENDER PASS |
| auto vkp_render_pass = std::make_shared<vkp::RenderPass>(device, image_format, true); |
| RTN_IF_MSG(1, !vkp_render_pass->Init(), "Render Pass Initialization Failed.\n"); |
| |
| // GRAPHICS PIPELINE |
| auto vkp_pipeline = std::make_unique<vkp::GraphicsPipeline>(device, extent, vkp_render_pass); |
| RTN_IF_MSG(1, !vkp_pipeline->Init(), "Graphics Pipeline Initialization Failed.\n"); |
| |
| // FRAMEBUFFER |
| auto vkp_framebuffer = |
| std::make_unique<vkp::Framebuffers>(device, extent, vkp_render_pass->get(), image_views); |
| RTN_IF_MSG(1, !vkp_framebuffer->Init(), "Framebuffers Initialization Failed.\n"); |
| |
| // COMMAND POOL |
| auto vkp_command_pool = |
| std::make_shared<vkp::CommandPool>(device, vkp_device.queue_family_index()); |
| RTN_IF_MSG(1, !vkp_command_pool->Init(), "Command Pool Initialization Failed.\n"); |
| |
| // COMMAND BUFFER |
| auto vkp_command_buffers = std::make_unique<vkp::CommandBuffers>( |
| device, vkp_command_pool, vkp_framebuffer->framebuffers(), vkp_pipeline->get(), |
| vkp_render_pass->get(), extent); |
| RTN_IF_MSG(1, !vkp_command_buffers->Init(), "Command Buffer Initialization Failed.\n"); |
| |
| sleep(1); |
| |
| // Warm up and force the driver to allocate all the memory it will need for the command buffer. |
| if (!DrawAllFrames(vkp_device, *vkp_command_buffers)) { |
| RTN_MSG(1, "First DrawAllFrames Failed.\n"); |
| } |
| |
| RTN_IF_MSG(1, vk::Result::eSuccess != device->waitIdle(), "waitIdle failed"); |
| |
| auto start_time = std::chrono::steady_clock::now(); |
| |
| if (!DrawAllFrames(vkp_device, *vkp_command_buffers)) { |
| RTN_MSG(1, "Second DrawAllFrames Failed.\n"); |
| } |
| RTN_IF_MSG(1, vk::Result::eSuccess != device->waitIdle(), "waitIdle failed"); |
| auto end_time = std::chrono::steady_clock::now(); |
| |
| fprintf(stderr, "End time: %lld\n", |
| std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time).count()); |
| |
| return 0; |
| } |
| |
| bool DrawAllFrames(const vkp::Device& device, const vkp::CommandBuffers& command_buffers) { |
| vk::SubmitInfo submit_info; |
| submit_info.commandBufferCount = static_cast<uint32_t>(command_buffers.command_buffers().size()); |
| std::vector<vk::CommandBuffer> command_buffer(submit_info.commandBufferCount); |
| for (uint32_t i = 0; i < submit_info.commandBufferCount; i++) { |
| command_buffer[i] = command_buffers.command_buffers()[i].get(); |
| } |
| submit_info.pCommandBuffers = command_buffer.data(); |
| |
| if (device.queue().submit(1, &submit_info, vk::Fence()) != vk::Result::eSuccess) { |
| RTN_MSG(false, "Failed to submit draw command buffer.\n"); |
| } |
| return true; |
| } |