Compare commits

...

23 Commits

Author SHA1 Message Date
Lioncash
8c82c594f0 vulkan_wrapper: Fix SetObjectName() always indicating objects as images
We should be using the passed in object type instead.
2021-07-27 07:19:15 -04:00
bunnei
d6c799494c Merge pull request #6696 from ameerj/speed-limit-rename
general: Rename "Frame Limit" references to "Speed Limit"
2021-07-26 18:51:00 -07:00
Rodrigo Locatti
7511f65e31 Merge pull request #6741 from ReinUsesLisp/stream-remove
vk_stream_buffer: Remove unused stream buffer
2021-07-26 20:35:01 -03:00
Rodrigo Locatti
1a94b3f452 Merge pull request #6740 from K0bin/hvv-fallback
Handle allocation failure in Staging buffer
2021-07-26 20:34:44 -03:00
Robin Kertels
75050c788c vk_staging_buffer_pool: Fall back to host memory when allocation fails 2021-07-26 23:37:18 +02:00
Rodrigo Locatti
c6991fa900 Merge pull request #6728 from ReinUsesLisp/null-buffer-usage
vk_buffer_cache: Add transform feedback usage to null buffer
2021-07-26 18:30:45 -03:00
Rodrigo Locatti
6c432d5349 Merge pull request #6729 from ReinUsesLisp/quad-indexed-barrier
vk_compute_pass: Fix pipeline barrier for indexed quads
2021-07-26 18:30:05 -03:00
ReinUsesLisp
5f9a4817a5 vk_stream_buffer: Remove unused stream buffer
Remove unused file.
2021-07-26 18:19:53 -03:00
Rodrigo Locatti
c0f99558fb Merge pull request #6724 from lioncash/nodisc-shader
shader_recompiler: Remove unnecessary [[nodiscard]] instances
2021-07-26 16:35:21 -03:00
Rodrigo Locatti
de0b89792c Merge pull request #6726 from lioncash/hguard
emit_spirv_instructions: Add missing header guard
2021-07-26 16:35:11 -03:00
Rodrigo Locatti
3d97f1e6cf Merge pull request #6727 from lioncash/topology
emit_glasm: Fix LINESS_ADJACENCY typo in InputPrimitive()
2021-07-26 16:35:03 -03:00
bunnei
7490117fa4 Merge pull request #6736 from CaptV0rt3x/patch-1
Config-graphics: reword GLASM option
2021-07-26 11:27:46 -07:00
Vamsi Krishna
c05bbf375d configure_graphics: reword GLASM option
Change wording to explain that GLASM is actually short for Assembly Shaders
2021-07-26 20:49:31 +05:30
Rodrigo Locatti
b2b3fcdccd Merge pull request #6723 from lioncash/shader
object_pool: Add missing return in Chunk move assignment operator
2021-07-26 06:01:21 -03:00
Rodrigo Locatti
4afc2de129 Merge pull request #6725 from lioncash/control-token
control_flow: Fix duplicate switch case in OpcodeToken
2021-07-26 06:00:23 -03:00
ReinUsesLisp
27ed6e7c2b vk_buffer_cache: Add transform feedback usage to null buffer
Fixes bad API usages on Vulkan.
2021-07-26 05:49:37 -03:00
Lioncash
3e7813e49d emit_glasm: Fix LINESS_ADJACENCY typo in InputPrimitive()
This should be LINES_ADJACENCY
2021-07-26 04:44:56 -04:00
Lioncash
c2915d9f2f emit_spirv_instructions: Add missing header guard 2021-07-26 04:28:35 -04:00
Lioncash
06ca911621 shader_recompiler: Remove unnecessary [[nodiscard]] instances
[[nodiscard]] doesn't do anything on functions with a void return type
and causes superfluous warnings.
2021-07-26 04:23:59 -04:00
Lioncash
0b67df1f7c control_flow: Fix duplicate switch case in OpcodeToken
This previously duplicated the case of the PBK case above it.
2021-07-26 04:16:34 -04:00
Lioncash
89ad9df0e9 object_pool: Add missing return in Chunk move assignment operator
Prevents undefined behavior from occurring.
2021-07-26 04:01:05 -04:00
ameerj
c80ae87b4e renderer_base: Removed redundant settings
use_framelimiter was not being used internally by the renderers.
set_background_color was always set to true as there is no toggle for the renderer background color, instead users directly choose the color of their choice.
2021-07-23 22:10:01 -04:00
ameerj
9dfbc9bdce general: Rename "Frame Limit" references to "Speed Limit"
This setting is best referred to as a speed limit, as it involves the limits of all timing based aspects of the emulator, not only framerate.
This allows us to differentiate it from the fps unlocker setting.
2021-07-23 22:10:01 -04:00
30 changed files with 119 additions and 351 deletions

