Merge pull request #10837 from liamwhite/mali-support

android: Mali support
This commit is contained in:
liamwhite 2023-06-28 12:53:17 -04:00 committed by GitHub
commit b60b70e86d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 1960 additions and 173 deletions

View file

@ -157,6 +157,9 @@ endif()
add_library(stb stb/stb_dxt.cpp) add_library(stb stb/stb_dxt.cpp)
target_include_directories(stb PUBLIC ./stb) target_include_directories(stb PUBLIC ./stb)
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
target_include_directories(bc_decoder PUBLIC ./bc_decoder)
if (ANDROID) if (ANDROID)
if (ARCHITECTURE_arm64) if (ARCHITECTURE_arm64)
add_subdirectory(libadrenotools) add_subdirectory(libadrenotools)

1522
externals/bc_decoder/bc_decoder.cpp vendored Normal file

File diff suppressed because it is too large Load diff

43
externals/bc_decoder/bc_decoder.h vendored Normal file
View file

@ -0,0 +1,43 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <cstdint>
namespace bcn {
/**
* @brief Decodes a BC1 encoded image to R8G8B8A8
*/
void DecodeBc1(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
/**
* @brief Decodes a BC2 encoded image to R8G8B8A8
*/
void DecodeBc2(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
/**
* @brief Decodes a BC3 encoded image to R8G8B8A8
*/
void DecodeBc3(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
/**
* @brief Decodes a BC4 encoded image to R8
*/
void DecodeBc4(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/**
* @brief Decodes a BC5 encoded image to R8G8
*/
void DecodeBc5(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/**
* @brief Decodes a BC6 encoded image to R16G16B16A16
*/
void DecodeBc6(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height, bool isSigned);
/**
* @brief Decodes a BC7 encoded image to R8G8B8A8
*/
void DecodeBc7(const uint8_t *src, uint8_t *dst, size_t x, size_t y, size_t width, size_t height);
}

View file

@ -220,8 +220,8 @@ add_library(video_core STATIC
surface.h surface.h
texture_cache/accelerated_swizzle.cpp texture_cache/accelerated_swizzle.cpp
texture_cache/accelerated_swizzle.h texture_cache/accelerated_swizzle.h
texture_cache/decode_bc4.cpp texture_cache/decode_bc.cpp
texture_cache/decode_bc4.h texture_cache/decode_bc.h
texture_cache/descriptor_table.h texture_cache/descriptor_table.h
texture_cache/formatter.cpp texture_cache/formatter.cpp
texture_cache/formatter.h texture_cache/formatter.h
@ -279,7 +279,7 @@ add_library(video_core STATIC
create_target_directory_groups(video_core) create_target_directory_groups(video_core)
target_link_libraries(video_core PUBLIC common core) target_link_libraries(video_core PUBLIC common core)
target_link_libraries(video_core PUBLIC glad shader_recompiler stb) target_link_libraries(video_core PUBLIC glad shader_recompiler stb bc_decoder)
if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID)) if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID))
add_dependencies(video_core ffmpeg-build) add_dependencies(video_core ffmpeg-build)

View file

@ -495,6 +495,9 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
const Region2D& dst_region, const Region2D& src_region, const Region2D& dst_region, const Region2D& src_region,
Tegra::Engines::Fermi2D::Filter filter, Tegra::Engines::Fermi2D::Filter filter,
Tegra::Engines::Fermi2D::Operation operation) { Tegra::Engines::Fermi2D::Operation operation) {
if (!device.IsExtShaderStencilExportSupported()) {
return;
}
ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point); ASSERT(filter == Tegra::Engines::Fermi2D::Filter::Point);
ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy); ASSERT(operation == Tegra::Engines::Fermi2D::Operation::SrcCopy);
const BlitImagePipelineKey key{ const BlitImagePipelineKey key{

View file

@ -259,6 +259,26 @@ FormatInfo SurfaceFormat(const Device& device, FormatType format_type, bool with
break; break;
} }
} }
// Transcode on hardware that doesn't support BCn natively
if (!device.IsOptimalBcnSupported() && VideoCore::Surface::IsPixelFormatBCn(pixel_format)) {
const bool is_srgb = with_srgb && VideoCore::Surface::IsPixelFormatSRGB(pixel_format);
if (pixel_format == PixelFormat::BC4_SNORM) {
tuple.format = VK_FORMAT_R8_SNORM;
} else if (pixel_format == PixelFormat::BC4_UNORM) {
tuple.format = VK_FORMAT_R8_UNORM;
} else if (pixel_format == PixelFormat::BC5_SNORM) {
tuple.format = VK_FORMAT_R8G8_SNORM;
} else if (pixel_format == PixelFormat::BC5_UNORM) {
tuple.format = VK_FORMAT_R8G8_UNORM;
} else if (pixel_format == PixelFormat::BC6H_SFLOAT ||
pixel_format == PixelFormat::BC6H_UFLOAT) {
tuple.format = VK_FORMAT_R16G16B16A16_SFLOAT;
} else if (is_srgb) {
tuple.format = VK_FORMAT_A8B8G8R8_SRGB_PACK32;
} else {
tuple.format = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
}
}
const bool attachable = (tuple.usage & Attachable) != 0; const bool attachable = (tuple.usage & Attachable) != 0;
const bool storage = (tuple.usage & Storage) != 0; const bool storage = (tuple.usage & Storage) != 0;

View file

