Skip to content

Commit

Permalink
update swapchain demo
Browse files Browse the repository at this point in the history
  • Loading branch information
YukinoHayakawa committed Mar 5, 2022
1 parent 7941cf2 commit 30fa99e
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 109 deletions.
229 changes: 124 additions & 105 deletions DemoHelloSwapchain/SystemClearSwapchainImage.hpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#pragma once

#include <Usagi/Entity/EntityDatabase.hpp>
#include <Usagi/Modules/Common/Color/Color.hpp>
#include <Usagi/Runtime/Service/Service.hpp>
#include <Usagi/Runtime/Service/LazyInitService.hpp>

#include <Usagi/Modules/Platforms/Vulkan/VulkanGpuDevice.hpp>
#include <Usagi/Modules/IO/Graphics/Enum.hpp>
#include <Usagi/Modules/IO/Windowing/ServiceNativeWindowManager.hpp>
#include <Usagi/Modules/Resources/ResVulkanWSI/RbVulkanSwapchain.hpp>

#include "ServiceColorChoice.hpp"

Expand All @@ -23,108 +22,128 @@ struct SystemClearSwapchainImage
using WriteAccess = C<>;
using ReadAccess = C<>;

void update(auto &&rt, auto &&db)
{
// The color used to fill the swapchain image
Color4f colors[] {
{ 245 / 255.f, 169 / 255.f, 184 / 255.f, 1.f },
{ 91 / 255.f, 206 / 255.f, 250 / 255.f, 1.f },
{ 255 / 255.f, 255 / 255.f, 255 / 255.f, 1.f },
};

// todo: need a way to allow different impl while providing an unified service name
// This service provides access to GPU resources with automatic lifetime
// management.
auto &gfx = USAGI_SERVICE(rt, ServiceHardwareGraphics);
// This services synchronizes window entities with the operating system.
auto &wnd_mgr = USAGI_SERVICE(rt, ServiceNativeWindowManager);
auto &color = USAGI_SERVICE(rt, ServiceColorChoice);

// Suppose the main window is already created by some initialization
// system and is called _main_.
NativeWindow * const wnd = wnd_mgr.window("main");
// Request the swapchain of the window from the graphics service.
// If the swapchain is already created, the cached swapchain will be
// returned. When not or the swapchain is not in a usable state,
// a new one will be created and returned.
// todo: ensure that the cached one has the same native window handle
// todo: how to know when the window is destroyed so the resource can be released.
// todo: how to specify the swapchain spec
auto &swapchain = gfx.swapchain(wnd);

// prepare synchronization primitives
auto sem_image_avail = gfx.allocate_semaphore();
auto sem_render_finished = gfx.allocate_semaphore();
std::array present_wait { sem_render_finished.get() };

const auto image_info = swapchain.acquire_next_image(
sem_image_avail.get());

// The graphics service internally manages a command list allocator
// for each thread.
// todo: how to know when the thread is destroyed so we can release the resource (perhaps needs some common mechanism as the window)
auto cmd_list = gfx.allocate_graphics_command_list(0);

// https://github.com/KhronosGroup/Vulkan-Guide/blob/master/chapters/extensions/VK_KHR_synchronization2.md#top_of_pipe-and-bottom_of_pipe-deprecation
// https://github.com/philiptaylor/vulkan-sxs/blob/master/04-clear/README.md
cmd_list.begin_recording();
cmd_list.image_transition(
image_info.image,
// end of pipeline of the last usage of the swapchain image
// GpuPipelineStage::ALL_COMMANDS,
GpuPipelineStage::TOP_OF_PIPE,
GpuAccessMask::NONE,
GpuImageLayout::UNDEFINED,
// clear color image is performed in transfer stage
GpuPipelineStage::TRANSFER_CLEAR,
GpuAccessMask::TRANSFER_WRITE,
GpuImageLayout::TRANSFER_DST
);
cmd_list.clear_color_image(
image_info.image,
GpuImageLayout::TRANSFER_DST,
colors[color.color_choice]
);
cmd_list.image_transition(
image_info.image,
GpuPipelineStage::TRANSFER_CLEAR,
GpuAccessMask::TRANSFER_WRITE,
GpuImageLayout::TRANSFER_DST,
// GpuPipelineStage::NONE,
GpuPipelineStage::BOTTOM_OF_PIPE,
// Presentation automatically performs a visibility operation
// https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues/1717
GpuAccessMask::NONE,
GpuImageLayout::PRESENT
);
cmd_list.end_recording();

auto cmd_submission_list = gfx.create_command_buffer_list();
cmd_submission_list.add(std::move(cmd_list));

auto wait_sem = gfx.create_semaphore_info();
wait_sem.add(
std::move(sem_image_avail),
GpuPipelineStage::TRANSFER_CLEAR
);
auto signal_sem = gfx.create_semaphore_info();
signal_sem.add(
std::move(sem_render_finished),
GpuPipelineStage::BOTTOM_OF_PIPE
);

// https://github.com/KhronosGroup/Vulkan-Guide/blob/master/chapters/extensions/VK_KHR_synchronization2.md
gfx.submit_graphics_jobs(
std::move(cmd_submission_list),
std::move(wait_sem),
// render finished sem signaled here
std::move(signal_sem)
);

// wait on render finished sem
swapchain.present(image_info, present_wait);

gfx.reclaim_resources();
}
void update(auto &&rt, auto &&db);
};

