presenter: render the game inside a ImGui window

This commit is contained in:
Vinicius Rangel 2025-01-14 16:58:30 -03:00
parent 34a5f2319c
commit f423d151cf
No known key found for this signature in database
GPG Key ID: A5B154D904B761D9
13 changed files with 175 additions and 75 deletions

View File

@ -131,6 +131,8 @@ class DebugStateImpl {
friend class Core::Devtools::Widget::FrameGraph;
friend class Core::Devtools::Widget::ShaderList;
static bool showing_debug_menu_bar;
std::queue<std::string> debug_message_popup;
std::mutex guest_threads_mutex{};
@ -160,6 +162,10 @@ public:
debug_message_popup.push(std::move(message));
}
bool& ShowingDebugMenuBar() {
return showing_debug_menu_bar;
}
void AddCurrentThreadToGuestList();
void RemoveCurrentThreadFromGuestList();

View File

@ -24,11 +24,12 @@ using namespace ImGui;
using namespace Core::Devtools;
using L = Core::Devtools::Layer;
bool DebugStateType::DebugStateImpl::showing_debug_menu_bar = false;
static bool show_simple_fps = false;
static bool visibility_toggled = false;
static float fps_scale = 1.0f;
static bool show_advanced_debug = false;
static int dump_frame_count = 1;
static Widget::FrameGraph frame_graph;
@ -265,7 +266,7 @@ static void LoadSettings(const char* line) {
return;
}
if (sscanf(line, "show_advanced_debug=%d", &i) == 1) {
show_advanced_debug = i != 0;
DebugState.ShowingDebugMenuBar() = i != 0;
return;
}
if (sscanf(line, "show_frame_graph=%d", &i) == 1) {
@ -310,7 +311,7 @@ void L::SetupSettings() {
handler.WriteAllFn = [](ImGuiContext*, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) {
buf->appendf("[%s][Data]\n", handler->TypeName);
buf->appendf("fps_scale=%f\n", fps_scale);
buf->appendf("show_advanced_debug=%d\n", show_advanced_debug);
buf->appendf("show_advanced_debug=%d\n", DebugState.ShowingDebugMenuBar());
buf->appendf("show_frame_graph=%d\n", frame_graph.is_open);
buf->appendf("dump_frame_count=%d\n", dump_frame_count);
buf->append("\n");
@ -341,7 +342,7 @@ void L::Draw() {
if (IsKeyPressed(ImGuiKey_F10, false)) {
if (io.KeyCtrl) {
show_advanced_debug = !show_advanced_debug;
DebugState.ShowingDebugMenuBar() ^= true;
} else {
show_simple_fps = !show_simple_fps;
}
@ -376,7 +377,7 @@ void L::Draw() {
End();
}
if (show_advanced_debug) {
if (DebugState.ShowingDebugMenuBar()) {
PushFont(io.Fonts->Fonts[IMGUI_FONT_MONO]);
PushID("DevtoolsLayer");
DrawAdvanced();

View File

@ -30,6 +30,12 @@ extern void assert_fail_debug_msg(const char* msg);
#define IM_VEC4_CLASS_EXTRA \
constexpr ImVec4(float _v) : x(_v), y(_v), z(_v), w(_v) {}
namespace ImGui {
struct Texture;
}
#define ImTextureID ImTextureID
using ImTextureID = ::ImGui::Texture*;
#ifdef IMGUI_USE_WCHAR32
#error "This project uses 16 bits wchar standard like Orbis"
#endif

View File

@ -6,6 +6,7 @@
#include "common/config.h"
#include "common/path_util.h"
#include "core/debug_state.h"
#include "core/devtools/layer.h"
#include "imgui/imgui_layer.h"
#include "imgui_core.h"
@ -167,7 +168,7 @@ bool ProcessEvent(SDL_Event* event) {
}
}
void NewFrame() {
ImGuiID NewFrame() {
{
std::scoped_lock lock{change_layers_mutex};
while (!change_layers.empty()) {
@ -185,14 +186,21 @@ void NewFrame() {
Sdl::NewFrame();
ImGui::NewFrame();
DockSpaceOverViewport(0, GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode);
ImGuiWindowFlags flags = ImGuiDockNodeFlags_PassthruCentralNode;
if (!DebugState.ShowingDebugMenuBar()) {
flags |= ImGuiDockNodeFlags_NoTabBar;
}
ImGuiID dockId = DockSpaceOverViewport(0, GetMainViewport(), flags);
for (auto* layer : layers) {
layer->Draw();
}
return dockId;
}
void Render(const vk::CommandBuffer& cmdbuf, ::Vulkan::Frame* frame) {
void Render(const vk::CommandBuffer& cmdbuf, const vk::ImageView& image_view,
const vk::Extent2D& extent) {
ImGui::Render();
ImDrawData* draw_data = GetDrawData();
if (draw_data->CmdListsCount == 0) {
@ -207,16 +215,16 @@ void Render(const vk::CommandBuffer& cmdbuf, ::Vulkan::Frame* frame) {
vk::RenderingAttachmentInfo color_attachments[1]{
{
.imageView = frame->image_view,
.imageView = image_view,
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
.loadOp = vk::AttachmentLoadOp::eLoad,
.loadOp = vk::AttachmentLoadOp::eClear,
.storeOp = vk::AttachmentStoreOp::eStore,
},
};
vk::RenderingInfo render_info{};
render_info.renderArea = vk::Rect2D{
.offset = {0, 0},
.extent = {frame->width, frame->height},
.extent = extent,
};
render_info.layerCount = 1;
render_info.colorAttachmentCount = 1;

View File

@ -3,6 +3,8 @@
#pragma once
#include <imgui.h>
#include "video_core/renderer_vulkan/vk_instance.h"
#include "vulkan/vulkan_handles.hpp"
@ -24,8 +26,9 @@ void Shutdown(const vk::Device& device);
bool ProcessEvent(SDL_Event* event);
void NewFrame();
ImGuiID NewFrame();
void Render(const vk::CommandBuffer& cmdbuf, Vulkan::Frame* frame);
void Render(const vk::CommandBuffer& cmdbuf, const vk::ImageView& image_view,
const vk::Extent2D& extent);
} // namespace ImGui::Core

View File

@ -57,11 +57,12 @@ struct VkData {
vk::DeviceMemory font_memory{};
vk::Image font_image{};
vk::ImageView font_view{};
vk::DescriptorSet font_descriptor_set{};
ImTextureID font_texture{};
vk::CommandBuffer font_command_buffer{};
// Render buffers
WindowRenderBuffers render_buffers{};
bool enabled_blending{true};
VkData(const InitInfo init_info) : init_info(init_info) {
render_buffers.count = init_info.image_count;
@ -252,8 +253,8 @@ void UploadTextureData::Destroy() {
const InitInfo& v = bd->init_info;
CheckVkErr(v.device.waitIdle());
RemoveTexture(descriptor_set);
descriptor_set = VK_NULL_HANDLE;
RemoveTexture(im_texture);
im_texture = nullptr;
v.device.destroyImageView(image_view, v.allocator);
image_view = VK_NULL_HANDLE;
@ -264,8 +265,8 @@ void UploadTextureData::Destroy() {
}
// Register a texture
vk::DescriptorSet AddTexture(vk::ImageView image_view, vk::ImageLayout image_layout,
vk::Sampler sampler) {
ImTextureID AddTexture(vk::ImageView image_view, vk::ImageLayout image_layout,
vk::Sampler sampler) {
VkData* bd = GetBackendData();
const InitInfo& v = bd->init_info;
@ -303,7 +304,9 @@ vk::DescriptorSet AddTexture(vk::ImageView image_view, vk::ImageLayout image_lay
};
v.device.updateDescriptorSets({write_desc}, {});
}
return descriptor_set;
return new Texture{
.descriptor_set = descriptor_set,
};
}
UploadTextureData UploadTexture(const void* data, vk::Format format, u32 width, u32 height,
size_t size) {
@ -370,7 +373,7 @@ UploadTextureData UploadTexture(const void* data, vk::Format format, u32 width,
}
// Create descriptor set (ImTextureID)
info.descriptor_set = AddTexture(info.image_view, vk::ImageLayout::eShaderReadOnlyOptimal);
info.im_texture = AddTexture(info.image_view, vk::ImageLayout::eShaderReadOnlyOptimal);
// Create Upload Buffer
{
@ -464,10 +467,12 @@ UploadTextureData UploadTexture(const void* data, vk::Format format, u32 width,
return info;
}
void RemoveTexture(vk::DescriptorSet descriptor_set) {
void RemoveTexture(ImTextureID texture) {
IM_ASSERT(texture != nullptr);
VkData* bd = GetBackendData();
const InitInfo& v = bd->init_info;
v.device.freeDescriptorSets(bd->descriptor_pool, {descriptor_set});
v.device.freeDescriptorSets(bd->descriptor_pool, {texture->descriptor_set});
delete texture;
}
static void CreateOrResizeBuffer(RenderBuffer& rb, size_t new_size, vk::BufferUsageFlagBits usage) {
@ -679,15 +684,11 @@ void RenderDrawData(ImDrawData& draw_data, vk::CommandBuffer command_buffer,
command_buffer.setScissor(0, 1, &scissor);
// Bind DescriptorSet with font or user texture
vk::DescriptorSet desc_set[1]{(VkDescriptorSet)pcmd->TextureId};
if (sizeof(ImTextureID) < sizeof(ImU64)) {
// We don't support texture switches if ImTextureID hasn't been redefined to be
// 64-bit. Do a flaky check that other textures haven't been used.
IM_ASSERT(pcmd->TextureId == (ImTextureID)bd->font_descriptor_set);
desc_set[0] = bd->font_descriptor_set;
}
vk::DescriptorSet desc_set[1]{pcmd->TextureId->descriptor_set};
command_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
bd->pipeline_layout, 0, {desc_set}, {});
command_buffer.setColorBlendEnableEXT(
0, {pcmd->TextureId->disable_blend ? vk::False : vk::True});
// Draw
command_buffer.drawIndexed(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset,
@ -709,7 +710,7 @@ static bool CreateFontsTexture() {
const InitInfo& v = bd->init_info;
// Destroy existing texture (if any)
if (bd->font_view || bd->font_image || bd->font_memory || bd->font_descriptor_set) {
if (bd->font_view || bd->font_image || bd->font_memory || bd->font_texture) {
CheckVkErr(v.queue.waitIdle());
DestroyFontsTexture();
}
@ -782,7 +783,7 @@ static bool CreateFontsTexture() {
}
// Create the Descriptor Set:
bd->font_descriptor_set = AddTexture(bd->font_view, vk::ImageLayout::eShaderReadOnlyOptimal);
bd->font_texture = AddTexture(bd->font_view, vk::ImageLayout::eShaderReadOnlyOptimal);
// Create the Upload Buffer:
vk::DeviceMemory upload_buffer_memory{};
@ -874,7 +875,7 @@ static bool CreateFontsTexture() {
}
// Store our identifier
io.Fonts->SetTexID(bd->font_descriptor_set);
io.Fonts->SetTexID(bd->font_texture);
// End command buffer
vk::SubmitInfo end_info = {};
@ -898,9 +899,9 @@ static void DestroyFontsTexture() {
VkData* bd = GetBackendData();
const InitInfo& v = bd->init_info;
if (bd->font_descriptor_set) {
RemoveTexture(bd->font_descriptor_set);
bd->font_descriptor_set = VK_NULL_HANDLE;
if (bd->font_texture) {
RemoveTexture(bd->font_texture);
bd->font_texture = nullptr;
io.Fonts->SetTexID(nullptr);
}
@ -1057,9 +1058,10 @@ static void CreatePipeline(vk::Device device, const vk::AllocationCallbacks* all
.pAttachments = color_attachment,
};
vk::DynamicState dynamic_states[2]{
vk::DynamicState dynamic_states[3]{
vk::DynamicState::eViewport,
vk::DynamicState::eScissor,
vk::DynamicState::eColorBlendEnableEXT,
};
vk::PipelineDynamicStateCreateInfo dynamic_state{
.dynamicStateCount = (uint32_t)IM_ARRAYSIZE(dynamic_states),

View File

@ -10,6 +10,13 @@
struct ImDrawData;
namespace ImGui {
struct Texture {
vk::DescriptorSet descriptor_set{nullptr};
bool disable_blend{false};
};
} // namespace ImGui
namespace ImGui::Vulkan {
struct InitInfo {
@ -34,29 +41,32 @@ struct InitInfo {
struct UploadTextureData {
vk::Image image;
vk::ImageView image_view;
vk::DescriptorSet descriptor_set;
vk::DeviceMemory image_memory;
vk::CommandBuffer command_buffer; // Submit to the queue
vk::Buffer upload_buffer;
vk::DeviceMemory upload_buffer_memory;
ImTextureID im_texture;
void Upload();
void Destroy();
};
vk::DescriptorSet AddTexture(vk::ImageView image_view, vk::ImageLayout image_layout,
vk::Sampler sampler = VK_NULL_HANDLE);
ImTextureID AddTexture(vk::ImageView image_view, vk::ImageLayout image_layout,
vk::Sampler sampler = VK_NULL_HANDLE);
UploadTextureData UploadTexture(const void* data, vk::Format format, u32 width, u32 height,
size_t size);
void RemoveTexture(vk::DescriptorSet descriptor_set);
void RemoveTexture(ImTextureID descriptor_set);
bool Init(InitInfo info);
void Shutdown();
void RenderDrawData(ImDrawData& draw_data, vk::CommandBuffer command_buffer,
vk::Pipeline pipeline = VK_NULL_HANDLE);
void SetBlendEnabled(bool enabled);
} // namespace ImGui::Vulkan

View File

@ -4,6 +4,7 @@
#include <deque>
#include <utility>
#include <imgui.h>
#include "common/assert.h"
#include "common/config.h"
#include "common/io_file.h"
@ -123,7 +124,7 @@ static std::deque<UploadJob> g_upload_list;
namespace Core::TextureManager {
Inner::~Inner() {
if (upload_data.descriptor_set != nullptr) {
if (upload_data.im_texture != nullptr) {
std::unique_lock lk{g_upload_mtx};
g_upload_list.emplace_back(UploadJob{
.data = this->upload_data,
@ -239,7 +240,7 @@ void Submit() {
}
if (upload.core != nullptr) {
upload.core->upload_data.Upload();
upload.core->texture_id = upload.core->upload_data.descriptor_set;
upload.core->texture_id = upload.core->upload_data.im_texture;
if (upload.core->count.fetch_sub(1) == 1) {
delete upload.core;
}

View File

@ -384,6 +384,7 @@ bool Instance::CreateDevice() {
},
vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT{
.extendedDynamicState3ColorWriteMask = true,
.extendedDynamicState3ColorBlendEnable = true,
},
vk::PhysicalDeviceDepthClipControlFeaturesEXT{
.depthClipControl = true,

View File

@ -20,6 +20,9 @@
#include <vk_mem_alloc.h>
#include <imgui.h>
#include "imgui/renderer/imgui_impl_vulkan.h"
namespace Vulkan {
bool CanBlitToSwapchain(const vk::PhysicalDevice physical_device, vk::Format format) {
@ -324,9 +327,6 @@ Presenter::Presenter(Frontend::WindowSDL& window_, AmdGpu::Liverpool* liverpool_
CreatePostProcessPipeline();
// Setup ImGui
ImGui::Core::Initialize(instance, window, num_images,
FormatToUnorm(swapchain.GetSurfaceFormat().format));
ImGui::Layer::AddLayer(Common::Singleton<Core::Devtools::Layer>::Instance());
}
@ -344,6 +344,9 @@ Presenter::~Presenter() {
void Presenter::RecreateFrame(Frame* frame, u32 width, u32 height) {
const vk::Device device = instance.GetDevice();
if (frame->imgui_texture) {
ImGui::Vulkan::RemoveTexture(frame->imgui_texture);
}
if (frame->image_view) {
device.destroyImageView(frame->image_view);
}
@ -361,7 +364,7 @@ void Presenter::RecreateFrame(Frame* frame, u32 width, u32 height) {
.arrayLayers = 1,
.samples = vk::SampleCountFlagBits::e1,
.usage = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst |
vk::ImageUsageFlagBits::eTransferSrc,
vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eSampled,
};
const VmaAllocationCreateInfo alloc_info = {
@ -403,6 +406,9 @@ void Presenter::RecreateFrame(Frame* frame, u32 width, u32 height) {
frame->image_view = view;
frame->width = width;
frame->height = height;
frame->imgui_texture = ImGui::Vulkan::AddTexture(view, vk::ImageLayout::eShaderReadOnlyOptimal);
frame->imgui_texture->disable_blend = true;
}
bool Presenter::ShowSplash(Frame* frame /*= nullptr*/) {
@ -499,6 +505,14 @@ Frame* Presenter::PrepareFrameInternal(VideoCore::ImageId image_id, bool is_eop)
// Request a free presentation frame.
Frame* frame = GetRenderFrame();
if (image_id != VideoCore::NULL_IMAGE_ID) {
const auto& image = texture_cache.GetImage(image_id);
const auto extent = image.info.size;
if (frame->width != extent.width || frame->height != extent.height) {
RecreateFrame(frame, extent.width, extent.height);
}
}
// EOP flips are triggered from GPU thread so use the drawing scheduler to record
// commands. Otherwise we are dealing with a CPU flip which could have arrived
// from any guest thread. Use a separate scheduler for that.
@ -636,8 +650,7 @@ void Presenter::Present(Frame* frame) {
};
// Recreate the swapchain if the window was resized.
if (window.GetWidth() != swapchain.GetExtent().width ||
window.GetHeight() != swapchain.GetExtent().height) {
if (window.GetWidth() != swapchain.GetWidth() || window.GetHeight() != swapchain.GetHeight()) {
swapchain.Recreate(window.GetWidth(), window.GetHeight());
}
@ -656,15 +669,14 @@ void Presenter::Present(Frame* frame) {
// the frame's present fence and future GetRenderFrame() call will hang waiting for this frame.
instance.GetDevice().resetFences(frame->present_done);
ImGui::Core::NewFrame();
ImGuiID dockId = ImGui::Core::NewFrame();
const vk::Image swapchain_image = swapchain.Image();
const vk::ImageView swapchain_image_view = swapchain.ImageView();
auto& scheduler = present_scheduler;
const auto cmdbuf = scheduler.CommandBuffer();
ImGui::Core::Render(cmdbuf, frame);
{
auto* profiler_ctx = instance.GetProfilerContext();
TracyVkNamedZoneC(profiler_ctx, renderer_gpu_zone, cmdbuf, "Host frame",
@ -674,9 +686,9 @@ void Presenter::Present(Frame* frame) {
const std::array pre_barriers{
vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eNone,
.dstAccessMask = vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
.oldLayout = vk::ImageLayout::eUndefined,
.newLayout = vk::ImageLayout::eTransferDstOptimal,
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = swapchain_image,
@ -690,9 +702,9 @@ void Presenter::Present(Frame* frame) {
},
vk::ImageMemoryBarrier{
.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
.dstAccessMask = vk::AccessFlagBits::eTransferRead,
.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead,
.oldLayout = vk::ImageLayout::eGeneral,
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = frame->image,
@ -705,10 +717,11 @@ void Presenter::Present(Frame* frame) {
},
},
};
const vk::ImageMemoryBarrier post_barrier{
.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
.dstAccessMask = vk::AccessFlagBits::eMemoryRead,
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
.newLayout = vk::ImageLayout::ePresentSrcKHR,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
@ -723,14 +736,29 @@ void Presenter::Present(Frame* frame) {
};
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eColorAttachmentOutput,
vk::DependencyFlagBits::eByRegion, {}, {}, pre_barriers);
cmdbuf.blitImage(
frame->image, vk::ImageLayout::eTransferSrcOptimal, swapchain_image,
vk::ImageLayout::eTransferDstOptimal,
MakeImageBlitStretch(frame->width, frame->height, extent.width, extent.height),
vk::Filter::eLinear);
{ // Draw the game
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{0.0f});
ImGui::SetNextWindowDockID(dockId, ImGuiCond_Once);
ImGui::Begin("Display##game_display", nullptr, ImGuiWindowFlags_NoNav);
ImVec2 contentArea = ImGui::GetContentRegionMax();
const vk::Rect2D imgRect =
FitImage(frame->width, frame->height, (s32)contentArea.x, (s32)contentArea.y);
ImGui::SetCursorPos({
(float)imgRect.offset.x,
(float)imgRect.offset.y,
});
ImGui::Image(frame->imgui_texture, {
static_cast<float>(imgRect.extent.width),
static_cast<float>(imgRect.extent.height),
});
ImGui::End();
ImGui::PopStyleVar();
}
ImGui::Core::Render(cmdbuf, swapchain_image_view, swapchain.GetExtent());
cmdbuf.pipelineBarrier(vk::PipelineStageFlagBits::eAllCommands,
vk::PipelineStageFlagBits::eAllCommands,
@ -790,9 +818,9 @@ Frame* Presenter::GetRenderFrame() {
}
}
// If the window dimensions changed, recreate this frame
if (frame->width != window.GetWidth() || frame->height != window.GetHeight()) {
RecreateFrame(frame, window.GetWidth(), window.GetHeight());
// Initialize default frame image
if (frame->width == 0 || frame->height == 0) {
RecreateFrame(frame, 1920, 1080);
}
return frame;

View File

@ -5,6 +5,7 @@
#include <condition_variable>
#include "imgui/imgui_config.h"
#include "video_core/amdgpu/liverpool.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
@ -30,6 +31,8 @@ struct Frame {
vk::Fence present_done;
vk::Semaphore ready_semaphore;
u64 ready_tick;
ImTextureID imgui_texture;
};
enum SchedulerType {

View File

@ -4,8 +4,8 @@
#include <algorithm>
#include <limits>
#include "common/assert.h"
#include "common/config.h"
#include "common/logging/log.h"
#include "imgui/renderer/imgui_core.h"
#include "sdl_window.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
@ -15,7 +15,9 @@ namespace Vulkan {
Swapchain::Swapchain(const Instance& instance_, const Frontend::WindowSDL& window)
: instance{instance_}, surface{CreateSurface(instance.GetInstance(), window)} {
FindPresentFormat();
Create(window.GetWidth(), window.GetHeight(), surface);
Create(window.GetWidth(), window.GetHeight());
ImGui::Core::Initialize(instance, window, image_count, surface_format.format);
}
Swapchain::~Swapchain() {
@ -23,10 +25,9 @@ Swapchain::~Swapchain() {
instance.GetInstance().destroySurfaceKHR(surface);
}
void Swapchain::Create(u32 width_, u32 height_, vk::SurfaceKHR surface_) {
void Swapchain::Create(u32 width_, u32 height_) {
width = width_;
height = height_;
surface = surface_;
needs_recreation = false;
Destroy();
@ -86,7 +87,7 @@ void Swapchain::Create(u32 width_, u32 height_, vk::SurfaceKHR surface_) {
void Swapchain::Recreate(u32 width_, u32 height_) {
LOG_DEBUG(Render_Vulkan, "Recreate the swapchain: width={} height={}", width_, height_);
Create(width_, height_, surface);
Create(width_, height_);
}
bool Swapchain::AcquireNextImage() {
@ -209,10 +210,14 @@ void Swapchain::Destroy() {
if (swapchain) {
device.destroySwapchainKHR(swapchain);
}
for (u32 i = 0; i < image_count; i++) {
device.destroySemaphore(image_acquired[i]);
device.destroySemaphore(present_ready[i]);
for (const auto& sem : image_acquired) {
device.destroySemaphore(sem);
}
for (const auto& sem : present_ready) {
device.destroySemaphore(sem);
}
image_acquired.clear();
present_ready.clear();
}
@ -249,9 +254,30 @@ void Swapchain::SetupImages() {
vk::to_string(images_result));
images = std::move(imgs);
image_count = static_cast<u32>(images.size());
images_view.resize(image_count);
for (u32 i = 0; i < image_count; ++i) {
if (images_view[i]) {
device.destroyImageView(images_view[i]);
}
auto [im_view_result, im_view] = device.createImageView(vk::ImageViewCreateInfo{
.image = images[i],
.viewType = vk::ImageViewType::e2D,
.format = surface_format.format,
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.levelCount = 1,
.layerCount = 1,
},
});
ASSERT_MSG(im_view_result == vk::Result::eSuccess, "Failed to create image view: {}",
vk::to_string(im_view_result));
images_view[i] = im_view;
}
for (u32 i = 0; i < image_count; ++i) {
SetObjectName(device, images[i], "Swapchain Image {}", i);
SetObjectName(device, images_view[i], "Swapchain ImageView {}", i);
}
}

View File

@ -23,7 +23,7 @@ public:
~Swapchain();
/// Creates (or recreates) the swapchain with a given size.
void Create(u32 width, u32 height, vk::SurfaceKHR surface);
void Create(u32 width, u32 height);
/// Recreates the swapchain with a given size and current surface.
void Recreate(u32 width, u32 height);
@ -42,6 +42,10 @@ public:
return images[image_index];
}
vk::ImageView ImageView() const {
return images_view[image_index];
}
vk::SurfaceFormatKHR GetSurfaceFormat() const {
return surface_format;
}
@ -103,6 +107,7 @@ private:
vk::SurfaceTransformFlagBitsKHR transform;
vk::CompositeAlphaFlagBitsKHR composite_alpha;
std::vector<vk::Image> images;
std::vector<vk::ImageView> images_view;
std::vector<vk::Semaphore> image_acquired;
std::vector<vk::Semaphore> present_ready;
u32 width = 0;