@ -12,6 +12,7 @@
#include <fmt/format.h> #include <fmt/format.h>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/polyfill_ranges.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "common/settings.h" #include "common/settings.h"
#include "common/telemetry.h" #include "common/telemetry.h"
@ -65,6 +66,21 @@ std::string BuildCommaSeparatedExtensions(
return fmt::format("{}", fmt::join(available_extensions, ",")); return fmt::format("{}", fmt::join(available_extensions, ","));
} }
DebugCallback MakeDebugCallback(const vk::Instance& instance, const vk::InstanceDispatch& dld) {
if (!Settings::values.renderer_debug) {
return DebugCallback{};
}
const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
const auto it = std::ranges::find_if(*properties, [](const auto& prop) {
return std::strcmp(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, prop.extensionName) == 0;
});
if (it != properties->end()) {
return CreateDebugUtilsCallback(instance);
} else {
return CreateDebugReportCallback(instance);
}
}
} // Anonymous namespace } // Anonymous namespace
Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
@ -87,7 +103,7 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())), cpu_memory(cpu_memory_), gpu(gpu_), library(OpenLibrary(context.get())),
instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, instance(CreateInstance(*library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type,
Settings::values.renderer_debug.GetValue())), Settings::values.renderer_debug.GetValue())),
debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), debug_callback(MakeDebugCallback(instance, dld)),
surface(CreateSurface(instance, render_window.GetWindowInfo())), surface(CreateSurface(instance, render_window.GetWindowInfo())),
device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(), device(CreateDevice(instance, dld, *surface)), memory_allocator(device), state_tracker(),
scheduler(device, state_tracker), scheduler(device, state_tracker),

View file

@ -5,6 +5,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <variant>
#include "common/dynamic_library.h" #include "common/dynamic_library.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
@ -33,6 +34,8 @@ class GPU;
namespace Vulkan { namespace Vulkan {
using DebugCallback = std::variant<vk::DebugUtilsMessenger, vk::DebugReportCallback>;
Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
VkSurfaceKHR surface); VkSurfaceKHR surface);
@ -71,7 +74,7 @@ private:
vk::InstanceDispatch dld; vk::InstanceDispatch dld;
vk::Instance instance; vk::Instance instance;
vk::DebugUtilsMessenger debug_callback; DebugCallback debug_callback;
vk::SurfaceKHR surface; vk::SurfaceKHR surface;
ScreenInfo screen_info; ScreenInfo screen_info;

View file

