summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/file_sys/patch_manager.cpp4
-rw-r--r--src/core/file_sys/romfs.cpp19
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/loader/nca.cpp6
-rw-r--r--src/shader_recompiler/backend/glsl/glsl_emit_context.cpp5
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp76
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h1
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_device.h5
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp17
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp14
-rw-r--r--src/yuzu/configuration/qt_config.cpp3
-rw-r--r--src/yuzu/main.cpp5
13 files changed, 68 insertions, 90 deletions
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 0bca05587..cc7af2ea3 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -429,10 +429,6 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
429 LOG_DEBUG(Loader, "{}", log_string); 429 LOG_DEBUG(Loader, "{}", log_string);
430 } 430 }
431 431
432 if (base_romfs == nullptr) {
433 return base_romfs;
434 }
435
436 auto romfs = base_romfs; 432 auto romfs = base_romfs;
437 433
438 // Game Updates 434 // Game Updates
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
index 1eb1f439a..6de2103a0 100644
--- a/src/core/file_sys/romfs.cpp
+++ b/src/core/file_sys/romfs.cpp
@@ -3,6 +3,7 @@
3 3
4#include <memory> 4#include <memory>
5 5
6#include "common/assert.h"
6#include "common/common_types.h" 7#include "common/common_types.h"
7#include "common/string_util.h" 8#include "common/string_util.h"
8#include "common/swap.h" 9#include "common/swap.h"
@@ -101,24 +102,30 @@ void ProcessDirectory(const VirtualFile& file, std::size_t dir_offset, std::size
101} // Anonymous namespace 102} // Anonymous namespace
102 103
103VirtualDir ExtractRomFS(VirtualFile file) { 104VirtualDir ExtractRomFS(VirtualFile file) {
105 auto root_container = std::make_shared<VectorVfsDirectory>();
106 if (!file) {
107 return root_container;
108 }
109
104 RomFSHeader header{}; 110 RomFSHeader header{};
105 if (file->ReadObject(&header) != sizeof(RomFSHeader)) 111 if (file->ReadObject(&header) != sizeof(RomFSHeader)) {
106 return nullptr; 112 return root_container;
113 }
107 114
108 if (header.header_size != sizeof(RomFSHeader)) 115 if (header.header_size != sizeof(RomFSHeader)) {
109 return nullptr; 116 return root_container;
117 }
110 118
111 const u64 file_offset = header.file_meta.offset; 119 const u64 file_offset = header.file_meta.offset;
112 const u64 dir_offset = header.directory_meta.offset; 120 const u64 dir_offset = header.directory_meta.offset;
113 121
114 auto root_container = std::make_shared<VectorVfsDirectory>();
115
116 ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root_container); 122 ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root_container);
117 123
118 if (auto root = root_container->GetSubdirectory(""); root) { 124 if (auto root = root_container->GetSubdirectory(""); root) {
119 return std::make_shared<CachedVfsDirectory>(std::move(root)); 125 return std::make_shared<CachedVfsDirectory>(std::move(root));
120 } 126 }
121 127
128 ASSERT(false);
122 return nullptr; 129 return nullptr;
123} 130}
124 131
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 1bc07dae5..35e149905 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -22,7 +22,7 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader, ContentProvider& provi
22 : content_provider{provider}, filesystem_controller{controller} { 22 : content_provider{provider}, filesystem_controller{controller} {
23 // Load the RomFS from the app 23 // Load the RomFS from the app
24 if (app_loader.ReadRomFS(file) != Loader::ResultStatus::Success) { 24 if (app_loader.ReadRomFS(file) != Loader::ResultStatus::Success) {
25 LOG_ERROR(Service_FS, "Unable to read RomFS!"); 25 LOG_WARNING(Service_FS, "Unable to read base RomFS");
26 } 26 }
27 27
28 updatable = app_loader.IsRomFSUpdatable(); 28 updatable = app_loader.IsRomFSUpdatable();
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index 4feb6968a..814407535 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -74,10 +74,8 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::KProcess& process, Core::S
74 return load_result; 74 return load_result;
75 } 75 }
76 76
77 if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0) { 77 system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(
78 system.GetFileSystemController().RegisterRomFS(std::make_unique<FileSys::RomFSFactory>( 78 *this, system.GetContentProvider(), system.GetFileSystemController()));
79 *this, system.GetContentProvider(), system.GetFileSystemController()));
80 }
81 79
82 is_loaded = true; 80 is_loaded = true;
83 return load_result; 81 return load_result;
diff --git a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
index fd9a99449..b2ceeefc4 100644
--- a/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
+++ b/src/shader_recompiler/backend/glsl/glsl_emit_context.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/div_ceil.h"
4#include "shader_recompiler/backend/bindings.h" 5#include "shader_recompiler/backend/bindings.h"
5#include "shader_recompiler/backend/glsl/glsl_emit_context.h" 6#include "shader_recompiler/backend/glsl/glsl_emit_context.h"
6#include "shader_recompiler/frontend/ir/program.h" 7#include "shader_recompiler/frontend/ir/program.h"
@@ -431,9 +432,11 @@ void EmitContext::DefineConstantBuffers(Bindings& bindings) {
431 } 432 }
432 for (const auto& desc : info.constant_buffer_descriptors) { 433 for (const auto& desc : info.constant_buffer_descriptors) {
433 const auto cbuf_type{profile.has_gl_cbuf_ftou_bug ? "uvec4" : "vec4"}; 434 const auto cbuf_type{profile.has_gl_cbuf_ftou_bug ? "uvec4" : "vec4"};
435 const u32 cbuf_used_size{Common::DivCeil(info.constant_buffer_used_sizes[desc.index], 16U)};
436 const u32 cbuf_binding_size{info.uses_global_memory ? 0x1000U : cbuf_used_size};
434 header += fmt::format("layout(std140,binding={}) uniform {}_cbuf_{}{{{} {}_cbuf{}[{}];}};", 437 header += fmt::format("layout(std140,binding={}) uniform {}_cbuf_{}{{{} {}_cbuf{}[{}];}};",
435 bindings.uniform_buffer, stage_name, desc.index, cbuf_type, 438 bindings.uniform_buffer, stage_name, desc.index, cbuf_type,
436 stage_name, desc.index, 4 * 1024); 439 stage_name, desc.index, cbuf_binding_size);
437 bindings.uniform_buffer += desc.count; 440 bindings.uniform_buffer += desc.count;
438 } 441 }
439} 442}
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index ed188b435..e6c70fb34 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -53,13 +53,11 @@ Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rast
53 VAddr cpu_addr_, u64 size_bytes_) 53 VAddr cpu_addr_, u64 size_bytes_)
54 : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_) { 54 : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(rasterizer_, cpu_addr_, size_bytes_) {
55 buffer.Create(); 55 buffer.Create();
56 const std::string name = fmt::format("Buffer 0x{:x}", CpuAddr()); 56 if (runtime.device.HasDebuggingToolAttached()) {
57 glObjectLabel(GL_BUFFER, buffer.handle, static_cast<GLsizei>(name.size()), name.data()); 57 const std::string name = fmt::format("Buffer 0x{:x}", CpuAddr());
58 glNamedBufferData(buffer.handle, SizeBytes(), nullptr, GL_DYNAMIC_DRAW); 58 glObjectLabel(GL_BUFFER, buffer.handle, static_cast<GLsizei>(name.size()), name.data());
59
60 if (runtime.has_unified_vertex_buffers) {
61 glGetNamedBufferParameterui64vNV(buffer.handle, GL_BUFFER_GPU_ADDRESS_NV, &address);
62 } 59 }
60 glNamedBufferData(buffer.handle, SizeBytes(), nullptr, GL_DYNAMIC_DRAW);
63} 61}
64 62
65void Buffer::ImmediateUpload(size_t offset, std::span<const u8> data) noexcept { 63void Buffer::ImmediateUpload(size_t offset, std::span<const u8> data) noexcept {
@@ -111,7 +109,6 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_,
111 : device{device_}, staging_buffer_pool{staging_buffer_pool_}, 109 : device{device_}, staging_buffer_pool{staging_buffer_pool_},
112 has_fast_buffer_sub_data{device.HasFastBufferSubData()}, 110 has_fast_buffer_sub_data{device.HasFastBufferSubData()},
113 use_assembly_shaders{device.UseAssemblyShaders()}, 111 use_assembly_shaders{device.UseAssemblyShaders()},
114 has_unified_vertex_buffers{device.HasVertexBufferUnifiedMemory()},
115 stream_buffer{has_fast_buffer_sub_data ? std::nullopt : std::make_optional<StreamBuffer>()} { 112 stream_buffer{has_fast_buffer_sub_data ? std::nullopt : std::make_optional<StreamBuffer>()} {
116 GLint gl_max_attributes; 113 GLint gl_max_attributes;
117 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &gl_max_attributes); 114 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &gl_max_attributes);
@@ -123,16 +120,18 @@ BufferCacheRuntime::BufferCacheRuntime(const Device& device_,
123 GL_STREAM_DRAW); 120 GL_STREAM_DRAW);
124 } 121 }
125 } 122 }
126 for (auto& stage_uniforms : copy_uniforms) { 123 if (use_assembly_shaders) {
127 for (OGLBuffer& buffer : stage_uniforms) { 124 for (auto& stage_uniforms : copy_uniforms) {
125 for (OGLBuffer& buffer : stage_uniforms) {
126 buffer.Create();
127 glNamedBufferData(buffer.handle, 0x10'000, nullptr, GL_STREAM_COPY);
128 }
129 }
130 for (OGLBuffer& buffer : copy_compute_uniforms) {
128 buffer.Create(); 131 buffer.Create();
129 glNamedBufferData(buffer.handle, 0x10'000, nullptr, GL_STREAM_COPY); 132 glNamedBufferData(buffer.handle, 0x10'000, nullptr, GL_STREAM_COPY);
130 } 133 }
131 } 134 }
132 for (OGLBuffer& buffer : copy_compute_uniforms) {
133 buffer.Create();
134 glNamedBufferData(buffer.handle, 0x10'000, nullptr, GL_STREAM_COPY);
135 }
136 135
137 device_access_memory = [this]() -> u64 { 136 device_access_memory = [this]() -> u64 {
138 if (device.CanReportMemoryUsage()) { 137 if (device.CanReportMemoryUsage()) {
@@ -211,14 +210,8 @@ void BufferCacheRuntime::ClearBuffer(Buffer& dest_buffer, u32 offset, size_t siz
211} 210}
212 211
213void BufferCacheRuntime::BindIndexBuffer(Buffer& buffer, u32 offset, u32 size) { 212void BufferCacheRuntime::BindIndexBuffer(Buffer& buffer, u32 offset, u32 size) {
214 if (has_unified_vertex_buffers) { 213 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.Handle());
215 buffer.MakeResident(GL_READ_ONLY); 214 index_buffer_offset = offset;
216 glBufferAddressRangeNV(GL_ELEMENT_ARRAY_ADDRESS_NV, 0, buffer.HostGpuAddr() + offset,
217 static_cast<GLsizeiptr>(Common::AlignUp(size, 4)));
218 } else {
219 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer.Handle());
220 index_buffer_offset = offset;
221 }
222} 215}
223 216
224void BufferCacheRuntime::BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, 217void BufferCacheRuntime::BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size,
@@ -226,24 +219,23 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, Buffer& buffer, u32 offset,
226 if (index >= max_attributes) { 219 if (index >= max_attributes) {
227 return; 220 return;
228 } 221 }
229 if (has_unified_vertex_buffers) { 222 glBindVertexBuffer(index, buffer.Handle(), static_cast<GLintptr>(offset),
230 buffer.MakeResident(GL_READ_ONLY); 223 static_cast<GLsizei>(stride));
231 glBindVertexBuffer(index, 0, 0, static_cast<GLsizei>(stride));
232 glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, index,
233 buffer.HostGpuAddr() + offset, static_cast<GLsizeiptr>(size));
234 } else {
235 glBindVertexBuffer(index, buffer.Handle(), static_cast<GLintptr>(offset),
236 static_cast<GLsizei>(stride));
237 }
238} 224}
239 225
240void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) { 226void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
241 for (u32 index = 0; index < bindings.buffers.size(); ++index) { 227 // TODO: Should HostBindings provide the correct runtime types to avoid these transforms?
242 BindVertexBuffer(bindings.min_index + index, *bindings.buffers[index], 228 std::array<GLuint, 32> buffer_handles;
243 static_cast<u32>(bindings.offsets[index]), 229 std::array<GLsizei, 32> buffer_strides;
244 static_cast<u32>(bindings.sizes[index]), 230 std::ranges::transform(bindings.buffers, buffer_handles.begin(),
245 static_cast<u32>(bindings.strides[index])); 231 [](const Buffer* const buffer) { return buffer->Handle(); });
246 } 232 std::ranges::transform(bindings.strides, buffer_strides.begin(),
233 [](u64 stride) { return static_cast<GLsizei>(stride); });
234 const u32 count =
235 std::min(static_cast<u32>(bindings.buffers.size()), max_attributes - bindings.min_index);
236 glBindVertexBuffers(bindings.min_index, static_cast<GLsizei>(count), buffer_handles.data(),
237 reinterpret_cast<const GLintptr*>(bindings.offsets.data()),
238 buffer_strides.data());
247} 239}
248 240
249void BufferCacheRuntime::BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, 241void BufferCacheRuntime::BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer,
@@ -335,11 +327,13 @@ void BufferCacheRuntime::BindTransformFeedbackBuffer(u32 index, Buffer& buffer,
335} 327}
336 328
337void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings<Buffer>& bindings) { 329void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
338 for (u32 index = 0; index < bindings.buffers.size(); ++index) { 330 std::array<GLuint, 4> buffer_handles;
339 glBindBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, index, bindings.buffers[index]->Handle(), 331 std::ranges::transform(bindings.buffers, buffer_handles.begin(),
340 static_cast<GLintptr>(bindings.offsets[index]), 332 [](const Buffer* const buffer) { return buffer->Handle(); });
341 static_cast<GLsizeiptr>(bindings.sizes[index])); 333 glBindBuffersRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0,
342 } 334 static_cast<GLsizei>(bindings.buffers.size()), buffer_handles.data(),
335 reinterpret_cast<const GLintptr*>(bindings.offsets.data()),
336 reinterpret_cast<const GLsizeiptr*>(bindings.strides.data()));
343} 337}
344 338
345void BufferCacheRuntime::BindTextureBuffer(Buffer& buffer, u32 offset, u32 size, 339void BufferCacheRuntime::BindTextureBuffer(Buffer& buffer, u32 offset, u32 size,
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index 1e8708f59..71cd45d35 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -209,7 +209,6 @@ private:
209 209
210 bool has_fast_buffer_sub_data = false; 210 bool has_fast_buffer_sub_data = false;
211 bool use_assembly_shaders = false; 211 bool use_assembly_shaders = false;
212 bool has_unified_vertex_buffers = false;
213 212
214 bool use_storage_buffers = false; 213 bool use_storage_buffers = false;
215 214
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp
index 993438a27..a6c93068f 100644
--- a/src/video_core/renderer_opengl/gl_device.cpp
+++ b/src/video_core/renderer_opengl/gl_device.cpp
@@ -200,7 +200,6 @@ Device::Device(Core::Frontend::EmuWindow& emu_window) {
200 has_broken_texture_view_formats = is_amd || (!is_linux && is_intel); 200 has_broken_texture_view_formats = is_amd || (!is_linux && is_intel);
201 has_nv_viewport_array2 = GLAD_GL_NV_viewport_array2; 201 has_nv_viewport_array2 = GLAD_GL_NV_viewport_array2;
202 has_derivative_control = GLAD_GL_ARB_derivative_control; 202 has_derivative_control = GLAD_GL_ARB_derivative_control;
203 has_vertex_buffer_unified_memory = GLAD_GL_NV_vertex_buffer_unified_memory;
204 has_debugging_tool_attached = IsDebugToolAttached(extensions); 203 has_debugging_tool_attached = IsDebugToolAttached(extensions);
205 has_depth_buffer_float = HasExtension(extensions, "GL_NV_depth_buffer_float"); 204 has_depth_buffer_float = HasExtension(extensions, "GL_NV_depth_buffer_float");
206 has_geometry_shader_passthrough = GLAD_GL_NV_geometry_shader_passthrough; 205 has_geometry_shader_passthrough = GLAD_GL_NV_geometry_shader_passthrough;
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h
index a5a6bbbba..96034ea4a 100644
--- a/src/video_core/renderer_opengl/gl_device.h
+++ b/src/video_core/renderer_opengl/gl_device.h
@@ -72,10 +72,6 @@ public:
72 return has_texture_shadow_lod; 72 return has_texture_shadow_lod;
73 } 73 }
74 74
75 bool HasVertexBufferUnifiedMemory() const {
76 return has_vertex_buffer_unified_memory;
77 }
78
79 bool HasASTC() const { 75 bool HasASTC() const {
80 return has_astc; 76 return has_astc;
81 } 77 }
@@ -215,7 +211,6 @@ private:
215 bool has_vertex_viewport_layer{}; 211 bool has_vertex_viewport_layer{};
216 bool has_image_load_formatted{}; 212 bool has_image_load_formatted{};
217 bool has_texture_shadow_lod{}; 213 bool has_texture_shadow_lod{};
218 bool has_vertex_buffer_unified_memory{};
219 bool has_astc{}; 214 bool has_astc{};
220 bool has_variable_aoffi{}; 215 bool has_variable_aoffi{};
221 bool has_component_indexing_bug{}; 216 bool has_component_indexing_bug{};
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 6b8d4e554..6bfed08a1 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -168,15 +168,6 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_,
168 if (!GLAD_GL_ARB_seamless_cubemap_per_texture && !GLAD_GL_AMD_seamless_cubemap_per_texture) { 168 if (!GLAD_GL_ARB_seamless_cubemap_per_texture && !GLAD_GL_AMD_seamless_cubemap_per_texture) {
169 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); 169 glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
170 } 170 }
171 // Enable unified vertex attributes and query vertex buffer address when the driver supports it
172 if (device.HasVertexBufferUnifiedMemory()) {
173 glEnableClientState(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV);
174 glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV);
175
176 glMakeNamedBufferResidentNV(vertex_buffer.handle, GL_READ_ONLY);
177 glGetNamedBufferParameterui64vNV(vertex_buffer.handle, GL_BUFFER_GPU_ADDRESS_NV,
178 &vertex_buffer_address);
179 }
180} 171}
181 172
182RendererOpenGL::~RendererOpenGL() = default; 173RendererOpenGL::~RendererOpenGL() = default;
@@ -680,13 +671,7 @@ void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
680 offsetof(ScreenRectVertex, tex_coord)); 671 offsetof(ScreenRectVertex, tex_coord));
681 glVertexAttribBinding(PositionLocation, 0); 672 glVertexAttribBinding(PositionLocation, 0);
682 glVertexAttribBinding(TexCoordLocation, 0); 673 glVertexAttribBinding(TexCoordLocation, 0);
683 if (device.HasVertexBufferUnifiedMemory()) { 674 glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex));
684 glBindVertexBuffer(0, 0, 0, sizeof(ScreenRectVertex));
685 glBufferAddressRangeNV(GL_VERTEX_ATTRIB_ARRAY_ADDRESS_NV, 0, vertex_buffer_address,
686 sizeof(vertices));
687 } else {
688 glBindVertexBuffer(0, vertex_buffer.handle, 0, sizeof(ScreenRectVertex));
689 }
690 675
691 if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::NearestNeighbor) { 676 if (Settings::values.scaling_filter.GetValue() != Settings::ScalingFilter::NearestNeighbor) {
692 glBindSampler(0, present_sampler.handle); 677 glBindSampler(0, present_sampler.handle);
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 07222e603..b6f52e017 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -75,14 +75,20 @@ VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t in
75 const float width = conv(src.scale_x * 2.0f); 75 const float width = conv(src.scale_x * 2.0f);
76 float y = conv(src.translate_y - src.scale_y); 76 float y = conv(src.translate_y - src.scale_y);
77 float height = conv(src.scale_y * 2.0f); 77 float height = conv(src.scale_y * 2.0f);
78 bool y_negate = regs.window_origin.mode != Maxwell::WindowOrigin::Mode::UpperLeft;
79 78
80 if (!device.IsNvViewportSwizzleSupported()) { 79 const bool lower_left = regs.window_origin.mode != Maxwell::WindowOrigin::Mode::UpperLeft;
81 y_negate = y_negate != (src.swizzle.y == Maxwell::ViewportSwizzle::NegativeY); 80 const bool y_negate = !device.IsNvViewportSwizzleSupported() &&
81 src.swizzle.y == Maxwell::ViewportSwizzle::NegativeY;
82
83 if (lower_left) {
84 // Flip by surface clip height
85 y += conv(static_cast<f32>(regs.surface_clip.height));
86 height = -height;
82 } 87 }
83 88
84 if (y_negate) { 89 if (y_negate) {
85 y += conv(static_cast<f32>(regs.surface_clip.height)); 90 // Flip by viewport height
91 y += height;
86 height = -height; 92 height = -height;
87 } 93 }
88 94
diff --git a/src/yuzu/configuration/qt_config.cpp b/src/yuzu/configuration/qt_config.cpp
index 5a8e69aa9..636c5e640 100644
--- a/src/yuzu/configuration/qt_config.cpp
+++ b/src/yuzu/configuration/qt_config.cpp
@@ -225,7 +225,8 @@ void QtConfig::ReadPathValues() {
225 UISettings::values.recent_files = 225 UISettings::values.recent_files =
226 QString::fromStdString(ReadStringSetting(std::string("recentFiles"))) 226 QString::fromStdString(ReadStringSetting(std::string("recentFiles")))
227 .split(QStringLiteral(", "), Qt::SkipEmptyParts, Qt::CaseSensitive); 227 .split(QStringLiteral(", "), Qt::SkipEmptyParts, Qt::CaseSensitive);
228 UISettings::values.language = ReadStringSetting(std::string("language"), std::string("")); 228 UISettings::values.language =
229 ReadStringSetting(std::string("language"), std::make_optional(std::string("")));
229 230
230 EndGroup(); 231 EndGroup();
231} 232}
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 10c788290..b056c3717 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -2713,11 +2713,6 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
2713 } 2713 }
2714 2714
2715 const auto base_romfs = base_nca->GetRomFS(); 2715 const auto base_romfs = base_nca->GetRomFS();
2716 if (!base_romfs) {
2717 failed();
2718 return;
2719 }
2720
2721 const auto dump_dir = 2716 const auto dump_dir =
2722 target == DumpRomFSTarget::Normal 2717 target == DumpRomFSTarget::Normal
2723 ? Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir) 2718 ? Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)