View File

@@ -48,8 +48,8 @@ void LogSettings() {
log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue());
log_setting("Renderer_UseFrameLimit", values.use_frame_limit.GetValue());
log_setting("Renderer_FrameLimit", values.frame_limit.GetValue());
log_setting("Renderer_UseSpeedLimit", values.use_speed_limit.GetValue());
log_setting("Renderer_SpeedLimit", values.speed_limit.GetValue());
log_setting("Renderer_UseDiskShaderCache", values.use_disk_shader_cache.GetValue());
log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue());
log_setting("Renderer_UseAsynchronousGpuEmulation",
@@ -132,8 +132,8 @@ void RestoreGlobalState(bool is_powered_on) {
values.vulkan_device.SetGlobal(true);
values.aspect_ratio.SetGlobal(true);
values.max_anisotropy.SetGlobal(true);
values.use_frame_limit.SetGlobal(true);
values.frame_limit.SetGlobal(true);
values.use_speed_limit.SetGlobal(true);
values.speed_limit.SetGlobal(true);
values.use_disk_shader_cache.SetGlobal(true);
values.gpu_accuracy.SetGlobal(true);
values.use_asynchronous_gpu_emulation.SetGlobal(true);

View File

@@ -331,8 +331,8 @@ struct Values {
"fullscreen_mode"};
Setting<int> aspect_ratio{0, "aspect_ratio"};
Setting<int> max_anisotropy{0, "max_anisotropy"};
Setting<bool> use_frame_limit{true, "use_frame_limit"};
Setting<u16> frame_limit{100, "frame_limit"};
Setting<bool> use_speed_limit{true, "use_speed_limit"};
Setting<u16> speed_limit{100, "speed_limit"};
Setting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
Setting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, "gpu_accuracy"};
Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};

View File