@ -590,7 +590,8 @@ void BufferCacheRuntime::ReserveNullBuffer() {
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
.size = 4, .size = 4,
.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0, .queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr, .pQueueFamilyIndices = nullptr,

View file

@ -652,13 +652,14 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
.pNext = nullptr, .pNext = nullptr,
.negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE, .negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE,
}; };
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
VkPipelineViewportStateCreateInfo viewport_ci{ VkPipelineViewportStateCreateInfo viewport_ci{
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
.viewportCount = Maxwell::NumViewports, .viewportCount = num_viewports,
.pViewports = nullptr, .pViewports = nullptr,
.scissorCount = Maxwell::NumViewports, .scissorCount = num_viewports,
.pScissors = nullptr, .pScissors = nullptr,
}; };
if (device.IsNvViewportSwizzleSupported()) { if (device.IsNvViewportSwizzleSupported()) {

View file

@ -309,7 +309,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
.support_int16 = device.IsShaderInt16Supported(), .support_int16 = device.IsShaderInt16Supported(),
.support_int64 = device.IsShaderInt64Supported(), .support_int64 = device.IsShaderInt64Supported(),
.support_vertex_instance_id = false, .support_vertex_instance_id = false,
.support_float_controls = true, .support_float_controls = device.IsKhrShaderFloatControlsSupported(),
.support_separate_denorm_behavior = .support_separate_denorm_behavior =
float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL, float_control.denormBehaviorIndependence == VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL,
.support_separate_rounding_mode = .support_separate_rounding_mode =
@ -325,12 +325,13 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
.support_fp64_signed_zero_nan_preserve = .support_fp64_signed_zero_nan_preserve =
float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE, float_control.shaderSignedZeroInfNanPreserveFloat64 != VK_FALSE,
.support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(), .support_explicit_workgroup_layout = device.IsKhrWorkgroupMemoryExplicitLayoutSupported(),
.support_vote = true, .support_vote = device.IsSubgroupFeatureSupported(VK_SUBGROUP_FEATURE_VOTE_BIT),
.support_viewport_index_layer_non_geometry = .support_viewport_index_layer_non_geometry =
device.IsExtShaderViewportIndexLayerSupported(), device.IsExtShaderViewportIndexLayerSupported(),
.support_viewport_mask = device.IsNvViewportArray2Supported(), .support_viewport_mask = device.IsNvViewportArray2Supported(),
.support_typeless_image_loads = device.IsFormatlessImageLoadSupported(), .support_typeless_image_loads = device.IsFormatlessImageLoadSupported(),
.support_demote_to_helper_invocation = true, .support_demote_to_helper_invocation =
device.IsExtShaderDemoteToHelperInvocationSupported(),
.support_int64_atomics = device.IsExtShaderAtomicInt64Supported(), .support_int64_atomics = device.IsExtShaderAtomicInt64Supported(),
.support_derivative_control = true, .support_derivative_control = true,
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(), .support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),

View file

@ -315,7 +315,14 @@ void RasterizerVulkan::Clear(u32 layer_count) {
FlushWork(); FlushWork();
gpu_memory->FlushCaching(); gpu_memory->FlushCaching();
#if ANDROID
if (Settings::IsGPULevelHigh()) {
// This is problematic on Android, disable on GPU Normal.
query_cache.UpdateCounters();
}
#else
query_cache.UpdateCounters(); query_cache.UpdateCounters();
#endif
auto& regs = maxwell3d->regs; auto& regs = maxwell3d->regs;
const bool use_color = regs.clear_surface.R || regs.clear_surface.G || regs.clear_surface.B || const bool use_color = regs.clear_surface.R || regs.clear_surface.G || regs.clear_surface.B ||
@ -925,7 +932,7 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
} }
const bool is_rescaling{texture_cache.IsRescaling()}; const bool is_rescaling{texture_cache.IsRescaling()};
const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f; const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f;
const std::array viewports{ const std::array viewport_list{
GetViewportState(device, regs, 0, scale), GetViewportState(device, regs, 1, scale), GetViewportState(device, regs, 0, scale), GetViewportState(device, regs, 1, scale),
GetViewportState(device, regs, 2, scale), GetViewportState(device, regs, 3, scale), GetViewportState(device, regs, 2, scale), GetViewportState(device, regs, 3, scale),
GetViewportState(device, regs, 4, scale), GetViewportState(device, regs, 5, scale), GetViewportState(device, regs, 4, scale), GetViewportState(device, regs, 5, scale),
@ -935,7 +942,11 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale), GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale),
GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale), GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale),
}; };
scheduler.Record([viewports](vk::CommandBuffer cmdbuf) { cmdbuf.SetViewport(0, viewports); }); scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) {
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports);
cmdbuf.SetViewport(0, viewports);
});
} }
void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs) { void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs) {
@ -948,7 +959,7 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
up_scale = Settings::values.resolution_info.up_scale; up_scale = Settings::values.resolution_info.up_scale;
down_shift = Settings::values.resolution_info.down_shift; down_shift = Settings::values.resolution_info.down_shift;
} }
const std::array scissors{ const std::array scissor_list{
GetScissorState(regs, 0, up_scale, down_shift), GetScissorState(regs, 0, up_scale, down_shift),
GetScissorState(regs, 1, up_scale, down_shift), GetScissorState(regs, 1, up_scale, down_shift),
GetScissorState(regs, 2, up_scale, down_shift), GetScissorState(regs, 2, up_scale, down_shift),
@ -966,7 +977,11 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
GetScissorState(regs, 14, up_scale, down_shift), GetScissorState(regs, 14, up_scale, down_shift),
GetScissorState(regs, 15, up_scale, down_shift), GetScissorState(regs, 15, up_scale, down_shift),
}; };
scheduler.Record([scissors](vk::CommandBuffer cmdbuf) { cmdbuf.SetScissor(0, scissors); }); scheduler.Record([this, scissor_list](vk::CommandBuffer cmdbuf) {
const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors);
cmdbuf.SetScissor(0, scissors);
});
} }
void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) { void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {

View file

@ -38,18 +38,20 @@ size_t Region(size_t iterator) noexcept {
StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_,
Scheduler& scheduler_) Scheduler& scheduler_)
: device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} { : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} {
const VkBufferCreateInfo stream_ci = { VkBufferCreateInfo stream_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
.size = STREAM_BUFFER_SIZE, .size = STREAM_BUFFER_SIZE,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0, .queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr, .pQueueFamilyIndices = nullptr,
}; };
if (device.IsExtTransformFeedbackSupported()) {
stream_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
}
stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream); stream_buffer = memory_allocator.CreateBuffer(stream_ci, MemoryUsage::Stream);
if (device.HasDebuggingToolAttached()) { if (device.HasDebuggingToolAttached()) {
stream_buffer.SetObjectNameEXT("Stream Buffer"); stream_buffer.SetObjectNameEXT("Stream Buffer");
@ -164,19 +166,21 @@ std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t s
StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage, StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage,
bool deferred) { bool deferred) {
const u32 log2 = Common::Log2Ceil64(size); const u32 log2 = Common::Log2Ceil64(size);
const VkBufferCreateInfo buffer_ci = { VkBufferCreateInfo buffer_ci = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
.flags = 0, .flags = 0,
.size = 1ULL << log2, .size = 1ULL << log2,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE, .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0, .queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr, .pQueueFamilyIndices = nullptr,
}; };
if (device.IsExtTransformFeedbackSupported()) {
buffer_ci.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
}
vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage); vk::Buffer buffer = memory_allocator.CreateBuffer(buffer_ci, usage);
if (device.HasDebuggingToolAttached()) { if (device.HasDebuggingToolAttached()) {
++buffer_index; ++buffer_index;

View file

@ -1279,6 +1279,10 @@ Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu
flags |= VideoCommon::ImageFlagBits::Converted; flags |= VideoCommon::ImageFlagBits::Converted;
flags |= VideoCommon::ImageFlagBits::CostlyLoad; flags |= VideoCommon::ImageFlagBits::CostlyLoad;
} }
if (IsPixelFormatBCn(info.format) && !runtime->device.IsOptimalBcnSupported()) {
flags |= VideoCommon::ImageFlagBits::Converted;
flags |= VideoCommon::ImageFlagBits::CostlyLoad;
}
if (runtime->device.HasDebuggingToolAttached()) { if (runtime->device.HasDebuggingToolAttached()) {
original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str()); original_image.SetObjectNameEXT(VideoCommon::Name(*this).c_str());
} }

View file