void SystemClearSwapchainImage::update(auto &&rt, auto &&db)
{
// The color used to fill the swapchain image
static const Color4f Colors[] {
{ 245 / 255.f, 169 / 255.f, 184 / 255.f, 1.f },
{ 91 / 255.f, 206 / 255.f, 250 / 255.f, 1.f },
{ 255 / 255.f, 255 / 255.f, 255 / 255.f, 1.f },
};

// todo: need a way to allow different impl while providing an unified service name
// This service provides access to GPU resources with automatic lifetime
// management.
auto &gfx = USAGI_SERVICE(rt, ServiceHardwareGraphics);
// This services synchronizes window entities with the operating system.
// auto &wnd_mgr = USAGI_SERVICE(rt, ServiceNativeWindowManager);
auto &color = USAGI_SERVICE(rt, ServiceColorChoice);
auto &worker = USAGI_SERVICE(rt, ServiceAsyncWorker);
auto &heap_mgr = rt.heap_manager();

// todo this is ugly
using GpuDevice = std::remove_reference_t<decltype(*&gfx)>;

// Request the swapchain of the window of the specified id (123). If the
// window does not exist, it will be created using the default parameters
// set in the tuple.
// todo: how to know when the window is destroyed so the resource can be released.
// todo: how to specify the swapchain spec
// todo this is hell difficult to debug with when it doesn't compile
auto swapchain_accessor = heap_mgr.template resource<typename GpuDevice::RbSwapchain>(
{ },
&worker,
[] {
return std::make_tuple(
123,
"main",
Vector2f(100, 100),
Vector2f(1280, 720),
1,
NativeWindowState::NORMAL
);
}
).make_request();
if(!swapchain_accessor.ready()) return;

auto swapchain = swapchain_accessor.get();

// prepare synchronization primitives
auto sem_image_avail = gfx.allocate_semaphore();
auto sem_render_finished = gfx.allocate_semaphore();
std::array present_wait { sem_render_finished.get() };

const auto image_info = swapchain->acquire_next_image(
sem_image_avail.get());

// The graphics service internally manages a command list allocator
// for each thread.
// todo: how to know when the thread is destroyed so we can release the resource (perhaps needs some common mechanism as the window)
auto cmd_list = gfx.allocate_graphics_command_list();

// https://github.com/KhronosGroup/Vulkan-Guide/blob/master/chapters/extensions/VK_KHR_synchronization2.md#top_of_pipe-and-bottom_of_pipe-deprecation
// https://github.com/philiptaylor/vulkan-sxs/blob/master/04-clear/README.md
cmd_list.begin_recording();
cmd_list.image_transition(
image_info.image,
// end of pipeline of the last usage of the swapchain image
// GpuPipelineStage::ALL_COMMANDS,
GpuPipelineStage::TOP_OF_PIPE,
GpuAccessMask::NONE,
GpuImageLayout::UNDEFINED,
// clear color image is performed in transfer stage
GpuPipelineStage::TRANSFER_CLEAR,
GpuAccessMask::TRANSFER_WRITE,
GpuImageLayout::TRANSFER_DST
);
cmd_list.clear_color_image(
image_info.image,
GpuImageLayout::TRANSFER_DST,
Colors[color.color_choice]
);
cmd_list.image_transition(
image_info.image,
GpuPipelineStage::TRANSFER_CLEAR,
GpuAccessMask::TRANSFER_WRITE,
GpuImageLayout::TRANSFER_DST,
// GpuPipelineStage::NONE,
GpuPipelineStage::BOTTOM_OF_PIPE,
// Presentation automatically performs a visibility operation
// https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers/issues/1717
GpuAccessMask::NONE,
GpuImageLayout::PRESENT
);
cmd_list.end_recording();

auto cmd_submission_list = gfx.create_command_buffer_list();
cmd_submission_list.add(std::move(cmd_list));

auto wait_sem = gfx.create_semaphore_info();
wait_sem.add(
std::move(sem_image_avail),
GpuPipelineStage::TRANSFER_CLEAR
);
auto signal_sem = gfx.create_semaphore_info();
signal_sem.add(
std::move(sem_render_finished),
GpuPipelineStage::BOTTOM_OF_PIPE
);

// https://github.com/KhronosGroup/Vulkan-Guide/blob/master/chapters/extensions/VK_KHR_synchronization2.md
gfx.submit_graphics_jobs(
std::move(cmd_submission_list),
std::move(wait_sem),
// render finished sem signaled here
std::move(signal_sem)
);

// wait on render finished sem
// todo what if semaphores released before present is done?
swapchain->present(image_info, present_wait);

gfx.reclaim_resources();
}
}
30 changes: 26 additions & 4 deletions DemoHelloSwapchain/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@
#include <Usagi/Modules/IO/Input/SystemInputEventPump.hpp>
#include <Usagi/Modules/IO/Windowing/ComponentNativeWindow.hpp>
#include <Usagi/Modules/IO/Windowing/ServiceNativeWindowManager.hpp>
#include <Usagi/Modules/IO/Windowing/SystemNativeWindowCoordinator.hpp>
#include <Usagi/Modules/IO/Windowing/SystemNativeWindowStateSynchronizer.hpp>

