diff options
Diffstat (limited to 'src/video_core/renderer_vulkan')
5 files changed, 64 insertions, 9 deletions
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index 9fe6bdbf9..9a950f4de 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h @@ -129,7 +129,7 @@ struct alignas(32) FixedPipelineState { auto& binding = bindings[index]; binding.raw = 0; binding.enabled.Assign(enabled ? 1 : 0); - binding.stride.Assign(stride); + binding.stride.Assign(static_cast<u16>(stride)); binding_divisors[index] = divisor; } diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 8a1f57891..68464e637 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -877,8 +877,12 @@ void RasterizerVulkan::SetupVertexArrays(FixedPipelineState::VertexInput& vertex const GPUVAddr start{vertex_array.StartAddress()}; const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()}; - ASSERT(end > start); - const std::size_t size{end - start + 1}; + ASSERT(end >= start); + const std::size_t size{end - start}; + if (size == 0) { + buffer_bindings.AddVertexBinding(DefaultBuffer(), 0); + continue; + } const auto [buffer, offset] = buffer_cache.UploadMemory(start, size); buffer_bindings.AddVertexBinding(buffer, offset); } @@ -1033,8 +1037,7 @@ void RasterizerVulkan::SetupConstBuffer(const ConstBufferEntry& entry, const Tegra::Engines::ConstBufferInfo& buffer) { if (!buffer.enabled) { // Set values to zero to unbind buffers - update_descriptor_queue.AddBuffer(buffer_cache.GetEmptyBuffer(sizeof(float)), 0, - sizeof(float)); + update_descriptor_queue.AddBuffer(DefaultBuffer(), 0, DEFAULT_BUFFER_SIZE); return; } @@ -1057,7 +1060,9 @@ void RasterizerVulkan::SetupGlobalBuffer(const GlobalBufferEntry& entry, GPUVAdd if (size == 0) { // Sometimes global memory pointers don't have a proper size. Upload a dummy entry // because Vulkan doesn't like empty buffers. - constexpr std::size_t dummy_size = 4; + // Note: Do *not* use DefaultBuffer() here, storage buffers can be written breaking the + // default buffer. + static constexpr std::size_t dummy_size = 4; const auto buffer = buffer_cache.GetEmptyBuffer(dummy_size); update_descriptor_queue.AddBuffer(buffer, 0, dummy_size); return; @@ -1222,7 +1227,7 @@ std::size_t RasterizerVulkan::CalculateVertexArraysSize() const { const GPUVAddr end{regs.vertex_array_limit[index].LimitAddress()}; DEBUG_ASSERT(end >= start); - size += (end - start + 1) * regs.vertex_array[index].enable; + size += (end - start) * regs.vertex_array[index].enable; } return size; } @@ -1269,4 +1274,29 @@ RenderPassParams RasterizerVulkan::GetRenderPassParams(Texceptions texceptions) return renderpass_params; } +VkBuffer RasterizerVulkan::DefaultBuffer() { + if (default_buffer) { + return *default_buffer; + } + + VkBufferCreateInfo ci; + ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + ci.pNext = nullptr; + ci.flags = 0; + ci.size = DEFAULT_BUFFER_SIZE; + ci.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + ci.queueFamilyIndexCount = 0; + ci.pQueueFamilyIndices = nullptr; + default_buffer = device.GetLogical().CreateBuffer(ci); + default_buffer_commit = memory_manager.Commit(default_buffer, false); + + scheduler.RequestOutsideRenderPassOperationContext(); + scheduler.Record([buffer = *default_buffer](vk::CommandBuffer cmdbuf) { + cmdbuf.FillBuffer(buffer, 0, DEFAULT_BUFFER_SIZE, 0); + }); + return *default_buffer; +} + } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 2fa46b0cc..d41a7929e 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -155,6 +155,7 @@ private: using Texceptions = std::bitset<Maxwell::NumRenderTargets + 1>; static constexpr std::size_t ZETA_TEXCEPTION_INDEX = 8; + static constexpr VkDeviceSize DEFAULT_BUFFER_SIZE = 4 * sizeof(float); void FlushWork(); @@ -247,6 +248,8 @@ private: RenderPassParams GetRenderPassParams(Texceptions texceptions) const; + VkBuffer DefaultBuffer(); + Core::System& system; Core::Frontend::EmuWindow& render_window; VKScreenInfo& screen_info; @@ -271,6 +274,9 @@ private: VKFenceManager fence_manager; VKQueryCache query_cache; + vk::Buffer default_buffer; + VKMemoryCommit default_buffer_commit; + std::array<View, Maxwell::NumRenderTargets> color_attachments; View zeta_attachment; diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 94d954d7a..c76ab5c2d 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp @@ -81,7 +81,7 @@ VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_v ci.size = 1ULL << log2; ci.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_INDEX_BUFFER_BIT; + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE; ci.queueFamilyIndexCount = 0; ci.pQueueFamilyIndices = nullptr; diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp index 539f3c974..7f5bc1404 100644 --- a/src/video_core/renderer_vulkan/wrapper.cpp +++ b/src/video_core/renderer_vulkan/wrapper.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <algorithm> #include <exception> #include <memory> #include <optional> @@ -16,6 +17,23 @@ namespace Vulkan::vk { namespace { +void SortPhysicalDevices(std::vector<VkPhysicalDevice>& devices, const InstanceDispatch& dld) { + std::stable_sort(devices.begin(), devices.end(), [&](auto lhs, auto rhs) { + // This will call Vulkan more than needed, but these calls are cheap. + const auto lhs_properties = vk::PhysicalDevice(lhs, dld).GetProperties(); + const auto rhs_properties = vk::PhysicalDevice(rhs, dld).GetProperties(); + + // Prefer discrete GPUs, Nvidia over AMD, AMD over Intel, Intel over the rest. + const bool preferred = + (lhs_properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && + rhs_properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) || + (lhs_properties.vendorID == 0x10DE && rhs_properties.vendorID != 0x10DE) || + (lhs_properties.vendorID == 0x1002 && rhs_properties.vendorID != 0x1002) || + (lhs_properties.vendorID == 0x8086 && rhs_properties.vendorID != 0x8086); + return !preferred; + }); +} + template <typename T> bool Proc(T& result, const InstanceDispatch& dld, const char* proc_name, VkInstance instance = nullptr) noexcept { @@ -389,7 +407,8 @@ std::optional<std::vector<VkPhysicalDevice>> Instance::EnumeratePhysicalDevices( if (dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()) != VK_SUCCESS) { return std::nullopt; } - return physical_devices; + SortPhysicalDevices(physical_devices, *dld); + return std::make_optional(std::move(physical_devices)); } DebugCallback Instance::TryCreateDebugCallback( |