@ -269,6 +269,28 @@ bool IsPixelFormatASTC(PixelFormat format) {
} }
} }
bool IsPixelFormatBCn(PixelFormat format) {
switch (format) {
case PixelFormat::BC1_RGBA_UNORM:
case PixelFormat::BC2_UNORM:
case PixelFormat::BC3_UNORM:
case PixelFormat::BC4_UNORM:
case PixelFormat::BC4_SNORM:
case PixelFormat::BC5_UNORM:
case PixelFormat::BC5_SNORM:
case PixelFormat::BC1_RGBA_SRGB:
case PixelFormat::BC2_SRGB:
case PixelFormat::BC3_SRGB:
case PixelFormat::BC7_UNORM:
case PixelFormat::BC6H_UFLOAT:
case PixelFormat::BC6H_SFLOAT:
case PixelFormat::BC7_SRGB:
return true;
default:
return false;
}
}
bool IsPixelFormatSRGB(PixelFormat format) { bool IsPixelFormatSRGB(PixelFormat format) {
switch (format) { switch (format) {
case PixelFormat::A8B8G8R8_SRGB: case PixelFormat::A8B8G8R8_SRGB:

View file

@ -501,6 +501,8 @@ SurfaceType GetFormatType(PixelFormat pixel_format);
bool IsPixelFormatASTC(PixelFormat format); bool IsPixelFormatASTC(PixelFormat format);
bool IsPixelFormatBCn(PixelFormat format);
bool IsPixelFormatSRGB(PixelFormat format); bool IsPixelFormatSRGB(PixelFormat format);
bool IsPixelFormatInteger(PixelFormat format); bool IsPixelFormatInteger(PixelFormat format);

View file

@ -0,0 +1,129 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <array>
#include <span>
#include <bc_decoder.h>
#include "common/common_types.h"
#include "video_core/texture_cache/decode_bc.h"
namespace VideoCommon {
namespace {
constexpr u32 BLOCK_SIZE = 4;
using VideoCore::Surface::PixelFormat;
constexpr bool IsSigned(PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::BC4_SNORM:
case PixelFormat::BC4_UNORM:
case PixelFormat::BC5_SNORM:
case PixelFormat::BC5_UNORM:
case PixelFormat::BC6H_SFLOAT:
case PixelFormat::BC6H_UFLOAT:
return true;
default:
return false;
}
}
constexpr u32 BlockSize(PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::BC1_RGBA_SRGB:
case PixelFormat::BC1_RGBA_UNORM:
case PixelFormat::BC4_SNORM:
case PixelFormat::BC4_UNORM:
return 8;
default:
return 16;
}
}
} // Anonymous namespace
u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::BC4_SNORM:
case PixelFormat::BC4_UNORM:
return 1;
case PixelFormat::BC5_SNORM:
case PixelFormat::BC5_UNORM:
return 2;
case PixelFormat::BC6H_SFLOAT:
case PixelFormat::BC6H_UFLOAT:
return 8;
default:
return 4;
}
}
template <auto decompress, PixelFormat pixel_format>
void DecompressBlocks(std::span<const u8> input, std::span<u8> output, Extent3D extent,
bool is_signed = false) {
const u32 out_bpp = ConvertedBytesPerBlock(pixel_format);
const u32 block_width = std::min(extent.width, BLOCK_SIZE);
const u32 block_height = std::min(extent.height, BLOCK_SIZE);
const u32 pitch = extent.width * out_bpp;
size_t input_offset = 0;
size_t output_offset = 0;
for (u32 slice = 0; slice < extent.depth; ++slice) {
for (u32 y = 0; y < extent.height; y += block_height) {
size_t row_offset = 0;
for (u32 x = 0; x < extent.width;
x += block_width, row_offset += block_width * out_bpp) {
const u8* src = input.data() + input_offset;
u8* const dst = output.data() + output_offset + row_offset;
if constexpr (IsSigned(pixel_format)) {
decompress(src, dst, x, y, extent.width, extent.height, is_signed);
} else {
decompress(src, dst, x, y, extent.width, extent.height);
}
input_offset += BlockSize(pixel_format);
}
output_offset += block_height * pitch;
}
}
}
void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
VideoCore::Surface::PixelFormat pixel_format) {
switch (pixel_format) {
case PixelFormat::BC1_RGBA_UNORM:
case PixelFormat::BC1_RGBA_SRGB:
DecompressBlocks<bcn::DecodeBc1, PixelFormat::BC1_RGBA_UNORM>(input, output, extent);
break;
case PixelFormat::BC2_UNORM:
case PixelFormat::BC2_SRGB:
DecompressBlocks<bcn::DecodeBc2, PixelFormat::BC2_UNORM>(input, output, extent);
break;
case PixelFormat::BC3_UNORM:
case PixelFormat::BC3_SRGB:
DecompressBlocks<bcn::DecodeBc3, PixelFormat::BC3_UNORM>(input, output, extent);
break;
case PixelFormat::BC4_SNORM:
case PixelFormat::BC4_UNORM:
DecompressBlocks<bcn::DecodeBc4, PixelFormat::BC4_UNORM>(
input, output, extent, pixel_format == PixelFormat::BC4_SNORM);
break;
case PixelFormat::BC5_SNORM:
case PixelFormat::BC5_UNORM:
DecompressBlocks<bcn::DecodeBc5, PixelFormat::BC5_UNORM>(
input, output, extent, pixel_format == PixelFormat::BC5_SNORM);
break;
case PixelFormat::BC6H_SFLOAT:
case PixelFormat::BC6H_UFLOAT:
DecompressBlocks<bcn::DecodeBc6, PixelFormat::BC6H_UFLOAT>(
input, output, extent, pixel_format == PixelFormat::BC6H_SFLOAT);
break;
case PixelFormat::BC7_SRGB:
case PixelFormat::BC7_UNORM:
DecompressBlocks<bcn::DecodeBc7, PixelFormat::BC7_UNORM>(input, output, extent);
break;
default:
LOG_WARNING(HW_GPU, "Unimplemented BCn decompression {}", pixel_format);
}
}
} // namespace VideoCommon

View file