@@ -411,7 +411,7 @@ struct System::Impl {
std::string status_details = "";
std::unique_ptr<Core::PerfStats> perf_stats;
Core::FrameLimiter frame_limiter;
Core::SpeedLimiter speed_limiter;
bool is_multicore{};
bool is_async_gpu{};
@@ -606,12 +606,12 @@ const Core::PerfStats& System::GetPerfStats() const {
return *impl->perf_stats;
}
Core::FrameLimiter& System::FrameLimiter() {
return impl->frame_limiter;
Core::SpeedLimiter& System::SpeedLimiter() {
return impl->speed_limiter;
}
const Core::FrameLimiter& System::FrameLimiter() const {
return impl->frame_limiter;
const Core::SpeedLimiter& System::SpeedLimiter() const {
return impl->speed_limiter;
}
Loader::ResultStatus System::GetGameName(std::string& out) const {

View File

@@ -94,7 +94,7 @@ class ARM_Interface;
class CpuManager;
class DeviceMemory;
class ExclusiveMonitor;
class FrameLimiter;
class SpeedLimiter;
class PerfStats;
class Reporter;
class TelemetrySession;
@@ -292,11 +292,11 @@ public:
/// Provides a constant reference to the internal PerfStats instance.
[[nodiscard]] const Core::PerfStats& GetPerfStats() const;
/// Provides a reference to the frame limiter;
[[nodiscard]] Core::FrameLimiter& FrameLimiter();
/// Provides a reference to the speed limiter;
[[nodiscard]] Core::SpeedLimiter& SpeedLimiter();
/// Provides a constant referent to the frame limiter
[[nodiscard]] const Core::FrameLimiter& FrameLimiter() const;
/// Provides a constant reference to the speed limiter
[[nodiscard]] const Core::SpeedLimiter& SpeedLimiter() const;
/// Gets the name of the current game
[[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;

View File

@@ -54,7 +54,7 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
system.GetPerfStats().EndSystemFrame();
system.GPU().SwapBuffers(&framebuffer);
system.FrameLimiter().DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs());
system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs());
system.GetPerfStats().BeginSystemFrame();
}

View File

@@ -127,15 +127,15 @@ double PerfStats::GetLastFrameTimeScale() const {
return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH;
}
void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) {
if (!Settings::values.use_frame_limit.GetValue() ||
void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) {
if (!Settings::values.use_speed_limit.GetValue() ||
Settings::values.use_multi_core.GetValue()) {
return;
}
auto now = Clock::now();
const double sleep_scale = Settings::values.frame_limit.GetValue() / 100.0;
const double sleep_scale = Settings::values.speed_limit.GetValue() / 100.0;
// Max lag caused by slow frames. Shouldn't be more than the length of a frame at the current
// speed percent or it will clamp too much and prevent this from properly limiting to that
@@ -143,17 +143,17 @@ void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) {
// limiting
const microseconds max_lag_time_us = duration_cast<microseconds>(
std::chrono::duration<double, std::chrono::microseconds::period>(25ms / sleep_scale));
frame_limiting_delta_err += duration_cast<microseconds>(
speed_limiting_delta_err += duration_cast<microseconds>(
std::chrono::duration<double, std::chrono::microseconds::period>(
(current_system_time_us - previous_system_time_us) / sleep_scale));
frame_limiting_delta_err -= duration_cast<microseconds>(now - previous_walltime);
frame_limiting_delta_err =
std::clamp(frame_limiting_delta_err, -max_lag_time_us, max_lag_time_us);
speed_limiting_delta_err -= duration_cast<microseconds>(now - previous_walltime);
speed_limiting_delta_err =
std::clamp(speed_limiting_delta_err, -max_lag_time_us, max_lag_time_us);
if (frame_limiting_delta_err > microseconds::zero()) {
std::this_thread::sleep_for(frame_limiting_delta_err);
if (speed_limiting_delta_err > microseconds::zero()) {
std::this_thread::sleep_for(speed_limiting_delta_err);
auto now_after_sleep = Clock::now();
frame_limiting_delta_err -= duration_cast<microseconds>(now_after_sleep - now);
speed_limiting_delta_err -= duration_cast<microseconds>(now_after_sleep - now);
now = now_after_sleep;
}

View File

@@ -85,11 +85,11 @@ private:
double previous_fps = 0;
};
class FrameLimiter {
class SpeedLimiter {
public:
using Clock = std::chrono::high_resolution_clock;
void DoFrameLimiting(std::chrono::microseconds current_system_time_us);
void DoSpeedLimiting(std::chrono::microseconds current_system_time_us);
private:
/// Emulated system time (in microseconds) at the last limiter invocation
@@ -98,7 +98,7 @@ private:
Clock::time_point previous_walltime = Clock::now();
/// Accumulated difference between walltime and emulated time
std::chrono::microseconds frame_limiting_delta_err{0};
std::chrono::microseconds speed_limiting_delta_err{0};
};
} // namespace Core

View File

@@ -221,8 +221,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
TranslateRenderer(Settings::values.renderer_backend.GetValue()));
AddField(field_type, "Renderer_ResolutionFactor",
Settings::values.resolution_factor.GetValue());
AddField(field_type, "Renderer_UseFrameLimit", Settings::values.use_frame_limit.GetValue());
AddField(field_type, "Renderer_FrameLimit", Settings::values.frame_limit.GetValue());
AddField(field_type, "Renderer_UseSpeedLimit", Settings::values.use_speed_limit.GetValue());
AddField(field_type, "Renderer_SpeedLimit", Settings::values.speed_limit.GetValue());
AddField(field_type, "Renderer_UseDiskShaderCache",
Settings::values.use_disk_shader_cache.GetValue());
AddField(field_type, "Renderer_GPUAccuracyLevel",

View File

@@ -350,7 +350,7 @@ std::string_view InputPrimitive(InputTopology topology) {
case InputTopology::Lines:
return "LINES";
case InputTopology::LinesAdjacency:
return "LINESS_ADJACENCY";
return "LINES_ADJACENCY";
case InputTopology::Triangles:
return "TRIANGLES";
case InputTopology::TrianglesAdjacency:

View File

@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <sirit/sirit.h>
#include "common/common_types.h"

View File

@@ -327,8 +327,8 @@ public:
const Value& derivates, const Value& offset,
const F32& lod_clamp, TextureInstInfo info);
[[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, TextureInstInfo info);
[[nodiscard]] void ImageWrite(const Value& handle, const Value& coords, const Value& color,
TextureInstInfo info);
void ImageWrite(const Value& handle, const Value& coords, const Value& color,
TextureInstInfo info);
[[nodiscard]] Value ImageAtomicIAdd(const Value& handle, const Value& coords,
const Value& value, TextureInstInfo info);

View File

@@ -197,8 +197,8 @@ public:
}
template <typename FlagsType>
requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>)
[[nodiscard]] void SetFlags(FlagsType value) noexcept {
requires(sizeof(FlagsType) <= sizeof(u32) &&
std::is_trivially_copyable_v<FlagsType>) void SetFlags(FlagsType value) noexcept {
std::memcpy(&flags, &value, sizeof(value));
}

View File

@@ -73,7 +73,7 @@ Token OpcodeToken(Opcode opcode) {
return Token::PBK;
case Opcode::PCNT:
case Opcode::CONT:
return Token::PBK;
return Token::PCNT;
case Opcode::PEXIT:
case Opcode::EXIT:
return Token::PEXIT;

View File

@@ -63,6 +63,7 @@ private:
used_objects = std::exchange(rhs.used_objects, 0);
num_objects = std::exchange(rhs.num_objects, 0);
storage = std::move(rhs.storage);
return *this;
}
Chunk(Chunk&& rhs) noexcept

View File

@@ -19,9 +19,6 @@ RendererBase::~RendererBase() = default;
void RendererBase::RefreshBaseSettings() {
UpdateCurrentFramebufferLayout();
renderer_settings.use_framelimiter = Settings::values.use_frame_limit.GetValue();
renderer_settings.set_background_color = true;
}
void RendererBase::UpdateCurrentFramebufferLayout() {

View File

@@ -21,9 +21,6 @@ class GraphicsContext;
namespace VideoCore {
struct RendererSettings {
std::atomic_bool use_framelimiter{false};
std::atomic_bool set_background_color{false};
// Screenshot
std::atomic<bool> screenshot_requested{false};
void* screenshot_bits{};

View File

@@ -328,12 +328,10 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
}
void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
if (renderer_settings.set_background_color) {
// Update background color before drawing
glClearColor(Settings::values.bg_red.GetValue() / 255.0f,
Settings::values.bg_green.GetValue() / 255.0f,
Settings::values.bg_blue.GetValue() / 255.0f, 1.0f);
}
// Update background color before drawing
glClearColor(Settings::values.bg_red.GetValue() / 255.0f,
Settings::values.bg_green.GetValue() / 255.0f,
Settings::values.bg_blue.GetValue() / 255.0f, 1.0f);
// Set projection matrix
const std::array ortho_matrix =

View File

@@ -358,7 +358,7 @@ void BufferCacheRuntime::ReserveNullBuffer() {
if (null_buffer) {
return;
}
null_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
VkBufferCreateInfo create_info{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -367,9 +367,13 @@ void BufferCacheRuntime::ReserveNullBuffer() {
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
});
};
if (device.IsExtTransformFeedbackSupported()) {
create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
}
null_buffer = device.GetLogical().CreateBuffer(create_info);
if (device.HasDebuggingToolAttached()) {
null_buffer.SetObjectNameEXT("Null index buffer");
null_buffer.SetObjectNameEXT("Null buffer");
}
null_buffer_commit = memory_allocator.Commit(null_buffer, MemoryUsage::DeviceLocal);

View File

@@ -61,11 +61,15 @@ std::optional<u32> FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& p
return std::nullopt;
}
u32 FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask) {
// Try to find a DEVICE_LOCAL_BIT type, Nvidia and AMD have a dedicated heap for this
std::optional<u32> type = FindMemoryTypeIndex(props, type_mask, STREAM_FLAGS);
if (type) {
return *type;
u32 FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask,
bool try_device_local) {
std::optional<u32> type;
if (try_device_local) {
// Try to find a DEVICE_LOCAL_BIT type, Nvidia and AMD have a dedicated heap for this
type = FindMemoryTypeIndex(props, type_mask, STREAM_FLAGS);
if (type) {
return *type;
}
}
// Otherwise try without the DEVICE_LOCAL_BIT
type = FindMemoryTypeIndex(props, type_mask, HOST_FLAGS);
@@ -115,12 +119,21 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem
.buffer = *stream_buffer,
};
const auto memory_properties = device.GetPhysical().GetMemoryProperties();
stream_memory = dev.AllocateMemory(VkMemoryAllocateInfo{
VkMemoryAllocateInfo stream_memory_info{
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = make_dedicated ? &dedicated_info : nullptr,
.allocationSize = requirements.size,
.memoryTypeIndex = FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits),
});
.memoryTypeIndex =
FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, true),
};
stream_memory = dev.TryAllocateMemory(stream_memory_info);
if (!stream_memory) {
LOG_INFO(Render_Vulkan, "Dynamic memory allocation failed, trying with system memory");
stream_memory_info.memoryTypeIndex =
FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, false);
stream_memory = dev.AllocateMemory(stream_memory_info);
}
if (device.HasDebuggingToolAttached()) {
stream_memory.SetObjectNameEXT("Stream Buffer Memory");
}

View File

@@ -1,168 +0,0 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <limits>
#include <optional>
#include <tuple>
#include <vector>
#include "common/alignment.h"
#include "common/assert.h"
#include "common/literals.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/vulkan_common/vulkan_device.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan {
namespace {
using namespace Common::Literals;
constexpr VkBufferUsageFlags BUFFER_USAGE =
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000;
constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000;
constexpr u64 PREFERRED_STREAM_BUFFER_SIZE = 256_MiB;
/// Find a memory type with the passed requirements
std::optional<u32> FindMemoryType(const VkPhysicalDeviceMemoryProperties& properties,
VkMemoryPropertyFlags wanted,
u32 filter = std::numeric_limits<u32>::max()) {
for (u32 i = 0; i < properties.memoryTypeCount; ++i) {
const auto flags = properties.memoryTypes[i].propertyFlags;
if ((flags & wanted) == wanted && (filter & (1U << i)) != 0) {
return i;
}
}
return std::nullopt;
}
/// Get the preferred host visible memory type.
u32 GetMemoryType(const VkPhysicalDeviceMemoryProperties& properties,
u32 filter = std::numeric_limits<u32>::max()) {
// Prefer device local host visible allocations. Both AMD and Nvidia now provide one.
// Otherwise search for a host visible allocation.
static constexpr auto HOST_MEMORY =
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
static constexpr auto DYNAMIC_MEMORY = HOST_MEMORY | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
std::optional preferred_type = FindMemoryType(properties, DYNAMIC_MEMORY);
if (!preferred_type) {
preferred_type = FindMemoryType(properties, HOST_MEMORY);
ASSERT_MSG(preferred_type, "No host visible and coherent memory type found");
}
return preferred_type.value_or(0);
}
} // Anonymous namespace
VKStreamBuffer::VKStreamBuffer(const Device& device_, VKScheduler& scheduler_)
: device{device_}, scheduler{scheduler_} {
CreateBuffers();
ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE);
ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE);
}
VKStreamBuffer::~VKStreamBuffer() = default;
std::pair<u8*, u64> VKStreamBuffer::Map(u64 size, u64 alignment) {
ASSERT(size <= stream_buffer_size);
mapped_size = size;
if (alignment > 0) {
offset = Common::AlignUp(offset, alignment);
}
WaitPendingOperations(offset);
if (offset + size > stream_buffer_size) {
// The buffer would overflow, save the amount of used watches and reset the state.
invalidation_mark = current_watch_cursor;
current_watch_cursor = 0;
offset = 0;
// Swap watches and reset waiting cursors.
std::swap(previous_watches, current_watches);
wait_cursor = 0;
wait_bound = 0;
// Ensure that we don't wait for uncommitted fences.
scheduler.Flush();
}
return std::make_pair(memory.Map(offset, size), offset);
}
void VKStreamBuffer::Unmap(u64 size) {
ASSERT_MSG(size <= mapped_size, "Reserved size is too small");
memory.Unmap();
offset += size;
if (current_watch_cursor + 1 >= current_watches.size()) {
// Ensure that there are enough watches.
ReserveWatches(current_watches, WATCHES_RESERVE_CHUNK);
}
auto& watch = current_watches[current_watch_cursor++];
watch.upper_bound = offset;
watch.tick = scheduler.CurrentTick();
}
void VKStreamBuffer::CreateBuffers() {
const auto memory_properties = device.GetPhysical().GetMemoryProperties();
const u32 preferred_type = GetMemoryType(memory_properties);
const u32 preferred_heap = memory_properties.memoryTypes[preferred_type].heapIndex;
// Substract from the preferred heap size some bytes to avoid getting out of memory.
const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size;
// As per DXVK's example, using `heap_size / 2`
const VkDeviceSize allocable_size = heap_size / 2;
buffer = device.GetLogical().CreateBuffer({
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size),
.usage = BUFFER_USAGE,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = nullptr,
});
const auto requirements = device.GetLogical().GetBufferMemoryRequirements(*buffer);
const u32 required_flags = requirements.memoryTypeBits;
stream_buffer_size = static_cast<u64>(requirements.size);
memory = device.GetLogical().AllocateMemory({
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.pNext = nullptr,
.allocationSize = requirements.size,
.memoryTypeIndex = GetMemoryType(memory_properties, required_flags),
});
buffer.BindMemory(*memory, 0);
}
void VKStreamBuffer::ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size) {
watches.resize(watches.size() + grow_size);
}
void VKStreamBuffer::WaitPendingOperations(u64 requested_upper_bound) {
if (!invalidation_mark) {
return;
}
while (requested_upper_bound < wait_bound && wait_cursor < *invalidation_mark) {
auto& watch = previous_watches[wait_cursor];
wait_bound = watch.upper_bound;
scheduler.Wait(watch.tick);
++wait_cursor;
}
}
} // namespace Vulkan

