/
kochou-framework
/
kochou
Обзор
Документация
Войти
/
kochou-framework
/
kochou
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
master
src/entity/swapchain.cpp
274 строки
10 KB
urlagushka
Please enter the commit message for your changes. Lines starting
23 май 2026, 05:58
23 май 2026, 05:58
47f6192
Код
Авторство
О чём код?
#include <algorithm> #include <limits> #include <ktl/api.hpp> #include <kochou/context/view.hpp> #include <kochou/entity/surface.hpp> #include <kochou/entity/swapchain.hpp> #include <kochou/log.hpp> #include <kochou/requirements/allowed.hpp> #include <kochou/requirements/ensure.hpp> #include <kochou/requirements/extension.hpp> #include <kochou/requirements/should.hpp> namespace { ktl::result< std::tuple< std::vector< ktl::api::format >, std::vector< ktl::api::color_space_khr > >, ktl::errc > get_colors(ktl::api::physical_device _physical_device, ktl::api::surface_khr _surface) noexcept { ktl::u32 amount = 0; ktl::api::result rc = ktl::api::get_physical_device_surface_formats_khr(_physical_device, _surface, &amount, nullptr); if (rc != ktl::api::result::v_success) { return ktl::err(ktl::cast_api_result(rc)); } std::vector< ktl::api::surface_format_khr > surface_formats(amount); rc = ktl::api::get_physical_device_surface_formats_khr(_physical_device, _surface, &amount, surface_formats.data()); if (rc != ktl::api::result::v_success) { return ktl::err(ktl::cast_api_result(rc)); } std::vector< ktl::api::format > formats(amount); std::vector< ktl::api::color_space_khr > color_spaces(amount); for (ktl::u32 i = 0; i < amount; ++i) { formats[i] = surface_formats[i].format; color_spaces[i] = surface_formats[i].color_space; } return std::make_tuple(formats, color_spaces); } ktl::result< std::vector< ktl::api::present_mode_khr >, ktl::errc > get_present_modes(ktl::api::physical_device _physical_device, ktl::api::surface_khr _surface) noexcept { ktl::u32 amount = 0; ktl::api::result rc = ktl::api::get_physical_device_surface_present_modes_khr(_physical_device, _surface, &amount, nullptr); if (rc != ktl::api::result::v_success) { return ktl::err(ktl::cast_api_result(rc)); } std::vector< ktl::api::present_mode_khr > present_modes(amount); rc = ktl::api::get_physical_device_surface_present_modes_khr(_physical_device, _surface, &amount, present_modes.data()); if (rc != ktl::api::result::v_success) { return ktl::err(ktl::cast_api_result(rc)); } return present_modes; } ktl::result< ktl::api::surface_capabilities_khr, ktl::errc > get_capabilities(ktl::api::physical_device _physical_device, ktl::api::surface_khr _surface) noexcept { ktl::api::surface_capabilities_khr capabilities; ktl::api::result rc = ktl::api::get_physical_device_surface_capabilities_khr(_physical_device, _surface, &capabilities); if (rc != ktl::api::result::v_success) { return ktl::err(ktl::cast_api_result(rc)); } return capabilities; } } // namespace ktl::errc kochou::entity::swapchain::ensure(kochou::shared_context _sctx) noexcept { return kochou::ensure< kochou::extension< ktl::api::extension::khr_swapchain > >(_sctx); } ktl::errc kochou::entity::swapchain::should(kochou::shared_context _sctx) noexcept { return kochou::should< kochou::extension< ktl::api::extension::khr_swapchain > >(_sctx); } bool kochou::entity::swapchain::allowed(kochou::shared_context _sctx) noexcept { return kochou::allowed< kochou::extension< ktl::api::extension::khr_swapchain > >(_sctx); } // TODO debug properties resolve ktl::result< std::tuple< kochou::entity::shared_swapchain, kochou::entity::swapchain::output_info >, ktl::errc > kochou::entity::swapchain::make(kochou::shared_context _sctx, kochou::entity::shared_surface _surface, const input_info & _input) noexcept { auto physical_device = kochou::view::physical_device(_sctx); kochou::log::debug("physical_device={}", physical_device); auto surface = _surface->raw; kochou::log::debug("surface={}", surface); auto width = _surface->width(); kochou::log::debug("width={}", width); auto height = _surface->height(); kochou::log::debug("height={}", height); auto colors_rc = get_colors(physical_device, surface); if (!colors_rc.has_value()) { kochou::log::error("get_colors failed"); return ktl::err(colors_rc.error()); } auto [formats, color_spaces] = colors_rc.take_value(); auto present_modes_rc = get_present_modes(physical_device, surface); if (!present_modes_rc.has_value()) { kochou::log::error("get_present_modes failed"); return ktl::err(present_modes_rc.error()); } auto present_modes = present_modes_rc.take_value(); auto capabilities_rc = get_capabilities(physical_device, surface); if (!capabilities_rc.has_value()) { kochou::log::error("get_capabilities failed"); return ktl::err(capabilities_rc.error()); } auto capabilities = capabilities_rc.take_value(); ktl::api::format chosen_format = _input.format; ktl::api::color_space_khr chosen_cs = _input.color_space; bool found = false; for (ktl::u32 i = 0; i < formats.size(); ++i) { if (formats[i] == chosen_format && color_spaces[i] == chosen_cs) { found = true; break; } } if (!found && !_input.is_strict && !formats.empty()) { chosen_format = formats[0]; chosen_cs = color_spaces[0]; } else if (!found) { return ktl::err(ktl::errc::unsupported_format); } kochou::log::debug("format resolved, chosen={}", static_cast< ktl::u32 >(chosen_format)); kochou::log::debug("color_space resolved, chosen={}", static_cast< ktl::u32 >(chosen_cs)); ktl::api::present_mode_khr chosen_mode = _input.present_mode; if (std::find(present_modes.begin(), present_modes.end(), chosen_mode) == present_modes.end()) { if (!_input.is_strict && !present_modes.empty()) { chosen_mode = present_modes[0]; } else { return ktl::err(ktl::errc::unsupported_present_mode); } } kochou::log::debug("present mode resolved, chosen={}", static_cast< ktl::u32 >(chosen_mode)); ktl::api::extent_2d actual_extent{}; if (capabilities.current_extent.width == std::numeric_limits< ktl::u32 >::max()) { actual_extent.width = std::clamp(width, capabilities.min_image_extent.width, capabilities.max_image_extent.width); actual_extent.height = std::clamp(height, capabilities.min_image_extent.height, capabilities.max_image_extent.height); } else { actual_extent = capabilities.current_extent; } kochou::log::debug("extend2d resolved, chosen={}:{}", actual_extent.width, actual_extent.height); ktl::api::swapchain_create_info_khr create_info{}; create_info.surface = surface; create_info.min_image_count = std::clamp(_input.buffering, capabilities.min_image_count, capabilities.max_image_count); create_info.image_format = chosen_format; create_info.image_color_space = chosen_cs; create_info.image_extent = actual_extent; create_info.image_array_layers = 1; create_info.image_usage = static_cast< ktl::api::image_usage_flags >(ktl::api::image_usage_flag_bits::v_color_attachment_bit); create_info.image_sharing_mode = ktl::api::sharing_mode::v_exclusive; create_info.pre_transform = capabilities.current_transform; create_info.composite_alpha = ktl::api::composite_alpha_flag_bits_khr::v_opaque_bit_khr; create_info.present_mode = chosen_mode; create_info.clipped = true; create_info.old_swapchain = {}; ktl::api::swapchain_khr raw_handle{}; auto rc = ktl::api::create_swapchain_khr(kochou::view::device(_sctx), &create_info, nullptr, &raw_handle); if (rc != ktl::api::result::v_success) { kochou::log::debug("create_swapchain_khr failed"); return ktl::err(ktl::cast_api_result(rc)); } auto shared_swapchain_rc = ktl::memory::make_shared< swapchain >(_sctx, _surface, raw_handle, true); if (!shared_swapchain_rc.has_value()) { return ktl::err(shared_swapchain_rc.error()); } return std::make_tuple(shared_swapchain_rc.take_value(), output_info{create_info.min_image_count, chosen_format, chosen_mode}); } kochou::entity::swapchain::swapchain(kochou::shared_context _sctx, kochou::entity::shared_surface _surface, ktl::api::swapchain_khr _swapchain, bool _is_need_destroy) noexcept : raw(_swapchain), is_need_destroy(_is_need_destroy), sctx_(_sctx), surface_(_surface) { } kochou::entity::swapchain::swapchain(swapchain && _rhs) noexcept : raw(std::exchange(_rhs.raw, nullptr)), is_need_destroy(std::exchange(_rhs.is_need_destroy, false)), sctx_(std::exchange(_rhs.sctx_, nullptr)), surface_(std::exchange(_rhs.surface_, nullptr)) { } kochou::entity::swapchain & kochou::entity::swapchain::operator=(swapchain && _rhs) noexcept { if (std::addressof(_rhs) == this) { return *this; } clean(); raw = std::exchange(_rhs.raw, nullptr); is_need_destroy = std::exchange(_rhs.is_need_destroy, false); sctx_ = std::exchange(_rhs.sctx_, nullptr); surface_ = std::exchange(_rhs.surface_, nullptr); return *this; } kochou::entity::swapchain::~swapchain() noexcept { kochou::log::debug("~swapchain"); clean(); } void kochou::entity::swapchain::clean() noexcept { if (raw && is_need_destroy && sctx_ && surface_) { auto device = kochou::view::device(sctx_); ktl::api::destroy_swapchain_khr(device, raw, nullptr); raw = nullptr; is_need_destroy = false; } sctx_ = nullptr; surface_ = nullptr; }