@ -6,10 +6,14 @@
#include <span> #include <span>
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/surface.h"
#include "video_core/texture_cache/types.h" #include "video_core/texture_cache/types.h"
namespace VideoCommon { namespace VideoCommon {
void DecompressBC4(std::span<const u8> data, Extent3D extent, std::span<u8> output); [[nodiscard]] u32 ConvertedBytesPerBlock(VideoCore::Surface::PixelFormat pixel_format);
void DecompressBCn(std::span<const u8> input, std::span<u8> output, Extent3D extent,
VideoCore::Surface::PixelFormat pixel_format);
} // namespace VideoCommon } // namespace VideoCommon

View file

@ -1,96 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <array>
#include <span>
#include "common/assert.h"
#include "common/common_types.h"
#include "video_core/texture_cache/decode_bc4.h"
#include "video_core/texture_cache/types.h"
namespace VideoCommon {
// https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_compression_rgtc.txt
[[nodiscard]] constexpr u32 DecompressBlock(u64 bits, u32 x, u32 y) {
const u32 code_offset = 16 + 3 * (4 * y + x);
const u32 code = (bits >> code_offset) & 7;
const u32 red0 = (bits >> 0) & 0xff;
const u32 red1 = (bits >> 8) & 0xff;
if (red0 > red1) {
switch (code) {
case 0:
return red0;
case 1:
return red1;
case 2:
return (6 * red0 + 1 * red1) / 7;
case 3:
return (5 * red0 + 2 * red1) / 7;
case 4:
return (4 * red0 + 3 * red1) / 7;
case 5:
return (3 * red0 + 4 * red1) / 7;
case 6:
return (2 * red0 + 5 * red1) / 7;
case 7:
return (1 * red0 + 6 * red1) / 7;
}
} else {
switch (code) {
case 0:
return red0;
case 1:
return red1;
case 2:
return (4 * red0 + 1 * red1) / 5;
case 3:
return (3 * red0 + 2 * red1) / 5;
case 4:
return (2 * red0 + 3 * red1) / 5;
case 5:
return (1 * red0 + 4 * red1) / 5;
case 6:
return 0;
case 7:
return 0xff;
}
}
return 0;
}
void DecompressBC4(std::span<const u8> input, Extent3D extent, std::span<u8> output) {
UNIMPLEMENTED_IF_MSG(extent.width % 4 != 0, "Unaligned width={}", extent.width);
UNIMPLEMENTED_IF_MSG(extent.height % 4 != 0, "Unaligned height={}", extent.height);
static constexpr u32 BLOCK_SIZE = 4;
size_t input_offset = 0;
for (u32 slice = 0; slice < extent.depth; ++slice) {
for (u32 block_y = 0; block_y < extent.height / 4; ++block_y) {
for (u32 block_x = 0; block_x < extent.width / 4; ++block_x) {
u64 bits;
std::memcpy(&bits, &input[input_offset], sizeof(bits));
input_offset += sizeof(bits);
for (u32 y = 0; y < BLOCK_SIZE; ++y) {
for (u32 x = 0; x < BLOCK_SIZE; ++x) {
const u32 linear_z = slice;
const u32 linear_y = block_y * BLOCK_SIZE + y;
const u32 linear_x = block_x * BLOCK_SIZE + x;
const u32 offset_z = linear_z * extent.width * extent.height;
const u32 offset_y = linear_y * extent.width;
const u32 offset_x = linear_x;
const u32 output_offset = (offset_z + offset_y + offset_x) * 4ULL;
const u32 color = DecompressBlock(bits, x, y);
output[output_offset + 0] = static_cast<u8>(color);
output[output_offset + 1] = 0;
output[output_offset + 2] = 0;
output[output_offset + 3] = 0xff;
}
}
}
}
}
}
} // namespace VideoCommon

View file

@ -24,7 +24,7 @@
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
#include "video_core/memory_manager.h" #include "video_core/memory_manager.h"
#include "video_core/surface.h" #include "video_core/surface.h"
#include "video_core/texture_cache/decode_bc4.h" #include "video_core/texture_cache/decode_bc.h"
#include "video_core/texture_cache/format_lookup_table.h" #include "video_core/texture_cache/format_lookup_table.h"
#include "video_core/texture_cache/formatter.h" #include "video_core/texture_cache/formatter.h"
#include "video_core/texture_cache/samples_helper.h" #include "video_core/texture_cache/samples_helper.h"
@ -61,8 +61,6 @@ using VideoCore::Surface::PixelFormatFromDepthFormat;
using VideoCore::Surface::PixelFormatFromRenderTargetFormat; using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
using VideoCore::Surface::SurfaceType; using VideoCore::Surface::SurfaceType;
constexpr u32 CONVERTED_BYTES_PER_BLOCK = BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
struct LevelInfo { struct LevelInfo {
Extent3D size; Extent3D size;
Extent3D block; Extent3D block;
@ -612,7 +610,8 @@ u32 CalculateConvertedSizeBytes(const ImageInfo& info) noexcept {
} }
return output_size; return output_size;
} }
return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers * CONVERTED_BYTES_PER_BLOCK; return NumBlocksPerLayer(info, TILE_SIZE) * info.resources.layers *
ConvertedBytesPerBlock(info.format);
} }
u32 CalculateLayerStride(const ImageInfo& info) noexcept { u32 CalculateLayerStride(const ImageInfo& info) noexcept {
@ -945,7 +944,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
tile_size.height, output.subspan(output_offset)); tile_size.height, output.subspan(output_offset));
output_offset += copy.image_extent.width * copy.image_extent.height * output_offset += copy.image_extent.width * copy.image_extent.height *
copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; copy.image_subresource.num_layers *
BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
} else if (astc) { } else if (astc) {
// BC1 uses 0.5 bytes per texel // BC1 uses 0.5 bytes per texel
// BC3 uses 1 byte per texel // BC3 uses 1 byte per texel
@ -956,7 +956,8 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
const u32 plane_dim = copy.image_extent.width * copy.image_extent.height; const u32 plane_dim = copy.image_extent.width * copy.image_extent.height;
const u32 level_size = plane_dim * copy.image_extent.depth * const u32 level_size = plane_dim * copy.image_extent.depth *
copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; copy.image_subresource.num_layers *
BytesPerBlock(PixelFormat::A8B8G8R8_UNORM);
decode_scratch.resize_destructive(level_size); decode_scratch.resize_destructive(level_size);
Tegra::Texture::ASTC::Decompress( Tegra::Texture::ASTC::Decompress(
@ -976,10 +977,15 @@ void ConvertImage(std::span<const u8> input, const ImageInfo& info, std::span<u8
bpp_div; bpp_div;
output_offset += static_cast<u32>(copy.buffer_size); output_offset += static_cast<u32>(copy.buffer_size);
} else { } else {
DecompressBC4(input_offset, copy.image_extent, output.subspan(output_offset)); const Extent3D image_extent{
.width = copy.image_extent.width,
.height = copy.image_extent.height * copy.image_subresource.num_layers,
.depth = copy.image_extent.depth,
};
DecompressBCn(input_offset, output.subspan(output_offset), image_extent, info.format);
output_offset += copy.image_extent.width * copy.image_extent.height * output_offset += copy.image_extent.width * copy.image_extent.height *
copy.image_subresource.num_layers * CONVERTED_BYTES_PER_BLOCK; copy.image_subresource.num_layers *
ConvertedBytesPerBlock(info.format);
} }
} }
} }

