diff options
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 | ||
| 107 | MICROPROFILE_DEFINE(AudioOutput, "Audio", "ReleaseActiveBuffer", MP_RGB(100, 100, 255)); | ||
| 108 | |||
| 109 | void Stream::ReleaseActiveBuffer() { | 106 | void 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 | ||
| 149 | void 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 | */ | ||
| 109 | class DebuggerBackend : public Backend { | ||
| 110 | public: | ||
| 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 | |||
| 106 | void AddBackend(std::unique_ptr<Backend> backend); | 120 | void AddBackend(std::unique_ptr<Backend> backend); |
| 107 | 121 | ||
| 108 | void RemoveBackend(std::string_view backend_name); | 122 | void 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 | }; |
| 58 | static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); | 58 | static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); |
| 59 | 59 | ||
| 60 | using ProfileUsername = std::array<u8, 0x20>; | 60 | constexpr std::size_t profile_username_size = 32; |
| 61 | using ProfileUsername = std::array<u8, profile_username_size>; | ||
| 61 | using ProfileData = std::array<u8, MAX_DATA>; | 62 | using ProfileData = std::array<u8, MAX_DATA>; |
| 62 | using UserIDArray = std::array<UUID, MAX_USERS>; | 63 | using 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 | ||
| 429 | Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const { | 429 | Kernel::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 | ||
| 42 | void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { | 58 | void 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); | |||
| 1075 | ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); | 1096 | ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); |
| 1076 | ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); | 1097 | ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); |
| 1077 | ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); | 1098 | ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); |
| 1099 | ASSERT_REG_POSITION(color_mask_common, 0x3E4); | ||
| 1078 | ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); | 1100 | ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); |
| 1079 | ASSERT_REG_POSITION(zeta, 0x3F8); | 1101 | ASSERT_REG_POSITION(zeta, 0x3F8); |
| 1080 | ASSERT_REG_POSITION(vertex_attrib_format, 0x458); | 1102 | ASSERT_REG_POSITION(vertex_attrib_format, 0x458); |
| @@ -1087,6 +1109,10 @@ ASSERT_REG_POSITION(depth_write_enabled, 0x4BA); | |||
| 1087 | ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB); | 1109 | ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB); |
| 1088 | ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2); | 1110 | ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2); |
| 1089 | ASSERT_REG_POSITION(depth_test_func, 0x4C3); | 1111 | ASSERT_REG_POSITION(depth_test_func, 0x4C3); |
| 1112 | ASSERT_REG_POSITION(alpha_test_ref, 0x4C4); | ||
| 1113 | ASSERT_REG_POSITION(alpha_test_func, 0x4C5); | ||
| 1114 | ASSERT_REG_POSITION(draw_tfb_stride, 0x4C6); | ||
| 1115 | ASSERT_REG_POSITION(blend_color, 0x4C7); | ||
| 1090 | ASSERT_REG_POSITION(blend, 0x4CF); | 1116 | ASSERT_REG_POSITION(blend, 0x4CF); |
| 1091 | ASSERT_REG_POSITION(stencil_enable, 0x4E0); | 1117 | ASSERT_REG_POSITION(stencil_enable, 0x4E0); |
| 1092 | ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1); | 1118 | ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1); |
| @@ -1117,6 +1143,7 @@ ASSERT_REG_POSITION(instanced_arrays, 0x620); | |||
| 1117 | ASSERT_REG_POSITION(cull, 0x646); | 1143 | ASSERT_REG_POSITION(cull, 0x646); |
| 1118 | ASSERT_REG_POSITION(logic_op, 0x671); | 1144 | ASSERT_REG_POSITION(logic_op, 0x671); |
| 1119 | ASSERT_REG_POSITION(clear_buffers, 0x674); | 1145 | ASSERT_REG_POSITION(clear_buffers, 0x674); |
| 1146 | ASSERT_REG_POSITION(color_mask, 0x680); | ||
| 1120 | ASSERT_REG_POSITION(query, 0x6C0); | 1147 | ASSERT_REG_POSITION(query, 0x6C0); |
| 1121 | ASSERT_REG_POSITION(vertex_array[0], 0x700); | 1148 | ASSERT_REG_POSITION(vertex_array[0], 0x700); |
| 1122 | ASSERT_REG_POSITION(independent_blend, 0x780); | 1149 | ASSERT_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 | ||
| 900 | void RasterizerOpenGL::SyncViewport() { | 899 | void 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 | ||
| 910 | void RasterizerOpenGL::SyncClipEnabled() { | 913 | void 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 | ||
| 949 | void 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 | |||
| 956 | void RasterizerOpenGL::SyncDepthTestState() { | 952 | void 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 | ||
| 996 | void RasterizerOpenGL::SyncBlendState() { | 992 | void 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. | 1004 | void 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 | ||
| 1018 | void RasterizerOpenGL::SyncLogicOpState() { | 1048 | void RasterizerOpenGL::SyncLogicOpState() { |
| @@ -1031,19 +1061,19 @@ void RasterizerOpenGL::SyncLogicOpState() { | |||
| 1031 | } | 1061 | } |
| 1032 | 1062 | ||
| 1033 | void RasterizerOpenGL::SyncScissorTest() { | 1063 | void 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 | ||
| 1049 | void RasterizerOpenGL::SyncTransformFeedback() { | 1079 | void 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 | ||
| 59 | std::size_t SurfaceParams::InnerMipmapMemorySize(u32 mip_level, bool force_gl, bool layer_only, | 60 | std::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 | ||
| 565 | MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64)); | ||
| 548 | static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, | 566 | static 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 | ||
| 709 | MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64)); | ||
| 690 | static void CopySurface(const Surface& src_surface, const Surface& dst_surface, | 710 | static 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 | */ |
| 899 | static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelFormat pixel_format, | 922 | static 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 | ||
| 956 | MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); | 982 | MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64)); |
| 957 | void CachedSurface::LoadGLBuffer() { | 983 | void 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 | ||
| 977 | MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); | 1003 | MICROPROFILE_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 | ||
| 1136 | MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); | 1164 | MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64)); |
| 1137 | void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { | 1165 | void 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 | |||
| 13 | MICROPROFILE_DEFINE(OpenGL_ResourceCreation, "OpenGL", "Resource Creation", | ||
| 14 | MP_RGB(128, 128, 192)); | ||
| 15 | MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", | ||
| 16 | MP_RGB(128, 128, 192)); | ||
| 17 | |||
| 18 | namespace OpenGL { | ||
| 19 | |||
| 20 | void OGLTexture::Create() { | ||
| 21 | if (handle != 0) | ||
| 22 | return; | ||
| 23 | |||
| 24 | MICROPROFILE_SCOPE(OpenGL_ResourceCreation); | ||
| 25 | glGenTextures(1, &handle); | ||
| 26 | } | ||
| 27 | |||
| 28 | void 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 | |||
| 38 | void OGLSampler::Create() { | ||
| 39 | if (handle != 0) | ||
| 40 | return; | ||
| 41 | |||
| 42 | MICROPROFILE_SCOPE(OpenGL_ResourceCreation); | ||
| 43 | glGenSamplers(1, &handle); | ||
| 44 | } | ||
| 45 | |||
| 46 | void 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 | |||
| 56 | void 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 | |||
| 66 | void OGLShader::Release() { | ||
| 67 | if (handle == 0) | ||
| 68 | return; | ||
| 69 | |||
| 70 | MICROPROFILE_SCOPE(OpenGL_ResourceDeletion); | ||
| 71 | glDeleteShader(handle); | ||
| 72 | handle = 0; | ||
| 73 | } | ||
| 74 | |||
| 75 | void 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 | |||
| 89 | void 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 | |||
| 99 | void OGLPipeline::Create() { | ||
| 100 | if (handle != 0) | ||
| 101 | return; | ||
| 102 | |||
| 103 | MICROPROFILE_SCOPE(OpenGL_ResourceCreation); | ||
| 104 | glGenProgramPipelines(1, &handle); | ||
| 105 | } | ||
| 106 | |||
| 107 | void 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 | |||
| 117 | void OGLBuffer::Create() { | ||
| 118 | if (handle != 0) | ||
| 119 | return; | ||
| 120 | |||
| 121 | MICROPROFILE_SCOPE(OpenGL_ResourceCreation); | ||
| 122 | glGenBuffers(1, &handle); | ||
| 123 | } | ||
| 124 | |||
| 125 | void 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 | |||
| 135 | void 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 | |||
| 143 | void 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 | |||
| 152 | void OGLVertexArray::Create() { | ||
| 153 | if (handle != 0) | ||
| 154 | return; | ||
| 155 | |||
| 156 | MICROPROFILE_SCOPE(OpenGL_ResourceCreation); | ||
| 157 | glGenVertexArrays(1, &handle); | ||
| 158 | } | ||
| 159 | |||
| 160 | void 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 | |||
| 170 | void OGLFramebuffer::Create() { | ||
| 171 | if (handle != 0) | ||
| 172 | return; | ||
| 173 | |||
| 174 | MICROPROFILE_SCOPE(OpenGL_ResourceCreation); | ||
| 175 | glGenFramebuffers(1, &handle); | ||
| 176 | } | ||
| 177 | |||
| 178 | void 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 | ||
| 13 | namespace OpenGL { | 12 | namespace 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 | ||
| 12 | namespace OpenGL::GLShader { | 13 | namespace 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 | ||
| 138 | void 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 | |||
| 137 | void OpenGLState::ApplyDepth() const { | 164 | void 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 | ||
| 162 | void OpenGLState::ApplyPrimitiveRestart() const { | 184 | void OpenGLState::ApplyPrimitiveRestart() const { |
| @@ -208,7 +230,7 @@ void OpenGLState::ApplyStencilTest() const { | |||
| 208 | } | 230 | } |
| 209 | } | 231 | } |
| 210 | 232 | ||
| 211 | void OpenGLState::ApplyScissorTest() const { | 233 | void 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 | ||
| 227 | void OpenGLState::ApplyBlending() const { | 249 | void 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 | |||
| 278 | void 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 | ||
| 316 | void 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 | |||
| 356 | void 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 | |||
| 260 | void OpenGLState::ApplyLogicOp() const { | 373 | void 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 | ||
| 13 | MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning", | ||
| 14 | MP_RGB(128, 128, 192)); | ||
| 15 | |||
| 12 | namespace OpenGL { | 16 | namespace OpenGL { |
| 13 | 17 | ||
| 14 | OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent) | 18 | OGLStreamBuffer::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 | ||
| 455 | std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) { | 462 | std::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 | ||
| 479 | bool IsFormatBCn(PixelFormat format) { | 466 | bool 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 | ||
| 207 | static 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 | |||
| 202 | static constexpr u32 GetDefaultBlockHeight(PixelFormat format) { | 280 | static 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, | |||
| 1598 | namespace Tegra::Texture::ASTC { | 1598 | namespace Tegra::Texture::ASTC { |
| 1599 | 1599 | ||
| 1600 | std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height, | 1600 | std::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 @@ | |||
| 10 | namespace Tegra::Texture::ASTC { | 10 | namespace Tegra::Texture::ASTC { |
| 11 | 11 | ||
| 12 | std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height, | 12 | std::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 | ||
| 230 | std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, | 230 | std::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 | */ |
| 22 | std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, | 22 | std::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 | ||
| 24 | namespace { | 24 | namespace { |
| 25 | constexpr std::array<int, 12> days_in_month = {{ | 25 | constexpr 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 | |||
| 87 | QString 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 | ||
| 88 | ConfigureSystem::ConfigureSystem(QWidget* parent) | 94 | ConfigureSystem::ConfigureSystem(QWidget* parent) |
| @@ -244,15 +250,13 @@ void ConfigureSystem::SelectUser(const QModelIndex& index) { | |||
| 244 | } | 250 | } |
| 245 | 251 | ||
| 246 | void ConfigureSystem::AddUser() { | 252 | void 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 | ||
| 147 | GMainWindow::GMainWindow() | 150 | GMainWindow::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 | ||
| 1381 | void GMainWindow::OnOpenYuzuFolder() { | ||
| 1382 | QDesktopServices::openUrl(QUrl::fromLocalFile( | ||
| 1383 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::UserDir)))); | ||
| 1384 | } | ||
| 1385 | |||
| 1377 | void GMainWindow::OnAbout() { | 1386 | void 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>&Help</string> | 110 | <string>&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 | |||
| 12 | LimitableInputDialog::LimitableInputDialog(QWidget* parent) : QDialog{parent} { | ||
| 13 | CreateUI(); | ||
| 14 | ConnectEvents(); | ||
| 15 | } | ||
| 16 | |||
| 17 | LimitableInputDialog::~LimitableInputDialog() = default; | ||
| 18 | |||
| 19 | void 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 | |||
| 34 | void LimitableInputDialog::ConnectEvents() { | ||
| 35 | connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); | ||
| 36 | connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); | ||
| 37 | } | ||
| 38 | |||
| 39 | QString 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 | |||
| 9 | class QDialogButtonBox; | ||
| 10 | class QLabel; | ||
| 11 | class 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. | ||
| 15 | class LimitableInputDialog final : public QDialog { | ||
| 16 | Q_OBJECT | ||
| 17 | public: | ||
| 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 | |||
| 24 | private: | ||
| 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 |