[UI] Image post-processing and full presentation/window rework
[GPU] Add FXAA post-processing [UI] Add FidelityFX FSR and CAS post-processing [UI] Add blue noise dithering from 10bpc to 8bpc [GPU] Apply the DC PWL gamma ramp closer to the spec, supporting fully white color [UI] Allow the GPU CP thread to present on the host directly, bypassing the UI thread OS paint event [UI] Allow variable refresh rate (or tearing) [UI] Present the newest frame (restart) on DXGI [UI] Replace GraphicsContext with a far more advanced Presenter with more coherent surface connection and UI overlay state management [UI] Connect presentation to windows via the Surface class, not native window handles [Vulkan] Switch to simpler Vulkan setup with no instance/device separation due to interdependencies and to pass fewer objects around [Vulkan] Lower the minimum required Vulkan version to 1.0 [UI/GPU] Various cleanup, mainly ComPtr usage [UI] Support per-monitor DPI awareness v2 on Windows [UI] DPI-scale Dear ImGui [UI] Replace the remaining non-detachable window delegates with unified window event and input listeners [UI] Allow listeners to safely destroy or close the window, and to register/unregister listeners without use-after-free and the ABA problem [UI] Explicit Z ordering of input listeners and UI overlays, top-down for input, bottom-up for drawing [UI] Add explicit window lifecycle phases [UI] Replace Window virtual functions with explicit desired state, its application, actual state, its feedback [UI] GTK: Apply the initial size to the drawing area [UI] Limit internal UI frame rate to that of the monitor [UI] Hide the cursor using a timer instead of polling due to no repeated UI thread paints with GPU CP thread presentation, and only within the window
This commit is contained in:
@@ -9,496 +9,187 @@
|
||||
|
||||
#include "xenia/ui/vulkan/vulkan_util.h"
|
||||
|
||||
#include "third_party/fmt/include/fmt/format.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include <cstdint>
|
||||
|
||||
// Implement AMD's VMA here.
|
||||
#define VMA_IMPLEMENTATION
|
||||
#include "xenia/ui/vulkan/vulkan_mem_alloc.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/ui/vulkan/vulkan_provider.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace vulkan {
|
||||
namespace util {
|
||||
|
||||
uint32_t Version::Make(uint32_t major, uint32_t minor, uint32_t patch) {
|
||||
return VK_MAKE_VERSION(major, minor, patch);
|
||||
}
|
||||
|
||||
Version Version::Parse(uint32_t value) {
|
||||
Version version;
|
||||
version.major = VK_VERSION_MAJOR(value);
|
||||
version.minor = VK_VERSION_MINOR(value);
|
||||
version.patch = VK_VERSION_PATCH(value);
|
||||
version.pretty_string =
|
||||
fmt::format("{}.{}.{}", version.major, version.minor, version.patch);
|
||||
return version;
|
||||
}
|
||||
|
||||
const char* to_string(VkFormat format) {
|
||||
switch (format) {
|
||||
#define STR(r) \
|
||||
case r: \
|
||||
return #r
|
||||
STR(VK_FORMAT_UNDEFINED);
|
||||
STR(VK_FORMAT_R4G4_UNORM_PACK8);
|
||||
STR(VK_FORMAT_R4G4B4A4_UNORM_PACK16);
|
||||
STR(VK_FORMAT_B4G4R4A4_UNORM_PACK16);
|
||||
STR(VK_FORMAT_R5G6B5_UNORM_PACK16);
|
||||
STR(VK_FORMAT_B5G6R5_UNORM_PACK16);
|
||||
STR(VK_FORMAT_R5G5B5A1_UNORM_PACK16);
|
||||
STR(VK_FORMAT_B5G5R5A1_UNORM_PACK16);
|
||||
STR(VK_FORMAT_A1R5G5B5_UNORM_PACK16);
|
||||
STR(VK_FORMAT_R8_UNORM);
|
||||
STR(VK_FORMAT_R8_SNORM);
|
||||
STR(VK_FORMAT_R8_USCALED);
|
||||
STR(VK_FORMAT_R8_SSCALED);
|
||||
STR(VK_FORMAT_R8_UINT);
|
||||
STR(VK_FORMAT_R8_SINT);
|
||||
STR(VK_FORMAT_R8_SRGB);
|
||||
STR(VK_FORMAT_R8G8_UNORM);
|
||||
STR(VK_FORMAT_R8G8_SNORM);
|
||||
STR(VK_FORMAT_R8G8_USCALED);
|
||||
STR(VK_FORMAT_R8G8_SSCALED);
|
||||
STR(VK_FORMAT_R8G8_UINT);
|
||||
STR(VK_FORMAT_R8G8_SINT);
|
||||
STR(VK_FORMAT_R8G8_SRGB);
|
||||
STR(VK_FORMAT_R8G8B8_UNORM);
|
||||
STR(VK_FORMAT_R8G8B8_SNORM);
|
||||
STR(VK_FORMAT_R8G8B8_USCALED);
|
||||
STR(VK_FORMAT_R8G8B8_SSCALED);
|
||||
STR(VK_FORMAT_R8G8B8_UINT);
|
||||
STR(VK_FORMAT_R8G8B8_SINT);
|
||||
STR(VK_FORMAT_R8G8B8_SRGB);
|
||||
STR(VK_FORMAT_B8G8R8_UNORM);
|
||||
STR(VK_FORMAT_B8G8R8_SNORM);
|
||||
STR(VK_FORMAT_B8G8R8_USCALED);
|
||||
STR(VK_FORMAT_B8G8R8_SSCALED);
|
||||
STR(VK_FORMAT_B8G8R8_UINT);
|
||||
STR(VK_FORMAT_B8G8R8_SINT);
|
||||
STR(VK_FORMAT_B8G8R8_SRGB);
|
||||
STR(VK_FORMAT_R8G8B8A8_UNORM);
|
||||
STR(VK_FORMAT_R8G8B8A8_SNORM);
|
||||
STR(VK_FORMAT_R8G8B8A8_USCALED);
|
||||
STR(VK_FORMAT_R8G8B8A8_SSCALED);
|
||||
STR(VK_FORMAT_R8G8B8A8_UINT);
|
||||
STR(VK_FORMAT_R8G8B8A8_SINT);
|
||||
STR(VK_FORMAT_R8G8B8A8_SRGB);
|
||||
STR(VK_FORMAT_B8G8R8A8_UNORM);
|
||||
STR(VK_FORMAT_B8G8R8A8_SNORM);
|
||||
STR(VK_FORMAT_B8G8R8A8_USCALED);
|
||||
STR(VK_FORMAT_B8G8R8A8_SSCALED);
|
||||
STR(VK_FORMAT_B8G8R8A8_UINT);
|
||||
STR(VK_FORMAT_B8G8R8A8_SINT);
|
||||
STR(VK_FORMAT_B8G8R8A8_SRGB);
|
||||
STR(VK_FORMAT_A8B8G8R8_UNORM_PACK32);
|
||||
STR(VK_FORMAT_A8B8G8R8_SNORM_PACK32);
|
||||
STR(VK_FORMAT_A8B8G8R8_USCALED_PACK32);
|
||||
STR(VK_FORMAT_A8B8G8R8_SSCALED_PACK32);
|
||||
STR(VK_FORMAT_A8B8G8R8_UINT_PACK32);
|
||||
STR(VK_FORMAT_A8B8G8R8_SINT_PACK32);
|
||||
STR(VK_FORMAT_A8B8G8R8_SRGB_PACK32);
|
||||
STR(VK_FORMAT_A2R10G10B10_UNORM_PACK32);
|
||||
STR(VK_FORMAT_A2R10G10B10_SNORM_PACK32);
|
||||
STR(VK_FORMAT_A2R10G10B10_USCALED_PACK32);
|
||||
STR(VK_FORMAT_A2R10G10B10_SSCALED_PACK32);
|
||||
STR(VK_FORMAT_A2R10G10B10_UINT_PACK32);
|
||||
STR(VK_FORMAT_A2R10G10B10_SINT_PACK32);
|
||||
STR(VK_FORMAT_A2B10G10R10_UNORM_PACK32);
|
||||
STR(VK_FORMAT_A2B10G10R10_SNORM_PACK32);
|
||||
STR(VK_FORMAT_A2B10G10R10_USCALED_PACK32);
|
||||
STR(VK_FORMAT_A2B10G10R10_SSCALED_PACK32);
|
||||
STR(VK_FORMAT_A2B10G10R10_UINT_PACK32);
|
||||
STR(VK_FORMAT_A2B10G10R10_SINT_PACK32);
|
||||
STR(VK_FORMAT_R16_UNORM);
|
||||
STR(VK_FORMAT_R16_SNORM);
|
||||
STR(VK_FORMAT_R16_USCALED);
|
||||
STR(VK_FORMAT_R16_SSCALED);
|
||||
STR(VK_FORMAT_R16_UINT);
|
||||
STR(VK_FORMAT_R16_SINT);
|
||||
STR(VK_FORMAT_R16_SFLOAT);
|
||||
STR(VK_FORMAT_R16G16_UNORM);
|
||||
STR(VK_FORMAT_R16G16_SNORM);
|
||||
STR(VK_FORMAT_R16G16_USCALED);
|
||||
STR(VK_FORMAT_R16G16_SSCALED);
|
||||
STR(VK_FORMAT_R16G16_UINT);
|
||||
STR(VK_FORMAT_R16G16_SINT);
|
||||
STR(VK_FORMAT_R16G16_SFLOAT);
|
||||
STR(VK_FORMAT_R16G16B16_UNORM);
|
||||
STR(VK_FORMAT_R16G16B16_SNORM);
|
||||
STR(VK_FORMAT_R16G16B16_USCALED);
|
||||
STR(VK_FORMAT_R16G16B16_SSCALED);
|
||||
STR(VK_FORMAT_R16G16B16_UINT);
|
||||
STR(VK_FORMAT_R16G16B16_SINT);
|
||||
STR(VK_FORMAT_R16G16B16_SFLOAT);
|
||||
STR(VK_FORMAT_R16G16B16A16_UNORM);
|
||||
STR(VK_FORMAT_R16G16B16A16_SNORM);
|
||||
STR(VK_FORMAT_R16G16B16A16_USCALED);
|
||||
STR(VK_FORMAT_R16G16B16A16_SSCALED);
|
||||
STR(VK_FORMAT_R16G16B16A16_UINT);
|
||||
STR(VK_FORMAT_R16G16B16A16_SINT);
|
||||
STR(VK_FORMAT_R16G16B16A16_SFLOAT);
|
||||
STR(VK_FORMAT_R32_UINT);
|
||||
STR(VK_FORMAT_R32_SINT);
|
||||
STR(VK_FORMAT_R32_SFLOAT);
|
||||
STR(VK_FORMAT_R32G32_UINT);
|
||||
STR(VK_FORMAT_R32G32_SINT);
|
||||
STR(VK_FORMAT_R32G32_SFLOAT);
|
||||
STR(VK_FORMAT_R32G32B32_UINT);
|
||||
STR(VK_FORMAT_R32G32B32_SINT);
|
||||
STR(VK_FORMAT_R32G32B32_SFLOAT);
|
||||
STR(VK_FORMAT_R32G32B32A32_UINT);
|
||||
STR(VK_FORMAT_R32G32B32A32_SINT);
|
||||
STR(VK_FORMAT_R32G32B32A32_SFLOAT);
|
||||
STR(VK_FORMAT_R64_UINT);
|
||||
STR(VK_FORMAT_R64_SINT);
|
||||
STR(VK_FORMAT_R64_SFLOAT);
|
||||
STR(VK_FORMAT_R64G64_UINT);
|
||||
STR(VK_FORMAT_R64G64_SINT);
|
||||
STR(VK_FORMAT_R64G64_SFLOAT);
|
||||
STR(VK_FORMAT_R64G64B64_UINT);
|
||||
STR(VK_FORMAT_R64G64B64_SINT);
|
||||
STR(VK_FORMAT_R64G64B64_SFLOAT);
|
||||
STR(VK_FORMAT_R64G64B64A64_UINT);
|
||||
STR(VK_FORMAT_R64G64B64A64_SINT);
|
||||
STR(VK_FORMAT_R64G64B64A64_SFLOAT);
|
||||
STR(VK_FORMAT_B10G11R11_UFLOAT_PACK32);
|
||||
STR(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32);
|
||||
STR(VK_FORMAT_D16_UNORM);
|
||||
STR(VK_FORMAT_X8_D24_UNORM_PACK32);
|
||||
STR(VK_FORMAT_D32_SFLOAT);
|
||||
STR(VK_FORMAT_S8_UINT);
|
||||
STR(VK_FORMAT_D16_UNORM_S8_UINT);
|
||||
STR(VK_FORMAT_D24_UNORM_S8_UINT);
|
||||
STR(VK_FORMAT_D32_SFLOAT_S8_UINT);
|
||||
STR(VK_FORMAT_BC1_RGB_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_BC1_RGB_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_BC1_RGBA_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_BC1_RGBA_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_BC2_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_BC2_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_BC3_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_BC3_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_BC4_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_BC4_SNORM_BLOCK);
|
||||
STR(VK_FORMAT_BC5_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_BC5_SNORM_BLOCK);
|
||||
STR(VK_FORMAT_BC6H_UFLOAT_BLOCK);
|
||||
STR(VK_FORMAT_BC6H_SFLOAT_BLOCK);
|
||||
STR(VK_FORMAT_BC7_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_BC7_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_EAC_R11_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_EAC_R11_SNORM_BLOCK);
|
||||
STR(VK_FORMAT_EAC_R11G11_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_EAC_R11G11_SNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_4x4_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_4x4_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_5x4_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_5x4_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_5x5_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_5x5_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_6x5_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_6x5_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_6x6_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_6x6_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_8x5_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_8x5_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_8x6_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_8x6_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_8x8_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_8x8_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_10x5_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_10x5_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_10x6_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_10x6_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_10x8_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_10x8_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_10x10_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_10x10_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_12x10_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_12x10_SRGB_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_12x12_UNORM_BLOCK);
|
||||
STR(VK_FORMAT_ASTC_12x12_SRGB_BLOCK);
|
||||
#undef STR
|
||||
default:
|
||||
return "UNKNOWN_FORMAT";
|
||||
void FlushMappedMemoryRange(const VulkanProvider& provider,
|
||||
VkDeviceMemory memory, uint32_t memory_type,
|
||||
VkDeviceSize offset, VkDeviceSize memory_size,
|
||||
VkDeviceSize size) {
|
||||
assert_false(size != VK_WHOLE_SIZE && memory_size == VK_WHOLE_SIZE);
|
||||
assert_true(memory_size == VK_WHOLE_SIZE || offset <= memory_size);
|
||||
assert_true(memory_size == VK_WHOLE_SIZE || size <= memory_size - offset);
|
||||
if (!size ||
|
||||
(provider.memory_types_host_coherent() & (uint32_t(1) << memory_type))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const char* to_string(VkPhysicalDeviceType type) {
|
||||
switch (type) {
|
||||
#define STR(r) \
|
||||
case r: \
|
||||
return #r
|
||||
STR(VK_PHYSICAL_DEVICE_TYPE_OTHER);
|
||||
STR(VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU);
|
||||
STR(VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU);
|
||||
STR(VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU);
|
||||
STR(VK_PHYSICAL_DEVICE_TYPE_CPU);
|
||||
#undef STR
|
||||
default:
|
||||
return "UNKNOWN_DEVICE";
|
||||
}
|
||||
}
|
||||
|
||||
const char* to_string(VkSharingMode sharing_mode) {
|
||||
switch (sharing_mode) {
|
||||
#define STR(r) \
|
||||
case r: \
|
||||
return #r
|
||||
STR(VK_SHARING_MODE_EXCLUSIVE);
|
||||
STR(VK_SHARING_MODE_CONCURRENT);
|
||||
#undef STR
|
||||
default:
|
||||
return "UNKNOWN_SHARING_MODE";
|
||||
}
|
||||
}
|
||||
|
||||
const char* to_string(VkResult result) {
|
||||
switch (result) {
|
||||
#define STR(r) \
|
||||
case r: \
|
||||
return #r
|
||||
STR(VK_SUCCESS);
|
||||
STR(VK_NOT_READY);
|
||||
STR(VK_TIMEOUT);
|
||||
STR(VK_EVENT_SET);
|
||||
STR(VK_EVENT_RESET);
|
||||
STR(VK_INCOMPLETE);
|
||||
STR(VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
STR(VK_ERROR_OUT_OF_DEVICE_MEMORY);
|
||||
STR(VK_ERROR_INITIALIZATION_FAILED);
|
||||
STR(VK_ERROR_DEVICE_LOST);
|
||||
STR(VK_ERROR_MEMORY_MAP_FAILED);
|
||||
STR(VK_ERROR_LAYER_NOT_PRESENT);
|
||||
STR(VK_ERROR_EXTENSION_NOT_PRESENT);
|
||||
STR(VK_ERROR_FEATURE_NOT_PRESENT);
|
||||
STR(VK_ERROR_INCOMPATIBLE_DRIVER);
|
||||
STR(VK_ERROR_TOO_MANY_OBJECTS);
|
||||
STR(VK_ERROR_FORMAT_NOT_SUPPORTED);
|
||||
STR(VK_ERROR_SURFACE_LOST_KHR);
|
||||
STR(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
|
||||
STR(VK_SUBOPTIMAL_KHR);
|
||||
STR(VK_ERROR_OUT_OF_DATE_KHR);
|
||||
STR(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
|
||||
STR(VK_ERROR_VALIDATION_FAILED_EXT);
|
||||
STR(VK_ERROR_INVALID_SHADER_NV);
|
||||
STR(VK_ERROR_OUT_OF_POOL_MEMORY_KHR);
|
||||
STR(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
|
||||
#undef STR
|
||||
default:
|
||||
return "UNKNOWN_RESULT";
|
||||
}
|
||||
}
|
||||
|
||||
std::string to_flags_string(VkImageUsageFlagBits flags) {
|
||||
std::string result;
|
||||
#define OR_FLAG(f) \
|
||||
if (flags & f) { \
|
||||
if (!result.empty()) { \
|
||||
result += " | "; \
|
||||
} \
|
||||
result += #f; \
|
||||
}
|
||||
OR_FLAG(VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
|
||||
OR_FLAG(VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
||||
OR_FLAG(VK_IMAGE_USAGE_SAMPLED_BIT);
|
||||
OR_FLAG(VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
OR_FLAG(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
||||
OR_FLAG(VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||
OR_FLAG(VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT);
|
||||
OR_FLAG(VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
|
||||
#undef OR_FLAG
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string to_flags_string(VkFormatFeatureFlagBits flags) {
|
||||
std::string result;
|
||||
#define OR_FLAG(f) \
|
||||
if (flags & f) { \
|
||||
if (!result.empty()) { \
|
||||
result += " | "; \
|
||||
} \
|
||||
result += #f; \
|
||||
}
|
||||
OR_FLAG(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_BLIT_SRC_BIT);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_BLIT_DST_BIT);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR);
|
||||
OR_FLAG(VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT);
|
||||
#undef OR_FLAG
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string to_flags_string(VkSurfaceTransformFlagBitsKHR flags) {
|
||||
std::string result;
|
||||
#define OR_FLAG(f) \
|
||||
if (flags & f) { \
|
||||
if (!result.empty()) { \
|
||||
result += " | "; \
|
||||
} \
|
||||
result += #f; \
|
||||
}
|
||||
OR_FLAG(VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR);
|
||||
OR_FLAG(VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR);
|
||||
OR_FLAG(VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR);
|
||||
OR_FLAG(VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR);
|
||||
OR_FLAG(VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR);
|
||||
OR_FLAG(VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR);
|
||||
OR_FLAG(VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR);
|
||||
OR_FLAG(VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR);
|
||||
OR_FLAG(VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR);
|
||||
#undef OR_FLAG
|
||||
return result;
|
||||
}
|
||||
|
||||
const char* to_string(VkColorSpaceKHR color_space) {
|
||||
switch (color_space) {
|
||||
#define STR(r) \
|
||||
case r: \
|
||||
return #r
|
||||
STR(VK_COLORSPACE_SRGB_NONLINEAR_KHR);
|
||||
#undef STR
|
||||
default:
|
||||
return "UNKNOWN_COLORSPACE";
|
||||
}
|
||||
}
|
||||
|
||||
const char* to_string(VkPresentModeKHR present_mode) {
|
||||
switch (present_mode) {
|
||||
#define STR(r) \
|
||||
case r: \
|
||||
return #r
|
||||
STR(VK_PRESENT_MODE_IMMEDIATE_KHR);
|
||||
STR(VK_PRESENT_MODE_MAILBOX_KHR);
|
||||
STR(VK_PRESENT_MODE_FIFO_KHR);
|
||||
STR(VK_PRESENT_MODE_FIFO_RELAXED_KHR);
|
||||
#undef STR
|
||||
default:
|
||||
return "UNKNOWN_PRESENT_MODE";
|
||||
}
|
||||
}
|
||||
|
||||
void FatalVulkanError(std::string error) {
|
||||
xe::FatalError(
|
||||
error +
|
||||
"\n\n"
|
||||
"Ensure you have the latest drivers for your GPU and that it supports "
|
||||
"Vulkan.\n"
|
||||
"\n"
|
||||
"See https://xenia.jp/faq/ for more information and a list of supported "
|
||||
"GPUs.");
|
||||
}
|
||||
|
||||
void CheckResult(VkResult result, const char* action) {
|
||||
if (result) {
|
||||
XELOGE("Vulkan check: {} returned {}", action, to_string(result));
|
||||
}
|
||||
assert_true(result == VK_SUCCESS, action);
|
||||
}
|
||||
|
||||
std::pair<bool, std::vector<const char*>> CheckRequirements(
|
||||
const std::vector<Requirement>& requirements,
|
||||
const std::vector<LayerInfo>& layer_infos) {
|
||||
bool any_missing = false;
|
||||
std::vector<const char*> enabled_layers;
|
||||
for (auto& requirement : requirements) {
|
||||
bool found = false;
|
||||
for (size_t j = 0; j < layer_infos.size(); ++j) {
|
||||
auto layer_name = layer_infos[j].properties.layerName;
|
||||
auto layer_version =
|
||||
Version::Parse(layer_infos[j].properties.specVersion);
|
||||
if (requirement.name == layer_name) {
|
||||
found = true;
|
||||
if (requirement.min_version > layer_infos[j].properties.specVersion) {
|
||||
if (requirement.is_optional) {
|
||||
XELOGVK("- optional layer {} ({}) version mismatch", layer_name,
|
||||
layer_version.pretty_string);
|
||||
continue;
|
||||
}
|
||||
XELOGE("ERROR: required layer {} ({}) version mismatch", layer_name,
|
||||
layer_version.pretty_string);
|
||||
any_missing = true;
|
||||
break;
|
||||
}
|
||||
XELOGVK("- enabling layer {} ({})", layer_name,
|
||||
layer_version.pretty_string);
|
||||
enabled_layers.push_back(layer_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (requirement.is_optional) {
|
||||
XELOGVK("- optional layer {} not found", requirement.name);
|
||||
} else {
|
||||
XELOGE("ERROR: required layer {} not found", requirement.name);
|
||||
any_missing = true;
|
||||
}
|
||||
VkMappedMemoryRange range;
|
||||
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
||||
range.pNext = nullptr;
|
||||
range.memory = memory;
|
||||
range.offset = offset;
|
||||
range.size = size;
|
||||
VkDeviceSize non_coherent_atom_size =
|
||||
provider.device_properties().limits.nonCoherentAtomSize;
|
||||
// On some Android implementations, nonCoherentAtomSize is 0, not 1.
|
||||
if (non_coherent_atom_size > 1) {
|
||||
range.offset = offset / non_coherent_atom_size * non_coherent_atom_size;
|
||||
if (size != VK_WHOLE_SIZE) {
|
||||
range.size = std::min(xe::round_up(offset + size, non_coherent_atom_size),
|
||||
memory_size) -
|
||||
range.offset;
|
||||
}
|
||||
}
|
||||
return {!any_missing, enabled_layers};
|
||||
provider.dfn().vkFlushMappedMemoryRanges(provider.device(), 1, &range);
|
||||
}
|
||||
|
||||
std::pair<bool, std::vector<const char*>> CheckRequirements(
|
||||
const std::vector<Requirement>& requirements,
|
||||
const std::vector<VkExtensionProperties>& extension_properties) {
|
||||
bool any_missing = false;
|
||||
std::vector<const char*> enabled_extensions;
|
||||
for (auto& requirement : requirements) {
|
||||
bool found = false;
|
||||
for (size_t j = 0; j < extension_properties.size(); ++j) {
|
||||
auto extension_name = extension_properties[j].extensionName;
|
||||
auto extension_version =
|
||||
Version::Parse(extension_properties[j].specVersion);
|
||||
if (requirement.name == extension_name) {
|
||||
found = true;
|
||||
if (requirement.min_version > extension_properties[j].specVersion) {
|
||||
if (requirement.is_optional) {
|
||||
XELOGVK("- optional extension {} ({}) version mismatch",
|
||||
extension_name, extension_version.pretty_string);
|
||||
continue;
|
||||
}
|
||||
XELOGE("ERROR: required extension {} ({}) version mismatch",
|
||||
extension_name, extension_version.pretty_string);
|
||||
any_missing = true;
|
||||
break;
|
||||
}
|
||||
XELOGVK("- enabling extension {} ({})", extension_name,
|
||||
extension_version.pretty_string);
|
||||
enabled_extensions.push_back(extension_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (requirement.is_optional) {
|
||||
XELOGVK("- optional extension {} not found", requirement.name);
|
||||
} else {
|
||||
XELOGE("ERROR: required extension {} not found", requirement.name);
|
||||
any_missing = true;
|
||||
}
|
||||
}
|
||||
bool CreateDedicatedAllocationBuffer(
|
||||
const VulkanProvider& provider, VkDeviceSize size, VkBufferUsageFlags usage,
|
||||
MemoryPurpose memory_purpose, VkBuffer& buffer_out,
|
||||
VkDeviceMemory& memory_out, uint32_t* memory_type_out,
|
||||
VkDeviceSize* memory_size_out) {
|
||||
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
|
||||
VkDevice device = provider.device();
|
||||
|
||||
VkBufferCreateInfo buffer_create_info;
|
||||
buffer_create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buffer_create_info.pNext = nullptr;
|
||||
buffer_create_info.flags = 0;
|
||||
buffer_create_info.size = size;
|
||||
buffer_create_info.usage = usage;
|
||||
buffer_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
buffer_create_info.queueFamilyIndexCount = 0;
|
||||
buffer_create_info.pQueueFamilyIndices = nullptr;
|
||||
VkBuffer buffer;
|
||||
if (dfn.vkCreateBuffer(device, &buffer_create_info, nullptr, &buffer) !=
|
||||
VK_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
return {!any_missing, enabled_extensions};
|
||||
|
||||
VkMemoryRequirements memory_requirements;
|
||||
dfn.vkGetBufferMemoryRequirements(device, buffer, &memory_requirements);
|
||||
uint32_t memory_type = ChooseMemoryType(
|
||||
provider, memory_requirements.memoryTypeBits, memory_purpose);
|
||||
if (memory_type == UINT32_MAX) {
|
||||
dfn.vkDestroyBuffer(device, buffer, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
VkMemoryAllocateInfo memory_allocate_info;
|
||||
VkMemoryAllocateInfo* memory_allocate_info_last = &memory_allocate_info;
|
||||
memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
memory_allocate_info.pNext = nullptr;
|
||||
memory_allocate_info.allocationSize = memory_requirements.size;
|
||||
memory_allocate_info.memoryTypeIndex = memory_type;
|
||||
VkMemoryDedicatedAllocateInfoKHR memory_dedicated_allocate_info;
|
||||
if (provider.device_extensions().khr_dedicated_allocation) {
|
||||
memory_allocate_info_last->pNext = &memory_dedicated_allocate_info;
|
||||
memory_allocate_info_last = reinterpret_cast<VkMemoryAllocateInfo*>(
|
||||
&memory_dedicated_allocate_info);
|
||||
memory_dedicated_allocate_info.sType =
|
||||
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR;
|
||||
memory_dedicated_allocate_info.pNext = nullptr;
|
||||
memory_dedicated_allocate_info.image = VK_NULL_HANDLE;
|
||||
memory_dedicated_allocate_info.buffer = buffer;
|
||||
}
|
||||
VkDeviceMemory memory;
|
||||
if (dfn.vkAllocateMemory(device, &memory_allocate_info, nullptr, &memory) !=
|
||||
VK_SUCCESS) {
|
||||
dfn.vkDestroyBuffer(device, buffer, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dfn.vkBindBufferMemory(device, buffer, memory, 0) != VK_SUCCESS) {
|
||||
dfn.vkDestroyBuffer(device, buffer, nullptr);
|
||||
dfn.vkFreeMemory(device, memory, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer_out = buffer;
|
||||
memory_out = memory;
|
||||
if (memory_type_out) {
|
||||
*memory_type_out = memory_type;
|
||||
}
|
||||
if (memory_size_out) {
|
||||
*memory_size_out = memory_allocate_info.allocationSize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateDedicatedAllocationImage(const VulkanProvider& provider,
|
||||
const VkImageCreateInfo& create_info,
|
||||
MemoryPurpose memory_purpose,
|
||||
VkImage& image_out,
|
||||
VkDeviceMemory& memory_out,
|
||||
uint32_t* memory_type_out,
|
||||
VkDeviceSize* memory_size_out) {
|
||||
const ui::vulkan::VulkanProvider::DeviceFunctions& dfn = provider.dfn();
|
||||
VkDevice device = provider.device();
|
||||
|
||||
VkImage image;
|
||||
if (dfn.vkCreateImage(device, &create_info, nullptr, &image) != VK_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VkMemoryRequirements memory_requirements;
|
||||
dfn.vkGetImageMemoryRequirements(device, image, &memory_requirements);
|
||||
uint32_t memory_type = ChooseMemoryType(
|
||||
provider, memory_requirements.memoryTypeBits, memory_purpose);
|
||||
if (memory_type == UINT32_MAX) {
|
||||
dfn.vkDestroyImage(device, image, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
VkMemoryAllocateInfo memory_allocate_info;
|
||||
VkMemoryAllocateInfo* memory_allocate_info_last = &memory_allocate_info;
|
||||
memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
memory_allocate_info.pNext = nullptr;
|
||||
memory_allocate_info.allocationSize = memory_requirements.size;
|
||||
memory_allocate_info.memoryTypeIndex = memory_type;
|
||||
VkMemoryDedicatedAllocateInfoKHR memory_dedicated_allocate_info;
|
||||
if (provider.device_extensions().khr_dedicated_allocation) {
|
||||
memory_allocate_info_last->pNext = &memory_dedicated_allocate_info;
|
||||
memory_allocate_info_last = reinterpret_cast<VkMemoryAllocateInfo*>(
|
||||
&memory_dedicated_allocate_info);
|
||||
memory_dedicated_allocate_info.sType =
|
||||
VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR;
|
||||
memory_dedicated_allocate_info.pNext = nullptr;
|
||||
memory_dedicated_allocate_info.image = image;
|
||||
memory_dedicated_allocate_info.buffer = VK_NULL_HANDLE;
|
||||
}
|
||||
VkDeviceMemory memory;
|
||||
if (dfn.vkAllocateMemory(device, &memory_allocate_info, nullptr, &memory) !=
|
||||
VK_SUCCESS) {
|
||||
dfn.vkDestroyImage(device, image, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dfn.vkBindImageMemory(device, image, memory, 0) != VK_SUCCESS) {
|
||||
dfn.vkDestroyImage(device, image, nullptr);
|
||||
dfn.vkFreeMemory(device, memory, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
image_out = image;
|
||||
memory_out = memory;
|
||||
if (memory_type_out) {
|
||||
*memory_type_out = memory_type;
|
||||
}
|
||||
if (memory_size_out) {
|
||||
*memory_size_out = memory_allocate_info.allocationSize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace vulkan
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
Reference in New Issue
Block a user