Merge branch 'dev' into dev

pull/65/head
BoomMicrophone 2024-03-31 17:55:38 +07:00
commit dcd2890af6
19 changed files with 170 additions and 89 deletions

@ -180,3 +180,7 @@ License: GPL-3.0-or-later
Files: dist/icns_generator.sh Files: dist/icns_generator.sh
Copyright: 2024 suyu Emulator Project Copyright: 2024 suyu Emulator Project
License: GPL-3.0-or-later License: GPL-3.0-or-later
Files: img/*
Copyright: 2024 suyu Emulator Project
License: CC0-1.0

@ -396,7 +396,71 @@ function(set_suyu_qt_components)
set(SUYU_QT_COMPONENTS ${SUYU_QT_COMPONENTS2} PARENT_SCOPE) set(SUYU_QT_COMPONENTS ${SUYU_QT_COMPONENTS2} PARENT_SCOPE)
endfunction(set_suyu_qt_components) endfunction(set_suyu_qt_components)
# find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the suyu_find_package
if (ENABLE_SDL2)
if (SUYU_USE_BUNDLED_SDL2)
# Detect toolchain and platform
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
set(SDL2_VER "SDL2-2.28.2")
else()
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable SUYU_USE_BUNDLED_SDL2 and provide your own.")
endif()
if (DEFINED SDL2_VER)
download_bundled_external("sdl2/" ${SDL2_VER} SDL2_PREFIX)
endif()
set(SDL2_FOUND YES)
set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers")
set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library")
set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll")
add_library(SDL2::SDL2 INTERFACE IMPORTED)
target_link_libraries(SDL2::SDL2 INTERFACE "${SDL2_LIBRARY}")
target_include_directories(SDL2::SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
elseif (SUYU_USE_EXTERNAL_SDL2)
message(STATUS "Using SDL2 from externals.")
else()
find_package(SDL2 2.26.4 REQUIRED)
endif()
endif()
# List of all FFmpeg components required
set(FFmpeg_COMPONENTS
avcodec
avfilter
avutil
swscale)
if (UNIX AND NOT APPLE AND NOT ANDROID)
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBVA libva)
endif()
if (NOT SUYU_USE_BUNDLED_FFMPEG)
# Use system installed FFmpeg
find_package(FFmpeg 4.3 REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS})
endif()
if (WIN32 AND SUYU_CRASH_DUMPS)
set(BREAKPAD_VER "breakpad-c89f9dd")
download_bundled_external("breakpad/" ${BREAKPAD_VER} BREAKPAD_PREFIX)
set(BREAKPAD_CLIENT_INCLUDE_DIR "${BREAKPAD_PREFIX}/include")
set(BREAKPAD_CLIENT_LIBRARY "${BREAKPAD_PREFIX}/lib/libbreakpad_client.lib")
add_library(libbreakpad_client INTERFACE IMPORTED)
target_link_libraries(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_LIBRARY}")
target_include_directories(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_INCLUDE_DIR}")
endif()
# Prefer the -pthread flag on Linux.
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
add_subdirectory(externals)
# Qt5 requires that we find components, so it doesn't fit our pretty little find package function # Qt5 requires that we find components, so it doesn't fit our pretty little find package function
# Qt6 sets Vulkan::Headers, so Qt search has to come after externals, so it doesn't get to do it.
if(ENABLE_QT) if(ENABLE_QT)
set(QT_VERSION 5.15) set(QT_VERSION 5.15)
# These are used to specify minimum versions # These are used to specify minimum versions
@ -535,67 +599,6 @@ if(ENABLE_QT)
endif() endif()
# find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the suyu_find_package
if (ENABLE_SDL2)
if (SUYU_USE_BUNDLED_SDL2)
# Detect toolchain and platform
if ((MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1940) AND ARCHITECTURE_x86_64)
set(SDL2_VER "SDL2-2.28.2")
else()
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable SUYU_USE_BUNDLED_SDL2 and provide your own.")
endif()
if (DEFINED SDL2_VER)
download_bundled_external("sdl2/" ${SDL2_VER} SDL2_PREFIX)
endif()
set(SDL2_FOUND YES)
set(SDL2_INCLUDE_DIR "${SDL2_PREFIX}/include" CACHE PATH "Path to SDL2 headers")
set(SDL2_LIBRARY "${SDL2_PREFIX}/lib/x64/SDL2.lib" CACHE PATH "Path to SDL2 library")
set(SDL2_DLL_DIR "${SDL2_PREFIX}/lib/x64/" CACHE PATH "Path to SDL2.dll")
add_library(SDL2::SDL2 INTERFACE IMPORTED)
target_link_libraries(SDL2::SDL2 INTERFACE "${SDL2_LIBRARY}")
target_include_directories(SDL2::SDL2 INTERFACE "${SDL2_INCLUDE_DIR}")
elseif (SUYU_USE_EXTERNAL_SDL2)
message(STATUS "Using SDL2 from externals.")
else()
find_package(SDL2 2.26.4 REQUIRED)
endif()
endif()
# List of all FFmpeg components required
set(FFmpeg_COMPONENTS
avcodec
avfilter
avutil
swscale)
if (UNIX AND NOT APPLE AND NOT ANDROID)
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBVA libva)
endif()
if (NOT SUYU_USE_BUNDLED_FFMPEG)
# Use system installed FFmpeg
find_package(FFmpeg 4.3 REQUIRED QUIET COMPONENTS ${FFmpeg_COMPONENTS})
endif()
if (WIN32 AND SUYU_CRASH_DUMPS)
set(BREAKPAD_VER "breakpad-c89f9dd")
download_bundled_external("breakpad/" ${BREAKPAD_VER} BREAKPAD_PREFIX)
set(BREAKPAD_CLIENT_INCLUDE_DIR "${BREAKPAD_PREFIX}/include")
set(BREAKPAD_CLIENT_LIBRARY "${BREAKPAD_PREFIX}/lib/libbreakpad_client.lib")
add_library(libbreakpad_client INTERFACE IMPORTED)
target_link_libraries(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_LIBRARY}")
target_include_directories(libbreakpad_client INTERFACE "${BREAKPAD_CLIENT_INCLUDE_DIR}")
endif()
# Prefer the -pthread flag on Linux.
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
# Platform-specific library requirements # Platform-specific library requirements
# ====================================== # ======================================
@ -710,7 +713,6 @@ if (SUYU_USE_FASTER_LD AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
endif() endif()
endif() endif()
add_subdirectory(externals)
add_subdirectory(src) add_subdirectory(src)
# Set suyu project or suyu-cmd project as default StartUp Project in Visual Studio depending on whether QT is enabled or not # Set suyu project or suyu-cmd project as default StartUp Project in Visual Studio depending on whether QT is enabled or not

@ -35,6 +35,9 @@ It is written in C++ with portability in mind, and we're actively working on bui
<a href="https://git.suyu.dev/suyu/suyu/actions">Pipelines</a> <a href="https://git.suyu.dev/suyu/suyu/actions">Pipelines</a>
</p> </p>
## Hardware Requirements
[Click here to see the Hardware Requirements](https://git.suyu.dev/suyu/suyu/wiki/Hardware-Requirements)
## Status ## Status
We currently have builds over at the [Releases](https://git.suyu.dev/suyu/suyu/releases) page. We currently have builds over at the [Releases](https://git.suyu.dev/suyu/suyu/releases) page.

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

@ -4,6 +4,7 @@
#include <atomic> #include <atomic>
#include <chrono> #include <chrono>
#include <climits> #include <climits>
#include <mutex>
#include <thread> #include <thread>
#include <fmt/format.h> #include <fmt/format.h>
@ -231,8 +232,15 @@ public:
if (!filter.CheckMessage(log_class, log_level)) { if (!filter.CheckMessage(log_class, log_level)) {
return; return;
} }
message_queue.EmplaceWait(
CreateEntry(log_class, log_level, filename, line_num, function, std::move(message))); auto entry =
CreateEntry(log_class, log_level, filename, line_num, function, std::move(message));
if (Settings::values.log_async) {
message_queue.EmplaceWait(entry);
} else {
std::scoped_lock l{sync_mutex};
ForEachBackend([&entry](Backend& backend) { backend.Write(entry); });
}
} }
private: private:
@ -313,6 +321,7 @@ private:
#endif #endif
MPSCQueue<Entry> message_queue{}; MPSCQueue<Entry> message_queue{};
std::mutex sync_mutex;
std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()}; std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
std::jthread backend_thread; std::jthread backend_thread;
}; };
@ -345,9 +354,11 @@ void SetColorConsoleBackendEnabled(bool enabled) {
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename, void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
unsigned int line_num, const char* function, fmt::string_view format, unsigned int line_num, const char* function, fmt::string_view format,
const fmt::format_args& args) { const fmt::format_args& args) {
if (!initialization_in_progress_suppress_logging) { if (initialization_in_progress_suppress_logging) {
return;
}
Impl::Instance().PushEntry(log_class, log_level, filename, line_num, function, Impl::Instance().PushEntry(log_class, log_level, filename, line_num, function,
fmt::vformat(format, args)); fmt::vformat(format, args));
}
} }
} // namespace Common::Log } // namespace Common::Log

@ -171,6 +171,7 @@ const char* GetLogClassName(Class log_class) {
#define SUB(x, y) \ #define SUB(x, y) \
case Class::x##_##y: \ case Class::x##_##y: \
return #x "." #y; return #x "." #y;
// return #x "_" #y;
ALL_LOG_CLASSES() ALL_LOG_CLASSES()
#undef CLS #undef CLS
#undef SUB #undef SUB

@ -605,6 +605,7 @@ struct Values {
// Miscellaneous // Miscellaneous
Setting<std::string> log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous}; Setting<std::string> log_filter{linkage, "*:Info", "log_filter", Category::Miscellaneous};
Setting<bool> log_async{linkage, true, "log_async", Category::Miscellaneous};
Setting<bool> use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous}; Setting<bool> use_dev_keys{linkage, false, "use_dev_keys", Category::Miscellaneous};
// Network // Network

@ -106,6 +106,7 @@ std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
out_control = nacp.GetRawBytes(); out_control = nacp.GetRawBytes();
} else { } else {
out_control.resize(sizeof(FileSys::RawNACP)); out_control.resize(sizeof(FileSys::RawNACP));
memset(out_control.data(), 0, sizeof(u8) * out_control.size());
} }
auto& storage = system.GetContentProviderUnion(); auto& storage = system.GetContentProviderUnion();

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2024 suyu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/applet_data_broker.h" #include "core/hle/service/am/applet_data_broker.h"
@ -101,6 +102,22 @@ Result ILibraryAppletAccessor::PushInData(SharedPointer<IStorage> storage) {
Result ILibraryAppletAccessor::PopOutData(Out<SharedPointer<IStorage>> out_storage) { Result ILibraryAppletAccessor::PopOutData(Out<SharedPointer<IStorage>> out_storage) {
LOG_DEBUG(Service_AM, "called"); LOG_DEBUG(Service_AM, "called");
// suyu todo: move library applet fix to another function
// since this function is only called for applets that give a result,
// applets that don't (e.g. info applets in 1st party games) simply freeze
if (auto caller = m_applet->caller_applet.lock(); caller != nullptr) {
caller->SetInteractibleLocked(true);
caller->lifecycle_manager.SetFocusState(FocusState::InFocus);
caller->lifecycle_manager.UpdateRequestedFocusState();
caller->lifecycle_manager.SetResumeNotificationEnabled(true);
caller->lifecycle_manager.RequestResumeNotification();
caller->UpdateSuspensionStateLocked(true);
} else {
LOG_CRITICAL(Service_AM, "Caller applet pointer is invalid.");
LOG_CRITICAL(Service_AM, "The emulator will freeze!");
}
R_RETURN(m_broker->GetOutData().Pop(out_storage.Get())); R_RETURN(m_broker->GetOutData().Pop(out_storage.Get()));
} }

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project, 2024 sudachi Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-FileCopyrightText: 2024 sudachi Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <string_view> #include <string_view>

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project, 2024 sudachi Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-FileCopyrightText: 2024 sudachi Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <string_view> #include <string_view>

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project, 2024 sudachi Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-FileCopyrightText: 2024 sudachi Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <bit> #include <bit>

@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project, 2024 sudachi Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-FileCopyrightText: 2024 sudachi Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once

@ -73,6 +73,7 @@ void ConfigureDebug::SetConfiguration() {
ui->disable_loop_safety_checks->setChecked( ui->disable_loop_safety_checks->setChecked(
Settings::values.disable_shader_loop_safety_checks.GetValue()); Settings::values.disable_shader_loop_safety_checks.GetValue());
ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue()); ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue());
ui->log_async->setChecked(Settings::values.log_async.GetValue());
ui->perform_vulkan_check->setChecked(Settings::values.perform_vulkan_check.GetValue()); ui->perform_vulkan_check->setChecked(Settings::values.perform_vulkan_check.GetValue());
#ifdef SUYU_USE_QT_WEB_ENGINE #ifdef SUYU_USE_QT_WEB_ENGINE
@ -115,6 +116,7 @@ void ConfigureDebug::ApplyConfiguration() {
Common::Log::Filter filter; Common::Log::Filter filter;
filter.ParseFilterString(Settings::values.log_filter.GetValue()); filter.ParseFilterString(Settings::values.log_filter.GetValue());
Common::Log::SetGlobalFilter(filter); Common::Log::SetGlobalFilter(filter);
Settings::values.log_async = ui->log_async->isChecked();
} }
void ConfigureDebug::changeEvent(QEvent* event) { void ConfigureDebug::changeEvent(QEvent* event) {

@ -164,6 +164,20 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1">
<widget class="QCheckBox" name="log_async">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>When checked, logging will run asynchronously. This may cut the log on crashes.
When unchecked, logging will run synchronously. This will slow down the emulator, but allow all logs to be written. Useful for debugging.</string>
</property>
<property name="text">
<string>Log asynchronously</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2"> <item row="0" column="0" colspan="2">
<widget class="QWidget" name="logging_widget" native="true"> <widget class="QWidget" name="logging_widget" native="true">
<property name="sizePolicy"> <property name="sizePolicy">
@ -199,7 +213,14 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLineEdit" name="log_filter_edit"/> <widget class="QLineEdit" name="log_filter_edit">
<property name="toolTip">
<string>Log filter in the form class:level.
Separate multiple filters with a space.
Levels: Trace, Debug, Info, Warning, Error, Critical
Classes: See Common/logging/types.h</string>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>

@ -1406,7 +1406,7 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
if (runtime->device.HasDebuggingToolAttached()) { if (runtime->device.HasDebuggingToolAttached()) {
original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
} }
current_image = *original_image; current_image = &Image::original_image;
storage_image_views.resize(info.resources.levels); storage_image_views.resize(info.resources.levels);
if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported() && if (IsPixelFormatASTC(info.format) && !runtime->device.IsOptimalAstcSupported() &&
Settings::values.astc_recompression.GetValue() == Settings::values.astc_recompression.GetValue() ==
@ -1550,8 +1550,8 @@ VkImageView Image::StorageImageView(s32 level) noexcept {
if (!view) { if (!view) {
const auto format_info = const auto format_info =
MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format); MaxwellToVK::SurfaceFormat(runtime->device, FormatType::Optimal, true, info.format);
view = view = MakeStorageView(runtime->device.GetLogical(), level, *(this->*current_image),
MakeStorageView(runtime->device.GetLogical(), level, current_image, format_info.format); format_info.format);
} }
return *view; return *view;
} }
@ -1582,7 +1582,7 @@ bool Image::ScaleUp(bool ignore) {
runtime->ViewFormats(info.format)); runtime->ViewFormats(info.format));
ignore = false; ignore = false;
} }
current_image = *scaled_image; current_image = &Image::scaled_image;
if (ignore) { if (ignore) {
return true; return true;
} }
@ -1607,7 +1607,7 @@ bool Image::ScaleDown(bool ignore) {
} }
ASSERT(info.type != ImageType::Linear); ASSERT(info.type != ImageType::Linear);
flags &= ~ImageFlagBits::Rescaled; flags &= ~ImageFlagBits::Rescaled;
current_image = *original_image; current_image = &Image::original_image;
if (ignore) { if (ignore) {
return true; return true;
} }
@ -1726,7 +1726,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
const VkImageViewUsageCreateInfo image_view_usage{ const VkImageViewUsageCreateInfo image_view_usage{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
.usage = ImageUsageFlags(format_info, format), .usage = image.UsageFlags(),
}; };
const VkImageViewCreateInfo create_info{ const VkImageViewCreateInfo create_info{
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,

@ -24,7 +24,6 @@ using Common::SlotVector;
using VideoCommon::ImageId; using VideoCommon::ImageId;
using VideoCommon::NUM_RT; using VideoCommon::NUM_RT;
using VideoCommon::Region2D; using VideoCommon::Region2D;
using VideoCommon::RenderTargets;
using VideoCore::Surface::PixelFormat; using VideoCore::Surface::PixelFormat;
class BlitImageHelper; class BlitImageHelper;
@ -157,13 +156,17 @@ public:
std::span<const VideoCommon::BufferImageCopy> copies); std::span<const VideoCommon::BufferImageCopy> copies);
[[nodiscard]] VkImage Handle() const noexcept { [[nodiscard]] VkImage Handle() const noexcept {
return current_image; return *(this->*current_image);
} }
[[nodiscard]] VkImageAspectFlags AspectMask() const noexcept { [[nodiscard]] VkImageAspectFlags AspectMask() const noexcept {
return aspect_mask; return aspect_mask;
} }
[[nodiscard]] VkImageUsageFlags UsageFlags() const noexcept {
return (this->*current_image).UsageFlags();
}
/// Returns true when the image is already initialized and mark it as initialized /// Returns true when the image is already initialized and mark it as initialized
[[nodiscard]] bool ExchangeInitialization() noexcept { [[nodiscard]] bool ExchangeInitialization() noexcept {
return std::exchange(initialized, true); return std::exchange(initialized, true);
@ -186,11 +189,15 @@ private:
TextureCacheRuntime* runtime{}; TextureCacheRuntime* runtime{};
vk::Image original_image; vk::Image original_image;
vk::Image scaled_image;
// Use a pointer to field because it is relative, so that the object can be
// moved without breaking the reference.
vk::Image Image::*current_image{};
std::vector<vk::ImageView> storage_image_views; std::vector<vk::ImageView> storage_image_views;
VkImageAspectFlags aspect_mask = 0; VkImageAspectFlags aspect_mask = 0;
bool initialized = false; bool initialized = false;
vk::Image scaled_image{};
VkImage current_image{};
std::unique_ptr<Framebuffer> scale_framebuffer; std::unique_ptr<Framebuffer> scale_framebuffer;
std::unique_ptr<ImageView> scale_view; std::unique_ptr<ImageView> scale_view;

@ -247,7 +247,7 @@ vk::Image MemoryAllocator::CreateImage(const VkImageCreateInfo& ci) const {
vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, nullptr)); vk::Check(vmaCreateImage(allocator, &ci, &alloc_ci, &handle, &allocation, nullptr));
return vk::Image(handle, *device.GetLogical(), allocator, allocation, return vk::Image(handle, ci.usage, *device.GetLogical(), allocator, allocation,
device.GetDispatchLoader()); device.GetDispatchLoader());
} }

@ -623,9 +623,10 @@ public:
class Image { class Image {
public: public:
explicit Image(VkImage handle_, VkDevice owner_, VmaAllocator allocator_, explicit Image(VkImage handle_, VkImageUsageFlags usage_, VkDevice owner_,
VmaAllocation allocation_, const DeviceDispatch& dld_) noexcept VmaAllocator allocator_, VmaAllocation allocation_,
: handle{handle_}, owner{owner_}, allocator{allocator_}, const DeviceDispatch& dld_) noexcept
: handle{handle_}, usage{usage_}, owner{owner_}, allocator{allocator_},
allocation{allocation_}, dld{&dld_} {} allocation{allocation_}, dld{&dld_} {}
Image() = default; Image() = default;
@ -633,12 +634,13 @@ public:
Image& operator=(const Image&) = delete; Image& operator=(const Image&) = delete;
Image(Image&& rhs) noexcept Image(Image&& rhs) noexcept
: handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator}, : handle{std::exchange(rhs.handle, nullptr)}, usage{rhs.usage}, owner{rhs.owner},
allocation{rhs.allocation}, dld{rhs.dld} {} allocator{rhs.allocator}, allocation{rhs.allocation}, dld{rhs.dld} {}
Image& operator=(Image&& rhs) noexcept { Image& operator=(Image&& rhs) noexcept {
Release(); Release();
handle = std::exchange(rhs.handle, nullptr); handle = std::exchange(rhs.handle, nullptr);
usage = rhs.usage;
owner = rhs.owner; owner = rhs.owner;
allocator = rhs.allocator; allocator = rhs.allocator;
allocation = rhs.allocation; allocation = rhs.allocation;
@ -665,10 +667,15 @@ public:
void SetObjectNameEXT(const char* name) const; void SetObjectNameEXT(const char* name) const;
[[nodiscard]] VkImageUsageFlags UsageFlags() const noexcept {
return usage;
}
private: private:
void Release() const noexcept; void Release() const noexcept;
VkImage handle = nullptr; VkImage handle = nullptr;
VkImageUsageFlags usage{};
VkDevice owner = nullptr; VkDevice owner = nullptr;
VmaAllocator allocator = nullptr; VmaAllocator allocator = nullptr;
VmaAllocation allocation = nullptr; VmaAllocation allocation = nullptr;