View file

@ -3,7 +3,6 @@
#include <stb_dxt.h> #include <stb_dxt.h>
#include <string.h> #include <string.h>
#include "common/alignment.h" #include "common/alignment.h"
#include "video_core/textures/bcn.h" #include "video_core/textures/bcn.h"
#include "video_core/textures/workers.h" #include "video_core/textures/workers.h"

View file

@ -4,14 +4,13 @@
#pragma once #pragma once
#include <span> #include <span>
#include <stdint.h>
#include "common/common_types.h"
namespace Tegra::Texture::BCN { namespace Tegra::Texture::BCN {
void CompressBC1(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, void CompressBC1(std::span<const u8> data, u32 width, u32 height, u32 depth, std::span<u8> output);
std::span<uint8_t> output);
void CompressBC3(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, void CompressBC3(std::span<const u8> data, u32 width, u32 height, u32 depth, std::span<u8> output);
std::span<uint8_t> output);
} // namespace Tegra::Texture::BCN } // namespace Tegra::Texture::BCN

View file

@ -7,10 +7,10 @@
namespace Vulkan { namespace Vulkan {
namespace { namespace {
VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkBool32 DebugUtilCallback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
VkDebugUtilsMessageTypeFlagsEXT type, VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT* data, const VkDebugUtilsMessengerCallbackDataEXT* data,
[[maybe_unused]] void* user_data) { [[maybe_unused]] void* user_data) {
// Skip logging known false-positive validation errors // Skip logging known false-positive validation errors
switch (static_cast<u32>(data->messageIdNumber)) { switch (static_cast<u32>(data->messageIdNumber)) {
#ifdef ANDROID #ifdef ANDROID
@ -62,9 +62,26 @@ VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
} }
return VK_FALSE; return VK_FALSE;
} }
VkBool32 DebugReportCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType,
uint64_t object, size_t location, int32_t messageCode,
const char* pLayerPrefix, const char* pMessage, void* pUserData) {
const VkDebugReportFlagBitsEXT severity = static_cast<VkDebugReportFlagBitsEXT>(flags);
const std::string_view message{pMessage};
if (severity & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
LOG_CRITICAL(Render_Vulkan, "{}", message);
} else if (severity & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
LOG_WARNING(Render_Vulkan, "{}", message);
} else if (severity & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
LOG_INFO(Render_Vulkan, "{}", message);
} else if (severity & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
LOG_DEBUG(Render_Vulkan, "{}", message);
}
return VK_FALSE;
}
} // Anonymous namespace } // Anonymous namespace
vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) { vk::DebugUtilsMessenger CreateDebugUtilsCallback(const vk::Instance& instance) {
return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{ return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
.pNext = nullptr, .pNext = nullptr,
@ -76,7 +93,18 @@ vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) {
.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
.pfnUserCallback = Callback, .pfnUserCallback = DebugUtilCallback,
.pUserData = nullptr,
});
}
vk::DebugReportCallback CreateDebugReportCallback(const vk::Instance& instance) {
return instance.CreateDebugReportCallback({
.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
.pNext = nullptr,
.flags = VK_DEBUG_REPORT_DEBUG_BIT_EXT | VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT,
.pfnCallback = DebugReportCallback,
.pUserData = nullptr, .pUserData = nullptr,
}); });
} }

View file

@ -7,6 +7,8 @@
namespace Vulkan { namespace Vulkan {
vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance); vk::DebugUtilsMessenger CreateDebugUtilsCallback(const vk::Instance& instance);
vk::DebugReportCallback CreateDebugReportCallback(const vk::Instance& instance);
} // namespace Vulkan } // namespace Vulkan

View file