View File

@@ -1,76 +0,0 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <optional>
#include <utility>
#include <vector>
#include "common/common_types.h"
#include "video_core/vulkan_common/vulkan_wrapper.h"
namespace Vulkan {
class Device;
class VKFenceWatch;
class VKScheduler;
class VKStreamBuffer final {
public:
explicit VKStreamBuffer(const Device& device, VKScheduler& scheduler);
~VKStreamBuffer();
/**
* Reserves a region of memory from the stream buffer.
* @param size Size to reserve.
* @returns A pair of a raw memory pointer (with offset added), and the buffer offset
*/
std::pair<u8*, u64> Map(u64 size, u64 alignment);
/// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy.
void Unmap(u64 size);
VkBuffer Handle() const noexcept {
return *buffer;
}
u64 Address() const noexcept {
return 0;
}
private:
struct Watch {
u64 tick{};
u64 upper_bound{};
};
/// Creates Vulkan buffer handles committing the required the required memory.
void CreateBuffers();
/// Increases the amount of watches available.
void ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size);
void WaitPendingOperations(u64 requested_upper_bound);
const Device& device; ///< Vulkan device manager.
VKScheduler& scheduler; ///< Command scheduler.
vk::Buffer buffer; ///< Mapped buffer.
vk::DeviceMemory memory; ///< Memory allocation.
u64 stream_buffer_size{}; ///< Stream buffer size.
u64 offset{}; ///< Buffer iterator.
u64 mapped_size{}; ///< Size reserved for the current copy.
std::vector<Watch> current_watches; ///< Watches recorded in the current iteration.
std::size_t current_watch_cursor{}; ///< Count of watches, reset on invalidation.
std::optional<std::size_t> invalidation_mark; ///< Number of watches used in the previous cycle.
std::vector<Watch> previous_watches; ///< Watches used in the previous iteration.
std::size_t wait_cursor{}; ///< Last watch being waited for completion.
u64 wait_bound{}; ///< Highest offset being watched for completion.
};
} // namespace Vulkan

