迁移到vulkan hpp

This commit is contained in:
2025-12-31 02:02:01 +08:00
parent b63b48732b
commit ecdc23ee19
56 changed files with 2943 additions and 3052 deletions

View File

@@ -51,11 +51,11 @@ renderer::renderer(renderer&& other) noexcept
{
other.state_ = render_state::uninitialized;
other.window_ = nullptr;
other.surface_ = VK_NULL_HANDLE;
other.surface_ = nullptr;
other.allocator_ = VK_NULL_HANDLE;
other.depth_image_ = VK_NULL_HANDLE;
other.depth_allocation_ = VK_NULL_HANDLE;
other.depth_image_view_ = VK_NULL_HANDLE;
other.depth_image_ = nullptr;
other.depth_allocation_ = nullptr;
other.depth_image_view_ = nullptr;
}
renderer& renderer::operator=(renderer&& other) noexcept {
@@ -90,23 +90,23 @@ renderer& renderer::operator=(renderer&& other) noexcept {
other.state_ = render_state::uninitialized;
other.window_ = nullptr;
other.surface_ = VK_NULL_HANDLE;
other.surface_ = nullptr;
other.allocator_ = VK_NULL_HANDLE;
other.depth_image_ = VK_NULL_HANDLE;
other.depth_allocation_ = VK_NULL_HANDLE;
other.depth_image_view_ = VK_NULL_HANDLE;
other.depth_image_ = nullptr;
other.depth_allocation_ = nullptr;
other.depth_image_view_ = nullptr;
}
return *this;
}
bool renderer::initialize(SDL_Window* window) {
if (state_ != render_state::uninitialized) {
LOG_WARN("Renderer already initialized");
MILAI_LOG_WARN("Renderer already initialized");
return true;
}
if (!window) {
LOG_ERROR("Invalid window pointer");
MILAI_LOG_ERROR("Invalid window pointer");
return false;
}
@@ -124,61 +124,53 @@ bool renderer::initialize(SDL_Window* window) {
instance_config.app_version = config_.app_version;
instance_config.enable_validation = config_.enable_validation;
// 获取 SDL 所需的 Vulkan 扩展
u32 sdl_extension_count = 0;
const char* const* sdl_extensions = SDL_Vulkan_GetInstanceExtensions(&sdl_extension_count);
if (sdl_extensions) {
for (u32 i = 0; i < sdl_extension_count; ++i) {
instance_config.required_extensions.push_back(sdl_extensions[i]);
}
}
// SDL 扩展由 vulkan_instance 自动获取,无需手动添加
instance_ = std::make_unique<vulkan_instance>(instance_config);
instance_ = std::make_shared<vulkan_instance>(instance_config);
if (!instance_->is_valid()) {
LOG_ERROR("Failed to create Vulkan instance");
MILAI_LOG_ERROR("Failed to create Vulkan instance");
return false;
}
// 2. 创建表面
if (!create_surface(window)) {
LOG_ERROR("Failed to create Vulkan surface");
MILAI_LOG_ERROR("Failed to create Vulkan surface");
return false;
}
// 3. 创建设备
vulkan_device_config device_config{};
device_config.required_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
device_config.enable_dynamic_rendering = true;
device_config.enable_synchronization2 = true;
device_config.surface = surface_;
device_config.extra_extensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
device_config.require_dynamic_rendering = true;
device_config.require_synchronization2 = true;
device_ = std::make_shared<vulkan_device>(instance_, device_config);
device_ = std::make_shared<vulkan_device>(instance_, surface_, device_config);
if (!device_->is_valid()) {
LOG_ERROR("Failed to create Vulkan device");
MILAI_LOG_ERROR("Failed to create Vulkan device");
return false;
}
// 4. 创建 VMA 分配器
if (!create_allocator()) {
LOG_ERROR("Failed to create VMA allocator");
MILAI_LOG_ERROR("Failed to create VMA allocator");
return false;
}
// 5. 创建交换链
if (!create_swapchain(config_.viewport_width, config_.viewport_height)) {
LOG_ERROR("Failed to create swapchain");
MILAI_LOG_ERROR("Failed to create swapchain");
return false;
}
// 6. 创建深度资源
if (!create_depth_resources()) {
LOG_ERROR("Failed to create depth resources");
MILAI_LOG_ERROR("Failed to create depth resources");
return false;
}
// 7. 创建命令池
if (!create_command_pools()) {
LOG_ERROR("Failed to create command pools");
MILAI_LOG_ERROR("Failed to create command pools");
return false;
}
@@ -188,7 +180,7 @@ bool renderer::initialize(SDL_Window* window) {
frame_sync_ = std::make_unique<frame_sync>(device_, swapchain_, sync_config);
if (!frame_sync_->is_valid()) {
LOG_ERROR("Failed to create frame sync");
MILAI_LOG_ERROR("Failed to create frame sync");
return false;
}
@@ -200,16 +192,16 @@ bool renderer::initialize(SDL_Window* window) {
batch_renderer_ = std::make_unique<batch_renderer>(device_, allocator_, batch_config);
if (!batch_renderer_->initialize(swapchain_->get_format(), depth_format_)) {
LOG_WARN("Batch renderer initialization incomplete (needs shaders)");
MILAI_LOG_WARN("Batch renderer initialization incomplete (needs shaders)");
// 不视为致命错误,因为着色器可能稍后加载
}
state_ = render_state::initialized;
LOG_INFO("Renderer initialized successfully");
LOG_INFO(" - Vulkan Instance: {}", (void*)instance_->get_instance());
LOG_INFO(" - Physical Device: {}", device_->get_physical_device_info().device_name);
LOG_INFO(" - Swapchain: {}x{}", swapchain_->get_extent().width, swapchain_->get_extent().height);
LOG_INFO(" - Frames in Flight: {}", config_.frames_in_flight);
MILAI_LOG_INFO("Renderer initialized successfully");
MILAI_LOG_INFO(" - Vulkan Instance: {}", (void*)static_cast<VkInstance>(instance_->get_instance()));
MILAI_LOG_INFO(" - Physical Device: {}", device_->get_device_name());
MILAI_LOG_INFO(" - Swapchain: {}x{}", swapchain_->get_extent().width, swapchain_->get_extent().height);
MILAI_LOG_INFO(" - Frames in Flight: {}", config_.frames_in_flight);
return true;
}
@@ -228,21 +220,21 @@ void renderer::shutdown() {
destroy_resources();
state_ = render_state::uninitialized;
LOG_INFO("Renderer shutdown");
MILAI_LOG_INFO("Renderer shutdown");
}
bool renderer::begin_frame() {
if (state_ != render_state::initialized) {
if (state_ == render_state::frame_in_progress) {
LOG_WARN("Frame already in progress");
MILAI_LOG_WARN("Frame already in progress");
return true;
}
LOG_ERROR("Cannot begin frame: renderer not in valid state");
MILAI_LOG_ERROR("Cannot begin frame: renderer not in valid state");
return false;
}
// 检查窗口是否最小化
u32 window_flags = SDL_GetWindowFlags(window_);
const auto window_flags = SDL_GetWindowFlags(window_);
window_minimized_ = (window_flags & SDL_WINDOW_MINIMIZED) != 0;
if (window_minimized_) {
@@ -262,7 +254,7 @@ bool renderer::begin_frame() {
SDL_GetWindowSize(window_, &width, &height);
if (!recreate_swapchain(static_cast<u32>(width), static_cast<u32>(height))) {
LOG_ERROR("Failed to recreate swapchain");
MILAI_LOG_ERROR("Failed to recreate swapchain");
state_ = render_state::error;
return false;
}
@@ -270,12 +262,12 @@ bool renderer::begin_frame() {
// 重试
auto [retry_result, retry_index] = frame_sync_->begin_frame();
if (retry_result != frame_begin_result::success) {
LOG_ERROR("Failed to begin frame after swapchain recreation");
MILAI_LOG_ERROR("Failed to begin frame after swapchain recreation");
return false;
}
image_index = retry_index;
} else if (result != frame_begin_result::success) {
LOG_ERROR("Failed to begin frame");
MILAI_LOG_ERROR("Failed to begin frame");
return false;
}
@@ -283,15 +275,14 @@ bool renderer::begin_frame() {
current_image_index_ = image_index;
// 重置并开始命令缓冲录制
VkCommandBuffer cmd_buffer = frame_sync_->get_current_command_buffer();
vk::CommandBuffer cmd_buffer = frame_sync_->get_current_command_buffer();
VkCommandBufferBeginInfo begin_info{};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vk::CommandBufferBeginInfo begin_info{};
begin_info.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit;
VkResult vk_result = vkBeginCommandBuffer(cmd_buffer, &begin_info);
if (vk_result != VK_SUCCESS) {
LOG_ERROR("Failed to begin command buffer: {}", vk_result_to_string(vk_result));
auto vk_result = cmd_buffer.begin(&begin_info);
if (vk_result != vk::Result::eSuccess) {
MILAI_LOG_ERROR("Failed to begin command buffer: {}", vk_result_to_string(vk_result));
return false;
}
@@ -308,7 +299,7 @@ bool renderer::begin_frame() {
bool renderer::end_frame() {
if (state_ != render_state::frame_in_progress &&
state_ != render_state::rendering_in_progress) {
LOG_ERROR("Cannot end frame: frame not in progress");
MILAI_LOG_ERROR("Cannot end frame: frame not in progress");
return false;
}
@@ -317,12 +308,12 @@ bool renderer::end_frame() {
end_rendering();
}
VkCommandBuffer cmd_buffer = frame_sync_->get_current_command_buffer();
vk::CommandBuffer cmd_buffer = frame_sync_->get_current_command_buffer();
// 结束命令缓冲录制
VkResult vk_result = vkEndCommandBuffer(cmd_buffer);
if (vk_result != VK_SUCCESS) {
LOG_ERROR("Failed to end command buffer: {}", vk_result_to_string(vk_result));
auto vk_result = cmd_buffer.end();
if (vk_result != vk::Result::eSuccess) {
MILAI_LOG_ERROR("Failed to end command buffer: {}", vk_result_to_string(vk_result));
return false;
}
@@ -333,7 +324,7 @@ bool renderer::end_frame() {
result == frame_end_result::swapchain_suboptimal) {
swapchain_needs_recreation_ = true;
} else if (result != frame_end_result::success) {
LOG_ERROR("Failed to end frame");
MILAI_LOG_ERROR("Failed to end frame");
return false;
}
@@ -364,26 +355,26 @@ bool renderer::end_frame() {
void renderer::begin_rendering(const render_target& target) {
if (state_ != render_state::frame_in_progress) {
LOG_ERROR("Cannot begin rendering: frame not in progress");
MILAI_LOG_ERROR("Cannot begin rendering: frame not in progress");
return;
}
VkCommandBuffer cmd_buffer = frame_sync_->get_current_command_buffer();
vk::CommandBuffer cmd_buffer = frame_sync_->get_current_command_buffer();
// 转换交换链图像布局到颜色附件
VkImage swapchain_image = swapchain_->get_images()[current_image_index_];
vk::Image swapchain_image = swapchain_->get_images()[current_image_index_];
transition_image_layout(cmd_buffer, swapchain_image,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
vk::ImageLayout::eUndefined,
vk::ImageLayout::eColorAttachmentOptimal);
// 构建渲染信息
rendering_info render_info(target);
// 开始动态渲染
vkCmdBeginRendering(cmd_buffer, render_info.get_vulkan_rendering_info());
cmd_buffer.beginRendering(render_info.get_vulkan_rendering_info());
// 设置视口和裁剪
VkViewport viewport{};
vk::Viewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = static_cast<f32>(target.render_area.extent.width);
@@ -391,10 +382,10 @@ void renderer::begin_rendering(const render_target& target) {
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
vkCmdSetViewport(cmd_buffer, 0, 1, &viewport);
cmd_buffer.setViewport(0, 1, &viewport);
VkRect2D scissor = target.render_area;
vkCmdSetScissor(cmd_buffer, 0, 1, &scissor);
vk::Rect2D scissor = target.render_area;
cmd_buffer.setScissor(0, 1, &scissor);
state_ = render_state::rendering_in_progress;
}
@@ -403,21 +394,21 @@ void renderer::begin_rendering(const clear_color& clear) {
// 创建默认渲染目标(使用当前交换链图像)
render_attachment color_attachment{};
color_attachment.image_view = swapchain_->get_image_views()[current_image_index_];
color_attachment.image_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_attachment.image_layout = vk::ImageLayout::eColorAttachmentOptimal;
color_attachment.load_op = attachment_load_op::clear;
color_attachment.store_op = attachment_store_op::store;
color_attachment.clear_value = clear;
render_target target;
target.color_attachments.push_back(color_attachment);
target.render_area.offset = {0, 0};
target.render_area.offset = vk::Offset2D{0, 0};
target.render_area.extent = swapchain_->get_extent();
// 添加深度附件(如果有)
if (depth_image_view_ != VK_NULL_HANDLE) {
if (depth_image_view_) {
render_attachment depth_attachment{};
depth_attachment.image_view = depth_image_view_;
depth_attachment.image_layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
depth_attachment.image_layout = vk::ImageLayout::eDepthAttachmentOptimal;
depth_attachment.load_op = attachment_load_op::clear;
depth_attachment.store_op = attachment_store_op::store;
depth_attachment.clear_depth_stencil_value = clear_depth_stencil(1.0f, 0);
@@ -429,29 +420,29 @@ void renderer::begin_rendering(const clear_color& clear) {
void renderer::end_rendering() {
if (state_ != render_state::rendering_in_progress) {
LOG_ERROR("Cannot end rendering: not in rendering state");
MILAI_LOG_ERROR("Cannot end rendering: not in rendering state");
return;
}
VkCommandBuffer cmd_buffer = frame_sync_->get_current_command_buffer();
vk::CommandBuffer cmd_buffer = frame_sync_->get_current_command_buffer();
// 结束动态渲染
vkCmdEndRendering(cmd_buffer);
cmd_buffer.endRendering();
// 转换交换链图像布局到呈现
VkImage swapchain_image = swapchain_->get_images()[current_image_index_];
vk::Image swapchain_image = swapchain_->get_images()[current_image_index_];
transition_image_layout(cmd_buffer, swapchain_image,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
vk::ImageLayout::eColorAttachmentOptimal,
vk::ImageLayout::ePresentSrcKHR);
state_ = render_state::frame_in_progress;
}
VkCommandBuffer renderer::get_command_buffer() const {
vk::CommandBuffer renderer::get_command_buffer() const {
if (frame_sync_) {
return frame_sync_->get_current_command_buffer();
}
return VK_NULL_HANDLE;
return nullptr;
}
command_buffer* renderer::get_current_command_buffer() {
@@ -461,20 +452,19 @@ command_buffer* renderer::get_current_command_buffer() {
return nullptr;
}
bool renderer::submit(VkCommandBuffer cmd_buffer) {
bool renderer::submit(vk::CommandBuffer cmd_buffer) {
// 直接提交到图形队列
VkSubmitInfo submit_info{};
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
vk::SubmitInfo submit_info{};
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &cmd_buffer;
VkResult result = vkQueueSubmit(device_->get_graphics_queue(), 1, &submit_info, VK_NULL_HANDLE);
return result == VK_SUCCESS;
auto result = device_->get_graphics_queue().submit(1, &submit_info, nullptr);
return result == vk::Result::eSuccess;
}
bool renderer::present() {
// 呈现由 end_frame 自动处理
LOG_WARN("present() called directly; use end_frame() instead");
MILAI_LOG_WARN("present() called directly; use end_frame() instead");
return true;
}
@@ -504,40 +494,40 @@ u32 renderer::get_current_image_index() const {
return current_image_index_;
}
VkExtent2D renderer::get_swapchain_extent() const {
return swapchain_ ? swapchain_->get_extent() : VkExtent2D{0, 0};
vk::Extent2D renderer::get_swapchain_extent() const {
return swapchain_ ? swapchain_->get_extent() : vk::Extent2D{0, 0};
}
VkFormat renderer::get_swapchain_format() const {
return swapchain_ ? swapchain_->get_format() : VK_FORMAT_UNDEFINED;
vk::Format renderer::get_swapchain_format() const {
return swapchain_ ? swapchain_->get_format() : vk::Format::eUndefined;
}
VkInstance renderer::get_vulkan_instance() const {
return instance_ ? instance_->get_instance() : VK_NULL_HANDLE;
vk::Instance renderer::get_vulkan_instance() const {
return instance_ ? instance_->get_instance() : nullptr;
}
VkDevice renderer::get_vulkan_device() const {
return device_ ? device_->get_device() : VK_NULL_HANDLE;
vk::Device renderer::get_vulkan_device() const {
return device_ ? device_->get_device() : nullptr;
}
VkPhysicalDevice renderer::get_vulkan_physical_device() const {
return device_ ? device_->get_physical_device() : VK_NULL_HANDLE;
vk::PhysicalDevice renderer::get_vulkan_physical_device() const {
return device_ ? device_->get_physical_device() : nullptr;
}
VkQueue renderer::get_graphics_queue() const {
return device_ ? device_->get_graphics_queue() : VK_NULL_HANDLE;
vk::Queue renderer::get_graphics_queue() const {
return device_ ? device_->get_graphics_queue() : nullptr;
}
VkQueue renderer::get_present_queue() const {
return device_ ? device_->get_present_queue() : VK_NULL_HANDLE;
vk::Queue renderer::get_present_queue() const {
return device_ ? device_->get_present_queue() : nullptr;
}
void renderer::on_created() {
LOG_DEBUG("Renderer created");
MILAI_LOG_DEBUG("Renderer created");
}
void renderer::on_destroying() {
LOG_DEBUG("Renderer destroying");
MILAI_LOG_DEBUG("Renderer destroying");
}
bool renderer::create_allocator() {
@@ -550,51 +540,54 @@ bool renderer::create_allocator() {
VkResult result = vmaCreateAllocator(&allocator_info, &allocator_);
if (result != VK_SUCCESS) {
LOG_ERROR("Failed to create VMA allocator: {}", vk_result_to_string(result));
MILAI_LOG_ERROR("Failed to create VMA allocator: {}", vk_result_to_string(static_cast<vk::Result>(result)));
return false;
}
LOG_DEBUG("VMA allocator created");
MILAI_LOG_DEBUG("VMA allocator created");
return true;
}
bool renderer::create_surface(SDL_Window* window) {
if (!SDL_Vulkan_CreateSurface(window, instance_->get_instance(), nullptr, &surface_)) {
LOG_ERROR("Failed to create Vulkan surface: {}", SDL_GetError());
VkSurfaceKHR c_surface = VK_NULL_HANDLE;
if (!SDL_Vulkan_CreateSurface(window, static_cast<VkInstance>(instance_->get_instance()), nullptr, &c_surface)) {
MILAI_LOG_ERROR("Failed to create Vulkan surface: {}", SDL_GetError());
return false;
}
surface_ = c_surface;
LOG_DEBUG("Vulkan surface created");
MILAI_LOG_DEBUG("Vulkan surface created");
return true;
}
bool renderer::create_swapchain(u32 width, u32 height) {
swapchain_config swap_config{};
swap_config.surface = surface_;
swap_config.width = width;
swap_config.height = height;
swap_config.enable_vsync = config_.enable_vsync;
if (config_.enable_vsync) {
swap_config.preferred_present_mode = vk::PresentModeKHR::eFifo;
} else {
swap_config.preferred_present_mode = vk::PresentModeKHR::eMailbox;
}
swapchain_ = std::make_shared<swapchain>(device_, swap_config);
swapchain_ = std::make_shared<swapchain>(device_, surface_, width, height, swap_config);
if (!swapchain_->is_valid()) {
LOG_ERROR("Failed to create swapchain");
MILAI_LOG_ERROR("Failed to create swapchain");
return false;
}
LOG_DEBUG("Swapchain created: {}x{}", width, height);
MILAI_LOG_DEBUG("Swapchain created: {}x{}", width, height);
return true;
}
bool renderer::create_command_pools() {
// 创建主命令池
command_pool_ = std::make_unique<command_pool>(
device_,
device_->get_queue_family_indices().graphics_family,
device_,
device_->get_graphics_queue_family(),
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
);
if (!command_pool_->is_valid()) {
LOG_ERROR("Failed to create command pool");
MILAI_LOG_ERROR("Failed to create command pool");
return false;
}
@@ -603,30 +596,29 @@ bool renderer::create_command_pools() {
for (u32 i = 0; i < config_.frames_in_flight; ++i) {
command_buffers_[i] = command_pool_->allocate_buffer();
if (!command_buffers_[i] || !command_buffers_[i]->is_valid()) {
LOG_ERROR("Failed to allocate command buffer {}", i);
MILAI_LOG_ERROR("Failed to allocate command buffer {}", i);
return false;
}
}
LOG_DEBUG("Command pools and buffers created");
MILAI_LOG_DEBUG("Command pools and buffers created");
return true;
}
bool renderer::create_depth_resources() {
// 选择深度格式
VkFormat candidates[] = {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT};
vk::Format candidates[] = {vk::Format::eD32Sfloat, vk::Format::eD32SfloatS8Uint, vk::Format::eD24UnormS8Uint};
for (VkFormat format : candidates) {
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(device_->get_physical_device(), format, &props);
for (vk::Format format : candidates) {
vk::FormatProperties props = device_->get_physical_device().getFormatProperties(format);
if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
if (props.optimalTilingFeatures & vk::FormatFeatureFlagBits::eDepthStencilAttachment) {
depth_format_ = format;
break;
}
}
VkExtent2D extent = swapchain_->get_extent();
vk::Extent2D extent = swapchain_->get_extent();
// 创建深度图像
VkImageCreateInfo image_info{};
@@ -637,7 +629,7 @@ bool renderer::create_depth_resources() {
image_info.extent.depth = 1;
image_info.mipLevels = 1;
image_info.arrayLayers = 1;
image_info.format = depth_format_;
image_info.format = static_cast<VkFormat>(depth_format_);
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
@@ -647,63 +639,66 @@ bool renderer::create_depth_resources() {
VmaAllocationCreateInfo alloc_info{};
alloc_info.usage = VMA_MEMORY_USAGE_GPU_ONLY;
VkImage depth_image_raw = VK_NULL_HANDLE;
VkResult result = vmaCreateImage(allocator_, &image_info, &alloc_info,
&depth_image_, &depth_allocation_, nullptr);
&depth_image_raw, &depth_allocation_, nullptr);
if (result != VK_SUCCESS) {
LOG_ERROR("Failed to create depth image: {}", vk_result_to_string(result));
MILAI_LOG_ERROR("Failed to create depth image: {}", vk_result_to_string(static_cast<vk::Result>(result)));
return false;
}
depth_image_ = depth_image_raw;
// 创建深度图像视图
VkImageViewCreateInfo view_info{};
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
vk::ImageViewCreateInfo view_info{};
view_info.image = depth_image_;
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
view_info.viewType = vk::ImageViewType::e2D;
view_info.format = depth_format_;
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
view_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eDepth;
view_info.subresourceRange.baseMipLevel = 0;
view_info.subresourceRange.levelCount = 1;
view_info.subresourceRange.baseArrayLayer = 0;
view_info.subresourceRange.layerCount = 1;
result = vkCreateImageView(device_->get_device(), &view_info, nullptr, &depth_image_view_);
if (result != VK_SUCCESS) {
LOG_ERROR("Failed to create depth image view: {}", vk_result_to_string(result));
auto [view_result, image_view] = device_->get_device().createImageView(view_info);
if (view_result != vk::Result::eSuccess) {
MILAI_LOG_ERROR("Failed to create depth image view: {}", vk_result_to_string(view_result));
return false;
}
depth_image_view_ = image_view;
LOG_DEBUG("Depth resources created: format={}", static_cast<int>(depth_format_));
MILAI_LOG_DEBUG("Depth resources created: format={}", static_cast<int>(depth_format_));
return true;
}
bool renderer::recreate_swapchain(u32 width, u32 height) {
LOG_DEBUG("Recreating swapchain: {}x{}", width, height);
MILAI_LOG_DEBUG("Recreating swapchain: {}x{}", width, height);
// 等待设备空闲
device_->wait_idle();
// 销毁旧的深度资源
if (depth_image_view_ != VK_NULL_HANDLE) {
vkDestroyImageView(device_->get_device(), depth_image_view_, nullptr);
depth_image_view_ = VK_NULL_HANDLE;
if (depth_image_view_) {
device_->get_device().destroyImageView(depth_image_view_);
depth_image_view_ = nullptr;
}
if (depth_image_ != VK_NULL_HANDLE) {
vmaDestroyImage(allocator_, depth_image_, depth_allocation_);
depth_image_ = VK_NULL_HANDLE;
depth_allocation_ = VK_NULL_HANDLE;
if (depth_image_) {
vmaDestroyImage(allocator_, static_cast<VkImage>(depth_image_), depth_allocation_);
depth_image_ = nullptr;
depth_allocation_ = nullptr;
}
// 重建交换链
swapchain_config swap_config{};
swap_config.surface = surface_;
swap_config.width = width;
swap_config.height = height;
swap_config.enable_vsync = config_.enable_vsync;
swap_config.old_swapchain = swapchain_ ? swapchain_->get_swapchain() : VK_NULL_HANDLE;
if (config_.enable_vsync) {
swap_config.preferred_present_mode = vk::PresentModeKHR::eFifo;
} else {
swap_config.preferred_present_mode = vk::PresentModeKHR::eMailbox;
}
swap_config.old_swapchain = swapchain_ ? swapchain_->get_swapchain() : nullptr;
auto new_swapchain = std::make_shared<swapchain>(device_, swap_config);
auto new_swapchain = std::make_shared<swapchain>(device_, surface_, width, height, swap_config);
if (!new_swapchain->is_valid()) {
LOG_ERROR("Failed to recreate swapchain");
MILAI_LOG_ERROR("Failed to recreate swapchain");
return false;
}
@@ -712,7 +707,7 @@ bool renderer::recreate_swapchain(u32 width, u32 height) {
// 重建深度资源
if (!create_depth_resources()) {
LOG_ERROR("Failed to recreate depth resources");
MILAI_LOG_ERROR("Failed to recreate depth resources");
return false;
}
@@ -732,7 +727,7 @@ bool renderer::recreate_swapchain(u32 width, u32 height) {
on_swapchain_recreated_();
}
LOG_INFO("Swapchain recreated: {}x{}", width, height);
MILAI_LOG_INFO("Swapchain recreated: {}x{}", width, height);
return true;
}
@@ -748,14 +743,14 @@ void renderer::destroy_resources() {
frame_sync_.reset();
// 销毁深度资源
if (depth_image_view_ != VK_NULL_HANDLE && device_) {
vkDestroyImageView(device_->get_device(), depth_image_view_, nullptr);
depth_image_view_ = VK_NULL_HANDLE;
if (depth_image_view_ && device_) {
device_->get_device().destroyImageView(depth_image_view_);
depth_image_view_ = nullptr;
}
if (depth_image_ != VK_NULL_HANDLE && allocator_) {
vmaDestroyImage(allocator_, depth_image_, depth_allocation_);
depth_image_ = VK_NULL_HANDLE;
depth_allocation_ = VK_NULL_HANDLE;
if (depth_image_ && allocator_) {
vmaDestroyImage(allocator_, static_cast<VkImage>(depth_image_), depth_allocation_);
depth_image_ = nullptr;
depth_allocation_ = nullptr;
}
// 销毁交换链
@@ -768,9 +763,9 @@ void renderer::destroy_resources() {
}
// 销毁表面
if (surface_ != VK_NULL_HANDLE && instance_) {
vkDestroySurfaceKHR(instance_->get_instance(), surface_, nullptr);
surface_ = VK_NULL_HANDLE;
if (surface_ && instance_) {
instance_->get_instance().destroySurfaceKHR(surface_);
surface_ = nullptr;
}
// 销毁设备
@@ -782,49 +777,47 @@ void renderer::destroy_resources() {
window_ = nullptr;
}
void renderer::transition_image_layout(VkCommandBuffer cmd_buffer, VkImage image,
VkImageLayout old_layout, VkImageLayout new_layout)
void renderer::transition_image_layout(vk::CommandBuffer cmd_buffer, vk::Image image,
vk::ImageLayout old_layout, vk::ImageLayout new_layout)
{
VkImageMemoryBarrier2 barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
vk::ImageMemoryBarrier2 barrier{};
barrier.oldLayout = old_layout;
barrier.newLayout = new_layout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
// 设置源和目标阶段/访问掩码
if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
new_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) {
barrier.srcStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT;
barrier.srcAccessMask = VK_ACCESS_2_NONE;
barrier.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
barrier.dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
} else if (old_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL &&
new_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
barrier.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
barrier.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
barrier.dstStageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT;
barrier.dstAccessMask = VK_ACCESS_2_NONE;
if (old_layout == vk::ImageLayout::eUndefined &&
new_layout == vk::ImageLayout::eColorAttachmentOptimal) {
barrier.srcStageMask = vk::PipelineStageFlagBits2::eTopOfPipe;
barrier.srcAccessMask = vk::AccessFlagBits2::eNone;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput;
barrier.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite;
} else if (old_layout == vk::ImageLayout::eColorAttachmentOptimal &&
new_layout == vk::ImageLayout::ePresentSrcKHR) {
barrier.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput;
barrier.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe;
barrier.dstAccessMask = vk::AccessFlagBits2::eNone;
} else {
// 通用转换
barrier.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
barrier.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT;
barrier.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
barrier.dstAccessMask = VK_ACCESS_2_MEMORY_READ_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT;
barrier.srcStageMask = vk::PipelineStageFlagBits2::eAllCommands;
barrier.srcAccessMask = vk::AccessFlagBits2::eMemoryWrite;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands;
barrier.dstAccessMask = vk::AccessFlagBits2::eMemoryRead | vk::AccessFlagBits2::eMemoryWrite;
}
VkDependencyInfo dependency_info{};
dependency_info.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
vk::DependencyInfo dependency_info{};
dependency_info.imageMemoryBarrierCount = 1;
dependency_info.pImageMemoryBarriers = &barrier;
vkCmdPipelineBarrier2(cmd_buffer, &dependency_info);
cmd_buffer.pipelineBarrier2(&dependency_info);
}
} // namespace milai