迁移到vulkan hpp
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user