View File

@@ -202,7 +202,7 @@ void SetObjectName(const DeviceDispatch* dld, VkDevice device, T handle, VkObjec
const VkDebugUtilsObjectNameInfoEXT name_info{
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
.pNext = nullptr,
.objectType = VK_OBJECT_TYPE_IMAGE,
.objectType = type,
.objectHandle = reinterpret_cast<u64>(handle),
.pObjectName = name,
};

View File

@@ -806,8 +806,8 @@ void Config::ReadRendererValues() {
ReadGlobalSetting(Settings::values.fullscreen_mode);
ReadGlobalSetting(Settings::values.aspect_ratio);
ReadGlobalSetting(Settings::values.max_anisotropy);
ReadGlobalSetting(Settings::values.use_frame_limit);
ReadGlobalSetting(Settings::values.frame_limit);
ReadGlobalSetting(Settings::values.use_speed_limit);
ReadGlobalSetting(Settings::values.speed_limit);
ReadGlobalSetting(Settings::values.use_disk_shader_cache);
ReadGlobalSetting(Settings::values.gpu_accuracy);
ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
@@ -1335,8 +1335,8 @@ void Config::SaveRendererValues() {
WriteGlobalSetting(Settings::values.fullscreen_mode);
WriteGlobalSetting(Settings::values.aspect_ratio);
WriteGlobalSetting(Settings::values.max_anisotropy);
WriteGlobalSetting(Settings::values.use_frame_limit);
WriteGlobalSetting(Settings::values.frame_limit);
WriteGlobalSetting(Settings::values.use_speed_limit);
WriteGlobalSetting(Settings::values.speed_limit);
WriteGlobalSetting(Settings::values.use_disk_shader_cache);
WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()),
static_cast<u32>(Settings::values.gpu_accuracy.GetValue(global)),

View File

@@ -24,8 +24,8 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
SetConfiguration();
if (Settings::IsConfiguringGlobal()) {
connect(ui->toggle_frame_limit, &QCheckBox::clicked, ui->frame_limit,
[this]() { ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked()); });
connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit,
[this]() { ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked()); });
}
connect(ui->button_reset_defaults, &QPushButton::clicked, this,
@@ -45,18 +45,18 @@ void ConfigureGeneral::SetConfiguration() {
ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue());
ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue());
ui->frame_limit->setValue(Settings::values.frame_limit.GetValue());
ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue());
ui->speed_limit->setValue(Settings::values.speed_limit.GetValue());
ui->fps_cap->setValue(Settings::values.fps_cap.GetValue());
ui->button_reset_defaults->setEnabled(runtime_lock);
if (Settings::IsConfiguringGlobal()) {
ui->frame_limit->setEnabled(Settings::values.use_frame_limit.GetValue());
ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue());
} else {
ui->frame_limit->setEnabled(Settings::values.use_frame_limit.GetValue() &&
use_frame_limit != ConfigurationShared::CheckState::Global);
ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() &&
use_speed_limit != ConfigurationShared::CheckState::Global);
}
}
@@ -92,19 +92,19 @@ void ConfigureGeneral::ApplyConfiguration() {
Settings::values.fps_cap.SetValue(ui->fps_cap->value());
// Guard if during game and set to game-specific value
if (Settings::values.use_frame_limit.UsingGlobal()) {
Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() ==
if (Settings::values.use_speed_limit.UsingGlobal()) {
Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() ==
Qt::Checked);
Settings::values.frame_limit.SetValue(ui->frame_limit->value());
Settings::values.speed_limit.SetValue(ui->speed_limit->value());
}
} else {
bool global_frame_limit = use_frame_limit == ConfigurationShared::CheckState::Global;
Settings::values.use_frame_limit.SetGlobal(global_frame_limit);
Settings::values.frame_limit.SetGlobal(global_frame_limit);
if (!global_frame_limit) {
Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() ==
bool global_speed_limit = use_speed_limit == ConfigurationShared::CheckState::Global;
Settings::values.use_speed_limit.SetGlobal(global_speed_limit);
Settings::values.speed_limit.SetGlobal(global_speed_limit);
if (!global_speed_limit) {
Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() ==
Qt::Checked);
Settings::values.frame_limit.SetValue(ui->frame_limit->value());
Settings::values.speed_limit.SetValue(ui->speed_limit->value());
}
}
}
@@ -126,8 +126,8 @@ void ConfigureGeneral::SetupPerGameUI() {
// Disables each setting if:
// - A game is running (thus settings in use), and
// - A non-global setting is applied.
ui->toggle_frame_limit->setEnabled(Settings::values.use_frame_limit.UsingGlobal());
ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal());
ui->toggle_speed_limit->setEnabled(Settings::values.use_speed_limit.UsingGlobal());
ui->speed_limit->setEnabled(Settings::values.speed_limit.UsingGlobal());
return;
}
@@ -139,13 +139,13 @@ void ConfigureGeneral::SetupPerGameUI() {
ui->button_reset_defaults->setVisible(false);
ConfigurationShared::SetColoredTristate(ui->toggle_frame_limit,
Settings::values.use_frame_limit, use_frame_limit);
ConfigurationShared::SetColoredTristate(ui->toggle_speed_limit,
Settings::values.use_speed_limit, use_speed_limit);
ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core,
use_multi_core);
connect(ui->toggle_frame_limit, &QCheckBox::clicked, ui->frame_limit, [this]() {
ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked() &&
(use_frame_limit != ConfigurationShared::CheckState::Global));
connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() {
ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() &&
(use_speed_limit != ConfigurationShared::CheckState::Global));
});
}

