summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/audio_core/stream.cpp4
-rw-r--r--src/common/logging/backend.cpp11
-rw-r--r--src/common/logging/backend.h14
-rw-r--r--src/core/hle/service/acc/profile_manager.h3
-rw-r--r--src/core/hle/service/audio/hwopus.cpp2
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp3
-rw-r--r--src/core/hle/service/hid/hid.cpp2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h4
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/engines/maxwell_3d.cpp16
-rw-r--r--src/video_core/engines/maxwell_3d.h37
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp118
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp61
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h4
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.cpp188
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h132
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h1
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp252
-rw-r--r--src/video_core/renderer_opengl/gl_state.h60
-rw-r--r--src/video_core/renderer_opengl/gl_stream_buffer.cpp5
-rw-r--r--src/video_core/surface.cpp29
-rw-r--r--src/video_core/surface.h108
-rw-r--r--src/video_core/textures/astc.cpp32
-rw-r--r--src/video_core/textures/astc.h2
-rw-r--r--src/video_core/textures/decoders.cpp12
-rw-r--r--src/video_core/textures/decoders.h4
-rw-r--r--src/yuzu/CMakeLists.txt2
-rw-r--r--src/yuzu/configuration/configure_system.cpp43
-rw-r--r--src/yuzu/debugger/graphics/graphics_surface.cpp6
-rw-r--r--src/yuzu/main.cpp11
-rw-r--r--src/yuzu/main.h1
-rw-r--r--src/yuzu/main.ui6
-rw-r--r--src/yuzu/util/limitable_input_dialog.cpp59
-rw-r--r--src/yuzu/util/limitable_input_dialog.h31
-rw-r--r--src/yuzu_cmd/yuzu.cpp3
36 files changed, 896 insertions, 379 deletions
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index 742a5e0a0..f35628e45 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -11,7 +11,6 @@
11#include "audio_core/stream.h" 11#include "audio_core/stream.h"
12#include "common/assert.h" 12#include "common/assert.h"
13#include "common/logging/log.h" 13#include "common/logging/log.h"
14#include "common/microprofile.h"
15#include "core/core_timing.h" 14#include "core/core_timing.h"
16#include "core/core_timing_util.h" 15#include "core/core_timing_util.h"
17#include "core/settings.h" 16#include "core/settings.h"
@@ -104,10 +103,7 @@ void Stream::PlayNextBuffer() {
104 CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {}); 103 CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
105} 104}
106 105
107MICROPROFILE_DEFINE(AudioOutput, "Audio", "ReleaseActiveBuffer", MP_RGB(100, 100, 255));
108
109void Stream::ReleaseActiveBuffer() { 106void Stream::ReleaseActiveBuffer() {
110 MICROPROFILE_SCOPE(AudioOutput);
111 ASSERT(active_buffer); 107 ASSERT(active_buffer);
112 released_buffers.push(std::move(active_buffer)); 108 released_buffers.push(std::move(active_buffer));
113 release_callback(); 109 release_callback();
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 6d5218465..5753b871a 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -12,7 +12,8 @@
12#include <thread> 12#include <thread>
13#include <vector> 13#include <vector>
14#ifdef _WIN32 14#ifdef _WIN32
15#include <share.h> // For _SH_DENYWR 15#include <share.h> // For _SH_DENYWR
16#include <windows.h> // For OutputDebugStringA
16#else 17#else
17#define _SH_DENYWR 0 18#define _SH_DENYWR 0
18#endif 19#endif
@@ -139,12 +140,18 @@ void FileBackend::Write(const Entry& entry) {
139 if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) { 140 if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) {
140 return; 141 return;
141 } 142 }
142 bytes_written += file.WriteString(FormatLogMessage(entry) + '\n'); 143 bytes_written += file.WriteString(FormatLogMessage(entry).append(1, '\n'));
143 if (entry.log_level >= Level::Error) { 144 if (entry.log_level >= Level::Error) {
144 file.Flush(); 145 file.Flush();
145 } 146 }
146} 147}
147 148
149void DebuggerBackend::Write(const Entry& entry) {
150#ifdef _WIN32
151 ::OutputDebugStringA(FormatLogMessage(entry).append(1, '\n').c_str());
152#endif
153}
154
148/// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this. 155/// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this.
149#define ALL_LOG_CLASSES() \ 156#define ALL_LOG_CLASSES() \
150 CLS(Log) \ 157 CLS(Log) \
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index 11edbf1b6..91bb0c309 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -103,6 +103,20 @@ private:
103 std::size_t bytes_written; 103 std::size_t bytes_written;
104}; 104};
105 105
106/**
107 * Backend that writes to Visual Studio's output window
108 */
109class DebuggerBackend : public Backend {
110public:
111 static const char* Name() {
112 return "debugger";
113 }
114 const char* GetName() const override {
115 return Name();
116 }
117 void Write(const Entry& entry) override;
118};
119
106void AddBackend(std::unique_ptr<Backend> backend); 120void AddBackend(std::unique_ptr<Backend> backend);
107 121
108void RemoveBackend(std::string_view backend_name); 122void RemoveBackend(std::string_view backend_name);
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index 1cd2e51b2..747c46c20 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -57,7 +57,8 @@ struct UUID {
57}; 57};
58static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); 58static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
59 59
60using ProfileUsername = std::array<u8, 0x20>; 60constexpr std::size_t profile_username_size = 32;
61using ProfileUsername = std::array<u8, profile_username_size>;
61using ProfileData = std::array<u8, MAX_DATA>; 62using ProfileData = std::array<u8, MAX_DATA>;
62using UserIDArray = std::array<UUID, MAX_USERS>; 63using UserIDArray = std::array<UUID, MAX_USERS>;
63 64
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 7168c6a10..783c39503 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -161,7 +161,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
161 ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); 161 ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
162 162
163 std::size_t worker_sz = WorkerBufferSize(channel_count); 163 std::size_t worker_sz = WorkerBufferSize(channel_count);
164 ASSERT_MSG(buffer_sz < worker_sz, "Worker buffer too large"); 164 ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large");
165 std::unique_ptr<OpusDecoder, OpusDeleter> decoder{ 165 std::unique_ptr<OpusDecoder, OpusDeleter> decoder{
166 static_cast<OpusDecoder*>(operator new(worker_sz))}; 166 static_cast<OpusDecoder*>(operator new(worker_sz))};
167 if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) { 167 if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 4b4d1324f..1ef789bd0 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -427,6 +427,9 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
427} 427}
428 428
429Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const { 429Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const {
430 // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
431 // be signalled at least once, and signaled after a new controller is connected?
432 styleset_changed_event->Signal();
430 return styleset_changed_event; 433 return styleset_changed_event;
431} 434}
432 435
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index a9aa9ec78..a45fd4954 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -96,6 +96,8 @@ public:
96 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) 96 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
97 97
98 CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event); 98 CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);
99
100 ReloadInputDevices();
99 } 101 }
100 102
101 void ActivateController(HidController controller) { 103 void ActivateController(HidController controller) {
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 2fe81a560..8cff5eb71 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -58,9 +58,9 @@ public:
58 /// Rotate source image 90 degrees clockwise 58 /// Rotate source image 90 degrees clockwise
59 Rotate90 = 0x04, 59 Rotate90 = 0x04,
60 /// Rotate source image 180 degrees 60 /// Rotate source image 180 degrees
61 Roate180 = 0x03, 61 Rotate180 = 0x03,
62 /// Rotate source image 270 degrees clockwise 62 /// Rotate source image 270 degrees clockwise
63 Roate270 = 0x07, 63 Rotate270 = 0x07,
64 }; 64 };
65 65
66 struct Buffer { 66 struct Buffer {
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index ddb1a1d69..0b1cc1290 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -33,6 +33,7 @@ add_library(video_core STATIC
33 renderer_opengl/gl_rasterizer.h 33 renderer_opengl/gl_rasterizer.h
34 renderer_opengl/gl_rasterizer_cache.cpp 34 renderer_opengl/gl_rasterizer_cache.cpp
35 renderer_opengl/gl_rasterizer_cache.h 35 renderer_opengl/gl_rasterizer_cache.h
36 renderer_opengl/gl_resource_manager.cpp
36 renderer_opengl/gl_resource_manager.h 37 renderer_opengl/gl_resource_manager.h
37 renderer_opengl/gl_shader_cache.cpp 38 renderer_opengl/gl_shader_cache.cpp
38 renderer_opengl/gl_shader_cache.h 39 renderer_opengl/gl_shader_cache.h
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index d79c50919..2cd595f26 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -37,6 +37,22 @@ void Maxwell3D::InitializeRegisterDefaults() {
37 regs.viewport[viewport].depth_range_near = 0.0f; 37 regs.viewport[viewport].depth_range_near = 0.0f;
38 regs.viewport[viewport].depth_range_far = 1.0f; 38 regs.viewport[viewport].depth_range_far = 1.0f;
39 } 39 }
40 // Doom and Bomberman seems to use the uninitialized registers and just enable blend
41 // so initialize blend registers with sane values
42 regs.blend.equation_rgb = Regs::Blend::Equation::Add;
43 regs.blend.factor_source_rgb = Regs::Blend::Factor::One;
44 regs.blend.factor_dest_rgb = Regs::Blend::Factor::Zero;
45 regs.blend.equation_a = Regs::Blend::Equation::Add;
46 regs.blend.factor_source_a = Regs::Blend::Factor::One;
47 regs.blend.factor_dest_a = Regs::Blend::Factor::Zero;
48 for (std::size_t blend_index = 0; blend_index < Regs::NumRenderTargets; blend_index++) {
49 regs.independent_blend[blend_index].equation_rgb = Regs::Blend::Equation::Add;
50 regs.independent_blend[blend_index].factor_source_rgb = Regs::Blend::Factor::One;
51 regs.independent_blend[blend_index].factor_dest_rgb = Regs::Blend::Factor::Zero;
52 regs.independent_blend[blend_index].equation_a = Regs::Blend::Equation::Add;
53 regs.independent_blend[blend_index].factor_source_a = Regs::Blend::Factor::One;
54 regs.independent_blend[blend_index].factor_dest_a = Regs::Blend::Factor::Zero;
55 }
40} 56}
41 57
42void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { 58void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 50873813e..0509ba3a2 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -462,6 +462,16 @@ public:
462 } 462 }
463 }; 463 };
464 464
465 struct ColorMask {
466 union {
467 u32 raw;
468 BitField<0, 4, u32> R;
469 BitField<4, 4, u32> G;
470 BitField<8, 4, u32> B;
471 BitField<12, 4, u32> A;
472 };
473 };
474
465 bool IsShaderConfigEnabled(std::size_t index) const { 475 bool IsShaderConfigEnabled(std::size_t index) const {
466 // The VertexB is always enabled. 476 // The VertexB is always enabled.
467 if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) { 477 if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) {
@@ -571,7 +581,11 @@ public:
571 u32 stencil_back_mask; 581 u32 stencil_back_mask;
572 u32 stencil_back_func_mask; 582 u32 stencil_back_func_mask;
573 583
574 INSERT_PADDING_WORDS(0x13); 584 INSERT_PADDING_WORDS(0xC);
585
586 u32 color_mask_common;
587
588 INSERT_PADDING_WORDS(0x6);
575 589
576 u32 rt_separate_frag_data; 590 u32 rt_separate_frag_data;
577 591
@@ -646,8 +660,14 @@ public:
646 ComparisonOp depth_test_func; 660 ComparisonOp depth_test_func;
647 float alpha_test_ref; 661 float alpha_test_ref;
648 ComparisonOp alpha_test_func; 662 ComparisonOp alpha_test_func;
649 663 u32 draw_tfb_stride;
650 INSERT_PADDING_WORDS(0x9); 664 struct {
665 float r;
666 float g;
667 float b;
668 float a;
669 } blend_color;
670 INSERT_PADDING_WORDS(0x4);
651 671
652 struct { 672 struct {
653 u32 separate_alpha; 673 u32 separate_alpha;
@@ -841,8 +861,9 @@ public:
841 BitField<6, 4, u32> RT; 861 BitField<6, 4, u32> RT;
842 BitField<10, 11, u32> layer; 862 BitField<10, 11, u32> layer;
843 } clear_buffers; 863 } clear_buffers;
844 864 INSERT_PADDING_WORDS(0xB);
845 INSERT_PADDING_WORDS(0x4B); 865 std::array<ColorMask, NumRenderTargets> color_mask;
866 INSERT_PADDING_WORDS(0x38);
846 867
847 struct { 868 struct {
848 u32 query_address_high; 869 u32 query_address_high;
@@ -1075,6 +1096,7 @@ ASSERT_REG_POSITION(scissor_test, 0x380);
1075ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); 1096ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
1076ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); 1097ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
1077ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); 1098ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
1099ASSERT_REG_POSITION(color_mask_common, 0x3E4);
1078ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); 1100ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
1079ASSERT_REG_POSITION(zeta, 0x3F8); 1101ASSERT_REG_POSITION(zeta, 0x3F8);
1080ASSERT_REG_POSITION(vertex_attrib_format, 0x458); 1102ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
@@ -1087,6 +1109,10 @@ ASSERT_REG_POSITION(depth_write_enabled, 0x4BA);
1087ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB); 1109ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB);
1088ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2); 1110ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2);
1089ASSERT_REG_POSITION(depth_test_func, 0x4C3); 1111ASSERT_REG_POSITION(depth_test_func, 0x4C3);
1112ASSERT_REG_POSITION(alpha_test_ref, 0x4C4);
1113ASSERT_REG_POSITION(alpha_test_func, 0x4C5);
1114ASSERT_REG_POSITION(draw_tfb_stride, 0x4C6);
1115ASSERT_REG_POSITION(blend_color, 0x4C7);
1090ASSERT_REG_POSITION(blend, 0x4CF); 1116ASSERT_REG_POSITION(blend, 0x4CF);
1091ASSERT_REG_POSITION(stencil_enable, 0x4E0); 1117ASSERT_REG_POSITION(stencil_enable, 0x4E0);
1092ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1); 1118ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1);
@@ -1117,6 +1143,7 @@ ASSERT_REG_POSITION(instanced_arrays, 0x620);
1117ASSERT_REG_POSITION(cull, 0x646); 1143ASSERT_REG_POSITION(cull, 0x646);
1118ASSERT_REG_POSITION(logic_op, 0x671); 1144ASSERT_REG_POSITION(logic_op, 0x671);
1119ASSERT_REG_POSITION(clear_buffers, 0x674); 1145ASSERT_REG_POSITION(clear_buffers, 0x674);
1146ASSERT_REG_POSITION(color_mask, 0x680);
1120ASSERT_REG_POSITION(query, 0x6C0); 1147ASSERT_REG_POSITION(query, 0x6C0);
1121ASSERT_REG_POSITION(vertex_array[0], 0x700); 1148ASSERT_REG_POSITION(vertex_array[0], 0x700);
1122ASSERT_REG_POSITION(independent_blend, 0x780); 1149ASSERT_REG_POSITION(independent_blend, 0x780);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index a0527fe57..bb263b6aa 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -511,10 +511,10 @@ void RasterizerOpenGL::Clear() {
511 511
512 OpenGLState clear_state; 512 OpenGLState clear_state;
513 clear_state.draw.draw_framebuffer = framebuffer.handle; 513 clear_state.draw.draw_framebuffer = framebuffer.handle;
514 clear_state.color_mask.red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE; 514 clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE;
515 clear_state.color_mask.green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE; 515 clear_state.color_mask[0].green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE;
516 clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE; 516 clear_state.color_mask[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
517 clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE; 517 clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
518 518
519 if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B || 519 if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
520 regs.clear_buffers.A) { 520 regs.clear_buffers.A) {
@@ -573,14 +573,13 @@ void RasterizerOpenGL::DrawArrays() {
573 ScopeAcquireGLContext acquire_context{emu_window}; 573 ScopeAcquireGLContext acquire_context{emu_window};
574 574
575 ConfigureFramebuffers(); 575 ConfigureFramebuffers();
576 576 SyncColorMask();
577 SyncDepthTestState(); 577 SyncDepthTestState();
578 SyncStencilTestState(); 578 SyncStencilTestState();
579 SyncBlendState(); 579 SyncBlendState();
580 SyncLogicOpState(); 580 SyncLogicOpState();
581 SyncCullMode(); 581 SyncCullMode();
582 SyncPrimitiveRestart(); 582 SyncPrimitiveRestart();
583 SyncDepthRange();
584 SyncScissorTest(); 583 SyncScissorTest();
585 // Alpha Testing is synced on shaders. 584 // Alpha Testing is synced on shaders.
586 SyncTransformFeedback(); 585 SyncTransformFeedback();
@@ -899,12 +898,16 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
899 898
900void RasterizerOpenGL::SyncViewport() { 899void RasterizerOpenGL::SyncViewport() {
901 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 900 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
902 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; 901 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
903 902 const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
904 state.viewport.x = viewport_rect.left; 903 auto& viewport = state.viewports[i];
905 state.viewport.y = viewport_rect.bottom; 904 viewport.x = viewport_rect.left;
906 state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth()); 905 viewport.y = viewport_rect.bottom;
907 state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight()); 906 viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth());
907 viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight());
908 viewport.depth_range_far = regs.viewport[i].depth_range_far;
909 viewport.depth_range_near = regs.viewport[i].depth_range_near;
910 }
908} 911}
909 912
910void RasterizerOpenGL::SyncClipEnabled() { 913void RasterizerOpenGL::SyncClipEnabled() {
@@ -946,13 +949,6 @@ void RasterizerOpenGL::SyncPrimitiveRestart() {
946 state.primitive_restart.index = regs.primitive_restart.index; 949 state.primitive_restart.index = regs.primitive_restart.index;
947} 950}
948 951
949void RasterizerOpenGL::SyncDepthRange() {
950 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
951
952 state.depth.depth_range_near = regs.viewport->depth_range_near;
953 state.depth.depth_range_far = regs.viewport->depth_range_far;
954}
955
956void RasterizerOpenGL::SyncDepthTestState() { 952void RasterizerOpenGL::SyncDepthTestState() {
957 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 953 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
958 954
@@ -993,26 +989,60 @@ void RasterizerOpenGL::SyncStencilTestState() {
993 state.stencil.back.write_mask = regs.stencil_back_mask; 989 state.stencil.back.write_mask = regs.stencil_back_mask;
994} 990}
995 991
996void RasterizerOpenGL::SyncBlendState() { 992void RasterizerOpenGL::SyncColorMask() {
997 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 993 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
994 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
995 const auto& source = regs.color_mask[regs.color_mask_common ? 0 : i];
996 auto& dest = state.color_mask[i];
997 dest.red_enabled = (source.R == 0) ? GL_FALSE : GL_TRUE;
998 dest.green_enabled = (source.G == 0) ? GL_FALSE : GL_TRUE;
999 dest.blue_enabled = (source.B == 0) ? GL_FALSE : GL_TRUE;
1000 dest.alpha_enabled = (source.A == 0) ? GL_FALSE : GL_TRUE;
1001 }
1002}
998 1003
999 // TODO(Subv): Support more than just render target 0. 1004void RasterizerOpenGL::SyncBlendState() {
1000 state.blend.enabled = regs.blend.enable[0] != 0; 1005 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1001 1006
1002 if (!state.blend.enabled) 1007 state.blend_color.red = regs.blend_color.r;
1008 state.blend_color.green = regs.blend_color.g;
1009 state.blend_color.blue = regs.blend_color.b;
1010 state.blend_color.alpha = regs.blend_color.a;
1011
1012 state.independant_blend.enabled = regs.independent_blend_enable;
1013 if (!state.independant_blend.enabled) {
1014 auto& blend = state.blend[0];
1015 blend.enabled = regs.blend.enable[0] != 0;
1016 blend.separate_alpha = regs.blend.separate_alpha;
1017 blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb);
1018 blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb);
1019 blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb);
1020 if (blend.separate_alpha) {
1021 blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a);
1022 blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a);
1023 blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a);
1024 }
1025 for (size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
1026 state.blend[i].enabled = false;
1027 }
1003 return; 1028 return;
1029 }
1004 1030
1005 ASSERT_MSG(regs.logic_op.enable == 0, 1031 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
1006 "Blending and logic op can't be enabled at the same time."); 1032 auto& blend = state.blend[i];
1007 1033 blend.enabled = regs.blend.enable[i] != 0;
1008 ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented"); 1034 if (!blend.enabled)
1009 ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented"); 1035 continue;
1010 state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb); 1036 blend.separate_alpha = regs.independent_blend[i].separate_alpha;
1011 state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_rgb); 1037 blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_rgb);
1012 state.blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_rgb); 1038 blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_rgb);
1013 state.blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_a); 1039 blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_rgb);
1014 state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_a); 1040 if (blend.separate_alpha) {
1015 state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_a); 1041 blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_a);
1042 blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_a);
1043 blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_a);
1044 }
1045 }
1016} 1046}
1017 1047
1018void RasterizerOpenGL::SyncLogicOpState() { 1048void RasterizerOpenGL::SyncLogicOpState() {
@@ -1031,19 +1061,19 @@ void RasterizerOpenGL::SyncLogicOpState() {
1031} 1061}
1032 1062
1033void RasterizerOpenGL::SyncScissorTest() { 1063void RasterizerOpenGL::SyncScissorTest() {
1064 // TODO: what is the correct behavior here, a single scissor for all targets
1065 // or scissor disabled for the rest of the targets?
1034 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1066 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1035
1036 state.scissor.enabled = (regs.scissor_test.enable != 0); 1067 state.scissor.enabled = (regs.scissor_test.enable != 0);
1037 // TODO(Blinkhawk): Figure if the hardware supports scissor testing per viewport and how it's 1068 if (regs.scissor_test.enable == 0) {
1038 // implemented. 1069 return;
1039 if (regs.scissor_test.enable != 0) {
1040 const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x;
1041 const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y;
1042 state.scissor.x = regs.scissor_test.min_x;
1043 state.scissor.y = regs.scissor_test.min_y;
1044 state.scissor.width = width;
1045 state.scissor.height = height;
1046 } 1070 }
1071 const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x;
1072 const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y;
1073 state.scissor.x = regs.scissor_test.min_x;
1074 state.scissor.y = regs.scissor_test.min_y;
1075 state.scissor.width = width;
1076 state.scissor.height = height;
1047} 1077}
1048 1078
1049void RasterizerOpenGL::SyncTransformFeedback() { 1079void RasterizerOpenGL::SyncTransformFeedback() {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 47097c569..60e783803 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -133,7 +133,7 @@ private:
133 u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader, 133 u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader,
134 GLenum primitive_mode, u32 current_unit); 134 GLenum primitive_mode, u32 current_unit);
135 135
136 /// Syncs the viewport to match the guest state 136 /// Syncs the viewport and depth range to match the guest state
137 void SyncViewport(); 137 void SyncViewport();
138 138
139 /// Syncs the clip enabled status to match the guest state 139 /// Syncs the clip enabled status to match the guest state
@@ -148,9 +148,6 @@ private:
148 /// Syncs the primitve restart to match the guest state 148 /// Syncs the primitve restart to match the guest state
149 void SyncPrimitiveRestart(); 149 void SyncPrimitiveRestart();
150 150
151 /// Syncs the depth range to match the guest state
152 void SyncDepthRange();
153
154 /// Syncs the depth test state to match the guest state 151 /// Syncs the depth test state to match the guest state
155 void SyncDepthTestState(); 152 void SyncDepthTestState();
156 153
@@ -172,6 +169,9 @@ private:
172 /// Syncs the point state to match the guest state 169 /// Syncs the point state to match the guest state
173 void SyncPointState(); 170 void SyncPointState();
174 171
172 /// Syncs Color Mask
173 void SyncColorMask();
174
175 /// Check asserts for alpha testing. 175 /// Check asserts for alpha testing.
176 void CheckAlphaTests(); 176 void CheckAlphaTests();
177 177
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index f194a7687..49d63e6f3 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -16,6 +16,7 @@
16#include "core/settings.h" 16#include "core/settings.h"
17#include "video_core/engines/maxwell_3d.h" 17#include "video_core/engines/maxwell_3d.h"
18#include "video_core/renderer_opengl/gl_rasterizer_cache.h" 18#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
19#include "video_core/renderer_opengl/gl_state.h"
19#include "video_core/renderer_opengl/utils.h" 20#include "video_core/renderer_opengl/utils.h"
20#include "video_core/surface.h" 21#include "video_core/surface.h"
21#include "video_core/textures/astc.h" 22#include "video_core/textures/astc.h"
@@ -58,16 +59,14 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
58 59
59std::size_t SurfaceParams::InnerMipmapMemorySize(u32 mip_level, bool force_gl, bool layer_only, 60std::size_t SurfaceParams::InnerMipmapMemorySize(u32 mip_level, bool force_gl, bool layer_only,
60 bool uncompressed) const { 61 bool uncompressed) const {
61 const u32 compression_factor{GetCompressionFactor(pixel_format)}; 62 const u32 tile_x{GetDefaultBlockWidth(pixel_format)};
63 const u32 tile_y{GetDefaultBlockHeight(pixel_format)};
62 const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)}; 64 const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)};
63 u32 m_depth = (layer_only ? 1U : depth); 65 u32 m_depth = (layer_only ? 1U : depth);
64 u32 m_width = MipWidth(mip_level); 66 u32 m_width = MipWidth(mip_level);
65 u32 m_height = MipHeight(mip_level); 67 u32 m_height = MipHeight(mip_level);
66 m_width = uncompressed ? m_width 68 m_width = uncompressed ? m_width : std::max(1U, (m_width + tile_x - 1) / tile_x);
67 : std::max(1U, (m_width + compression_factor - 1) / compression_factor); 69 m_height = uncompressed ? m_height : std::max(1U, (m_height + tile_y - 1) / tile_y);
68 m_height = uncompressed
69 ? m_height
70 : std::max(1U, (m_height + compression_factor - 1) / compression_factor);
71 m_depth = std::max(1U, m_depth >> mip_level); 70 m_depth = std::max(1U, m_depth >> mip_level);
72 u32 m_block_height = MipBlockHeight(mip_level); 71 u32 m_block_height = MipBlockHeight(mip_level);
73 u32 m_block_depth = MipBlockDepth(mip_level); 72 u32 m_block_depth = MipBlockDepth(mip_level);
@@ -128,6 +127,13 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
128 params.target = SurfaceTarget::Texture2D; 127 params.target = SurfaceTarget::Texture2D;
129 } 128 }
130 break; 129 break;
130 case SurfaceTarget::TextureCubeArray:
131 params.depth = config.tic.Depth() * 6;
132 if (!entry.IsArray()) {
133 ASSERT(params.depth == 6);
134 params.target = SurfaceTarget::TextureCubemap;
135 }
136 break;
131 default: 137 default:
132 LOG_CRITICAL(HW_GPU, "Unknown depth for target={}", static_cast<u32>(params.target)); 138 LOG_CRITICAL(HW_GPU, "Unknown depth for target={}", static_cast<u32>(params.target));
133 UNREACHABLE(); 139 UNREACHABLE();
@@ -305,6 +311,8 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
305 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB 311 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB
306 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB 312 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB
307 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB 313 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB
314 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5
315 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB
308 316
309 // Depth formats 317 // Depth formats
310 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F 318 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
@@ -334,6 +342,8 @@ static GLenum SurfaceTargetToGL(SurfaceTarget target) {
334 return GL_TEXTURE_2D_ARRAY; 342 return GL_TEXTURE_2D_ARRAY;
335 case SurfaceTarget::TextureCubemap: 343 case SurfaceTarget::TextureCubemap:
336 return GL_TEXTURE_CUBE_MAP; 344 return GL_TEXTURE_CUBE_MAP;
345 case SurfaceTarget::TextureCubeArray:
346 return GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
337 } 347 }
338 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target)); 348 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
339 UNREACHABLE(); 349 UNREACHABLE();
@@ -364,15 +374,18 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 d
364 374
365 // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual 375 // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
366 // pixel values. 376 // pixel values.
367 const u32 tile_size{IsFormatBCn(format) ? 4U : 1U}; 377 const u32 tile_size_x{GetDefaultBlockWidth(format)};
378 const u32 tile_size_y{GetDefaultBlockHeight(format)};
368 379
369 if (morton_to_gl) { 380 if (morton_to_gl) {
370 const std::vector<u8> data = Tegra::Texture::UnswizzleTexture( 381 const std::vector<u8> data =
371 addr, tile_size, bytes_per_pixel, stride, height, depth, block_height, block_depth); 382 Tegra::Texture::UnswizzleTexture(addr, tile_size_x, tile_size_y, bytes_per_pixel,
383 stride, height, depth, block_height, block_depth);
372 const std::size_t size_to_copy{std::min(gl_buffer_size, data.size())}; 384 const std::size_t size_to_copy{std::min(gl_buffer_size, data.size())};
373 memcpy(gl_buffer, data.data(), size_to_copy); 385 memcpy(gl_buffer, data.data(), size_to_copy);
374 } else { 386 } else {
375 Tegra::Texture::CopySwizzledData(stride / tile_size, height / tile_size, depth, 387 Tegra::Texture::CopySwizzledData((stride + tile_size_x - 1) / tile_size_x,
388 (height + tile_size_y - 1) / tile_size_y, depth,
376 bytes_per_pixel, bytes_per_pixel, Memory::GetPointer(addr), 389 bytes_per_pixel, bytes_per_pixel, Memory::GetPointer(addr),
377 gl_buffer, false, block_height, block_depth); 390 gl_buffer, false, block_height, block_depth);
378 } 391 }
@@ -440,6 +453,8 @@ static constexpr GLConversionArray morton_to_gl_fns = {
440 MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>, 453 MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>,
441 MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>, 454 MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>,
442 MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>, 455 MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>,
456 MortonCopy<true, PixelFormat::ASTC_2D_5X5>,
457 MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>,
443 MortonCopy<true, PixelFormat::Z32F>, 458 MortonCopy<true, PixelFormat::Z32F>,
444 MortonCopy<true, PixelFormat::Z16>, 459 MortonCopy<true, PixelFormat::Z16>,
445 MortonCopy<true, PixelFormat::Z24S8>, 460 MortonCopy<true, PixelFormat::Z24S8>,
@@ -508,6 +523,8 @@ static constexpr GLConversionArray gl_to_morton_fns = {
508 nullptr, 523 nullptr,
509 nullptr, 524 nullptr,
510 nullptr, 525 nullptr,
526 nullptr,
527 nullptr,
511 MortonCopy<false, PixelFormat::Z32F>, 528 MortonCopy<false, PixelFormat::Z32F>,
512 MortonCopy<false, PixelFormat::Z16>, 529 MortonCopy<false, PixelFormat::Z16>,
513 MortonCopy<false, PixelFormat::Z24S8>, 530 MortonCopy<false, PixelFormat::Z24S8>,
@@ -545,9 +562,11 @@ void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params
545 } 562 }
546} 563}
547 564
565MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64));
548static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, 566static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
549 GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0, 567 GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0,
550 GLenum dst_attachment = 0, std::size_t cubemap_face = 0) { 568 GLenum dst_attachment = 0, std::size_t cubemap_face = 0) {
569 MICROPROFILE_SCOPE(OpenGL_BlitSurface);
551 570
552 const auto& src_params{src_surface->GetSurfaceParams()}; 571 const auto& src_params{src_surface->GetSurfaceParams()};
553 const auto& dst_params{dst_surface->GetSurfaceParams()}; 572 const auto& dst_params{dst_surface->GetSurfaceParams()};
@@ -687,9 +706,11 @@ static void FastCopySurface(const Surface& src_surface, const Surface& dst_surfa
687 0, 0, width, height, 1); 706 0, 0, width, height, 1);
688} 707}
689 708
709MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64));
690static void CopySurface(const Surface& src_surface, const Surface& dst_surface, 710static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
691 GLuint copy_pbo_handle, GLenum src_attachment = 0, 711 GLuint copy_pbo_handle, GLenum src_attachment = 0,
692 GLenum dst_attachment = 0, std::size_t cubemap_face = 0) { 712 GLenum dst_attachment = 0, std::size_t cubemap_face = 0) {
713 MICROPROFILE_SCOPE(OpenGL_CopySurface);
693 ASSERT_MSG(dst_attachment == 0, "Unimplemented"); 714 ASSERT_MSG(dst_attachment == 0, "Unimplemented");
694 715
695 const auto& src_params{src_surface->GetSurfaceParams()}; 716 const auto& src_params{src_surface->GetSurfaceParams()};
@@ -754,6 +775,7 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
754 break; 775 break;
755 case SurfaceTarget::Texture3D: 776 case SurfaceTarget::Texture3D:
756 case SurfaceTarget::Texture2DArray: 777 case SurfaceTarget::Texture2DArray:
778 case SurfaceTarget::TextureCubeArray:
757 glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height, 779 glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height,
758 static_cast<GLsizei>(dst_params.depth), dest_format.format, 780 static_cast<GLsizei>(dst_params.depth), dest_format.format,
759 dest_format.type, nullptr); 781 dest_format.type, nullptr);
@@ -806,6 +828,7 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
806 break; 828 break;
807 case SurfaceTarget::Texture3D: 829 case SurfaceTarget::Texture3D:
808 case SurfaceTarget::Texture2DArray: 830 case SurfaceTarget::Texture2DArray:
831 case SurfaceTarget::TextureCubeArray:
809 glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level, 832 glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level,
810 format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(), 833 format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(),
811 params.depth); 834 params.depth);
@@ -897,21 +920,24 @@ static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
897 * typical desktop GPUs. 920 * typical desktop GPUs.
898 */ 921 */
899static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelFormat pixel_format, 922static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelFormat pixel_format,
900 u32 width, u32 height) { 923 u32 width, u32 height, u32 depth) {
901 switch (pixel_format) { 924 switch (pixel_format) {
902 case PixelFormat::ASTC_2D_4X4: 925 case PixelFormat::ASTC_2D_4X4:
903 case PixelFormat::ASTC_2D_8X8: 926 case PixelFormat::ASTC_2D_8X8:
904 case PixelFormat::ASTC_2D_8X5: 927 case PixelFormat::ASTC_2D_8X5:
905 case PixelFormat::ASTC_2D_5X4: 928 case PixelFormat::ASTC_2D_5X4:
929 case PixelFormat::ASTC_2D_5X5:
906 case PixelFormat::ASTC_2D_4X4_SRGB: 930 case PixelFormat::ASTC_2D_4X4_SRGB:
907 case PixelFormat::ASTC_2D_8X8_SRGB: 931 case PixelFormat::ASTC_2D_8X8_SRGB:
908 case PixelFormat::ASTC_2D_8X5_SRGB: 932 case PixelFormat::ASTC_2D_8X5_SRGB:
909 case PixelFormat::ASTC_2D_5X4_SRGB: { 933 case PixelFormat::ASTC_2D_5X4_SRGB:
934 case PixelFormat::ASTC_2D_5X5_SRGB: {
910 // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC. 935 // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC.
911 u32 block_width{}; 936 u32 block_width{};
912 u32 block_height{}; 937 u32 block_height{};
913 std::tie(block_width, block_height) = GetASTCBlockSize(pixel_format); 938 std::tie(block_width, block_height) = GetASTCBlockSize(pixel_format);
914 data = Tegra::Texture::ASTC::Decompress(data, width, height, block_width, block_height); 939 data =
940 Tegra::Texture::ASTC::Decompress(data, width, height, depth, block_width, block_height);
915 break; 941 break;
916 } 942 }
917 case PixelFormat::S8Z24: 943 case PixelFormat::S8Z24:
@@ -953,7 +979,7 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm
953 } 979 }
954} 980}
955 981
956MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); 982MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64));
957void CachedSurface::LoadGLBuffer() { 983void CachedSurface::LoadGLBuffer() {
958 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); 984 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
959 gl_buffer.resize(params.max_mip_level); 985 gl_buffer.resize(params.max_mip_level);
@@ -971,7 +997,7 @@ void CachedSurface::LoadGLBuffer() {
971 } 997 }
972 for (u32 i = 0; i < params.max_mip_level; i++) 998 for (u32 i = 0; i < params.max_mip_level; i++)
973 ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i), 999 ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i),
974 params.MipHeight(i)); 1000 params.MipHeight(i), params.MipDepth(i));
975} 1001}
976 1002
977MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); 1003MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
@@ -1055,6 +1081,7 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
1055 &gl_buffer[mip_map][buffer_offset]); 1081 &gl_buffer[mip_map][buffer_offset]);
1056 break; 1082 break;
1057 case SurfaceTarget::Texture2DArray: 1083 case SurfaceTarget::Texture2DArray:
1084 case SurfaceTarget::TextureCubeArray:
1058 glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format, 1085 glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
1059 static_cast<GLsizei>(params.MipWidth(mip_map)), 1086 static_cast<GLsizei>(params.MipWidth(mip_map)),
1060 static_cast<GLsizei>(params.MipHeight(mip_map)), 1087 static_cast<GLsizei>(params.MipHeight(mip_map)),
@@ -1104,6 +1131,7 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
1104 tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]); 1131 tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
1105 break; 1132 break;
1106 case SurfaceTarget::Texture2DArray: 1133 case SurfaceTarget::Texture2DArray:
1134 case SurfaceTarget::TextureCubeArray:
1107 glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0, 1135 glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
1108 static_cast<GLsizei>(rect.GetWidth()), 1136 static_cast<GLsizei>(rect.GetWidth()),
1109 static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, 1137 static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
@@ -1133,7 +1161,7 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
1133 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 1161 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1134} 1162}
1135 1163
1136MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); 1164MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64));
1137void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { 1165void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) {
1138 if (params.type == SurfaceType::Fill) 1166 if (params.type == SurfaceType::Fill)
1139 return; 1167 return;
@@ -1306,6 +1334,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1306 break; 1334 break;
1307 case SurfaceTarget::TextureCubemap: 1335 case SurfaceTarget::TextureCubemap:
1308 case SurfaceTarget::Texture3D: 1336 case SurfaceTarget::Texture3D:
1337 case SurfaceTarget::TextureCubeArray:
1309 AccurateCopySurface(old_surface, new_surface); 1338 AccurateCopySurface(old_surface, new_surface);
1310 break; 1339 break;
1311 default: 1340 default:
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index f255f4419..c0b6bc4e6 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -49,6 +49,8 @@ struct SurfaceParams {
49 return "Texture2DArray"; 49 return "Texture2DArray";
50 case SurfaceTarget::TextureCubemap: 50 case SurfaceTarget::TextureCubemap:
51 return "TextureCubemap"; 51 return "TextureCubemap";
52 case SurfaceTarget::TextureCubeArray:
53 return "TextureCubeArray";
52 default: 54 default:
53 LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target)); 55 LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
54 UNREACHABLE(); 56 UNREACHABLE();
@@ -139,7 +141,7 @@ struct SurfaceParams {
139 } 141 }
140 142
141 u32 MipDepth(u32 mip_level) const { 143 u32 MipDepth(u32 mip_level) const {
142 return std::max(1U, depth >> mip_level); 144 return is_layered ? depth : std::max(1U, depth >> mip_level);
143 } 145 }
144 146
145 // Auto block resizing algorithm from: 147 // Auto block resizing algorithm from:
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp
new file mode 100644
index 000000000..161318c5f
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp
@@ -0,0 +1,188 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <utility>
6#include <glad/glad.h>
7#include "common/common_types.h"
8#include "common/microprofile.h"
9#include "video_core/renderer_opengl/gl_resource_manager.h"
10#include "video_core/renderer_opengl/gl_shader_util.h"
11#include "video_core/renderer_opengl/gl_state.h"
12
13MICROPROFILE_DEFINE(OpenGL_ResourceCreation, "OpenGL", "Resource Creation",
14 MP_RGB(128, 128, 192));
15MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion",
16 MP_RGB(128, 128, 192));
17
18namespace OpenGL {
19
20void OGLTexture::Create() {
21 if (handle != 0)
22 return;
23
24 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
25 glGenTextures(1, &handle);
26}
27
28void OGLTexture::Release() {
29 if (handle == 0)
30 return;
31
32 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
33 glDeleteTextures(1, &handle);
34 OpenGLState::GetCurState().UnbindTexture(handle).Apply();
35 handle = 0;
36}
37
38void OGLSampler::Create() {
39 if (handle != 0)
40 return;
41
42 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
43 glGenSamplers(1, &handle);
44}
45
46void OGLSampler::Release() {
47 if (handle == 0)
48 return;
49
50 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
51 glDeleteSamplers(1, &handle);
52 OpenGLState::GetCurState().ResetSampler(handle).Apply();
53 handle = 0;
54}
55
56void OGLShader::Create(const char* source, GLenum type) {
57 if (handle != 0)
58 return;
59 if (source == nullptr)
60 return;
61
62 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
63 handle = GLShader::LoadShader(source, type);
64}
65
66void OGLShader::Release() {
67 if (handle == 0)
68 return;
69
70 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
71 glDeleteShader(handle);
72 handle = 0;
73}
74
75void OGLProgram::CreateFromSource(const char* vert_shader, const char* geo_shader,
76 const char* frag_shader, bool separable_program) {
77 OGLShader vert, geo, frag;
78 if (vert_shader)
79 vert.Create(vert_shader, GL_VERTEX_SHADER);
80 if (geo_shader)
81 geo.Create(geo_shader, GL_GEOMETRY_SHADER);
82 if (frag_shader)
83 frag.Create(frag_shader, GL_FRAGMENT_SHADER);
84
85 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
86 Create(separable_program, vert.handle, geo.handle, frag.handle);
87}
88
89void OGLProgram::Release() {
90 if (handle == 0)
91 return;
92
93 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
94 glDeleteProgram(handle);
95 OpenGLState::GetCurState().ResetProgram(handle).Apply();
96 handle = 0;
97}
98
99void OGLPipeline::Create() {
100 if (handle != 0)
101 return;
102
103 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
104 glGenProgramPipelines(1, &handle);
105}
106
107void OGLPipeline::Release() {
108 if (handle == 0)
109 return;
110
111 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
112 glDeleteProgramPipelines(1, &handle);
113 OpenGLState::GetCurState().ResetPipeline(handle).Apply();
114 handle = 0;
115}
116
117void OGLBuffer::Create() {
118 if (handle != 0)
119 return;
120
121 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
122 glGenBuffers(1, &handle);
123}
124
125void OGLBuffer::Release() {
126 if (handle == 0)
127 return;
128
129 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
130 glDeleteBuffers(1, &handle);
131 OpenGLState::GetCurState().ResetBuffer(handle).Apply();
132 handle = 0;
133}
134
135void OGLSync::Create() {
136 if (handle != 0)
137 return;
138
139 // Don't profile here, this one is expected to happen ingame.
140 handle = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
141}
142
143void OGLSync::Release() {
144 if (handle == 0)
145 return;
146
147 // Don't profile here, this one is expected to happen ingame.
148 glDeleteSync(handle);
149 handle = 0;
150}
151
152void OGLVertexArray::Create() {
153 if (handle != 0)
154 return;
155
156 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
157 glGenVertexArrays(1, &handle);
158}
159
160void OGLVertexArray::Release() {
161 if (handle == 0)
162 return;
163
164 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
165 glDeleteVertexArrays(1, &handle);
166 OpenGLState::GetCurState().ResetVertexArray(handle).Apply();
167 handle = 0;
168}
169
170void OGLFramebuffer::Create() {
171 if (handle != 0)
172 return;
173
174 MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
175 glGenFramebuffers(1, &handle);
176}
177
178void OGLFramebuffer::Release() {
179 if (handle == 0)
180 return;
181
182 MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
183 glDeleteFramebuffers(1, &handle);
184 OpenGLState::GetCurState().ResetFramebuffer(handle).Apply();
185 handle = 0;
186}
187
188} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index 3bc1b83b5..e33f1e973 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -8,7 +8,6 @@
8#include <glad/glad.h> 8#include <glad/glad.h>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "video_core/renderer_opengl/gl_shader_util.h" 10#include "video_core/renderer_opengl/gl_shader_util.h"
11#include "video_core/renderer_opengl/gl_state.h"
12 11
13namespace OpenGL { 12namespace OpenGL {
14 13
@@ -29,20 +28,10 @@ public:
29 } 28 }
30 29
31 /// Creates a new internal OpenGL resource and stores the handle 30 /// Creates a new internal OpenGL resource and stores the handle
32 void Create() { 31 void Create();
33 if (handle != 0)
34 return;
35 glGenTextures(1, &handle);
36 }
37 32
38 /// Deletes the internal OpenGL resource 33 /// Deletes the internal OpenGL resource
39 void Release() { 34 void Release();
40 if (handle == 0)
41 return;
42 glDeleteTextures(1, &handle);
43 OpenGLState::GetCurState().UnbindTexture(handle).Apply();
44 handle = 0;
45 }
46 35
47 GLuint handle = 0; 36 GLuint handle = 0;
48}; 37};
@@ -64,20 +53,10 @@ public:
64 } 53 }
65 54
66 /// Creates a new internal OpenGL resource and stores the handle 55 /// Creates a new internal OpenGL resource and stores the handle
67 void Create() { 56 void Create();
68 if (handle != 0)
69 return;
70 glGenSamplers(1, &handle);
71 }
72 57
73 /// Deletes the internal OpenGL resource 58 /// Deletes the internal OpenGL resource
74 void Release() { 59 void Release();
75 if (handle == 0)
76 return;
77 glDeleteSamplers(1, &handle);
78 OpenGLState::GetCurState().ResetSampler(handle).Apply();
79 handle = 0;
80 }
81 60
82 GLuint handle = 0; 61 GLuint handle = 0;
83}; 62};
@@ -98,20 +77,9 @@ public:
98 return *this; 77 return *this;
99 } 78 }
100 79
101 void Create(const char* source, GLenum type) { 80 void Create(const char* source, GLenum type);
102 if (handle != 0)
103 return;
104 if (source == nullptr)
105 return;
106 handle = GLShader::LoadShader(source, type);
107 }
108 81
109 void Release() { 82 void Release();
110 if (handle == 0)
111 return;
112 glDeleteShader(handle);
113 handle = 0;
114 }
115 83
116 GLuint handle = 0; 84 GLuint handle = 0;
117}; 85};
@@ -141,25 +109,10 @@ public:
141 109
142 /// Creates a new internal OpenGL resource and stores the handle 110 /// Creates a new internal OpenGL resource and stores the handle
143 void CreateFromSource(const char* vert_shader, const char* geo_shader, const char* frag_shader, 111 void CreateFromSource(const char* vert_shader, const char* geo_shader, const char* frag_shader,
144 bool separable_program = false) { 112 bool separable_program = false);
145 OGLShader vert, geo, frag;
146 if (vert_shader)
147 vert.Create(vert_shader, GL_VERTEX_SHADER);
148 if (geo_shader)
149 geo.Create(geo_shader, GL_GEOMETRY_SHADER);
150 if (frag_shader)
151 frag.Create(frag_shader, GL_FRAGMENT_SHADER);
152 Create(separable_program, vert.handle, geo.handle, frag.handle);
153 }
154 113
155 /// Deletes the internal OpenGL resource 114 /// Deletes the internal OpenGL resource
156 void Release() { 115 void Release();
157 if (handle == 0)
158 return;
159 glDeleteProgram(handle);
160 OpenGLState::GetCurState().ResetProgram(handle).Apply();
161 handle = 0;
162 }
163 116
164 GLuint handle = 0; 117 GLuint handle = 0;
165}; 118};
@@ -178,20 +131,10 @@ public:
178 } 131 }
179 132
180 /// Creates a new internal OpenGL resource and stores the handle 133 /// Creates a new internal OpenGL resource and stores the handle
181 void Create() { 134 void Create();
182 if (handle != 0)
183 return;
184 glGenProgramPipelines(1, &handle);
185 }
186 135
187 /// Deletes the internal OpenGL resource 136 /// Deletes the internal OpenGL resource
188 void Release() { 137 void Release();
189 if (handle == 0)
190 return;
191 glDeleteProgramPipelines(1, &handle);
192 OpenGLState::GetCurState().ResetPipeline(handle).Apply();
193 handle = 0;
194 }
195 138
196 GLuint handle = 0; 139 GLuint handle = 0;
197}; 140};
@@ -213,20 +156,10 @@ public:
213 } 156 }
214 157
215 /// Creates a new internal OpenGL resource and stores the handle 158 /// Creates a new internal OpenGL resource and stores the handle
216 void Create() { 159 void Create();
217 if (handle != 0)
218 return;
219 glGenBuffers(1, &handle);
220 }
221 160
222 /// Deletes the internal OpenGL resource 161 /// Deletes the internal OpenGL resource
223 void Release() { 162 void Release();
224 if (handle == 0)
225 return;
226 glDeleteBuffers(1, &handle);
227 OpenGLState::GetCurState().ResetBuffer(handle).Apply();
228 handle = 0;
229 }
230 163
231 GLuint handle = 0; 164 GLuint handle = 0;
232}; 165};
@@ -247,19 +180,10 @@ public:
247 } 180 }
248 181
249 /// Creates a new internal OpenGL resource and stores the handle 182 /// Creates a new internal OpenGL resource and stores the handle
250 void Create() { 183 void Create();
251 if (handle != 0)
252 return;
253 handle = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
254 }
255 184
256 /// Deletes the internal OpenGL resource 185 /// Deletes the internal OpenGL resource
257 void Release() { 186 void Release();
258 if (handle == 0)
259 return;
260 glDeleteSync(handle);
261 handle = 0;
262 }
263 187
264 GLsync handle = 0; 188 GLsync handle = 0;
265}; 189};
@@ -281,20 +205,10 @@ public:
281 } 205 }
282 206
283 /// Creates a new internal OpenGL resource and stores the handle 207 /// Creates a new internal OpenGL resource and stores the handle
284 void Create() { 208 void Create();
285 if (handle != 0)
286 return;
287 glGenVertexArrays(1, &handle);
288 }
289 209
290 /// Deletes the internal OpenGL resource 210 /// Deletes the internal OpenGL resource
291 void Release() { 211 void Release();
292 if (handle == 0)
293 return;
294 glDeleteVertexArrays(1, &handle);
295 OpenGLState::GetCurState().ResetVertexArray(handle).Apply();
296 handle = 0;
297 }
298 212
299 GLuint handle = 0; 213 GLuint handle = 0;
300}; 214};
@@ -316,20 +230,10 @@ public:
316 } 230 }
317 231
318 /// Creates a new internal OpenGL resource and stores the handle 232 /// Creates a new internal OpenGL resource and stores the handle
319 void Create() { 233 void Create();
320 if (handle != 0)
321 return;
322 glGenFramebuffers(1, &handle);
323 }
324 234
325 /// Deletes the internal OpenGL resource 235 /// Deletes the internal OpenGL resource
326 void Release() { 236 void Release();
327 if (handle == 0)
328 return;
329 glDeleteFramebuffers(1, &handle);
330 OpenGLState::GetCurState().ResetFramebuffer(handle).Apply();
331 handle = 0;
332 }
333 237
334 GLuint handle = 0; 238 GLuint handle = 0;
335}; 239};
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index 36fe1f04c..2a069cdd8 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -7,6 +7,7 @@
7#include <glad/glad.h> 7#include <glad/glad.h>
8 8
9#include "video_core/renderer_opengl/gl_resource_manager.h" 9#include "video_core/renderer_opengl/gl_resource_manager.h"
10#include "video_core/renderer_opengl/gl_state.h"
10#include "video_core/renderer_opengl/maxwell_to_gl.h" 11#include "video_core/renderer_opengl/maxwell_to_gl.h"
11 12
12namespace OpenGL::GLShader { 13namespace OpenGL::GLShader {
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index b6b426f34..9517285e5 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -22,17 +22,15 @@ OpenGLState::OpenGLState() {
22 depth.test_enabled = false; 22 depth.test_enabled = false;
23 depth.test_func = GL_LESS; 23 depth.test_func = GL_LESS;
24 depth.write_mask = GL_TRUE; 24 depth.write_mask = GL_TRUE;
25 depth.depth_range_near = 0.0f;
26 depth.depth_range_far = 1.0f;
27 25
28 primitive_restart.enabled = false; 26 primitive_restart.enabled = false;
29 primitive_restart.index = 0; 27 primitive_restart.index = 0;
30 28 for (auto& item : color_mask) {
31 color_mask.red_enabled = GL_TRUE; 29 item.red_enabled = GL_TRUE;
32 color_mask.green_enabled = GL_TRUE; 30 item.green_enabled = GL_TRUE;
33 color_mask.blue_enabled = GL_TRUE; 31 item.blue_enabled = GL_TRUE;
34 color_mask.alpha_enabled = GL_TRUE; 32 item.alpha_enabled = GL_TRUE;
35 33 }
36 stencil.test_enabled = false; 34 stencil.test_enabled = false;
37 auto reset_stencil = [](auto& config) { 35 auto reset_stencil = [](auto& config) {
38 config.test_func = GL_ALWAYS; 36 config.test_func = GL_ALWAYS;
@@ -45,19 +43,33 @@ OpenGLState::OpenGLState() {
45 }; 43 };
46 reset_stencil(stencil.front); 44 reset_stencil(stencil.front);
47 reset_stencil(stencil.back); 45 reset_stencil(stencil.back);
48 46 for (auto& item : viewports) {
49 blend.enabled = true; 47 item.x = 0;
50 blend.rgb_equation = GL_FUNC_ADD; 48 item.y = 0;
51 blend.a_equation = GL_FUNC_ADD; 49 item.width = 0;
52 blend.src_rgb_func = GL_ONE; 50 item.height = 0;
53 blend.dst_rgb_func = GL_ZERO; 51 item.depth_range_near = 0.0f;
54 blend.src_a_func = GL_ONE; 52 item.depth_range_far = 1.0f;
55 blend.dst_a_func = GL_ZERO; 53 }
56 blend.color.red = 0.0f; 54 scissor.enabled = false;
57 blend.color.green = 0.0f; 55 scissor.x = 0;
58 blend.color.blue = 0.0f; 56 scissor.y = 0;
59 blend.color.alpha = 0.0f; 57 scissor.width = 0;
60 58 scissor.height = 0;
59 for (auto& item : blend) {
60 item.enabled = true;
61 item.rgb_equation = GL_FUNC_ADD;
62 item.a_equation = GL_FUNC_ADD;
63 item.src_rgb_func = GL_ONE;
64 item.dst_rgb_func = GL_ZERO;
65 item.src_a_func = GL_ONE;
66 item.dst_a_func = GL_ZERO;
67 }
68 independant_blend.enabled = false;
69 blend_color.red = 0.0f;
70 blend_color.green = 0.0f;
71 blend_color.blue = 0.0f;
72 blend_color.alpha = 0.0f;
61 logic_op.enabled = false; 73 logic_op.enabled = false;
62 logic_op.operation = GL_COPY; 74 logic_op.operation = GL_COPY;
63 75
@@ -73,17 +85,6 @@ OpenGLState::OpenGLState() {
73 draw.shader_program = 0; 85 draw.shader_program = 0;
74 draw.program_pipeline = 0; 86 draw.program_pipeline = 0;
75 87
76 scissor.enabled = false;
77 scissor.x = 0;
78 scissor.y = 0;
79 scissor.width = 0;
80 scissor.height = 0;
81
82 viewport.x = 0;
83 viewport.y = 0;
84 viewport.width = 0;
85 viewport.height = 0;
86
87 clip_distance = {}; 88 clip_distance = {};
88 89
89 point.size = 1; 90 point.size = 1;
@@ -134,6 +135,32 @@ void OpenGLState::ApplyCulling() const {
134 } 135 }
135} 136}
136 137
138void OpenGLState::ApplyColorMask() const {
139 if (GLAD_GL_ARB_viewport_array) {
140 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
141 const auto& updated = color_mask[i];
142 const auto& current = cur_state.color_mask[i];
143 if (updated.red_enabled != current.red_enabled ||
144 updated.green_enabled != current.green_enabled ||
145 updated.blue_enabled != current.blue_enabled ||
146 updated.alpha_enabled != current.alpha_enabled) {
147 glColorMaski(static_cast<GLuint>(i), updated.red_enabled, updated.green_enabled,
148 updated.blue_enabled, updated.alpha_enabled);
149 }
150 }
151 } else {
152 const auto& updated = color_mask[0];
153 const auto& current = cur_state.color_mask[0];
154 if (updated.red_enabled != current.red_enabled ||
155 updated.green_enabled != current.green_enabled ||
156 updated.blue_enabled != current.blue_enabled ||
157 updated.alpha_enabled != current.alpha_enabled) {
158 glColorMask(updated.red_enabled, updated.green_enabled, updated.blue_enabled,
159 updated.alpha_enabled);
160 }
161 }
162}
163
137void OpenGLState::ApplyDepth() const { 164void OpenGLState::ApplyDepth() const {
138 // Depth test 165 // Depth test
139 const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled; 166 const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled;
@@ -152,11 +179,6 @@ void OpenGLState::ApplyDepth() const {
152 if (depth.write_mask != cur_state.depth.write_mask) { 179 if (depth.write_mask != cur_state.depth.write_mask) {
153 glDepthMask(depth.write_mask); 180 glDepthMask(depth.write_mask);
154 } 181 }
155 // Depth range
156 if (depth.depth_range_near != cur_state.depth.depth_range_near ||
157 depth.depth_range_far != cur_state.depth.depth_range_far) {
158 glDepthRange(depth.depth_range_near, depth.depth_range_far);
159 }
160} 182}
161 183
162void OpenGLState::ApplyPrimitiveRestart() const { 184void OpenGLState::ApplyPrimitiveRestart() const {
@@ -208,7 +230,7 @@ void OpenGLState::ApplyStencilTest() const {
208 } 230 }
209} 231}
210 232
211void OpenGLState::ApplyScissorTest() const { 233void OpenGLState::ApplyScissor() const {
212 const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled; 234 const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled;
213 if (scissor_changed) { 235 if (scissor_changed) {
214 if (scissor.enabled) { 236 if (scissor.enabled) {
@@ -217,51 +239,141 @@ void OpenGLState::ApplyScissorTest() const {
217 glDisable(GL_SCISSOR_TEST); 239 glDisable(GL_SCISSOR_TEST);
218 } 240 }
219 } 241 }
220 if (scissor_changed || scissor_changed || scissor.x != cur_state.scissor.x || 242 if (scissor.enabled &&
221 scissor.y != cur_state.scissor.y || scissor.width != cur_state.scissor.width || 243 (scissor_changed || scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y ||
222 scissor.height != cur_state.scissor.height) { 244 scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height)) {
223 glScissor(scissor.x, scissor.y, scissor.width, scissor.height); 245 glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
224 } 246 }
225} 247}
226 248
227void OpenGLState::ApplyBlending() const { 249void OpenGLState::ApplyViewport() const {
228 const bool blend_changed = blend.enabled != cur_state.blend.enabled; 250 if (GLAD_GL_ARB_viewport_array) {
251 for (GLuint i = 0;
252 i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); i++) {
253 const auto& current = cur_state.viewports[i];
254 const auto& updated = viewports[i];
255 if (updated.x != current.x || updated.y != current.y ||
256 updated.width != current.width || updated.height != current.height) {
257 glViewportIndexedf(i, updated.x, updated.y, updated.width, updated.height);
258 }
259 if (updated.depth_range_near != current.depth_range_near ||
260 updated.depth_range_far != current.depth_range_far) {
261 glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far);
262 }
263 }
264 } else {
265 const auto& current = cur_state.viewports[0];
266 const auto& updated = viewports[0];
267 if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
268 updated.height != current.height) {
269 glViewport(updated.x, updated.y, updated.width, updated.height);
270 }
271 if (updated.depth_range_near != current.depth_range_near ||
272 updated.depth_range_far != current.depth_range_far) {
273 glDepthRange(updated.depth_range_near, updated.depth_range_far);
274 }
275 }
276}
277
278void OpenGLState::ApplyGlobalBlending() const {
279 const Blend& current = cur_state.blend[0];
280 const Blend& updated = blend[0];
281 const bool blend_changed = updated.enabled != current.enabled;
229 if (blend_changed) { 282 if (blend_changed) {
230 if (blend.enabled) { 283 if (updated.enabled) {
231 ASSERT(!logic_op.enabled);
232 glEnable(GL_BLEND); 284 glEnable(GL_BLEND);
233 } else { 285 } else {
234 glDisable(GL_BLEND); 286 glDisable(GL_BLEND);
235 } 287 }
236 } 288 }
237 if (blend.enabled) { 289 if (!updated.enabled) {
238 if (blend_changed || blend.color.red != cur_state.blend.color.red || 290 return;
239 blend.color.green != cur_state.blend.color.green || 291 }
240 blend.color.blue != cur_state.blend.color.blue || 292 if (updated.separate_alpha) {
241 blend.color.alpha != cur_state.blend.color.alpha) { 293 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
242 glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha); 294 updated.dst_rgb_func != current.dst_rgb_func ||
295 updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) {
296 glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func,
297 updated.dst_a_func);
243 } 298 }
244 299
245 if (blend_changed || blend.src_rgb_func != cur_state.blend.src_rgb_func || 300 if (blend_changed || updated.rgb_equation != current.rgb_equation ||
246 blend.dst_rgb_func != cur_state.blend.dst_rgb_func || 301 updated.a_equation != current.a_equation) {
247 blend.src_a_func != cur_state.blend.src_a_func || 302 glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
248 blend.dst_a_func != cur_state.blend.dst_a_func) { 303 }
249 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, 304 } else {
250 blend.dst_a_func); 305 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
306 updated.dst_rgb_func != current.dst_rgb_func) {
307 glBlendFunc(updated.src_rgb_func, updated.dst_rgb_func);
251 } 308 }
252 309
253 if (blend_changed || blend.rgb_equation != cur_state.blend.rgb_equation || 310 if (blend_changed || updated.rgb_equation != current.rgb_equation) {
254 blend.a_equation != cur_state.blend.a_equation) { 311 glBlendEquation(updated.rgb_equation);
255 glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
256 } 312 }
257 } 313 }
258} 314}
259 315
316void OpenGLState::ApplyTargetBlending(int target, bool force) const {
317 const Blend& updated = blend[target];
318 const Blend& current = cur_state.blend[target];
319 const bool blend_changed = updated.enabled != current.enabled || force;
320 if (blend_changed) {
321 if (updated.enabled) {
322 glEnablei(GL_BLEND, static_cast<GLuint>(target));
323 } else {
324 glDisablei(GL_BLEND, static_cast<GLuint>(target));
325 }
326 }
327 if (!updated.enabled) {
328 return;
329 }
330 if (updated.separate_alpha) {
331 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
332 updated.dst_rgb_func != current.dst_rgb_func ||
333 updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) {
334 glBlendFuncSeparateiARB(static_cast<GLuint>(target), updated.src_rgb_func,
335 updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
336 }
337
338 if (blend_changed || updated.rgb_equation != current.rgb_equation ||
339 updated.a_equation != current.a_equation) {
340 glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation,
341 updated.a_equation);
342 }
343 } else {
344 if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
345 updated.dst_rgb_func != current.dst_rgb_func) {
346 glBlendFunciARB(static_cast<GLuint>(target), updated.src_rgb_func,
347 updated.dst_rgb_func);
348 }
349
350 if (blend_changed || updated.rgb_equation != current.rgb_equation) {
351 glBlendEquationiARB(static_cast<GLuint>(target), updated.rgb_equation);
352 }
353 }
354}
355
356void OpenGLState::ApplyBlending() const {
357 if (independant_blend.enabled) {
358 for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
359 ApplyTargetBlending(i,
360 independant_blend.enabled != cur_state.independant_blend.enabled);
361 }
362 } else {
363 ApplyGlobalBlending();
364 }
365 if (blend_color.red != cur_state.blend_color.red ||
366 blend_color.green != cur_state.blend_color.green ||
367 blend_color.blue != cur_state.blend_color.blue ||
368 blend_color.alpha != cur_state.blend_color.alpha) {
369 glBlendColor(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha);
370 }
371}
372
260void OpenGLState::ApplyLogicOp() const { 373void OpenGLState::ApplyLogicOp() const {
261 const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled; 374 const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled;
262 if (logic_op_changed) { 375 if (logic_op_changed) {
263 if (logic_op.enabled) { 376 if (logic_op.enabled) {
264 ASSERT(!blend.enabled);
265 glEnable(GL_COLOR_LOGIC_OP); 377 glEnable(GL_COLOR_LOGIC_OP);
266 } else { 378 } else {
267 glDisable(GL_COLOR_LOGIC_OP); 379 glDisable(GL_COLOR_LOGIC_OP);
@@ -348,12 +460,6 @@ void OpenGLState::Apply() const {
348 if (draw.program_pipeline != cur_state.draw.program_pipeline) { 460 if (draw.program_pipeline != cur_state.draw.program_pipeline) {
349 glBindProgramPipeline(draw.program_pipeline); 461 glBindProgramPipeline(draw.program_pipeline);
350 } 462 }
351 // Viewport
352 if (viewport.x != cur_state.viewport.x || viewport.y != cur_state.viewport.y ||
353 viewport.width != cur_state.viewport.width ||
354 viewport.height != cur_state.viewport.height) {
355 glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
356 }
357 // Clip distance 463 // Clip distance
358 for (std::size_t i = 0; i < clip_distance.size(); ++i) { 464 for (std::size_t i = 0; i < clip_distance.size(); ++i) {
359 if (clip_distance[i] != cur_state.clip_distance[i]) { 465 if (clip_distance[i] != cur_state.clip_distance[i]) {
@@ -364,19 +470,13 @@ void OpenGLState::Apply() const {
364 } 470 }
365 } 471 }
366 } 472 }
367 // Color mask
368 if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
369 color_mask.green_enabled != cur_state.color_mask.green_enabled ||
370 color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
371 color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
372 glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled,
373 color_mask.alpha_enabled);
374 }
375 // Point 473 // Point
376 if (point.size != cur_state.point.size) { 474 if (point.size != cur_state.point.size) {
377 glPointSize(point.size); 475 glPointSize(point.size);
378 } 476 }
379 ApplyScissorTest(); 477 ApplyColorMask();
478 ApplyViewport();
479 ApplyScissor();
380 ApplyStencilTest(); 480 ApplyStencilTest();
381 ApplySRgb(); 481 ApplySRgb();
382 ApplyCulling(); 482 ApplyCulling();
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index fe648aff6..b8cf1f637 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -46,11 +46,9 @@ public:
46 } cull; 46 } cull;
47 47
48 struct { 48 struct {
49 bool test_enabled; // GL_DEPTH_TEST 49 bool test_enabled; // GL_DEPTH_TEST
50 GLenum test_func; // GL_DEPTH_FUNC 50 GLenum test_func; // GL_DEPTH_FUNC
51 GLboolean write_mask; // GL_DEPTH_WRITEMASK 51 GLboolean write_mask; // GL_DEPTH_WRITEMASK
52 GLfloat depth_range_near; // GL_DEPTH_RANGE
53 GLfloat depth_range_far; // GL_DEPTH_RANGE
54 } depth; 52 } depth;
55 53
56 struct { 54 struct {
@@ -58,13 +56,14 @@ public:
58 GLuint index; 56 GLuint index;
59 } primitive_restart; // GL_PRIMITIVE_RESTART 57 } primitive_restart; // GL_PRIMITIVE_RESTART
60 58
61 struct { 59 struct ColorMask {
62 GLboolean red_enabled; 60 GLboolean red_enabled;
63 GLboolean green_enabled; 61 GLboolean green_enabled;
64 GLboolean blue_enabled; 62 GLboolean blue_enabled;
65 GLboolean alpha_enabled; 63 GLboolean alpha_enabled;
66 } color_mask; // GL_COLOR_WRITEMASK 64 };
67 65 std::array<ColorMask, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets>
66 color_mask; // GL_COLOR_WRITEMASK
68 struct { 67 struct {
69 bool test_enabled; // GL_STENCIL_TEST 68 bool test_enabled; // GL_STENCIL_TEST
70 struct { 69 struct {
@@ -78,22 +77,28 @@ public:
78 } front, back; 77 } front, back;
79 } stencil; 78 } stencil;
80 79
81 struct { 80 struct Blend {
82 bool enabled; // GL_BLEND 81 bool enabled; // GL_BLEND
82 bool separate_alpha; // Independent blend enabled
83 GLenum rgb_equation; // GL_BLEND_EQUATION_RGB 83 GLenum rgb_equation; // GL_BLEND_EQUATION_RGB
84 GLenum a_equation; // GL_BLEND_EQUATION_ALPHA 84 GLenum a_equation; // GL_BLEND_EQUATION_ALPHA
85 GLenum src_rgb_func; // GL_BLEND_SRC_RGB 85 GLenum src_rgb_func; // GL_BLEND_SRC_RGB
86 GLenum dst_rgb_func; // GL_BLEND_DST_RGB 86 GLenum dst_rgb_func; // GL_BLEND_DST_RGB
87 GLenum src_a_func; // GL_BLEND_SRC_ALPHA 87 GLenum src_a_func; // GL_BLEND_SRC_ALPHA
88 GLenum dst_a_func; // GL_BLEND_DST_ALPHA 88 GLenum dst_a_func; // GL_BLEND_DST_ALPHA
89 };
90 std::array<Blend, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> blend;
89 91
90 struct { 92 struct {
91 GLclampf red; 93 bool enabled;
92 GLclampf green; 94 } independant_blend;
93 GLclampf blue; 95
94 GLclampf alpha; 96 struct {
95 } color; // GL_BLEND_COLOR 97 GLclampf red;
96 } blend; 98 GLclampf green;
99 GLclampf blue;
100 GLclampf alpha;
101 } blend_color; // GL_BLEND_COLOR
97 102
98 struct { 103 struct {
99 bool enabled; // GL_LOGIC_OP_MODE 104 bool enabled; // GL_LOGIC_OP_MODE
@@ -138,6 +143,16 @@ public:
138 GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING 143 GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING
139 } draw; 144 } draw;
140 145
146 struct viewport {
147 GLfloat x;
148 GLfloat y;
149 GLfloat width;
150 GLfloat height;
151 GLfloat depth_range_near; // GL_DEPTH_RANGE
152 GLfloat depth_range_far; // GL_DEPTH_RANGE
153 };
154 std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> viewports;
155
141 struct { 156 struct {
142 bool enabled; // GL_SCISSOR_TEST 157 bool enabled; // GL_SCISSOR_TEST
143 GLint x; 158 GLint x;
@@ -147,13 +162,6 @@ public:
147 } scissor; 162 } scissor;
148 163
149 struct { 164 struct {
150 GLint x;
151 GLint y;
152 GLsizei width;
153 GLsizei height;
154 } viewport;
155
156 struct {
157 float size; // GL_POINT_SIZE 165 float size; // GL_POINT_SIZE
158 } point; 166 } point;
159 167
@@ -191,14 +199,18 @@ private:
191 static bool s_rgb_used; 199 static bool s_rgb_used;
192 void ApplySRgb() const; 200 void ApplySRgb() const;
193 void ApplyCulling() const; 201 void ApplyCulling() const;
202 void ApplyColorMask() const;
194 void ApplyDepth() const; 203 void ApplyDepth() const;
195 void ApplyPrimitiveRestart() const; 204 void ApplyPrimitiveRestart() const;
196 void ApplyStencilTest() const; 205 void ApplyStencilTest() const;
197 void ApplyScissorTest() const; 206 void ApplyViewport() const;
207 void ApplyTargetBlending(int target, bool force) const;
208 void ApplyGlobalBlending() const;
198 void ApplyBlending() const; 209 void ApplyBlending() const;
199 void ApplyLogicOp() const; 210 void ApplyLogicOp() const;
200 void ApplyTextures() const; 211 void ApplyTextures() const;
201 void ApplySamplers() const; 212 void ApplySamplers() const;
213 void ApplyScissor() const;
202}; 214};
203 215
204} // namespace OpenGL 216} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
index e409228cc..b97b895a4 100644
--- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
@@ -6,9 +6,13 @@
6#include <vector> 6#include <vector>
7#include "common/alignment.h" 7#include "common/alignment.h"
8#include "common/assert.h" 8#include "common/assert.h"
9#include "common/microprofile.h"
9#include "video_core/renderer_opengl/gl_state.h" 10#include "video_core/renderer_opengl/gl_state.h"
10#include "video_core/renderer_opengl/gl_stream_buffer.h" 11#include "video_core/renderer_opengl/gl_stream_buffer.h"
11 12
13MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning",
14 MP_RGB(128, 128, 192));
15
12namespace OpenGL { 16namespace OpenGL {
13 17
14OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent) 18OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent)
@@ -75,6 +79,7 @@ std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr a
75 } 79 }
76 80
77 if (invalidate || !persistent) { 81 if (invalidate || !persistent) {
82 MICROPROFILE_SCOPE(OpenGL_StreamBuffer);
78 GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) | 83 GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) |
79 (coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) | 84 (coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) |
80 (invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT); 85 (invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT);
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index d9a97e30b..051ad3964 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -19,6 +19,8 @@ SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_t
19 return SurfaceTarget::Texture3D; 19 return SurfaceTarget::Texture3D;
20 case Tegra::Texture::TextureType::TextureCubemap: 20 case Tegra::Texture::TextureType::TextureCubemap:
21 return SurfaceTarget::TextureCubemap; 21 return SurfaceTarget::TextureCubemap;
22 case Tegra::Texture::TextureType::TextureCubeArray:
23 return SurfaceTarget::TextureCubeArray;
22 case Tegra::Texture::TextureType::Texture1DArray: 24 case Tegra::Texture::TextureType::Texture1DArray:
23 return SurfaceTarget::Texture1DArray; 25 return SurfaceTarget::Texture1DArray;
24 case Tegra::Texture::TextureType::Texture2DArray: 26 case Tegra::Texture::TextureType::Texture2DArray:
@@ -39,6 +41,7 @@ bool SurfaceTargetIsLayered(SurfaceTarget target) {
39 case SurfaceTarget::Texture1DArray: 41 case SurfaceTarget::Texture1DArray:
40 case SurfaceTarget::Texture2DArray: 42 case SurfaceTarget::Texture2DArray:
41 case SurfaceTarget::TextureCubemap: 43 case SurfaceTarget::TextureCubemap:
44 case SurfaceTarget::TextureCubeArray:
42 return true; 45 return true;
43 default: 46 default:
44 LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target)); 47 LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
@@ -297,6 +300,8 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
297 return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4; 300 return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4;
298 case Tegra::Texture::TextureFormat::ASTC_2D_5X4: 301 case Tegra::Texture::TextureFormat::ASTC_2D_5X4:
299 return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4; 302 return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4;
303 case Tegra::Texture::TextureFormat::ASTC_2D_5X5:
304 return is_srgb ? PixelFormat::ASTC_2D_5X5_SRGB : PixelFormat::ASTC_2D_5X5;
300 case Tegra::Texture::TextureFormat::ASTC_2D_8X8: 305 case Tegra::Texture::TextureFormat::ASTC_2D_8X8:
301 return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8; 306 return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8;
302 case Tegra::Texture::TextureFormat::ASTC_2D_8X5: 307 case Tegra::Texture::TextureFormat::ASTC_2D_8X5:
@@ -440,10 +445,12 @@ bool IsPixelFormatASTC(PixelFormat format) {
440 switch (format) { 445 switch (format) {
441 case PixelFormat::ASTC_2D_4X4: 446 case PixelFormat::ASTC_2D_4X4:
442 case PixelFormat::ASTC_2D_5X4: 447 case PixelFormat::ASTC_2D_5X4:
448 case PixelFormat::ASTC_2D_5X5:
443 case PixelFormat::ASTC_2D_8X8: 449 case PixelFormat::ASTC_2D_8X8:
444 case PixelFormat::ASTC_2D_8X5: 450 case PixelFormat::ASTC_2D_8X5:
445 case PixelFormat::ASTC_2D_4X4_SRGB: 451 case PixelFormat::ASTC_2D_4X4_SRGB:
446 case PixelFormat::ASTC_2D_5X4_SRGB: 452 case PixelFormat::ASTC_2D_5X4_SRGB:
453 case PixelFormat::ASTC_2D_5X5_SRGB:
447 case PixelFormat::ASTC_2D_8X8_SRGB: 454 case PixelFormat::ASTC_2D_8X8_SRGB:
448 case PixelFormat::ASTC_2D_8X5_SRGB: 455 case PixelFormat::ASTC_2D_8X5_SRGB:
449 return true; 456 return true;
@@ -453,27 +460,7 @@ bool IsPixelFormatASTC(PixelFormat format) {
453} 460}
454 461
455std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) { 462std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
456 switch (format) { 463 return {GetDefaultBlockWidth(format), GetDefaultBlockHeight(format)};
457 case PixelFormat::ASTC_2D_4X4:
458 return {4, 4};
459 case PixelFormat::ASTC_2D_5X4:
460 return {5, 4};
461 case PixelFormat::ASTC_2D_8X8:
462 return {8, 8};
463 case PixelFormat::ASTC_2D_8X5:
464 return {8, 5};
465 case PixelFormat::ASTC_2D_4X4_SRGB:
466 return {4, 4};
467 case PixelFormat::ASTC_2D_5X4_SRGB:
468 return {5, 4};
469 case PixelFormat::ASTC_2D_8X8_SRGB:
470 return {8, 8};
471 case PixelFormat::ASTC_2D_8X5_SRGB:
472 return {8, 5};
473 default:
474 LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
475 UNREACHABLE();
476 }
477} 464}
478 465
479bool IsFormatBCn(PixelFormat format) { 466bool IsFormatBCn(PixelFormat format) {
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 3232e437f..dfdb8d122 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -72,19 +72,21 @@ enum class PixelFormat {
72 ASTC_2D_8X8_SRGB = 54, 72 ASTC_2D_8X8_SRGB = 54,
73 ASTC_2D_8X5_SRGB = 55, 73 ASTC_2D_8X5_SRGB = 55,
74 ASTC_2D_5X4_SRGB = 56, 74 ASTC_2D_5X4_SRGB = 56,
75 ASTC_2D_5X5 = 57,
76 ASTC_2D_5X5_SRGB = 58,
75 77
76 MaxColorFormat, 78 MaxColorFormat,
77 79
78 // Depth formats 80 // Depth formats
79 Z32F = 57, 81 Z32F = 59,
80 Z16 = 58, 82 Z16 = 60,
81 83
82 MaxDepthFormat, 84 MaxDepthFormat,
83 85
84 // DepthStencil formats 86 // DepthStencil formats
85 Z24S8 = 59, 87 Z24S8 = 61,
86 S8Z24 = 60, 88 S8Z24 = 62,
87 Z32FS8 = 61, 89 Z32FS8 = 63,
88 90
89 MaxDepthStencilFormat, 91 MaxDepthStencilFormat,
90 92
@@ -118,6 +120,7 @@ enum class SurfaceTarget {
118 Texture1DArray, 120 Texture1DArray,
119 Texture2DArray, 121 Texture2DArray,
120 TextureCubemap, 122 TextureCubemap,
123 TextureCubeArray,
121}; 124};
122 125
123/** 126/**
@@ -188,6 +191,8 @@ static constexpr u32 GetCompressionFactor(PixelFormat format) {
188 4, // ASTC_2D_8X8_SRGB 191 4, // ASTC_2D_8X8_SRGB
189 4, // ASTC_2D_8X5_SRGB 192 4, // ASTC_2D_8X5_SRGB
190 4, // ASTC_2D_5X4_SRGB 193 4, // ASTC_2D_5X4_SRGB
194 4, // ASTC_2D_5X5
195 4, // ASTC_2D_5X5_SRGB
191 1, // Z32F 196 1, // Z32F
192 1, // Z16 197 1, // Z16
193 1, // Z24S8 198 1, // Z24S8
@@ -199,6 +204,79 @@ static constexpr u32 GetCompressionFactor(PixelFormat format) {
199 return compression_factor_table[static_cast<std::size_t>(format)]; 204 return compression_factor_table[static_cast<std::size_t>(format)];
200} 205}
201 206
207static constexpr u32 GetDefaultBlockWidth(PixelFormat format) {
208 if (format == PixelFormat::Invalid)
209 return 0;
210 constexpr std::array<u32, MaxPixelFormat> block_width_table = {{
211 1, // ABGR8U
212 1, // ABGR8S
213 1, // ABGR8UI
214 1, // B5G6R5U
215 1, // A2B10G10R10U
216 1, // A1B5G5R5U
217 1, // R8U
218 1, // R8UI
219 1, // RGBA16F
220 1, // RGBA16U
221 1, // RGBA16UI
222 1, // R11FG11FB10F
223 1, // RGBA32UI
224 4, // DXT1
225 4, // DXT23
226 4, // DXT45
227 4, // DXN1
228 4, // DXN2UNORM
229 4, // DXN2SNORM
230 4, // BC7U
231 4, // BC6H_UF16
232 4, // BC6H_SF16
233 4, // ASTC_2D_4X4
234 1, // G8R8U
235 1, // G8R8S
236 1, // BGRA8
237 1, // RGBA32F
238 1, // RG32F
239 1, // R32F
240 1, // R16F
241 1, // R16U
242 1, // R16S
243 1, // R16UI
244 1, // R16I
245 1, // RG16
246 1, // RG16F
247 1, // RG16UI
248 1, // RG16I
249 1, // RG16S
250 1, // RGB32F
251 1, // RGBA8_SRGB
252 1, // RG8U
253 1, // RG8S
254 1, // RG32UI
255 1, // R32UI
256 8, // ASTC_2D_8X8
257 8, // ASTC_2D_8X5
258 5, // ASTC_2D_5X4
259 1, // BGRA8_SRGB
260 4, // DXT1_SRGB
261 4, // DXT23_SRGB
262 4, // DXT45_SRGB
263 4, // BC7U_SRGB
264 4, // ASTC_2D_4X4_SRGB
265 8, // ASTC_2D_8X8_SRGB
266 8, // ASTC_2D_8X5_SRGB
267 5, // ASTC_2D_5X4_SRGB
268 5, // ASTC_2D_5X5
269 5, // ASTC_2D_5X5_SRGB
270 1, // Z32F
271 1, // Z16
272 1, // Z24S8
273 1, // S8Z24
274 1, // Z32FS8
275 }};
276 ASSERT(static_cast<std::size_t>(format) < block_width_table.size());
277 return block_width_table[static_cast<std::size_t>(format)];
278}
279
202static constexpr u32 GetDefaultBlockHeight(PixelFormat format) { 280static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
203 if (format == PixelFormat::Invalid) 281 if (format == PixelFormat::Invalid)
204 return 0; 282 return 0;
@@ -261,6 +339,8 @@ static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
261 8, // ASTC_2D_8X8_SRGB 339 8, // ASTC_2D_8X8_SRGB
262 5, // ASTC_2D_8X5_SRGB 340 5, // ASTC_2D_8X5_SRGB
263 4, // ASTC_2D_5X4_SRGB 341 4, // ASTC_2D_5X4_SRGB
342 5, // ASTC_2D_5X5
343 5, // ASTC_2D_5X5_SRGB
264 1, // Z32F 344 1, // Z32F
265 1, // Z16 345 1, // Z16
266 1, // Z24S8 346 1, // Z24S8
@@ -299,7 +379,7 @@ static constexpr u32 GetFormatBpp(PixelFormat format) {
299 128, // BC7U 379 128, // BC7U
300 128, // BC6H_UF16 380 128, // BC6H_UF16
301 128, // BC6H_SF16 381 128, // BC6H_SF16
302 32, // ASTC_2D_4X4 382 128, // ASTC_2D_4X4
303 16, // G8R8U 383 16, // G8R8U
304 16, // G8R8S 384 16, // G8R8S
305 32, // BGRA8 385 32, // BGRA8
@@ -322,18 +402,20 @@ static constexpr u32 GetFormatBpp(PixelFormat format) {
322 16, // RG8S 402 16, // RG8S
323 64, // RG32UI 403 64, // RG32UI
324 32, // R32UI 404 32, // R32UI
325 16, // ASTC_2D_8X8 405 128, // ASTC_2D_8X8
326 16, // ASTC_2D_8X5 406 128, // ASTC_2D_8X5
327 32, // ASTC_2D_5X4 407 128, // ASTC_2D_5X4
328 32, // BGRA8_SRGB 408 32, // BGRA8_SRGB
329 64, // DXT1_SRGB 409 64, // DXT1_SRGB
330 128, // DXT23_SRGB 410 128, // DXT23_SRGB
331 128, // DXT45_SRGB 411 128, // DXT45_SRGB
332 128, // BC7U 412 128, // BC7U
333 32, // ASTC_2D_4X4_SRGB 413 128, // ASTC_2D_4X4_SRGB
334 16, // ASTC_2D_8X8_SRGB 414 128, // ASTC_2D_8X8_SRGB
335 16, // ASTC_2D_8X5_SRGB 415 128, // ASTC_2D_8X5_SRGB
336 32, // ASTC_2D_5X4_SRGB 416 128, // ASTC_2D_5X4_SRGB
417 128, // ASTC_2D_5X5
418 128, // ASTC_2D_5X5_SRGB
337 32, // Z32F 419 32, // Z32F
338 16, // Z16 420 16, // Z16
339 32, // Z24S8 421 32, // Z24S8
diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp
index b1feacae9..bc50a4876 100644
--- a/src/video_core/textures/astc.cpp
+++ b/src/video_core/textures/astc.cpp
@@ -1598,27 +1598,29 @@ static void DecompressBlock(uint8_t inBuf[16], const uint32_t blockWidth,
1598namespace Tegra::Texture::ASTC { 1598namespace Tegra::Texture::ASTC {
1599 1599
1600std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height, 1600std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height,
1601 uint32_t block_width, uint32_t block_height) { 1601 uint32_t depth, uint32_t block_width, uint32_t block_height) {
1602 uint32_t blockIdx = 0; 1602 uint32_t blockIdx = 0;
1603 std::vector<uint8_t> outData(height * width * 4); 1603 std::vector<uint8_t> outData(height * width * depth * 4);
1604 for (uint32_t j = 0; j < height; j += block_height) { 1604 for (uint32_t k = 0; k < depth; k++) {
1605 for (uint32_t i = 0; i < width; i += block_width) { 1605 for (uint32_t j = 0; j < height; j += block_height) {
1606 for (uint32_t i = 0; i < width; i += block_width) {
1606 1607
1607 uint8_t* blockPtr = data.data() + blockIdx * 16; 1608 uint8_t* blockPtr = data.data() + blockIdx * 16;
1608 1609
1609 // Blocks can be at most 12x12 1610 // Blocks can be at most 12x12
1610 uint32_t uncompData[144]; 1611 uint32_t uncompData[144];
1611 ASTCC::DecompressBlock(blockPtr, block_width, block_height, uncompData); 1612 ASTCC::DecompressBlock(blockPtr, block_width, block_height, uncompData);
1612 1613
1613 uint32_t decompWidth = std::min(block_width, width - i); 1614 uint32_t decompWidth = std::min(block_width, width - i);
1614 uint32_t decompHeight = std::min(block_height, height - j); 1615 uint32_t decompHeight = std::min(block_height, height - j);
1615 1616
1616 uint8_t* outRow = outData.data() + (j * width + i) * 4; 1617 uint8_t* outRow = outData.data() + (j * width + i) * 4;
1617 for (uint32_t jj = 0; jj < decompHeight; jj++) { 1618 for (uint32_t jj = 0; jj < decompHeight; jj++) {
1618 memcpy(outRow + jj * width * 4, uncompData + jj * block_width, decompWidth * 4); 1619 memcpy(outRow + jj * width * 4, uncompData + jj * block_width, decompWidth * 4);
1619 } 1620 }
1620 1621
1621 blockIdx++; 1622 blockIdx++;
1623 }
1622 } 1624 }
1623 } 1625 }
1624 1626
diff --git a/src/video_core/textures/astc.h b/src/video_core/textures/astc.h
index f0d7c0e56..d419dd025 100644
--- a/src/video_core/textures/astc.h
+++ b/src/video_core/textures/astc.h
@@ -10,6 +10,6 @@
10namespace Tegra::Texture::ASTC { 10namespace Tegra::Texture::ASTC {
11 11
12std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height, 12std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height,
13 uint32_t block_width, uint32_t block_height); 13 uint32_t depth, uint32_t block_width, uint32_t block_height);
14 14
15} // namespace Tegra::Texture::ASTC 15} // namespace Tegra::Texture::ASTC
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 550ca856c..3066abf61 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -227,12 +227,14 @@ u32 BytesPerPixel(TextureFormat format) {
227 } 227 }
228} 228}
229 229
230std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, 230std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y,
231 u32 height, u32 depth, u32 block_height, u32 block_depth) { 231 u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
232 u32 block_height, u32 block_depth) {
232 std::vector<u8> unswizzled_data(width * height * depth * bytes_per_pixel); 233 std::vector<u8> unswizzled_data(width * height * depth * bytes_per_pixel);
233 CopySwizzledData(width / tile_size, height / tile_size, depth, bytes_per_pixel, bytes_per_pixel, 234 CopySwizzledData((width + tile_size_x - 1) / tile_size_x,
234 Memory::GetPointer(address), unswizzled_data.data(), true, block_height, 235 (height + tile_size_y - 1) / tile_size_y, depth, bytes_per_pixel,
235 block_depth); 236 bytes_per_pixel, Memory::GetPointer(address), unswizzled_data.data(), true,
237 block_height, block_depth);
236 return unswizzled_data; 238 return unswizzled_data;
237} 239}
238 240
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index b390219e4..ba065510b 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -19,8 +19,8 @@ inline std::size_t GetGOBSize() {
19/** 19/**
20 * Unswizzles a swizzled texture without changing its format. 20 * Unswizzles a swizzled texture without changing its format.
21 */ 21 */
22std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, 22std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y,
23 u32 height, u32 depth, 23 u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
24 u32 block_height = TICEntry::DefaultBlockHeight, 24 u32 block_height = TICEntry::DefaultBlockHeight,
25 u32 block_depth = TICEntry::DefaultBlockHeight); 25 u32 block_depth = TICEntry::DefaultBlockHeight);
26 26
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 9379d9110..f9ca2948e 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -56,6 +56,8 @@ add_executable(yuzu
56 main.h 56 main.h
57 ui_settings.cpp 57 ui_settings.cpp
58 ui_settings.h 58 ui_settings.h
59 util/limitable_input_dialog.cpp
60 util/limitable_input_dialog.h
59 util/spinbox.cpp 61 util/spinbox.cpp
60 util/spinbox.h 62 util/spinbox.h
61 util/util.cpp 63 util/util.cpp
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 1b8aa7de2..b4b4a4a56 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -6,20 +6,20 @@
6#include <QFileDialog> 6#include <QFileDialog>
7#include <QGraphicsItem> 7#include <QGraphicsItem>
8#include <QGraphicsScene> 8#include <QGraphicsScene>
9#include <QInputDialog> 9#include <QHeaderView>
10#include <QMessageBox> 10#include <QMessageBox>
11#include <QStandardItemModel> 11#include <QStandardItemModel>
12#include <QTreeView> 12#include <QTreeView>
13#include <QVBoxLayout> 13#include <QVBoxLayout>
14#include "common/common_paths.h" 14#include "common/assert.h"
15#include "common/logging/backend.h" 15#include "common/file_util.h"
16#include "common/string_util.h" 16#include "common/string_util.h"
17#include "core/core.h" 17#include "core/core.h"
18#include "core/hle/service/acc/profile_manager.h" 18#include "core/hle/service/acc/profile_manager.h"
19#include "core/settings.h" 19#include "core/settings.h"
20#include "ui_configure_system.h" 20#include "ui_configure_system.h"
21#include "yuzu/configuration/configure_system.h" 21#include "yuzu/configuration/configure_system.h"
22#include "yuzu/main.h" 22#include "yuzu/util/limitable_input_dialog.h"
23 23
24namespace { 24namespace {
25constexpr std::array<int, 12> days_in_month = {{ 25constexpr std::array<int, 12> days_in_month = {{
@@ -83,6 +83,12 @@ QPixmap GetIcon(Service::Account::UUID uuid) {
83 83
84 return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); 84 return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
85} 85}
86
87QString GetProfileUsernameFromUser(QWidget* parent, const QString& description_text) {
88 return LimitableInputDialog::GetText(parent, ConfigureSystem::tr("Enter Username"),
89 description_text, 1,
90 static_cast<int>(Service::Account::profile_username_size));
91}
86} // Anonymous namespace 92} // Anonymous namespace
87 93
88ConfigureSystem::ConfigureSystem(QWidget* parent) 94ConfigureSystem::ConfigureSystem(QWidget* parent)
@@ -244,15 +250,13 @@ void ConfigureSystem::SelectUser(const QModelIndex& index) {
244} 250}
245 251
246void ConfigureSystem::AddUser() { 252void ConfigureSystem::AddUser() {
247 const auto uuid = Service::Account::UUID::Generate();
248
249 bool ok = false;
250 const auto username = 253 const auto username =
251 QInputDialog::getText(this, tr("Enter Username"), tr("Enter a username for the new user:"), 254 GetProfileUsernameFromUser(this, tr("Enter a username for the new user:"));
252 QLineEdit::Normal, QString(), &ok); 255 if (username.isEmpty()) {
253 if (!ok)
254 return; 256 return;
257 }
255 258
259 const auto uuid = Service::Account::UUID::Generate();
256 profile_manager->CreateNewUser(uuid, username.toStdString()); 260 profile_manager->CreateNewUser(uuid, username.toStdString());
257 261
258 item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)}); 262 item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)});
@@ -267,23 +271,14 @@ void ConfigureSystem::RenameUser() {
267 if (!profile_manager->GetProfileBase(*uuid, profile)) 271 if (!profile_manager->GetProfileBase(*uuid, profile))
268 return; 272 return;
269 273
270 bool ok = false; 274 const auto new_username = GetProfileUsernameFromUser(this, tr("Enter a new username:"));
271 const auto old_username = GetAccountUsername(*profile_manager, *uuid); 275 if (new_username.isEmpty()) {
272 const auto new_username =
273 QInputDialog::getText(this, tr("Enter Username"), tr("Enter a new username:"),
274 QLineEdit::Normal, old_username, &ok);
275
276 if (!ok)
277 return; 276 return;
277 }
278 278
279 std::fill(profile.username.begin(), profile.username.end(), '\0');
280 const auto username_std = new_username.toStdString(); 279 const auto username_std = new_username.toStdString();
281 if (username_std.size() > profile.username.size()) { 280 std::fill(profile.username.begin(), profile.username.end(), '\0');
282 std::copy_n(username_std.begin(), std::min(profile.username.size(), username_std.size()), 281 std::copy(username_std.begin(), username_std.end(), profile.username.begin());
283 profile.username.begin());
284 } else {
285 std::copy(username_std.begin(), username_std.end(), profile.username.begin());
286 }
287 282
288 profile_manager->SetProfileBase(*uuid, profile); 283 profile_manager->SetProfileBase(*uuid, profile);
289 284
diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp
index 0adbab27d..707747422 100644
--- a/src/yuzu/debugger/graphics/graphics_surface.cpp
+++ b/src/yuzu/debugger/graphics/graphics_surface.cpp
@@ -386,9 +386,9 @@ void GraphicsSurfaceWidget::OnUpdate() {
386 386
387 // TODO(bunnei): Will not work with BCn formats that swizzle 4x4 tiles. 387 // TODO(bunnei): Will not work with BCn formats that swizzle 4x4 tiles.
388 // Needs to be fixed if we plan to use this feature more, otherwise we may remove it. 388 // Needs to be fixed if we plan to use this feature more, otherwise we may remove it.
389 auto unswizzled_data = 389 auto unswizzled_data = Tegra::Texture::UnswizzleTexture(
390 Tegra::Texture::UnswizzleTexture(*address, 1, Tegra::Texture::BytesPerPixel(surface_format), 390 *address, 1, 1, Tegra::Texture::BytesPerPixel(surface_format), surface_width,
391 surface_width, surface_height, 1U); 391 surface_height, 1U);
392 392
393 auto texture_data = Tegra::Texture::DecodeTexture(unswizzled_data, surface_format, 393 auto texture_data = Tegra::Texture::DecodeTexture(unswizzled_data, surface_format,
394 surface_width, surface_height); 394 surface_width, surface_height);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index c5a56cbfd..74a44be37 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -142,6 +142,9 @@ static void InitializeLogging() {
142 const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir); 142 const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
143 FileUtil::CreateFullPath(log_dir); 143 FileUtil::CreateFullPath(log_dir);
144 Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE)); 144 Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
145#ifdef _WIN32
146 Log::AddBackend(std::make_unique<Log::DebuggerBackend>());
147#endif
145} 148}
146 149
147GMainWindow::GMainWindow() 150GMainWindow::GMainWindow()
@@ -454,6 +457,7 @@ void GMainWindow::ConnectMenuEvents() {
454 connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); 457 connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
455 458
456 // Help 459 // Help
460 connect(ui.action_Open_yuzu_Folder, &QAction::triggered, this, &GMainWindow::OnOpenYuzuFolder);
457 connect(ui.action_Rederive, &QAction::triggered, this, 461 connect(ui.action_Rederive, &QAction::triggered, this,
458 std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning)); 462 std::bind(&GMainWindow::OnReinitializeKeys, this, ReinitializeKeyBehavior::Warning));
459 connect(ui.action_About, &QAction::triggered, this, &GMainWindow::OnAbout); 463 connect(ui.action_About, &QAction::triggered, this, &GMainWindow::OnAbout);
@@ -1374,6 +1378,11 @@ void GMainWindow::OnLoadAmiibo() {
1374 } 1378 }
1375} 1379}
1376 1380
1381void GMainWindow::OnOpenYuzuFolder() {
1382 QDesktopServices::openUrl(QUrl::fromLocalFile(
1383 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::UserDir))));
1384}
1385
1377void GMainWindow::OnAbout() { 1386void GMainWindow::OnAbout() {
1378 AboutDialog aboutDialog(this); 1387 AboutDialog aboutDialog(this);
1379 aboutDialog.exec(); 1388 aboutDialog.exec();
@@ -1532,7 +1541,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
1532 "derivation. It will be attempted but may not complete.<br><br>") + 1541 "derivation. It will be attempted but may not complete.<br><br>") +
1533 errors + 1542 errors +
1534 tr("<br><br>You can get all of these and dump all of your games easily by " 1543 tr("<br><br>You can get all of these and dump all of your games easily by "
1535 "following <a href='https://yuzu-emu.org/help/quickstart/quickstart/'>the " 1544 "following <a href='https://yuzu-emu.org/help/quickstart/'>the "
1536 "quickstart guide</a>. Alternatively, you can use another method of dumping " 1545 "quickstart guide</a>. Alternatively, you can use another method of dumping "
1537 "to obtain all of your keys.")); 1546 "to obtain all of your keys."));
1538 } 1547 }
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index af637d89e..929250e8c 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -167,6 +167,7 @@ private slots:
167 void OnMenuRecentFile(); 167 void OnMenuRecentFile();
168 void OnConfigure(); 168 void OnConfigure();
169 void OnLoadAmiibo(); 169 void OnLoadAmiibo();
170 void OnOpenYuzuFolder();
170 void OnAbout(); 171 void OnAbout();
171 void OnToggleFilterBar(); 172 void OnToggleFilterBar();
172 void OnDisplayTitleBars(bool); 173 void OnDisplayTitleBars(bool);
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 48d099591..28cf269e7 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -110,6 +110,7 @@
110 <string>&amp;Help</string> 110 <string>&amp;Help</string>
111 </property> 111 </property>
112 <addaction name="action_Report_Compatibility"/> 112 <addaction name="action_Report_Compatibility"/>
113 <addaction name="action_Open_yuzu_Folder" />
113 <addaction name="separator"/> 114 <addaction name="separator"/>
114 <addaction name="action_About"/> 115 <addaction name="action_About"/>
115 </widget> 116 </widget>
@@ -277,6 +278,11 @@
277 <bool>false</bool> 278 <bool>false</bool>
278 </property> 279 </property>
279 </action> 280 </action>
281 <action name="action_Open_yuzu_Folder">
282 <property name="text">
283 <string>Open yuzu Folder</string>
284 </property>
285 </action>
280 </widget> 286 </widget>
281 <resources/> 287 <resources/>
282 <connections/> 288 <connections/>
diff --git a/src/yuzu/util/limitable_input_dialog.cpp b/src/yuzu/util/limitable_input_dialog.cpp
new file mode 100644
index 000000000..edd78e579
--- /dev/null
+++ b/src/yuzu/util/limitable_input_dialog.cpp
@@ -0,0 +1,59 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QDialogButtonBox>
6#include <QLabel>
7#include <QLineEdit>
8#include <QPushButton>
9#include <QVBoxLayout>
10#include "yuzu/util/limitable_input_dialog.h"
11
12LimitableInputDialog::LimitableInputDialog(QWidget* parent) : QDialog{parent} {
13 CreateUI();
14 ConnectEvents();
15}
16
17LimitableInputDialog::~LimitableInputDialog() = default;
18
19void LimitableInputDialog::CreateUI() {
20 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
21
22 text_label = new QLabel(this);
23 text_entry = new QLineEdit(this);
24 buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
25
26 auto* const layout = new QVBoxLayout;
27 layout->addWidget(text_label);
28 layout->addWidget(text_entry);
29 layout->addWidget(buttons);
30
31 setLayout(layout);
32}
33
34void LimitableInputDialog::ConnectEvents() {
35 connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
36 connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
37}
38
39QString LimitableInputDialog::GetText(QWidget* parent, const QString& title, const QString& text,
40 int min_character_limit, int max_character_limit) {
41 Q_ASSERT(min_character_limit <= max_character_limit);
42
43 LimitableInputDialog dialog{parent};
44 dialog.setWindowTitle(title);
45 dialog.text_label->setText(text);
46 dialog.text_entry->setMaxLength(max_character_limit);
47
48 auto* const ok_button = dialog.buttons->button(QDialogButtonBox::Ok);
49 ok_button->setEnabled(false);
50 connect(dialog.text_entry, &QLineEdit::textEdited, [&](const QString& new_text) {
51 ok_button->setEnabled(new_text.length() >= min_character_limit);
52 });
53
54 if (dialog.exec() != QDialog::Accepted) {
55 return {};
56 }
57
58 return dialog.text_entry->text();
59}
diff --git a/src/yuzu/util/limitable_input_dialog.h b/src/yuzu/util/limitable_input_dialog.h
new file mode 100644
index 000000000..164ad7301
--- /dev/null
+++ b/src/yuzu/util/limitable_input_dialog.h
@@ -0,0 +1,31 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QDialog>
8
9class QDialogButtonBox;
10class QLabel;
11class QLineEdit;
12
13/// A QDialog that functions similarly to QInputDialog, however, it allows
14/// restricting the minimum and total number of characters that can be entered.
15class LimitableInputDialog final : public QDialog {
16 Q_OBJECT
17public:
18 explicit LimitableInputDialog(QWidget* parent = nullptr);
19 ~LimitableInputDialog() override;
20
21 static QString GetText(QWidget* parent, const QString& title, const QString& text,
22 int min_character_limit, int max_character_limit);
23
24private:
25 void CreateUI();
26 void ConnectEvents();
27
28 QLabel* text_label;
29 QLineEdit* text_entry;
30 QDialogButtonBox* buttons;
31};
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index c8b93b85b..806127b12 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -76,6 +76,9 @@ static void InitializeLogging() {
76 const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir); 76 const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
77 FileUtil::CreateFullPath(log_dir); 77 FileUtil::CreateFullPath(log_dir);
78 Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE)); 78 Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
79#ifdef _WIN32
80 Log::AddBackend(std::make_unique<Log::DebuggerBackend>());
81#endif
79} 82}
80 83
81/// Application entry point 84/// Application entry point