@ -349,7 +349,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
const bool is_s8gen2 = device_id == 0x43050a01; const bool is_s8gen2 = device_id == 0x43050a01;
const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY; const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY;
if ((is_mvk || is_qualcomm || is_turnip) && !is_suitable) { if ((is_mvk || is_qualcomm || is_turnip || is_arm) && !is_suitable) {
LOG_WARNING(Render_Vulkan, "Unsuitable driver, continuing anyway"); LOG_WARNING(Render_Vulkan, "Unsuitable driver, continuing anyway");
} else if (!is_suitable) { } else if (!is_suitable) {
throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER); throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
@ -905,6 +905,10 @@ bool Device::GetSuitability(bool requires_swapchain) {
properties.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; properties.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
SetNext(next, properties.driver); SetNext(next, properties.driver);
// Retrieve subgroup properties.
properties.subgroup_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
SetNext(next, properties.subgroup_properties);
// Retrieve relevant extension properties. // Retrieve relevant extension properties.
if (extensions.shader_float_controls) { if (extensions.shader_float_controls) {
properties.float_controls.sType = properties.float_controls.sType =

View file

@ -293,6 +293,11 @@ public:
return features.features.textureCompressionASTC_LDR; return features.features.textureCompressionASTC_LDR;
} }
/// Returns true if BCn is natively supported.
bool IsOptimalBcnSupported() const {
return features.features.textureCompressionBC;
}
/// Returns true if descriptor aliasing is natively supported. /// Returns true if descriptor aliasing is natively supported.
bool IsDescriptorAliasingSupported() const { bool IsDescriptorAliasingSupported() const {
return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY; return GetDriverID() != VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
@ -323,6 +328,11 @@ public:
return properties.subgroup_size_control.requiredSubgroupSizeStages & stage; return properties.subgroup_size_control.requiredSubgroupSizeStages & stage;
} }
/// Returns true if the device supports the provided subgroup feature.
bool IsSubgroupFeatureSupported(VkSubgroupFeatureFlagBits feature) const {
return properties.subgroup_properties.supportedOperations & feature;
}
/// Returns the maximum number of push descriptors. /// Returns the maximum number of push descriptors.
u32 MaxPushDescriptors() const { u32 MaxPushDescriptors() const {
return properties.push_descriptor.maxPushDescriptors; return properties.push_descriptor.maxPushDescriptors;
@ -388,6 +398,11 @@ public:
return extensions.swapchain_mutable_format; return extensions.swapchain_mutable_format;
} }
/// Returns true if VK_KHR_shader_float_controls is enabled.
bool IsKhrShaderFloatControlsSupported() const {
return extensions.shader_float_controls;
}
/// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout. /// Returns true if the device supports VK_KHR_workgroup_memory_explicit_layout.
bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const { bool IsKhrWorkgroupMemoryExplicitLayoutSupported() const {
return extensions.workgroup_memory_explicit_layout; return extensions.workgroup_memory_explicit_layout;
@ -413,6 +428,11 @@ public:
return extensions.sampler_filter_minmax; return extensions.sampler_filter_minmax;
} }
/// Returns true if the device supports VK_EXT_shader_stencil_export.
bool IsExtShaderStencilExportSupported() const {
return extensions.shader_stencil_export;
}
/// Returns true if the device supports VK_EXT_depth_range_unrestricted. /// Returns true if the device supports VK_EXT_depth_range_unrestricted.
bool IsExtDepthRangeUnrestrictedSupported() const { bool IsExtDepthRangeUnrestrictedSupported() const {
return extensions.depth_range_unrestricted; return extensions.depth_range_unrestricted;
@ -482,9 +502,9 @@ public:
return extensions.vertex_input_dynamic_state; return extensions.vertex_input_dynamic_state;
} }
/// Returns true if the device supports VK_EXT_shader_stencil_export. /// Returns true if the device supports VK_EXT_shader_demote_to_helper_invocation
bool IsExtShaderStencilExportSupported() const { bool IsExtShaderDemoteToHelperInvocationSupported() const {
return extensions.shader_stencil_export; return extensions.shader_demote_to_helper_invocation;
} }
/// Returns true if the device supports VK_EXT_conservative_rasterization. /// Returns true if the device supports VK_EXT_conservative_rasterization.
@ -518,12 +538,12 @@ public:
if (extensions.spirv_1_4) { if (extensions.spirv_1_4) {
return 0x00010400U; return 0x00010400U;
} }
return 0x00010000U; return 0x00010300U;
} }
/// Returns true when a known debugging tool is attached. /// Returns true when a known debugging tool is attached.
bool HasDebuggingToolAttached() const { bool HasDebuggingToolAttached() const {
return has_renderdoc || has_nsight_graphics || Settings::values.renderer_debug.GetValue(); return has_renderdoc || has_nsight_graphics;
} }
/// @returns True if compute pipelines can cause crashing. /// @returns True if compute pipelines can cause crashing.
@ -588,6 +608,10 @@ public:
return properties.properties.limits.maxVertexInputBindings; return properties.properties.limits.maxVertexInputBindings;
} }
u32 GetMaxViewports() const {
return properties.properties.limits.maxViewports;
}
bool SupportsConditionalBarriers() const { bool SupportsConditionalBarriers() const {
return supports_conditional_barriers; return supports_conditional_barriers;
} }
@ -680,6 +704,7 @@ private:
struct Properties { struct Properties {
VkPhysicalDeviceDriverProperties driver{}; VkPhysicalDeviceDriverProperties driver{};
VkPhysicalDeviceSubgroupProperties subgroup_properties{};
VkPhysicalDeviceFloatControlsProperties float_controls{}; VkPhysicalDeviceFloatControlsProperties float_controls{};
VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{}; VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{};
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{}; VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};

View file

@ -31,10 +31,34 @@
namespace Vulkan { namespace Vulkan {
namespace { namespace {
[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld,
std::span<const char* const> extensions) {
const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
if (!properties) {
LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
return false;
}
for (const char* extension : extensions) {
const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) {
return std::strcmp(extension, prop.extensionName) == 0;
});
if (it == properties->end()) {
LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
return false;
}
}
return true;
}
[[nodiscard]] std::vector<const char*> RequiredExtensions( [[nodiscard]] std::vector<const char*> RequiredExtensions(
Core::Frontend::WindowSystemType window_type, bool enable_validation) { const vk::InstanceDispatch& dld, Core::Frontend::WindowSystemType window_type,
bool enable_validation) {
std::vector<const char*> extensions; std::vector<const char*> extensions;
extensions.reserve(6); extensions.reserve(6);
#ifdef __APPLE__
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif
switch (window_type) { switch (window_type) {
case Core::Frontend::WindowSystemType::Headless: case Core::Frontend::WindowSystemType::Headless:
break; break;
@ -66,35 +90,14 @@ namespace {
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
} }
if (enable_validation) { if (enable_validation) {
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); const bool debug_utils =
AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
extensions.push_back(debug_utils ? VK_EXT_DEBUG_UTILS_EXTENSION_NAME
: VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
} }
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
#ifdef __APPLE__
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif
return extensions; return extensions;
} }
[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld,
std::span<const char* const> extensions) {
const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld);
if (!properties) {
LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
return false;
}
for (const char* extension : extensions) {
const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) {
return std::strcmp(extension, prop.extensionName) == 0;
});
if (it == properties->end()) {
LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
return false;
}
}
return true;
}
[[nodiscard]] std::vector<const char*> Layers(bool enable_validation) { [[nodiscard]] std::vector<const char*> Layers(bool enable_validation) {
std::vector<const char*> layers; std::vector<const char*> layers;
if (enable_validation) { if (enable_validation) {
@ -138,7 +141,8 @@ vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceD
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers"); LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers");
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
} }
const std::vector<const char*> extensions = RequiredExtensions(window_type, enable_validation); const std::vector<const char*> extensions =
RequiredExtensions(dld, window_type, enable_validation);
if (!AreExtensionsSupported(dld, extensions)) { if (!AreExtensionsSupported(dld, extensions)) {
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT);
} }

View file

@ -259,7 +259,9 @@ bool Load(VkInstance instance, InstanceDispatch& dld) noexcept {
// These functions may fail to load depending on the enabled extensions. // These functions may fail to load depending on the enabled extensions.
// Don't return a failure on these. // Don't return a failure on these.
X(vkCreateDebugUtilsMessengerEXT); X(vkCreateDebugUtilsMessengerEXT);
X(vkCreateDebugReportCallbackEXT);
X(vkDestroyDebugUtilsMessengerEXT); X(vkDestroyDebugUtilsMessengerEXT);
X(vkDestroyDebugReportCallbackEXT);
X(vkDestroySurfaceKHR); X(vkDestroySurfaceKHR);
X(vkGetPhysicalDeviceFeatures2); X(vkGetPhysicalDeviceFeatures2);
X(vkGetPhysicalDeviceProperties2); X(vkGetPhysicalDeviceProperties2);
@ -481,6 +483,11 @@ void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle,
dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr); dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr);
} }
void Destroy(VkInstance instance, VkDebugReportCallbackEXT handle,
const InstanceDispatch& dld) noexcept {
dld.vkDestroyDebugReportCallbackEXT(instance, handle, nullptr);
}
void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept { void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept {
dld.vkDestroySurfaceKHR(instance, handle, nullptr); dld.vkDestroySurfaceKHR(instance, handle, nullptr);
} }
@ -549,6 +556,13 @@ DebugUtilsMessenger Instance::CreateDebugUtilsMessenger(
return DebugUtilsMessenger(object, handle, *dld); return DebugUtilsMessenger(object, handle, *dld);
} }
DebugReportCallback Instance::CreateDebugReportCallback(
const VkDebugReportCallbackCreateInfoEXT& create_info) const {
VkDebugReportCallbackEXT object;
Check(dld->vkCreateDebugReportCallbackEXT(handle, &create_info, nullptr, &object));
return DebugReportCallback(object, handle, *dld);
}
void Image::SetObjectNameEXT(const char* name) const { void Image::SetObjectNameEXT(const char* name) const {
SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name); SetObjectName(dld, owner, handle, VK_OBJECT_TYPE_IMAGE, name);
} }

