diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio_core/cubeb_sink.cpp | 3 | ||||
| -rw-r--r-- | src/core/crypto/key_manager.cpp | 2 | ||||
| -rw-r--r-- | src/core/file_sys/patch_manager.cpp | 13 | ||||
| -rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.cpp | 28 | ||||
| -rw-r--r-- | src/core/loader/nsp.cpp | 37 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 17 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 21 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 95 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.h | 140 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.cpp | 28 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 19 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 14 | ||||
| -rw-r--r-- | src/video_core/textures/texture.h | 5 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_system.cpp | 121 |
15 files changed, 425 insertions, 121 deletions
diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp index 392039688..d31a1c844 100644 --- a/src/audio_core/cubeb_sink.cpp +++ b/src/audio_core/cubeb_sink.cpp | |||
| @@ -121,7 +121,8 @@ CubebSink::CubebSink(std::string target_device_name) { | |||
| 121 | const auto collection_end{collection.device + collection.count}; | 121 | const auto collection_end{collection.device + collection.count}; |
| 122 | const auto device{ | 122 | const auto device{ |
| 123 | std::find_if(collection.device, collection_end, [&](const cubeb_device_info& info) { | 123 | std::find_if(collection.device, collection_end, [&](const cubeb_device_info& info) { |
| 124 | return target_device_name == info.friendly_name; | 124 | return info.friendly_name != nullptr && |
| 125 | target_device_name == info.friendly_name; | ||
| 125 | })}; | 126 | })}; |
| 126 | if (device != collection_end) { | 127 | if (device != collection_end) { |
| 127 | output_device = device->devid; | 128 | output_device = device->devid; |
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index fefc3c747..89ae79eb3 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -395,7 +395,7 @@ static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_ | |||
| 395 | if (base.size() < begin + length) | 395 | if (base.size() < begin + length) |
| 396 | return false; | 396 | return false; |
| 397 | return std::all_of(base.begin() + begin, base.begin() + begin + length, | 397 | return std::all_of(base.begin() + begin, base.begin() + begin + length, |
| 398 | [](u8 c) { return std::isdigit(c); }); | 398 | [](u8 c) { return std::isxdigit(c); }); |
| 399 | } | 399 | } |
| 400 | 400 | ||
| 401 | void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { | 401 | void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { |
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 1f4928562..cb457b987 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp | |||
| @@ -61,13 +61,12 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { | |||
| 61 | // Game Updates | 61 | // Game Updates |
| 62 | const auto update_tid = GetUpdateTitleID(title_id); | 62 | const auto update_tid = GetUpdateTitleID(title_id); |
| 63 | const auto update = installed->GetEntry(update_tid, ContentRecordType::Program); | 63 | const auto update = installed->GetEntry(update_tid, ContentRecordType::Program); |
| 64 | if (update != nullptr) { | 64 | |
| 65 | if (update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS && | 65 | if (update != nullptr && update->GetExeFS() != nullptr && |
| 66 | update->GetExeFS() != nullptr) { | 66 | update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { |
| 67 | LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", | 67 | LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", |
| 68 | FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0))); | 68 | FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0))); |
| 69 | exefs = update->GetExeFS(); | 69 | exefs = update->GetExeFS(); |
| 70 | } | ||
| 71 | } | 70 | } |
| 72 | 71 | ||
| 73 | return exefs; | 72 | return exefs; |
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index c87721c39..c1c83a11d 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -273,8 +273,8 @@ public: | |||
| 273 | {0, &IFileSystem::CreateFile, "CreateFile"}, | 273 | {0, &IFileSystem::CreateFile, "CreateFile"}, |
| 274 | {1, &IFileSystem::DeleteFile, "DeleteFile"}, | 274 | {1, &IFileSystem::DeleteFile, "DeleteFile"}, |
| 275 | {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, | 275 | {2, &IFileSystem::CreateDirectory, "CreateDirectory"}, |
| 276 | {3, nullptr, "DeleteDirectory"}, | 276 | {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"}, |
| 277 | {4, nullptr, "DeleteDirectoryRecursively"}, | 277 | {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"}, |
| 278 | {5, &IFileSystem::RenameFile, "RenameFile"}, | 278 | {5, &IFileSystem::RenameFile, "RenameFile"}, |
| 279 | {6, nullptr, "RenameDirectory"}, | 279 | {6, nullptr, "RenameDirectory"}, |
| 280 | {7, &IFileSystem::GetEntryType, "GetEntryType"}, | 280 | {7, &IFileSystem::GetEntryType, "GetEntryType"}, |
| @@ -329,6 +329,30 @@ public: | |||
| 329 | rb.Push(backend.CreateDirectory(name)); | 329 | rb.Push(backend.CreateDirectory(name)); |
| 330 | } | 330 | } |
| 331 | 331 | ||
| 332 | void DeleteDirectory(Kernel::HLERequestContext& ctx) { | ||
| 333 | const IPC::RequestParser rp{ctx}; | ||
| 334 | |||
| 335 | const auto file_buffer = ctx.ReadBuffer(); | ||
| 336 | std::string name = Common::StringFromBuffer(file_buffer); | ||
| 337 | |||
| 338 | LOG_DEBUG(Service_FS, "called directory {}", name); | ||
| 339 | |||
| 340 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 341 | rb.Push(backend.DeleteDirectory(name)); | ||
| 342 | } | ||
| 343 | |||
| 344 | void DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) { | ||
| 345 | const IPC::RequestParser rp{ctx}; | ||
| 346 | |||
| 347 | const auto file_buffer = ctx.ReadBuffer(); | ||
| 348 | std::string name = Common::StringFromBuffer(file_buffer); | ||
| 349 | |||
| 350 | LOG_DEBUG(Service_FS, "called directory {}", name); | ||
| 351 | |||
| 352 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 353 | rb.Push(backend.DeleteDirectoryRecursively(name)); | ||
| 354 | } | ||
| 355 | |||
| 332 | void RenameFile(Kernel::HLERequestContext& ctx) { | 356 | void RenameFile(Kernel::HLERequestContext& ctx) { |
| 333 | IPC::RequestParser rp{ctx}; | 357 | IPC::RequestParser rp{ctx}; |
| 334 | 358 | ||
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index 13e57848d..080d89904 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp | |||
| @@ -36,6 +36,16 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file) | |||
| 36 | 36 | ||
| 37 | std::tie(nacp_file, icon_file) = | 37 | std::tie(nacp_file, icon_file) = |
| 38 | FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(*control_nca); | 38 | FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(*control_nca); |
| 39 | |||
| 40 | if (nsp->IsExtractedType()) { | ||
| 41 | secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS()); | ||
| 42 | } else { | ||
| 43 | if (title_id == 0) | ||
| 44 | return; | ||
| 45 | |||
| 46 | secondary_loader = std::make_unique<AppLoader_NCA>( | ||
| 47 | nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); | ||
| 48 | } | ||
| 39 | } | 49 | } |
| 40 | 50 | ||
| 41 | AppLoader_NSP::~AppLoader_NSP() = default; | 51 | AppLoader_NSP::~AppLoader_NSP() = default; |
| @@ -67,26 +77,19 @@ ResultStatus AppLoader_NSP::Load(Kernel::Process& process) { | |||
| 67 | return ResultStatus::ErrorAlreadyLoaded; | 77 | return ResultStatus::ErrorAlreadyLoaded; |
| 68 | } | 78 | } |
| 69 | 79 | ||
| 70 | if (nsp->IsExtractedType()) { | 80 | if (title_id == 0) |
| 71 | secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS()); | 81 | return ResultStatus::ErrorNSPMissingProgramNCA; |
| 72 | } else { | ||
| 73 | if (title_id == 0) | ||
| 74 | return ResultStatus::ErrorNSPMissingProgramNCA; | ||
| 75 | |||
| 76 | secondary_loader = std::make_unique<AppLoader_NCA>( | ||
| 77 | nsp->GetNCAFile(title_id, FileSys::ContentRecordType::Program)); | ||
| 78 | 82 | ||
| 79 | if (nsp->GetStatus() != ResultStatus::Success) | 83 | if (nsp->GetStatus() != ResultStatus::Success) |
| 80 | return nsp->GetStatus(); | 84 | return nsp->GetStatus(); |
| 81 | 85 | ||
| 82 | if (nsp->GetProgramStatus(title_id) != ResultStatus::Success) | 86 | if (nsp->GetProgramStatus(title_id) != ResultStatus::Success) |
| 83 | return nsp->GetProgramStatus(title_id); | 87 | return nsp->GetProgramStatus(title_id); |
| 84 | 88 | ||
| 85 | if (nsp->GetNCA(title_id, FileSys::ContentRecordType::Program) == nullptr) { | 89 | if (nsp->GetNCA(title_id, FileSys::ContentRecordType::Program) == nullptr) { |
| 86 | if (!Core::Crypto::KeyManager::KeyFileExists(false)) | 90 | if (!Core::Crypto::KeyManager::KeyFileExists(false)) |
| 87 | return ResultStatus::ErrorMissingProductionKeyFile; | 91 | return ResultStatus::ErrorMissingProductionKeyFile; |
| 88 | return ResultStatus::ErrorNSPMissingProgramNCA; | 92 | return ResultStatus::ErrorNSPMissingProgramNCA; |
| 89 | } | ||
| 90 | } | 93 | } |
| 91 | 94 | ||
| 92 | const auto result = secondary_loader->Load(process); | 95 | const auto result = secondary_loader->Load(process); |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 754a149fa..443affc36 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -723,7 +723,11 @@ public: | |||
| 723 | StencilOp stencil_back_op_zpass; | 723 | StencilOp stencil_back_op_zpass; |
| 724 | ComparisonOp stencil_back_func_func; | 724 | ComparisonOp stencil_back_func_func; |
| 725 | 725 | ||
| 726 | INSERT_PADDING_WORDS(0x17); | 726 | INSERT_PADDING_WORDS(0x4); |
| 727 | |||
| 728 | u32 framebuffer_srgb; | ||
| 729 | |||
| 730 | INSERT_PADDING_WORDS(0x12); | ||
| 727 | 731 | ||
| 728 | union { | 732 | union { |
| 729 | BitField<2, 1, u32> coord_origin; | 733 | BitField<2, 1, u32> coord_origin; |
| @@ -751,7 +755,14 @@ public: | |||
| 751 | }; | 755 | }; |
| 752 | } draw; | 756 | } draw; |
| 753 | 757 | ||
| 754 | INSERT_PADDING_WORDS(0x6B); | 758 | INSERT_PADDING_WORDS(0xA); |
| 759 | |||
| 760 | struct { | ||
| 761 | u32 enabled; | ||
| 762 | u32 index; | ||
| 763 | } primitive_restart; | ||
| 764 | |||
| 765 | INSERT_PADDING_WORDS(0x5F); | ||
| 755 | 766 | ||
| 756 | struct { | 767 | struct { |
| 757 | u32 start_addr_high; | 768 | u32 start_addr_high; |
| @@ -1079,9 +1090,11 @@ ASSERT_REG_POSITION(stencil_back_op_fail, 0x566); | |||
| 1079 | ASSERT_REG_POSITION(stencil_back_op_zfail, 0x567); | 1090 | ASSERT_REG_POSITION(stencil_back_op_zfail, 0x567); |
| 1080 | ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568); | 1091 | ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568); |
| 1081 | ASSERT_REG_POSITION(stencil_back_func_func, 0x569); | 1092 | ASSERT_REG_POSITION(stencil_back_func_func, 0x569); |
| 1093 | ASSERT_REG_POSITION(framebuffer_srgb, 0x56E); | ||
| 1082 | ASSERT_REG_POSITION(point_coord_replace, 0x581); | 1094 | ASSERT_REG_POSITION(point_coord_replace, 0x581); |
| 1083 | ASSERT_REG_POSITION(code_address, 0x582); | 1095 | ASSERT_REG_POSITION(code_address, 0x582); |
| 1084 | ASSERT_REG_POSITION(draw, 0x585); | 1096 | ASSERT_REG_POSITION(draw, 0x585); |
| 1097 | ASSERT_REG_POSITION(primitive_restart, 0x591); | ||
| 1085 | ASSERT_REG_POSITION(index_array, 0x5F2); | 1098 | ASSERT_REG_POSITION(index_array, 0x5F2); |
| 1086 | ASSERT_REG_POSITION(instanced_arrays, 0x620); | 1099 | ASSERT_REG_POSITION(instanced_arrays, 0x620); |
| 1087 | ASSERT_REG_POSITION(cull, 0x646); | 1100 | ASSERT_REG_POSITION(cull, 0x646); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index b472f421f..cb180b93c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -418,6 +418,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep | |||
| 418 | // Bind the framebuffer surfaces | 418 | // Bind the framebuffer surfaces |
| 419 | state.draw.draw_framebuffer = framebuffer.handle; | 419 | state.draw.draw_framebuffer = framebuffer.handle; |
| 420 | state.Apply(); | 420 | state.Apply(); |
| 421 | state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0; | ||
| 421 | 422 | ||
| 422 | if (using_color_fb) { | 423 | if (using_color_fb) { |
| 423 | if (single_color_target) { | 424 | if (single_color_target) { |
| @@ -429,6 +430,9 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep | |||
| 429 | // Assume that a surface will be written to if it is used as a framebuffer, even if | 430 | // Assume that a surface will be written to if it is used as a framebuffer, even if |
| 430 | // the shader doesn't actually write to it. | 431 | // the shader doesn't actually write to it. |
| 431 | color_surface->MarkAsModified(true, res_cache); | 432 | color_surface->MarkAsModified(true, res_cache); |
| 433 | // Workaround for and issue in nvidia drivers | ||
| 434 | // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/ | ||
| 435 | state.framebuffer_srgb.enabled |= color_surface->GetSurfaceParams().srgb_conversion; | ||
| 432 | } | 436 | } |
| 433 | 437 | ||
| 434 | glFramebufferTexture2D( | 438 | glFramebufferTexture2D( |
| @@ -446,6 +450,11 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep | |||
| 446 | // Assume that a surface will be written to if it is used as a framebuffer, even | 450 | // Assume that a surface will be written to if it is used as a framebuffer, even |
| 447 | // if the shader doesn't actually write to it. | 451 | // if the shader doesn't actually write to it. |
| 448 | color_surface->MarkAsModified(true, res_cache); | 452 | color_surface->MarkAsModified(true, res_cache); |
| 453 | // Enable sRGB only for supported formats | ||
| 454 | // Workaround for and issue in nvidia drivers | ||
| 455 | // https://devtalk.nvidia.com/default/topic/776591/opengl/gl_framebuffer_srgb-functions-incorrectly/ | ||
| 456 | state.framebuffer_srgb.enabled |= | ||
| 457 | color_surface->GetSurfaceParams().srgb_conversion; | ||
| 449 | } | 458 | } |
| 450 | 459 | ||
| 451 | buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); | 460 | buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index); |
| @@ -537,7 +546,9 @@ void RasterizerOpenGL::Clear() { | |||
| 537 | 546 | ||
| 538 | ConfigureFramebuffers(use_color, use_depth || use_stencil, false, | 547 | ConfigureFramebuffers(use_color, use_depth || use_stencil, false, |
| 539 | regs.clear_buffers.RT.Value()); | 548 | regs.clear_buffers.RT.Value()); |
| 540 | 549 | // Copy the sRGB setting to the clear state to avoid problem with | |
| 550 | // specific driver implementations | ||
| 551 | clear_state.framebuffer_srgb.enabled = state.framebuffer_srgb.enabled; | ||
| 541 | clear_state.Apply(); | 552 | clear_state.Apply(); |
| 542 | 553 | ||
| 543 | if (use_color) { | 554 | if (use_color) { |
| @@ -570,6 +581,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 570 | SyncBlendState(); | 581 | SyncBlendState(); |
| 571 | SyncLogicOpState(); | 582 | SyncLogicOpState(); |
| 572 | SyncCullMode(); | 583 | SyncCullMode(); |
| 584 | SyncPrimitiveRestart(); | ||
| 573 | SyncDepthRange(); | 585 | SyncDepthRange(); |
| 574 | SyncScissorTest(); | 586 | SyncScissorTest(); |
| 575 | // Alpha Testing is synced on shaders. | 587 | // Alpha Testing is synced on shaders. |
| @@ -924,6 +936,13 @@ void RasterizerOpenGL::SyncCullMode() { | |||
| 924 | } | 936 | } |
| 925 | } | 937 | } |
| 926 | 938 | ||
| 939 | void RasterizerOpenGL::SyncPrimitiveRestart() { | ||
| 940 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||
| 941 | |||
| 942 | state.primitive_restart.enabled = regs.primitive_restart.enabled; | ||
| 943 | state.primitive_restart.index = regs.primitive_restart.index; | ||
| 944 | } | ||
| 945 | |||
| 927 | void RasterizerOpenGL::SyncDepthRange() { | 946 | void RasterizerOpenGL::SyncDepthRange() { |
| 928 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 947 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 929 | 948 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 731a336d5..5020a5392 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -144,6 +144,9 @@ private: | |||
| 144 | /// Syncs the cull mode to match the guest state | 144 | /// Syncs the cull mode to match the guest state |
| 145 | void SyncCullMode(); | 145 | void SyncCullMode(); |
| 146 | 146 | ||
| 147 | /// Syncs the primitve restart to match the guest state | ||
| 148 | void SyncPrimitiveRestart(); | ||
| 149 | |||
| 147 | /// Syncs the depth range to match the guest state | 150 | /// Syncs the depth range to match the guest state |
| 148 | void SyncDepthRange(); | 151 | void SyncDepthRange(); |
| 149 | 152 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 591ec7998..b057e2efa 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -40,6 +40,10 @@ static bool IsPixelFormatASTC(PixelFormat format) { | |||
| 40 | case PixelFormat::ASTC_2D_5X4: | 40 | case PixelFormat::ASTC_2D_5X4: |
| 41 | case PixelFormat::ASTC_2D_8X8: | 41 | case PixelFormat::ASTC_2D_8X8: |
| 42 | case PixelFormat::ASTC_2D_8X5: | 42 | case PixelFormat::ASTC_2D_8X5: |
| 43 | case PixelFormat::ASTC_2D_4X4_SRGB: | ||
| 44 | case PixelFormat::ASTC_2D_5X4_SRGB: | ||
| 45 | case PixelFormat::ASTC_2D_8X8_SRGB: | ||
| 46 | case PixelFormat::ASTC_2D_8X5_SRGB: | ||
| 43 | return true; | 47 | return true; |
| 44 | default: | 48 | default: |
| 45 | return false; | 49 | return false; |
| @@ -56,6 +60,14 @@ static std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) { | |||
| 56 | return {8, 8}; | 60 | return {8, 8}; |
| 57 | case PixelFormat::ASTC_2D_8X5: | 61 | case PixelFormat::ASTC_2D_8X5: |
| 58 | return {8, 5}; | 62 | return {8, 5}; |
| 63 | case PixelFormat::ASTC_2D_4X4_SRGB: | ||
| 64 | return {4, 4}; | ||
| 65 | case PixelFormat::ASTC_2D_5X4_SRGB: | ||
| 66 | return {5, 4}; | ||
| 67 | case PixelFormat::ASTC_2D_8X8_SRGB: | ||
| 68 | return {8, 8}; | ||
| 69 | case PixelFormat::ASTC_2D_8X5_SRGB: | ||
| 70 | return {8, 5}; | ||
| 59 | default: | 71 | default: |
| 60 | LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format)); | 72 | LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format)); |
| 61 | UNREACHABLE(); | 73 | UNREACHABLE(); |
| @@ -108,8 +120,9 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { | |||
| 108 | params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0, | 120 | params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0, |
| 109 | params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, | 121 | params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, |
| 110 | params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0, | 122 | params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0, |
| 111 | params.pixel_format = | 123 | params.srgb_conversion = config.tic.IsSrgbConversionEnabled(); |
| 112 | PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value()); | 124 | params.pixel_format = PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(), |
| 125 | params.srgb_conversion); | ||
| 113 | params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value()); | 126 | params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value()); |
| 114 | params.type = GetFormatType(params.pixel_format); | 127 | params.type = GetFormatType(params.pixel_format); |
| 115 | params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); | 128 | params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); |
| @@ -166,6 +179,8 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { | |||
| 166 | params.block_height = 1 << config.memory_layout.block_height; | 179 | params.block_height = 1 << config.memory_layout.block_height; |
| 167 | params.block_depth = 1 << config.memory_layout.block_depth; | 180 | params.block_depth = 1 << config.memory_layout.block_depth; |
| 168 | params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); | 181 | params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); |
| 182 | params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || | ||
| 183 | config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; | ||
| 169 | params.component_type = ComponentTypeFromRenderTarget(config.format); | 184 | params.component_type = ComponentTypeFromRenderTarget(config.format); |
| 170 | params.type = GetFormatType(params.pixel_format); | 185 | params.type = GetFormatType(params.pixel_format); |
| 171 | params.width = config.width; | 186 | params.width = config.width; |
| @@ -201,6 +216,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { | |||
| 201 | params.pixel_format = PixelFormatFromDepthFormat(format); | 216 | params.pixel_format = PixelFormatFromDepthFormat(format); |
| 202 | params.component_type = ComponentTypeFromDepthFormat(format); | 217 | params.component_type = ComponentTypeFromDepthFormat(format); |
| 203 | params.type = GetFormatType(params.pixel_format); | 218 | params.type = GetFormatType(params.pixel_format); |
| 219 | params.srgb_conversion = false; | ||
| 204 | params.width = zeta_width; | 220 | params.width = zeta_width; |
| 205 | params.height = zeta_height; | 221 | params.height = zeta_height; |
| 206 | params.unaligned_height = zeta_height; | 222 | params.unaligned_height = zeta_height; |
| @@ -224,6 +240,8 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { | |||
| 224 | params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0, | 240 | params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0, |
| 225 | params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0, | 241 | params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0, |
| 226 | params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); | 242 | params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); |
| 243 | params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || | ||
| 244 | config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; | ||
| 227 | params.component_type = ComponentTypeFromRenderTarget(config.format); | 245 | params.component_type = ComponentTypeFromRenderTarget(config.format); |
| 228 | params.type = GetFormatType(params.pixel_format); | 246 | params.type = GetFormatType(params.pixel_format); |
| 229 | params.width = config.width; | 247 | params.width = config.width; |
| @@ -289,14 +307,29 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form | |||
| 289 | {GL_RG16I, GL_RG_INTEGER, GL_SHORT, ComponentType::SInt, false}, // RG16I | 307 | {GL_RG16I, GL_RG_INTEGER, GL_SHORT, ComponentType::SInt, false}, // RG16I |
| 290 | {GL_RG16_SNORM, GL_RG, GL_SHORT, ComponentType::SNorm, false}, // RG16S | 308 | {GL_RG16_SNORM, GL_RG, GL_SHORT, ComponentType::SNorm, false}, // RG16S |
| 291 | {GL_RGB32F, GL_RGB, GL_FLOAT, ComponentType::Float, false}, // RGB32F | 309 | {GL_RGB32F, GL_RGB, GL_FLOAT, ComponentType::Float, false}, // RGB32F |
| 292 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // SRGBA8 | 310 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, |
| 293 | {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // RG8U | 311 | false}, // RGBA8_SRGB |
| 294 | {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S | 312 | {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // RG8U |
| 295 | {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RG32UI | 313 | {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S |
| 296 | {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // R32UI | 314 | {GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RG32UI |
| 297 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8 | 315 | {GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // R32UI |
| 298 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5 | 316 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8 |
| 299 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4 | 317 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5 |
| 318 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4 | ||
| 319 | {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8 | ||
| 320 | // Compressed sRGB formats | ||
| 321 | {GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 322 | true}, // DXT1_SRGB | ||
| 323 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 324 | true}, // DXT23_SRGB | ||
| 325 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 326 | true}, // DXT45_SRGB | ||
| 327 | {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, | ||
| 328 | ComponentType::UNorm, true}, // BC7U_SRGB | ||
| 329 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB | ||
| 330 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB | ||
| 331 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB | ||
| 332 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB | ||
| 300 | 333 | ||
| 301 | // Depth formats | 334 | // Depth formats |
| 302 | {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F | 335 | {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F |
| @@ -361,6 +394,10 @@ static bool IsFormatBCn(PixelFormat format) { | |||
| 361 | case PixelFormat::BC7U: | 394 | case PixelFormat::BC7U: |
| 362 | case PixelFormat::BC6H_UF16: | 395 | case PixelFormat::BC6H_UF16: |
| 363 | case PixelFormat::BC6H_SF16: | 396 | case PixelFormat::BC6H_SF16: |
| 397 | case PixelFormat::DXT1_SRGB: | ||
| 398 | case PixelFormat::DXT23_SRGB: | ||
| 399 | case PixelFormat::DXT45_SRGB: | ||
| 400 | case PixelFormat::BC7U_SRGB: | ||
| 364 | return true; | 401 | return true; |
| 365 | } | 402 | } |
| 366 | return false; | 403 | return false; |
| @@ -432,7 +469,7 @@ static constexpr GLConversionArray morton_to_gl_fns = { | |||
| 432 | MortonCopy<true, PixelFormat::RG16I>, | 469 | MortonCopy<true, PixelFormat::RG16I>, |
| 433 | MortonCopy<true, PixelFormat::RG16S>, | 470 | MortonCopy<true, PixelFormat::RG16S>, |
| 434 | MortonCopy<true, PixelFormat::RGB32F>, | 471 | MortonCopy<true, PixelFormat::RGB32F>, |
| 435 | MortonCopy<true, PixelFormat::SRGBA8>, | 472 | MortonCopy<true, PixelFormat::RGBA8_SRGB>, |
| 436 | MortonCopy<true, PixelFormat::RG8U>, | 473 | MortonCopy<true, PixelFormat::RG8U>, |
| 437 | MortonCopy<true, PixelFormat::RG8S>, | 474 | MortonCopy<true, PixelFormat::RG8S>, |
| 438 | MortonCopy<true, PixelFormat::RG32UI>, | 475 | MortonCopy<true, PixelFormat::RG32UI>, |
| @@ -440,6 +477,15 @@ static constexpr GLConversionArray morton_to_gl_fns = { | |||
| 440 | MortonCopy<true, PixelFormat::ASTC_2D_8X8>, | 477 | MortonCopy<true, PixelFormat::ASTC_2D_8X8>, |
| 441 | MortonCopy<true, PixelFormat::ASTC_2D_8X5>, | 478 | MortonCopy<true, PixelFormat::ASTC_2D_8X5>, |
| 442 | MortonCopy<true, PixelFormat::ASTC_2D_5X4>, | 479 | MortonCopy<true, PixelFormat::ASTC_2D_5X4>, |
| 480 | MortonCopy<true, PixelFormat::BGRA8_SRGB>, | ||
| 481 | MortonCopy<true, PixelFormat::DXT1_SRGB>, | ||
| 482 | MortonCopy<true, PixelFormat::DXT23_SRGB>, | ||
| 483 | MortonCopy<true, PixelFormat::DXT45_SRGB>, | ||
| 484 | MortonCopy<true, PixelFormat::BC7U_SRGB>, | ||
| 485 | MortonCopy<true, PixelFormat::ASTC_2D_4X4_SRGB>, | ||
| 486 | MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>, | ||
| 487 | MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>, | ||
| 488 | MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>, | ||
| 443 | MortonCopy<true, PixelFormat::Z32F>, | 489 | MortonCopy<true, PixelFormat::Z32F>, |
| 444 | MortonCopy<true, PixelFormat::Z16>, | 490 | MortonCopy<true, PixelFormat::Z16>, |
| 445 | MortonCopy<true, PixelFormat::Z24S8>, | 491 | MortonCopy<true, PixelFormat::Z24S8>, |
| @@ -491,7 +537,7 @@ static constexpr GLConversionArray gl_to_morton_fns = { | |||
| 491 | MortonCopy<false, PixelFormat::RG16I>, | 537 | MortonCopy<false, PixelFormat::RG16I>, |
| 492 | MortonCopy<false, PixelFormat::RG16S>, | 538 | MortonCopy<false, PixelFormat::RG16S>, |
| 493 | MortonCopy<false, PixelFormat::RGB32F>, | 539 | MortonCopy<false, PixelFormat::RGB32F>, |
| 494 | MortonCopy<false, PixelFormat::SRGBA8>, | 540 | MortonCopy<false, PixelFormat::RGBA8_SRGB>, |
| 495 | MortonCopy<false, PixelFormat::RG8U>, | 541 | MortonCopy<false, PixelFormat::RG8U>, |
| 496 | MortonCopy<false, PixelFormat::RG8S>, | 542 | MortonCopy<false, PixelFormat::RG8S>, |
| 497 | MortonCopy<false, PixelFormat::RG32UI>, | 543 | MortonCopy<false, PixelFormat::RG32UI>, |
| @@ -499,6 +545,15 @@ static constexpr GLConversionArray gl_to_morton_fns = { | |||
| 499 | nullptr, | 545 | nullptr, |
| 500 | nullptr, | 546 | nullptr, |
| 501 | nullptr, | 547 | nullptr, |
| 548 | MortonCopy<false, PixelFormat::BGRA8_SRGB>, | ||
| 549 | MortonCopy<false, PixelFormat::DXT1_SRGB>, | ||
| 550 | MortonCopy<false, PixelFormat::DXT23_SRGB>, | ||
| 551 | MortonCopy<false, PixelFormat::DXT45_SRGB>, | ||
| 552 | MortonCopy<false, PixelFormat::BC7U_SRGB>, | ||
| 553 | nullptr, | ||
| 554 | nullptr, | ||
| 555 | nullptr, | ||
| 556 | nullptr, | ||
| 502 | MortonCopy<false, PixelFormat::Z32F>, | 557 | MortonCopy<false, PixelFormat::Z32F>, |
| 503 | MortonCopy<false, PixelFormat::Z16>, | 558 | MortonCopy<false, PixelFormat::Z16>, |
| 504 | MortonCopy<false, PixelFormat::Z24S8>, | 559 | MortonCopy<false, PixelFormat::Z24S8>, |
| @@ -546,6 +601,8 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface, | |||
| 546 | OpenGLState state; | 601 | OpenGLState state; |
| 547 | state.draw.read_framebuffer = read_fb_handle; | 602 | state.draw.read_framebuffer = read_fb_handle; |
| 548 | state.draw.draw_framebuffer = draw_fb_handle; | 603 | state.draw.draw_framebuffer = draw_fb_handle; |
| 604 | // Set sRGB enabled if the destination surfaces need it | ||
| 605 | state.framebuffer_srgb.enabled = dst_params.srgb_conversion; | ||
| 549 | state.Apply(); | 606 | state.Apply(); |
| 550 | 607 | ||
| 551 | u32 buffers{}; | 608 | u32 buffers{}; |
| @@ -881,7 +938,11 @@ static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelForma | |||
| 881 | case PixelFormat::ASTC_2D_4X4: | 938 | case PixelFormat::ASTC_2D_4X4: |
| 882 | case PixelFormat::ASTC_2D_8X8: | 939 | case PixelFormat::ASTC_2D_8X8: |
| 883 | case PixelFormat::ASTC_2D_8X5: | 940 | case PixelFormat::ASTC_2D_8X5: |
| 884 | case PixelFormat::ASTC_2D_5X4: { | 941 | case PixelFormat::ASTC_2D_5X4: |
| 942 | case PixelFormat::ASTC_2D_4X4_SRGB: | ||
| 943 | case PixelFormat::ASTC_2D_8X8_SRGB: | ||
| 944 | case PixelFormat::ASTC_2D_8X5_SRGB: | ||
| 945 | case PixelFormat::ASTC_2D_5X4_SRGB: { | ||
| 885 | // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC. | 946 | // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC. |
| 886 | u32 block_width{}; | 947 | u32 block_width{}; |
| 887 | u32 block_height{}; | 948 | u32 block_height{}; |
| @@ -913,7 +974,9 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm | |||
| 913 | case PixelFormat::G8R8U: | 974 | case PixelFormat::G8R8U: |
| 914 | case PixelFormat::G8R8S: | 975 | case PixelFormat::G8R8S: |
| 915 | case PixelFormat::ASTC_2D_4X4: | 976 | case PixelFormat::ASTC_2D_4X4: |
| 916 | case PixelFormat::ASTC_2D_8X8: { | 977 | case PixelFormat::ASTC_2D_8X8: |
| 978 | case PixelFormat::ASTC_2D_4X4_SRGB: | ||
| 979 | case PixelFormat::ASTC_2D_8X8_SRGB: { | ||
| 917 | LOG_CRITICAL(HW_GPU, "Conversion of format {} after texture flushing is not implemented", | 980 | LOG_CRITICAL(HW_GPU, "Conversion of format {} after texture flushing is not implemented", |
| 918 | static_cast<u32>(pixel_format)); | 981 | static_cast<u32>(pixel_format)); |
| 919 | UNREACHABLE(); | 982 | UNREACHABLE(); |
| @@ -960,8 +1023,8 @@ void CachedSurface::FlushGLBuffer() { | |||
| 960 | glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width)); | 1023 | glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width)); |
| 961 | ASSERT(!tuple.compressed); | 1024 | ASSERT(!tuple.compressed); |
| 962 | glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); | 1025 | glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); |
| 963 | glGetTextureImage(texture.handle, 0, tuple.format, tuple.type, gl_buffer.size(), | 1026 | glGetTextureImage(texture.handle, 0, tuple.format, tuple.type, |
| 964 | gl_buffer.data()); | 1027 | static_cast<GLsizei>(gl_buffer.size()), gl_buffer.data()); |
| 965 | glPixelStorei(GL_PACK_ROW_LENGTH, 0); | 1028 | glPixelStorei(GL_PACK_ROW_LENGTH, 0); |
| 966 | ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width, | 1029 | ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width, |
| 967 | params.height); | 1030 | params.height); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 50a7ab47d..b4701a616 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h | |||
| @@ -69,7 +69,7 @@ struct SurfaceParams { | |||
| 69 | RG16I = 37, | 69 | RG16I = 37, |
| 70 | RG16S = 38, | 70 | RG16S = 38, |
| 71 | RGB32F = 39, | 71 | RGB32F = 39, |
| 72 | SRGBA8 = 40, | 72 | RGBA8_SRGB = 40, |
| 73 | RG8U = 41, | 73 | RG8U = 41, |
| 74 | RG8S = 42, | 74 | RG8S = 42, |
| 75 | RG32UI = 43, | 75 | RG32UI = 43, |
| @@ -77,19 +77,28 @@ struct SurfaceParams { | |||
| 77 | ASTC_2D_8X8 = 45, | 77 | ASTC_2D_8X8 = 45, |
| 78 | ASTC_2D_8X5 = 46, | 78 | ASTC_2D_8X5 = 46, |
| 79 | ASTC_2D_5X4 = 47, | 79 | ASTC_2D_5X4 = 47, |
| 80 | BGRA8_SRGB = 48, | ||
| 81 | DXT1_SRGB = 49, | ||
| 82 | DXT23_SRGB = 50, | ||
| 83 | DXT45_SRGB = 51, | ||
| 84 | BC7U_SRGB = 52, | ||
| 85 | ASTC_2D_4X4_SRGB = 53, | ||
| 86 | ASTC_2D_8X8_SRGB = 54, | ||
| 87 | ASTC_2D_8X5_SRGB = 55, | ||
| 88 | ASTC_2D_5X4_SRGB = 56, | ||
| 80 | 89 | ||
| 81 | MaxColorFormat, | 90 | MaxColorFormat, |
| 82 | 91 | ||
| 83 | // Depth formats | 92 | // Depth formats |
| 84 | Z32F = 48, | 93 | Z32F = 57, |
| 85 | Z16 = 49, | 94 | Z16 = 58, |
| 86 | 95 | ||
| 87 | MaxDepthFormat, | 96 | MaxDepthFormat, |
| 88 | 97 | ||
| 89 | // DepthStencil formats | 98 | // DepthStencil formats |
| 90 | Z24S8 = 50, | 99 | Z24S8 = 59, |
| 91 | S8Z24 = 51, | 100 | S8Z24 = 60, |
| 92 | Z32FS8 = 52, | 101 | Z32FS8 = 61, |
| 93 | 102 | ||
| 94 | MaxDepthStencilFormat, | 103 | MaxDepthStencilFormat, |
| 95 | 104 | ||
| @@ -236,7 +245,7 @@ struct SurfaceParams { | |||
| 236 | 1, // RG16I | 245 | 1, // RG16I |
| 237 | 1, // RG16S | 246 | 1, // RG16S |
| 238 | 1, // RGB32F | 247 | 1, // RGB32F |
| 239 | 1, // SRGBA8 | 248 | 1, // RGBA8_SRGB |
| 240 | 1, // RG8U | 249 | 1, // RG8U |
| 241 | 1, // RG8S | 250 | 1, // RG8S |
| 242 | 1, // RG32UI | 251 | 1, // RG32UI |
| @@ -244,6 +253,15 @@ struct SurfaceParams { | |||
| 244 | 4, // ASTC_2D_8X8 | 253 | 4, // ASTC_2D_8X8 |
| 245 | 4, // ASTC_2D_8X5 | 254 | 4, // ASTC_2D_8X5 |
| 246 | 4, // ASTC_2D_5X4 | 255 | 4, // ASTC_2D_5X4 |
| 256 | 1, // BGRA8_SRGB | ||
| 257 | 4, // DXT1_SRGB | ||
| 258 | 4, // DXT23_SRGB | ||
| 259 | 4, // DXT45_SRGB | ||
| 260 | 4, // BC7U_SRGB | ||
| 261 | 4, // ASTC_2D_4X4_SRGB | ||
| 262 | 4, // ASTC_2D_8X8_SRGB | ||
| 263 | 4, // ASTC_2D_8X5_SRGB | ||
| 264 | 4, // ASTC_2D_5X4_SRGB | ||
| 247 | 1, // Z32F | 265 | 1, // Z32F |
| 248 | 1, // Z16 | 266 | 1, // Z16 |
| 249 | 1, // Z24S8 | 267 | 1, // Z24S8 |
| @@ -255,6 +273,77 @@ struct SurfaceParams { | |||
| 255 | return compression_factor_table[static_cast<std::size_t>(format)]; | 273 | return compression_factor_table[static_cast<std::size_t>(format)]; |
| 256 | } | 274 | } |
| 257 | 275 | ||
| 276 | static constexpr u32 GetDefaultBlockHeight(PixelFormat format) { | ||
| 277 | if (format == PixelFormat::Invalid) | ||
| 278 | return 0; | ||
| 279 | constexpr std::array<u32, MaxPixelFormat> block_height_table = {{ | ||
| 280 | 1, // ABGR8U | ||
| 281 | 1, // ABGR8S | ||
| 282 | 1, // ABGR8UI | ||
| 283 | 1, // B5G6R5U | ||
| 284 | 1, // A2B10G10R10U | ||
| 285 | 1, // A1B5G5R5U | ||
| 286 | 1, // R8U | ||
| 287 | 1, // R8UI | ||
| 288 | 1, // RGBA16F | ||
| 289 | 1, // RGBA16U | ||
| 290 | 1, // RGBA16UI | ||
| 291 | 1, // R11FG11FB10F | ||
| 292 | 1, // RGBA32UI | ||
| 293 | 4, // DXT1 | ||
| 294 | 4, // DXT23 | ||
| 295 | 4, // DXT45 | ||
| 296 | 4, // DXN1 | ||
| 297 | 4, // DXN2UNORM | ||
| 298 | 4, // DXN2SNORM | ||
| 299 | 4, // BC7U | ||
| 300 | 4, // BC6H_UF16 | ||
| 301 | 4, // BC6H_SF16 | ||
| 302 | 4, // ASTC_2D_4X4 | ||
| 303 | 1, // G8R8U | ||
| 304 | 1, // G8R8S | ||
| 305 | 1, // BGRA8 | ||
| 306 | 1, // RGBA32F | ||
| 307 | 1, // RG32F | ||
| 308 | 1, // R32F | ||
| 309 | 1, // R16F | ||
| 310 | 1, // R16U | ||
| 311 | 1, // R16S | ||
| 312 | 1, // R16UI | ||
| 313 | 1, // R16I | ||
| 314 | 1, // RG16 | ||
| 315 | 1, // RG16F | ||
| 316 | 1, // RG16UI | ||
| 317 | 1, // RG16I | ||
| 318 | 1, // RG16S | ||
| 319 | 1, // RGB32F | ||
| 320 | 1, // RGBA8_SRGB | ||
| 321 | 1, // RG8U | ||
| 322 | 1, // RG8S | ||
| 323 | 1, // RG32UI | ||
| 324 | 1, // R32UI | ||
| 325 | 8, // ASTC_2D_8X8 | ||
| 326 | 5, // ASTC_2D_8X5 | ||
| 327 | 4, // ASTC_2D_5X4 | ||
| 328 | 1, // BGRA8_SRGB | ||
| 329 | 4, // DXT1_SRGB | ||
| 330 | 4, // DXT23_SRGB | ||
| 331 | 4, // DXT45_SRGB | ||
| 332 | 4, // BC7U_SRGB | ||
| 333 | 4, // ASTC_2D_4X4_SRGB | ||
| 334 | 8, // ASTC_2D_8X8_SRGB | ||
| 335 | 5, // ASTC_2D_8X5_SRGB | ||
| 336 | 4, // ASTC_2D_5X4_SRGB | ||
| 337 | 1, // Z32F | ||
| 338 | 1, // Z16 | ||
| 339 | 1, // Z24S8 | ||
| 340 | 1, // S8Z24 | ||
| 341 | 1, // Z32FS8 | ||
| 342 | }}; | ||
| 343 | ASSERT(static_cast<std::size_t>(format) < block_height_table.size()); | ||
| 344 | return block_height_table[static_cast<std::size_t>(format)]; | ||
| 345 | } | ||
| 346 | |||
| 258 | static constexpr u32 GetFormatBpp(PixelFormat format) { | 347 | static constexpr u32 GetFormatBpp(PixelFormat format) { |
| 259 | if (format == PixelFormat::Invalid) | 348 | if (format == PixelFormat::Invalid) |
| 260 | return 0; | 349 | return 0; |
| @@ -300,7 +389,7 @@ struct SurfaceParams { | |||
| 300 | 32, // RG16I | 389 | 32, // RG16I |
| 301 | 32, // RG16S | 390 | 32, // RG16S |
| 302 | 96, // RGB32F | 391 | 96, // RGB32F |
| 303 | 32, // SRGBA8 | 392 | 32, // RGBA8_SRGB |
| 304 | 16, // RG8U | 393 | 16, // RG8U |
| 305 | 16, // RG8S | 394 | 16, // RG8S |
| 306 | 64, // RG32UI | 395 | 64, // RG32UI |
| @@ -308,6 +397,15 @@ struct SurfaceParams { | |||
| 308 | 16, // ASTC_2D_8X8 | 397 | 16, // ASTC_2D_8X8 |
| 309 | 32, // ASTC_2D_8X5 | 398 | 32, // ASTC_2D_8X5 |
| 310 | 32, // ASTC_2D_5X4 | 399 | 32, // ASTC_2D_5X4 |
| 400 | 32, // BGRA8_SRGB | ||
| 401 | 64, // DXT1_SRGB | ||
| 402 | 128, // DXT23_SRGB | ||
| 403 | 128, // DXT45_SRGB | ||
| 404 | 128, // BC7U | ||
| 405 | 32, // ASTC_2D_4X4_SRGB | ||
| 406 | 16, // ASTC_2D_8X8_SRGB | ||
| 407 | 32, // ASTC_2D_8X5_SRGB | ||
| 408 | 32, // ASTC_2D_5X4_SRGB | ||
| 311 | 32, // Z32F | 409 | 32, // Z32F |
| 312 | 16, // Z16 | 410 | 16, // Z16 |
| 313 | 32, // Z24S8 | 411 | 32, // Z24S8 |
| @@ -346,6 +444,7 @@ struct SurfaceParams { | |||
| 346 | // TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the | 444 | // TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the |
| 347 | // gamma. | 445 | // gamma. |
| 348 | case Tegra::RenderTargetFormat::RGBA8_SRGB: | 446 | case Tegra::RenderTargetFormat::RGBA8_SRGB: |
| 447 | return PixelFormat::RGBA8_SRGB; | ||
| 349 | case Tegra::RenderTargetFormat::RGBA8_UNORM: | 448 | case Tegra::RenderTargetFormat::RGBA8_UNORM: |
| 350 | return PixelFormat::ABGR8U; | 449 | return PixelFormat::ABGR8U; |
| 351 | case Tegra::RenderTargetFormat::RGBA8_SNORM: | 450 | case Tegra::RenderTargetFormat::RGBA8_SNORM: |
| @@ -353,6 +452,7 @@ struct SurfaceParams { | |||
| 353 | case Tegra::RenderTargetFormat::RGBA8_UINT: | 452 | case Tegra::RenderTargetFormat::RGBA8_UINT: |
| 354 | return PixelFormat::ABGR8UI; | 453 | return PixelFormat::ABGR8UI; |
| 355 | case Tegra::RenderTargetFormat::BGRA8_SRGB: | 454 | case Tegra::RenderTargetFormat::BGRA8_SRGB: |
| 455 | return PixelFormat::BGRA8_SRGB; | ||
| 356 | case Tegra::RenderTargetFormat::BGRA8_UNORM: | 456 | case Tegra::RenderTargetFormat::BGRA8_UNORM: |
| 357 | return PixelFormat::BGRA8; | 457 | return PixelFormat::BGRA8; |
| 358 | case Tegra::RenderTargetFormat::RGB10_A2_UNORM: | 458 | case Tegra::RenderTargetFormat::RGB10_A2_UNORM: |
| @@ -416,10 +516,14 @@ struct SurfaceParams { | |||
| 416 | } | 516 | } |
| 417 | 517 | ||
| 418 | static PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format, | 518 | static PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format, |
| 419 | Tegra::Texture::ComponentType component_type) { | 519 | Tegra::Texture::ComponentType component_type, |
| 520 | bool is_srgb) { | ||
| 420 | // TODO(Subv): Properly implement this | 521 | // TODO(Subv): Properly implement this |
| 421 | switch (format) { | 522 | switch (format) { |
| 422 | case Tegra::Texture::TextureFormat::A8R8G8B8: | 523 | case Tegra::Texture::TextureFormat::A8R8G8B8: |
| 524 | if (is_srgb) { | ||
| 525 | return PixelFormat::RGBA8_SRGB; | ||
| 526 | } | ||
| 423 | switch (component_type) { | 527 | switch (component_type) { |
| 424 | case Tegra::Texture::ComponentType::UNORM: | 528 | case Tegra::Texture::ComponentType::UNORM: |
| 425 | return PixelFormat::ABGR8U; | 529 | return PixelFormat::ABGR8U; |
| @@ -554,11 +658,11 @@ struct SurfaceParams { | |||
| 554 | case Tegra::Texture::TextureFormat::Z24S8: | 658 | case Tegra::Texture::TextureFormat::Z24S8: |
| 555 | return PixelFormat::Z24S8; | 659 | return PixelFormat::Z24S8; |
| 556 | case Tegra::Texture::TextureFormat::DXT1: | 660 | case Tegra::Texture::TextureFormat::DXT1: |
| 557 | return PixelFormat::DXT1; | 661 | return is_srgb ? PixelFormat::DXT1_SRGB : PixelFormat::DXT1; |
| 558 | case Tegra::Texture::TextureFormat::DXT23: | 662 | case Tegra::Texture::TextureFormat::DXT23: |
| 559 | return PixelFormat::DXT23; | 663 | return is_srgb ? PixelFormat::DXT23_SRGB : PixelFormat::DXT23; |
| 560 | case Tegra::Texture::TextureFormat::DXT45: | 664 | case Tegra::Texture::TextureFormat::DXT45: |
| 561 | return PixelFormat::DXT45; | 665 | return is_srgb ? PixelFormat::DXT45_SRGB : PixelFormat::DXT45; |
| 562 | case Tegra::Texture::TextureFormat::DXN1: | 666 | case Tegra::Texture::TextureFormat::DXN1: |
| 563 | return PixelFormat::DXN1; | 667 | return PixelFormat::DXN1; |
| 564 | case Tegra::Texture::TextureFormat::DXN2: | 668 | case Tegra::Texture::TextureFormat::DXN2: |
| @@ -572,19 +676,19 @@ struct SurfaceParams { | |||
| 572 | static_cast<u32>(component_type)); | 676 | static_cast<u32>(component_type)); |
| 573 | UNREACHABLE(); | 677 | UNREACHABLE(); |
| 574 | case Tegra::Texture::TextureFormat::BC7U: | 678 | case Tegra::Texture::TextureFormat::BC7U: |
| 575 | return PixelFormat::BC7U; | 679 | return is_srgb ? PixelFormat::BC7U_SRGB : PixelFormat::BC7U; |
| 576 | case Tegra::Texture::TextureFormat::BC6H_UF16: | 680 | case Tegra::Texture::TextureFormat::BC6H_UF16: |
| 577 | return PixelFormat::BC6H_UF16; | 681 | return PixelFormat::BC6H_UF16; |
| 578 | case Tegra::Texture::TextureFormat::BC6H_SF16: | 682 | case Tegra::Texture::TextureFormat::BC6H_SF16: |
| 579 | return PixelFormat::BC6H_SF16; | 683 | return PixelFormat::BC6H_SF16; |
| 580 | case Tegra::Texture::TextureFormat::ASTC_2D_4X4: | 684 | case Tegra::Texture::TextureFormat::ASTC_2D_4X4: |
| 581 | return PixelFormat::ASTC_2D_4X4; | 685 | return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4; |
| 582 | case Tegra::Texture::TextureFormat::ASTC_2D_5X4: | 686 | case Tegra::Texture::TextureFormat::ASTC_2D_5X4: |
| 583 | return PixelFormat::ASTC_2D_5X4; | 687 | return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4; |
| 584 | case Tegra::Texture::TextureFormat::ASTC_2D_8X8: | 688 | case Tegra::Texture::TextureFormat::ASTC_2D_8X8: |
| 585 | return PixelFormat::ASTC_2D_8X8; | 689 | return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8; |
| 586 | case Tegra::Texture::TextureFormat::ASTC_2D_8X5: | 690 | case Tegra::Texture::TextureFormat::ASTC_2D_8X5: |
| 587 | return PixelFormat::ASTC_2D_8X5; | 691 | return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5; |
| 588 | case Tegra::Texture::TextureFormat::R16_G16: | 692 | case Tegra::Texture::TextureFormat::R16_G16: |
| 589 | switch (component_type) { | 693 | switch (component_type) { |
| 590 | case Tegra::Texture::ComponentType::FLOAT: | 694 | case Tegra::Texture::ComponentType::FLOAT: |
| @@ -819,7 +923,7 @@ struct SurfaceParams { | |||
| 819 | SurfaceTarget target; | 923 | SurfaceTarget target; |
| 820 | u32 max_mip_level; | 924 | u32 max_mip_level; |
| 821 | bool is_layered; | 925 | bool is_layered; |
| 822 | 926 | bool srgb_conversion; | |
| 823 | // Parameters used for caching | 927 | // Parameters used for caching |
| 824 | VAddr addr; | 928 | VAddr addr; |
| 825 | Tegra::GPUVAddr gpu_addr; | 929 | Tegra::GPUVAddr gpu_addr; |
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index ba6c6919a..d8a43cc94 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -11,9 +11,10 @@ | |||
| 11 | namespace OpenGL { | 11 | namespace OpenGL { |
| 12 | 12 | ||
| 13 | OpenGLState OpenGLState::cur_state; | 13 | OpenGLState OpenGLState::cur_state; |
| 14 | 14 | bool OpenGLState::s_rgb_used; | |
| 15 | OpenGLState::OpenGLState() { | 15 | OpenGLState::OpenGLState() { |
| 16 | // These all match default OpenGL values | 16 | // These all match default OpenGL values |
| 17 | framebuffer_srgb.enabled = false; | ||
| 17 | cull.enabled = false; | 18 | cull.enabled = false; |
| 18 | cull.mode = GL_BACK; | 19 | cull.mode = GL_BACK; |
| 19 | cull.front_face = GL_CCW; | 20 | cull.front_face = GL_CCW; |
| @@ -24,6 +25,9 @@ OpenGLState::OpenGLState() { | |||
| 24 | depth.depth_range_near = 0.0f; | 25 | depth.depth_range_near = 0.0f; |
| 25 | depth.depth_range_far = 1.0f; | 26 | depth.depth_range_far = 1.0f; |
| 26 | 27 | ||
| 28 | primitive_restart.enabled = false; | ||
| 29 | primitive_restart.index = 0; | ||
| 30 | |||
| 27 | color_mask.red_enabled = GL_TRUE; | 31 | color_mask.red_enabled = GL_TRUE; |
| 28 | color_mask.green_enabled = GL_TRUE; | 32 | color_mask.green_enabled = GL_TRUE; |
| 29 | color_mask.blue_enabled = GL_TRUE; | 33 | color_mask.blue_enabled = GL_TRUE; |
| @@ -86,6 +90,16 @@ OpenGLState::OpenGLState() { | |||
| 86 | } | 90 | } |
| 87 | 91 | ||
| 88 | void OpenGLState::Apply() const { | 92 | void OpenGLState::Apply() const { |
| 93 | // sRGB | ||
| 94 | if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) { | ||
| 95 | if (framebuffer_srgb.enabled) { | ||
| 96 | // Track if sRGB is used | ||
| 97 | s_rgb_used = true; | ||
| 98 | glEnable(GL_FRAMEBUFFER_SRGB); | ||
| 99 | } else { | ||
| 100 | glDisable(GL_FRAMEBUFFER_SRGB); | ||
| 101 | } | ||
| 102 | } | ||
| 89 | // Culling | 103 | // Culling |
| 90 | if (cull.enabled != cur_state.cull.enabled) { | 104 | if (cull.enabled != cur_state.cull.enabled) { |
| 91 | if (cull.enabled) { | 105 | if (cull.enabled) { |
| @@ -127,6 +141,18 @@ void OpenGLState::Apply() const { | |||
| 127 | glDepthRange(depth.depth_range_near, depth.depth_range_far); | 141 | glDepthRange(depth.depth_range_near, depth.depth_range_far); |
| 128 | } | 142 | } |
| 129 | 143 | ||
| 144 | // Primitive restart | ||
| 145 | if (primitive_restart.enabled != cur_state.primitive_restart.enabled) { | ||
| 146 | if (primitive_restart.enabled) { | ||
| 147 | glEnable(GL_PRIMITIVE_RESTART); | ||
| 148 | } else { | ||
| 149 | glDisable(GL_PRIMITIVE_RESTART); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | if (primitive_restart.index != cur_state.primitive_restart.index) { | ||
| 153 | glPrimitiveRestartIndex(primitive_restart.index); | ||
| 154 | } | ||
| 155 | |||
| 130 | // Color mask | 156 | // Color mask |
| 131 | if (color_mask.red_enabled != cur_state.color_mask.red_enabled || | 157 | if (color_mask.red_enabled != cur_state.color_mask.red_enabled || |
| 132 | color_mask.green_enabled != cur_state.color_mask.green_enabled || | 158 | color_mask.green_enabled != cur_state.color_mask.green_enabled || |
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index daf7eb533..9e2c573b5 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -36,6 +36,10 @@ constexpr TextureUnit ProcTexDiffLUT{9}; | |||
| 36 | class OpenGLState { | 36 | class OpenGLState { |
| 37 | public: | 37 | public: |
| 38 | struct { | 38 | struct { |
| 39 | bool enabled; // GL_FRAMEBUFFER_SRGB | ||
| 40 | } framebuffer_srgb; | ||
| 41 | |||
| 42 | struct { | ||
| 39 | bool enabled; // GL_CULL_FACE | 43 | bool enabled; // GL_CULL_FACE |
| 40 | GLenum mode; // GL_CULL_FACE_MODE | 44 | GLenum mode; // GL_CULL_FACE_MODE |
| 41 | GLenum front_face; // GL_FRONT_FACE | 45 | GLenum front_face; // GL_FRONT_FACE |
| @@ -50,6 +54,11 @@ public: | |||
| 50 | } depth; | 54 | } depth; |
| 51 | 55 | ||
| 52 | struct { | 56 | struct { |
| 57 | bool enabled; | ||
| 58 | GLuint index; | ||
| 59 | } primitive_restart; // GL_PRIMITIVE_RESTART | ||
| 60 | |||
| 61 | struct { | ||
| 53 | GLboolean red_enabled; | 62 | GLboolean red_enabled; |
| 54 | GLboolean green_enabled; | 63 | GLboolean green_enabled; |
| 55 | GLboolean blue_enabled; | 64 | GLboolean blue_enabled; |
| @@ -156,7 +165,12 @@ public: | |||
| 156 | static OpenGLState GetCurState() { | 165 | static OpenGLState GetCurState() { |
| 157 | return cur_state; | 166 | return cur_state; |
| 158 | } | 167 | } |
| 159 | 168 | static bool GetsRGBUsed() { | |
| 169 | return s_rgb_used; | ||
| 170 | } | ||
| 171 | static void ClearsRGBUsed() { | ||
| 172 | s_rgb_used = false; | ||
| 173 | } | ||
| 160 | /// Apply this state as the current OpenGL state | 174 | /// Apply this state as the current OpenGL state |
| 161 | void Apply() const; | 175 | void Apply() const; |
| 162 | 176 | ||
| @@ -171,6 +185,9 @@ public: | |||
| 171 | 185 | ||
| 172 | private: | 186 | private: |
| 173 | static OpenGLState cur_state; | 187 | static OpenGLState cur_state; |
| 188 | // Workaround for sRGB problems caused by | ||
| 189 | // QT not supporting srgb output | ||
| 190 | static bool s_rgb_used; | ||
| 174 | }; | 191 | }; |
| 175 | 192 | ||
| 176 | } // namespace OpenGL | 193 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 96d916b07..90b68943d 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -283,7 +283,8 @@ void RendererOpenGL::CreateRasterizer() { | |||
| 283 | if (rasterizer) { | 283 | if (rasterizer) { |
| 284 | return; | 284 | return; |
| 285 | } | 285 | } |
| 286 | 286 | // Initialize sRGB Usage | |
| 287 | OpenGLState::ClearsRGBUsed(); | ||
| 287 | rasterizer = std::make_unique<RasterizerOpenGL>(render_window, screen_info); | 288 | rasterizer = std::make_unique<RasterizerOpenGL>(render_window, screen_info); |
| 288 | } | 289 | } |
| 289 | 290 | ||
| @@ -356,13 +357,20 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, | |||
| 356 | 357 | ||
| 357 | state.texture_units[0].texture = screen_info.display_texture; | 358 | state.texture_units[0].texture = screen_info.display_texture; |
| 358 | state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; | 359 | state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; |
| 360 | // Workaround brigthness problems in SMO by enabling sRGB in the final output | ||
| 361 | // if it has been used in the frame | ||
| 362 | // Needed because of this bug in QT | ||
| 363 | // QTBUG-50987 | ||
| 364 | state.framebuffer_srgb.enabled = OpenGLState::GetsRGBUsed(); | ||
| 359 | state.Apply(); | 365 | state.Apply(); |
| 360 | |||
| 361 | glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data()); | 366 | glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data()); |
| 362 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | 367 | glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| 363 | 368 | // restore default state | |
| 369 | state.framebuffer_srgb.enabled = false; | ||
| 364 | state.texture_units[0].texture = 0; | 370 | state.texture_units[0].texture = 0; |
| 365 | state.Apply(); | 371 | state.Apply(); |
| 372 | // Clear sRGB state for the next frame | ||
| 373 | OpenGLState::ClearsRGBUsed(); | ||
| 366 | } | 374 | } |
| 367 | 375 | ||
| 368 | /** | 376 | /** |
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index 5947bd2b9..d12d2ecb8 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h | |||
| @@ -173,6 +173,7 @@ struct TICEntry { | |||
| 173 | }; | 173 | }; |
| 174 | union { | 174 | union { |
| 175 | BitField<0, 16, u32> width_minus_1; | 175 | BitField<0, 16, u32> width_minus_1; |
| 176 | BitField<22, 1, u32> srgb_conversion; | ||
| 176 | BitField<23, 4, TextureType> texture_type; | 177 | BitField<23, 4, TextureType> texture_type; |
| 177 | }; | 178 | }; |
| 178 | union { | 179 | union { |
| @@ -227,6 +228,10 @@ struct TICEntry { | |||
| 227 | return header_version == TICHeaderVersion::BlockLinear || | 228 | return header_version == TICHeaderVersion::BlockLinear || |
| 228 | header_version == TICHeaderVersion::BlockLinearColorKey; | 229 | header_version == TICHeaderVersion::BlockLinearColorKey; |
| 229 | } | 230 | } |
| 231 | |||
| 232 | bool IsSrgbConversionEnabled() const { | ||
| 233 | return srgb_conversion != 0; | ||
| 234 | } | ||
| 230 | }; | 235 | }; |
| 231 | static_assert(sizeof(TICEntry) == 0x20, "TICEntry has wrong size"); | 236 | static_assert(sizeof(TICEntry) == 0x20, "TICEntry has wrong size"); |
| 232 | 237 | ||
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 20ffb0a9a..4b34c1e28 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp | |||
| @@ -48,20 +48,40 @@ constexpr std::array<u8, 107> backup_jpeg{ | |||
| 48 | 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, | 48 | 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, |
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | std::string GetImagePath(Service::Account::UUID uuid) { | 51 | QString GetImagePath(Service::Account::UUID uuid) { |
| 52 | return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + | 52 | const auto path = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + |
| 53 | "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; | 53 | "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; |
| 54 | return QString::fromStdString(path); | ||
| 54 | } | 55 | } |
| 55 | 56 | ||
| 56 | std::string GetAccountUsername(const Service::Account::ProfileManager& manager, | 57 | QString GetAccountUsername(const Service::Account::ProfileManager& manager, |
| 57 | Service::Account::UUID uuid) { | 58 | Service::Account::UUID uuid) { |
| 58 | Service::Account::ProfileBase profile; | 59 | Service::Account::ProfileBase profile; |
| 59 | if (!manager.GetProfileBase(uuid, profile)) { | 60 | if (!manager.GetProfileBase(uuid, profile)) { |
| 60 | return ""; | 61 | return {}; |
| 61 | } | 62 | } |
| 62 | 63 | ||
| 63 | return Common::StringFromFixedZeroTerminatedBuffer( | 64 | const auto text = Common::StringFromFixedZeroTerminatedBuffer( |
| 64 | reinterpret_cast<const char*>(profile.username.data()), profile.username.size()); | 65 | reinterpret_cast<const char*>(profile.username.data()), profile.username.size()); |
| 66 | return QString::fromStdString(text); | ||
| 67 | } | ||
| 68 | |||
| 69 | QString FormatUserEntryText(const QString& username, Service::Account::UUID uuid) { | ||
| 70 | return ConfigureSystem::tr("%1\n%2", | ||
| 71 | "%1 is the profile username, %2 is the formatted UUID (e.g. " | ||
| 72 | "00112233-4455-6677-8899-AABBCCDDEEFF))") | ||
| 73 | .arg(username, QString::fromStdString(uuid.FormatSwitch())); | ||
| 74 | } | ||
| 75 | |||
| 76 | QPixmap GetIcon(Service::Account::UUID uuid) { | ||
| 77 | QPixmap icon{GetImagePath(uuid)}; | ||
| 78 | |||
| 79 | if (!icon) { | ||
| 80 | icon.fill(Qt::black); | ||
| 81 | icon.loadFromData(backup_jpeg.data(), backup_jpeg.size()); | ||
| 82 | } | ||
| 83 | |||
| 84 | return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); | ||
| 65 | } | 85 | } |
| 66 | } // Anonymous namespace | 86 | } // Anonymous namespace |
| 67 | 87 | ||
| @@ -131,18 +151,6 @@ void ConfigureSystem::setConfiguration() { | |||
| 131 | UpdateCurrentUser(); | 151 | UpdateCurrentUser(); |
| 132 | } | 152 | } |
| 133 | 153 | ||
| 134 | static QPixmap GetIcon(Service::Account::UUID uuid) { | ||
| 135 | const auto icon_url = QString::fromStdString(GetImagePath(uuid)); | ||
| 136 | QPixmap icon{icon_url}; | ||
| 137 | |||
| 138 | if (!icon) { | ||
| 139 | icon.fill(Qt::black); | ||
| 140 | icon.loadFromData(backup_jpeg.data(), backup_jpeg.size()); | ||
| 141 | } | ||
| 142 | |||
| 143 | return icon; | ||
| 144 | } | ||
| 145 | |||
| 146 | void ConfigureSystem::PopulateUserList() { | 154 | void ConfigureSystem::PopulateUserList() { |
| 147 | const auto& profiles = profile_manager->GetAllUsers(); | 155 | const auto& profiles = profile_manager->GetAllUsers(); |
| 148 | for (const auto& user : profiles) { | 156 | for (const auto& user : profiles) { |
| @@ -154,8 +162,7 @@ void ConfigureSystem::PopulateUserList() { | |||
| 154 | reinterpret_cast<const char*>(profile.username.data()), profile.username.size()); | 162 | reinterpret_cast<const char*>(profile.username.data()), profile.username.size()); |
| 155 | 163 | ||
| 156 | list_items.push_back(QList<QStandardItem*>{new QStandardItem{ | 164 | list_items.push_back(QList<QStandardItem*>{new QStandardItem{ |
| 157 | GetIcon(user).scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | 165 | GetIcon(user), FormatUserEntryText(QString::fromStdString(username), user)}}); |
| 158 | QString::fromStdString(username + '\n' + user.FormatSwitch())}}); | ||
| 159 | } | 166 | } |
| 160 | 167 | ||
| 161 | for (const auto& item : list_items) | 168 | for (const auto& item : list_items) |
| @@ -172,7 +179,7 @@ void ConfigureSystem::UpdateCurrentUser() { | |||
| 172 | scene->clear(); | 179 | scene->clear(); |
| 173 | scene->addPixmap( | 180 | scene->addPixmap( |
| 174 | GetIcon(*current_user).scaled(48, 48, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); | 181 | GetIcon(*current_user).scaled(48, 48, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); |
| 175 | ui->current_user_username->setText(QString::fromStdString(username)); | 182 | ui->current_user_username->setText(username); |
| 176 | } | 183 | } |
| 177 | 184 | ||
| 178 | void ConfigureSystem::ReadSystemSettings() {} | 185 | void ConfigureSystem::ReadSystemSettings() {} |
| @@ -248,25 +255,23 @@ void ConfigureSystem::AddUser() { | |||
| 248 | 255 | ||
| 249 | profile_manager->CreateNewUser(uuid, username.toStdString()); | 256 | profile_manager->CreateNewUser(uuid, username.toStdString()); |
| 250 | 257 | ||
| 251 | item_model->appendRow(new QStandardItem{ | 258 | item_model->appendRow(new QStandardItem{GetIcon(uuid), FormatUserEntryText(username, uuid)}); |
| 252 | GetIcon(uuid).scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | ||
| 253 | QString::fromStdString(username.toStdString() + '\n' + uuid.FormatSwitch())}); | ||
| 254 | } | 259 | } |
| 255 | 260 | ||
| 256 | void ConfigureSystem::RenameUser() { | 261 | void ConfigureSystem::RenameUser() { |
| 257 | const auto user = tree_view->currentIndex().row(); | 262 | const auto user = tree_view->currentIndex().row(); |
| 258 | const auto uuid = profile_manager->GetUser(user); | 263 | const auto uuid = profile_manager->GetUser(user); |
| 259 | ASSERT(uuid != std::nullopt); | 264 | ASSERT(uuid != std::nullopt); |
| 260 | const auto username = GetAccountUsername(*profile_manager, *uuid); | ||
| 261 | 265 | ||
| 262 | Service::Account::ProfileBase profile; | 266 | Service::Account::ProfileBase profile; |
| 263 | if (!profile_manager->GetProfileBase(*uuid, profile)) | 267 | if (!profile_manager->GetProfileBase(*uuid, profile)) |
| 264 | return; | 268 | return; |
| 265 | 269 | ||
| 266 | bool ok = false; | 270 | bool ok = false; |
| 271 | const auto old_username = GetAccountUsername(*profile_manager, *uuid); | ||
| 267 | const auto new_username = | 272 | const auto new_username = |
| 268 | QInputDialog::getText(this, tr("Enter Username"), tr("Enter a new username:"), | 273 | QInputDialog::getText(this, tr("Enter Username"), tr("Enter a new username:"), |
| 269 | QLineEdit::Normal, QString::fromStdString(username), &ok); | 274 | QLineEdit::Normal, old_username, &ok); |
| 270 | 275 | ||
| 271 | if (!ok) | 276 | if (!ok) |
| 272 | return; | 277 | return; |
| @@ -284,12 +289,8 @@ void ConfigureSystem::RenameUser() { | |||
| 284 | 289 | ||
| 285 | item_model->setItem( | 290 | item_model->setItem( |
| 286 | user, 0, | 291 | user, 0, |
| 287 | new QStandardItem{ | 292 | new QStandardItem{GetIcon(*uuid), |
| 288 | GetIcon(*uuid).scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | 293 | FormatUserEntryText(QString::fromStdString(username_std), *uuid)}); |
| 289 | tr("%1\n%2", "%1 is the profile username, %2 is the formatted UUID (e.g. " | ||
| 290 | "00112233-4455-6677-8899-AABBCCDDEEFF))") | ||
| 291 | .arg(QString::fromStdString(username_std), | ||
| 292 | QString::fromStdString(uuid->FormatSwitch()))}); | ||
| 293 | UpdateCurrentUser(); | 294 | UpdateCurrentUser(); |
| 294 | } | 295 | } |
| 295 | 296 | ||
| @@ -299,10 +300,9 @@ void ConfigureSystem::DeleteUser() { | |||
| 299 | ASSERT(uuid != std::nullopt); | 300 | ASSERT(uuid != std::nullopt); |
| 300 | const auto username = GetAccountUsername(*profile_manager, *uuid); | 301 | const auto username = GetAccountUsername(*profile_manager, *uuid); |
| 301 | 302 | ||
| 302 | const auto confirm = | 303 | const auto confirm = QMessageBox::question( |
| 303 | QMessageBox::question(this, tr("Confirm Delete"), | 304 | this, tr("Confirm Delete"), |
| 304 | tr("You are about to delete user with name %1. Are you sure?") | 305 | tr("You are about to delete user with name \"%1\". Are you sure?").arg(username)); |
| 305 | .arg(QString::fromStdString(username))); | ||
| 306 | 306 | ||
| 307 | if (confirm == QMessageBox::No) | 307 | if (confirm == QMessageBox::No) |
| 308 | return; | 308 | return; |
| @@ -325,28 +325,47 @@ void ConfigureSystem::SetUserImage() { | |||
| 325 | const auto index = tree_view->currentIndex().row(); | 325 | const auto index = tree_view->currentIndex().row(); |
| 326 | const auto uuid = profile_manager->GetUser(index); | 326 | const auto uuid = profile_manager->GetUser(index); |
| 327 | ASSERT(uuid != std::nullopt); | 327 | ASSERT(uuid != std::nullopt); |
| 328 | const auto username = GetAccountUsername(*profile_manager, *uuid); | ||
| 329 | 328 | ||
| 330 | const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(), | 329 | const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(), |
| 331 | tr("JPEG Images (*.jpg *.jpeg)")); | 330 | tr("JPEG Images (*.jpg *.jpeg)")); |
| 332 | 331 | ||
| 333 | if (file.isEmpty()) | 332 | if (file.isEmpty()) { |
| 334 | return; | 333 | return; |
| 334 | } | ||
| 335 | |||
| 336 | const auto image_path = GetImagePath(*uuid); | ||
| 337 | if (QFile::exists(image_path) && !QFile::remove(image_path)) { | ||
| 338 | QMessageBox::warning( | ||
| 339 | this, tr("Error deleting image"), | ||
| 340 | tr("Error occurred attempting to overwrite previous image at: %1.").arg(image_path)); | ||
| 341 | return; | ||
| 342 | } | ||
| 335 | 343 | ||
| 336 | FileUtil::Delete(GetImagePath(*uuid)); | 344 | const auto raw_path = QString::fromStdString( |
| 345 | FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000010"); | ||
| 346 | const QFileInfo raw_info{raw_path}; | ||
| 347 | if (raw_info.exists() && !raw_info.isDir() && !QFile::remove(raw_path)) { | ||
| 348 | QMessageBox::warning(this, tr("Error deleting file"), | ||
| 349 | tr("Unable to delete existing file: %1.").arg(raw_path)); | ||
| 350 | return; | ||
| 351 | } | ||
| 337 | 352 | ||
| 338 | const auto raw_path = | 353 | const QString absolute_dst_path = QFileInfo{image_path}.absolutePath(); |
| 339 | FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000010"; | 354 | if (!QDir{raw_path}.mkpath(absolute_dst_path)) { |
| 340 | if (FileUtil::Exists(raw_path) && !FileUtil::IsDirectory(raw_path)) | 355 | QMessageBox::warning( |
| 341 | FileUtil::Delete(raw_path); | 356 | this, tr("Error creating user image directory"), |
| 357 | tr("Unable to create directory %1 for storing user images.").arg(absolute_dst_path)); | ||
| 358 | return; | ||
| 359 | } | ||
| 342 | 360 | ||
| 343 | FileUtil::CreateFullPath(GetImagePath(*uuid)); | 361 | if (!QFile::copy(file, image_path)) { |
| 344 | FileUtil::Copy(file.toStdString(), GetImagePath(*uuid)); | 362 | QMessageBox::warning(this, tr("Error copying user image"), |
| 363 | tr("Unable to copy image from %1 to %2").arg(file, image_path)); | ||
| 364 | return; | ||
| 365 | } | ||
| 345 | 366 | ||
| 346 | item_model->setItem( | 367 | const auto username = GetAccountUsername(*profile_manager, *uuid); |
| 347 | index, 0, | 368 | item_model->setItem(index, 0, |
| 348 | new QStandardItem{ | 369 | new QStandardItem{GetIcon(*uuid), FormatUserEntryText(username, *uuid)}); |
| 349 | GetIcon(*uuid).scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), | ||
| 350 | QString::fromStdString(username + '\n' + uuid->FormatSwitch())}); | ||
| 351 | UpdateCurrentUser(); | 370 | UpdateCurrentUser(); |
| 352 | } | 371 | } |