View File

@@ -43,6 +43,6 @@ private:
std::unique_ptr<Ui::ConfigureGeneral> ui;
ConfigurationShared::CheckState use_frame_limit;
ConfigurationShared::CheckState use_speed_limit;
ConfigurationShared::CheckState use_multi_core;
};

View File

@@ -27,14 +27,14 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="toggle_frame_limit">
<widget class="QCheckBox" name="toggle_speed_limit">
<property name="text">
<string>Limit Speed Percent</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="frame_limit">
<widget class="QSpinBox" name="speed_limit">
<property name="suffix">
<string>%</string>
</property>

View File

@@ -31,7 +31,7 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
}
ui->backend->addItem(QStringLiteral("GLSL"));
ui->backend->addItem(tr("GLASM (NVIDIA Only)"));
ui->backend->addItem(tr("GLASM (Assembly Shaders, NVIDIA Only)"));
ui->backend->addItem(QStringLiteral("SPIR-V (Experimental, Mesa Only)"));
SetupPerGameUI();

View File

@@ -972,23 +972,23 @@ void GMainWindow::InitializeHotkeys() {
});
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this),
&QShortcut::activated, this, [&] {
Settings::values.use_frame_limit.SetValue(
!Settings::values.use_frame_limit.GetValue());
Settings::values.use_speed_limit.SetValue(
!Settings::values.use_speed_limit.GetValue());
UpdateStatusBar();
});
constexpr u16 SPEED_LIMIT_STEP = 5;
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this),
&QShortcut::activated, this, [&] {
if (Settings::values.frame_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) {
Settings::values.frame_limit.SetValue(SPEED_LIMIT_STEP +
Settings::values.frame_limit.GetValue());
if (Settings::values.speed_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) {
Settings::values.speed_limit.SetValue(SPEED_LIMIT_STEP +
Settings::values.speed_limit.GetValue());
UpdateStatusBar();
}
});
connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this),
&QShortcut::activated, this, [&] {
if (Settings::values.frame_limit.GetValue() > SPEED_LIMIT_STEP) {
Settings::values.frame_limit.SetValue(Settings::values.frame_limit.GetValue() -
if (Settings::values.speed_limit.GetValue() > SPEED_LIMIT_STEP) {
Settings::values.speed_limit.SetValue(Settings::values.speed_limit.GetValue() -
SPEED_LIMIT_STEP);
UpdateStatusBar();
}
@@ -2910,10 +2910,10 @@ void GMainWindow::UpdateStatusBar() {
shader_building_label->setVisible(false);
}
if (Settings::values.use_frame_limit.GetValue()) {
if (Settings::values.use_speed_limit.GetValue()) {
emu_speed_label->setText(tr("Speed: %1% / %2%")
.arg(results.emulation_speed * 100.0, 0, 'f', 0)
.arg(Settings::values.frame_limit.GetValue()));
.arg(Settings::values.speed_limit.GetValue()));
} else {
emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
}

View File

@@ -451,8 +451,8 @@ void Config::ReadValues() {
ReadSetting("Renderer", Settings::values.fullscreen_mode);
ReadSetting("Renderer", Settings::values.aspect_ratio);
ReadSetting("Renderer", Settings::values.max_anisotropy);
ReadSetting("Renderer", Settings::values.use_frame_limit);
ReadSetting("Renderer", Settings::values.frame_limit);
ReadSetting("Renderer", Settings::values.use_speed_limit);
ReadSetting("Renderer", Settings::values.speed_limit);
ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
ReadSetting("Renderer", Settings::values.gpu_accuracy);
ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);

View File

@@ -265,13 +265,13 @@ use_nvdec_emulation =
# 0: Off, 1 (default): On
accelerate_astc =
# Turns on the frame limiter, which will limit frames output to the target game speed
# Turns on the speed limiter, which will limit the emulation speed to the desired speed limit value
# 0: Off, 1: On (default)
use_frame_limit =
use_speed_limit =
# Limits the speed of the game to run no faster than this value as a percentage of target speed
# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default)
frame_limit =
speed_limit =
# Whether to use disk based shader cache
# 0: Off, 1 (default): On