View file

@ -164,8 +164,10 @@ struct InstanceDispatch {
PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties{}; PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties{};
PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT{}; PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT{};
PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT{};
PFN_vkCreateDevice vkCreateDevice{}; PFN_vkCreateDevice vkCreateDevice{};
PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT{}; PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT{};
PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT{};
PFN_vkDestroyDevice vkDestroyDevice{}; PFN_vkDestroyDevice vkDestroyDevice{};
PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR{}; PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR{};
PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties{}; PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties{};
@ -366,6 +368,7 @@ void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept; void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept;
void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept; void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept;
void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept; void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept;
void Destroy(VkInstance, VkDebugReportCallbackEXT, const InstanceDispatch&) noexcept;
void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept; void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept;
VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept; VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept;
@ -581,6 +584,7 @@ private:
}; };
using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>; using DebugUtilsMessenger = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;
using DebugReportCallback = Handle<VkDebugReportCallbackEXT, VkInstance, InstanceDispatch>;
using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>; using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;
using DescriptorUpdateTemplate = Handle<VkDescriptorUpdateTemplate, VkDevice, DeviceDispatch>; using DescriptorUpdateTemplate = Handle<VkDescriptorUpdateTemplate, VkDevice, DeviceDispatch>;
using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>; using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;
@ -613,6 +617,11 @@ public:
DebugUtilsMessenger CreateDebugUtilsMessenger( DebugUtilsMessenger CreateDebugUtilsMessenger(
const VkDebugUtilsMessengerCreateInfoEXT& create_info) const; const VkDebugUtilsMessengerCreateInfoEXT& create_info) const;
/// Creates a debug report callback.
/// @throw Exception on creation failure.
DebugReportCallback CreateDebugReportCallback(
const VkDebugReportCallbackCreateInfoEXT& create_info) const;
/// Returns dispatch table. /// Returns dispatch table.
const InstanceDispatch& Dispatch() const noexcept { const InstanceDispatch& Dispatch() const noexcept {
return *dld; return *dld;