[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:
Triang3l
2022-01-29 13:22:03 +03:00
parent 372bdd3ec9
commit fe3f0f26e4
428 changed files with 75942 additions and 18360 deletions

View File

@@ -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