#include <Usagi/Modules/Platforms/WinCommon/Input/InputEventSourceWin32RawInput.hpp>
#include <Usagi/Modules/Platforms/WinCommon/Windowing/NativeWindowManagerWin32.hpp>
#include <Usagi/Modules/Resources/ResWindowManager/HeapWindowManager.hpp>
#include <Usagi/Modules/Runtime/Executive/ServiceAsyncWorker.hpp>
#include <Usagi/Modules/Runtime/HeapManager/HeapManagerStatic.hpp>

#include "ServiceColorChoice.hpp"
#include "SystemClearSwapchainImage.hpp"
Expand All @@ -36,11 +39,20 @@ struct Services
, ServiceStateTransitionGraph
, ServiceHardwareGraphics
, ServiceColorChoice
, HeapManagerStatic<
HeapWindowManager,
HeapVulkanObjectManager
>
, ServiceAsyncWorker
{
Services()
: ServiceInputSource(Tag<InputEventSourceWin32RawInput>())
// todo: use templatized type to help devirtualization (but how to change service provider during runtime?)
, ServiceNativeWindowManager(Tag<NativeWindowManagerWin32>())
, HeapManagerStatic(
std::forward_as_tuple(), // Window Manager
std::forward_as_tuple(&ServiceHardwareGraphics::get_service()) // Vulkan
)
{
}
};
Expand All @@ -51,7 +63,7 @@ Archetype<
> gArchetypeWindow;

using TaskList = SystemTaskList<
SystemNativeWindowCoordinator,
// SystemNativeWindowStateSynchronizer,
SystemClearSwapchainImage
>;
TaskList gTaskList;
Expand All @@ -63,10 +75,12 @@ int main(int argc, char *argv[])
std::filesystem::remove_all("demo_window_swapchain");

App app { "demo_window_swapchain" };
[[maybe_unused]]
auto &db = app.database_world();
InputEventQueue input_event_queue;
SystemInputEventPump pump;

/*
if(std::ranges::distance(db.create_access<ComponentAccessReadOnly>()
.view<ComponentNativeWindow>()) == 0)
{
Expand All @@ -78,13 +92,21 @@ int main(int argc, char *argv[])
c_region.position = { 100, 100 };
db.insert(gArchetypeWindow);
}
*/

// auto &wnd_mgr = USAGI_SERVICE(gServices, ServiceNativeWindowManager);

[[maybe_unused]]
auto &rt = app.services();
auto &tg = USAGI_SERVICE(app.services(), ServiceStateTransitionGraph);
[[maybe_unused]]
auto &gfx = USAGI_SERVICE(app.services(), ServiceHardwareGraphics);
auto &color = USAGI_SERVICE(app.services(), ServiceColorChoice);
gfx.set_thread_resource_pool_size(1);
// gfx.set_thread_resource_pool_size(1);
[[maybe_unused]]
auto &heap_mgr = app.services().heap_manager();
// using GpuDevice = std::remove_reference_t<decltype(*&gfx)>;
[[maybe_unused]]
auto &worker = USAGI_SERVICE(rt, ServiceAsyncWorker);

while(!tg.should_exit)
{
Expand Down

0 comments on commit 30fa99e

Please sign in to comment.