diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1d1e343..e19959e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,7 +5,7 @@ on: [push, pull_request] jobs: build: runs-on: ubuntu-latest - container: devkitpro/devkita64:20220216 + container: devkitpro/devkita64:latest steps: - name: Install 7z @@ -19,7 +19,6 @@ jobs: run: | make -C common -j$(nproc) make dist -j$(nproc) - make dist-chl -j$(nproc) - uses: actions/upload-artifact@master with: diff --git a/.gitmodules b/.gitmodules index 690b529..4e2e506 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,6 @@ [submodule "lib/inih/inih"] path = lib/inih/inih url = https://github.com/benhoyt/inih.git -[submodule "lib/libstratosphere/libstratosphere"] - path = lib/libstratosphere/libstratosphere - url = https://github.com/averne/libstratosphere.git [submodule "lib/libtesla"] path = lib/libtesla url = https://github.com/WerWolv/libtesla.git diff --git a/.vscode/Fizeau.code-workspace b/.vscode/Fizeau.code-workspace deleted file mode 100644 index fbb3503..0000000 --- a/.vscode/Fizeau.code-workspace +++ /dev/null @@ -1,14 +0,0 @@ -{ - "folders": [ - { - "path": ".." - }, - { - "path": "../../../libnx" - } - ], - "settings": { - "licenser.license": "GPLv2", - "licenser.projectName": "Fizeau" - } -} \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 419c02e..c1fa30b 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -8,7 +8,6 @@ "${workspaceFolder}/lib/imgui/include", "${workspaceFolder}/lib/imgui-nx/include", "${workspaceFolder}/lib/inih/include", - "${workspaceFolder}/lib/libstratosphere/include", "${workspaceFolder}/lib/nvjpg/oss-nvjpg/include", "${workspaceFolder}/lib/libtesla/include", @@ -22,20 +21,16 @@ "${DEVKITPRO}/portlibs/switch/include", "${DEVKITPRO}/devkitA64/aarch64-none-elf/include", - "${DEVKITPRO}/devkitA64/lib/gcc/aarch64-none-elf/*/include", - - "/usr/include" + "${DEVKITPRO}/devkitA64/lib/gcc/aarch64-none-elf/*/include" ], "defines": [ "__aarch64__", "__SWITCH__", - "DEBUG", + // "DEBUG", "SYSMODULE", // "TWILI", "VERSION=\"0.0.0\"", - "COMMIT=\"0000000\"", - "ATMOSPHERE_IS_STRATOSPHERE", - "ATMOSPHERE_BOARD_NINTENDO_SWITCH" + "COMMIT=\"0000000\"" ], "compilerPath": "${DEVKITPRO}/devkitA64/bin/aarch64-none-elf-gcc", "cStandard": "gnu11", diff --git a/.vscode/settings.json b/.vscode/settings.json index 6ef4c29..a2206c3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,4 @@ "*.nacp": true, "*.nro": true }, - "licenser.license": "GPLv2", - "licenser.projectName": "Fizeau", } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 4152443..132b599 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -46,6 +46,7 @@ "command": "make", "args": [ "application", + "overlay", "sysmodule", "clean" ], @@ -68,102 +69,6 @@ }, "problemMatcher": [] }, - { - "label": "application all", - "type": "shell", - "command": "make", - "args": [ - "application", - "-j$(nproc)" - ], - "presentation": { - "reveal": "always", - "panel": "shared", - "clear": true - }, - "problemMatcher": { - "base": "$gcc", - "fileLocation": "absolute" - } - }, - { - "label": "application clean", - "type": "shell", - "command": "make", - "args": [ - "application", - "clean" - ], - "presentation": { - "panel": "shared", - "reveal": "never" - }, - "problemMatcher": [] - }, - { - "label": "sysmodule all", - "type": "shell", - "command": "make", - "args": [ - "sysmodule", - "-j$(nproc)" - ], - "presentation": { - "reveal": "always", - "panel": "shared", - "clear": true - }, - "problemMatcher": { - "base": "$gcc", - "fileLocation": "absolute" - } - }, - { - "label": "sysmodule clean", - "type": "shell", - "command": "make", - "args": [ - "sysmodule", - "clean" - ], - "presentation": { - "panel": "shared", - "reveal": "never" - }, - "problemMatcher": [] - }, - { - "label": "overlay all", - "type": "shell", - "command": "make", - "args": [ - "overlay", - "-j$(nproc)" - ], - "presentation": { - "reveal": "always", - "panel": "shared", - "clear": true - }, - "problemMatcher": { - "base": "$gcc", - "fileLocation": "absolute" - } - }, - { - "label": "overlay clean", - "type": "shell", - "command": "make", - "args": [ - "overlay", - "clean" - ], - "presentation": { - "panel": "shared", - "reveal": "never" - }, - "problemMatcher": [] - }, { "label": "application run", "type": "shell", diff --git a/Makefile b/Makefile index 6191a6d..2968149 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,6 @@ export FZ_VERSION = 2.4.3 export FZ_COMMIT = $(shell git rev-parse --short HEAD) export FZ_TID = 0100000000000F12 -export FZ_CHL_TID = 010000000000CF12 # Vscode fails to parse non-english error codes export LANG = en @@ -16,13 +15,12 @@ export FZ_COMMIT := $(addsuffix -dirty,$(FZ_COMMIT)) endif DIST_TARGET = $(OUT)/Fizeau-$(FZ_VERSION)-$(FZ_COMMIT).zip -DIST_CHL_TARGET = $(OUT)/Fizeau-chl-$(FZ_VERSION)-$(FZ_COMMIT).zip # ----------------------------------------------- -MODULES = application sysmodule overlay chainloader +MODULES = application sysmodule overlay -.PHONY: all dist dist-chl clean mrproper $(MODULES) +.PHONY: all dist clean mrproper $(MODULES) all: $(MODULES) @: @@ -30,7 +28,7 @@ all: $(MODULES) dist: $(DIST_TARGET) @: -$(DIST_TARGET): | application overlay sysmodule +$(DIST_TARGET): | all @rm -rf $(OUT)/Fizeau-?.?.?-*.zip @mkdir -p $(OUT)/config/Fizeau @@ -50,32 +48,6 @@ $(DIST_TARGET): | application overlay sysmodule @rm -r $(OUT)/atmosphere $(OUT)/config $(OUT)/switch @echo Compressed release to $@ -dist-chl: $(DIST_CHL_TARGET) - @: - -$(DIST_CHL_TARGET): | all - @rm -rf $(OUT)/Fizeau-chl*.zip - - @mkdir -p $(OUT)/config/Fizeau - @mkdir -p $(OUT)/switch/Fizeau - @cp misc/default.ini $(OUT)/config/Fizeau/config.ini - @cp application/out/Fizeau.nro $(OUT)/switch/Fizeau/Fizeau.nro - - @mkdir -p $(OUT)/switch/.overlays - @cp overlay/out/Fizeau.ovl $(OUT)/switch/.overlays/Fizeau.ovl - - @mkdir -p $(OUT)/atmosphere/contents/$(FZ_TID) - @cp sysmodule/out/Fizeau.nsp $(OUT)/atmosphere/contents/$(FZ_TID)/exefs.nsp - - @mkdir -p $(OUT)/atmosphere/contents/$(FZ_CHL_TID)/flags - @cp chainloader/out/Fizeau-chl.nsp $(OUT)/atmosphere/contents/$(FZ_CHL_TID)/exefs.nsp - @cp chainloader/toolbox.json $(OUT)/atmosphere/contents/$(FZ_CHL_TID)/toolbox.json - @touch $(OUT)/atmosphere/contents/$(FZ_CHL_TID)/flags/boot2.flag - - @7z a $@ ./$(OUT)/atmosphere ./$(OUT)/config ./$(OUT)/switch >/dev/null - @rm -r $(OUT)/atmosphere $(OUT)/config $(OUT)/switch - @echo Compressed release to $@ - clean: @rm -rf out @@ -83,16 +55,13 @@ mrproper: clean @for dir in $(MODULES); do $(MAKE) --no-print-directory -C $$dir mrproper; done application: - @$(MAKE) -s -C $@ $(filter-out $(MODULES) dist dist-chl,$(MAKECMDGOALS)) --no-print-directory + @$(MAKE) -s -C $@ $(filter-out $(MODULES) dist,$(MAKECMDGOALS)) --no-print-directory sysmodule: - @$(MAKE) -s -C $@ $(filter-out $(MODULES) dist dist-chl,$(MAKECMDGOALS)) --no-print-directory + @$(MAKE) -s -C $@ $(filter-out $(MODULES) dist,$(MAKECMDGOALS)) --no-print-directory overlay: - @$(MAKE) -s -C $@ $(filter-out $(MODULES) dist dist-chl,$(MAKECMDGOALS)) --no-print-directory - -chainloader: - @$(MAKE) -s -C $@ $(filter-out $(MODULES) dist dist-chl,$(MAKECMDGOALS)) --no-print-directory + @$(MAKE) -s -C $@ $(filter-out $(MODULES) dist,$(MAKECMDGOALS)) --no-print-directory %: @: diff --git a/application/Makefile b/application/Makefile index a62e888..b42bf5a 100644 --- a/application/Makefile +++ b/application/Makefile @@ -22,8 +22,7 @@ CUSTOM_LIBS = ../common ../lib/imgui-nx ../lib/imgui ../lib/inih ../lib ROMFS = res DEFINES = __SWITCH__ VERSION=\"$(FZ_VERSION)\" COMMIT=\"$(FZ_COMMIT)\" \ - ATMOSPHERE_IS_STRATOSPHERE ATMOSPHERE_BOARD_NINTENDO_NX \ - ATMOSPHERE_ARCH_ARM64 ATMOSPHERE_OS_HORIZON APPLICATION TWILI + APPLICATION NXLINK ARCH = -march=armv8-a+crc+crypto+simd -mtune=cortex-a57 -mtp=soft -fpie FLAGS = -Wall -pipe -g -O2 -ffunction-sections -fdata-sections CFLAGS = -std=gnu11 diff --git a/application/src/gfx.cpp b/application/src/gfx.cpp index 0b0b4ce..dd7df33 100644 --- a/application/src/gfx.cpp +++ b/application/src/gfx.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -259,7 +259,7 @@ void exit() { deko3dExit(); } -void register_texture(dk::MemBlock memblk, dk::Image &image, const nj::Surface &surf, std::uint32_t sampler_id, std::uint32_t image_id) { +void register_texture(dk::MemBlock &memblk, dk::Image &image, const nj::Surface &surf, std::uint32_t sampler_id, std::uint32_t image_id) { // upload data to deko3d std::tie(memblk, image) = surf.to_deko3d(s_device, 0); diff --git a/application/src/gfx.hpp b/application/src/gfx.hpp index 22bc003..e936cf3 100644 --- a/application/src/gfx.hpp +++ b/application/src/gfx.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -29,6 +29,6 @@ bool loop(); void render(); void exit(); -void register_texture(dk::MemBlock memblk, dk::Image &image, const nj::Surface &surf, std::uint32_t sampler_id, std::uint32_t image_id); +void register_texture(dk::MemBlock &memblk, dk::Image &image, const nj::Surface &surf, std::uint32_t sampler_id, std::uint32_t image_id); } // namespace fz::gfx diff --git a/application/src/gui.cpp b/application/src/gui.cpp index 680f4a4..3e1d321 100644 --- a/application/src/gui.cpp +++ b/application/src/gui.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -15,10 +15,10 @@ // You should have received a copy of the GNU General Public License // along with Fizeau. If not, see . +#include #include #include #include -#include #include #include "swkbd.hpp" @@ -60,7 +60,7 @@ bool new_slider(auto name, auto label, T &val, T min, T max, auto fmt, Args &&.. auto slider_pos = im::GetWindowPos().x + 0.04f * width; bool ret = false; im::PushItemWidth(im::GetWindowWidth() - 0.08f * width); - ON_SCOPE_EXIT { im::PopItemWidth(); }; + FZ_SCOPEGUARD([] { im::PopItemWidth(); }); im::TextUnformatted(name); im::SameLine(); im::SetCursorPosX(slider_pos); if constexpr (std::is_floating_point_v) { ret |= im::SliderFloat(label, reinterpret_cast(&val), min, max, fmt); @@ -82,7 +82,7 @@ bool new_combo(auto name, auto label, auto &val, const std::array(&ctx.active_internal_profile), profile_names.data(), profile_names.size())) - R_TRY(fizeauSetActiveInternalProfileId(ctx.active_internal_profile)); + if (im::Combo("##activeintp", reinterpret_cast(&ctx.internal_profile), profile_names.data(), profile_names.size())) { + if (auto rc = fizeauSetActiveProfileId(false, ctx.internal_profile); R_FAILED(rc)) + return rc; + } im::TextUnformatted("Active docked profile:"); - if (im::Combo("##activeextp", reinterpret_cast(&ctx.active_external_profile), profile_names.data(), profile_names.size())) - R_TRY(fizeauSetActiveExternalProfileId(ctx.active_external_profile)); + if (im::Combo("##activeextp", reinterpret_cast(&ctx.external_profile), profile_names.data(), profile_names.size())) { + if (auto rc = fizeauSetActiveProfileId(true, ctx.external_profile); R_FAILED(rc)) + return rc; + } im::Separator(); im::TextUnformatted("Currently editing profile:"); - if (im::Combo("##editp", reinterpret_cast(&ctx.cur_profile_id), profile_names.data(), profile_names.size())) - R_TRY(cfg::open_profile(ctx, ctx.cur_profile_id)); + if (im::Combo("##editp", reinterpret_cast(&ctx.cur_profile_id), profile_names.data(), profile_names.size())) { + if (auto rc = ctx.open_profile(ctx.cur_profile_id); R_FAILED(rc)) + return rc; + } if (im::Button("Apply")) { - R_TRY(cfg::apply(ctx)); + if (auto rc = ctx.apply(); R_FAILED(rc)) + return rc; ctx.is_editing_day_profile = ctx.is_editing_night_profile = false; } im::SameLine(); if (im::Button("Reset")) { - R_TRY(cfg::reset(ctx)); + ctx.reset(); ctx.is_editing_day_profile = ctx.is_editing_night_profile = false; } @@ -196,68 +203,64 @@ Result draw_profile_tab(cfg::Config &ctx) { return 0; } -Result draw_color_tab(cfg::Config &ctx) { +Result draw_color_tab(Config &ctx) { if (!im::BeginTabItem("Colors")) return 0; static bool enable_extra_hot_temps = false; - if ((ctx.temperature_day > D65_TEMP) ||(ctx.temperature_night > D65_TEMP)) + if ((ctx.profile.day_settings.temperature > D65_TEMP) ||(ctx.profile.night_settings.temperature > D65_TEMP)) enable_extra_hot_temps = true; - // Temperature slider + // Temperature sliders im::TextUnformatted("Temperature"); auto max_temp = enable_extra_hot_temps ? MAX_TEMP : D65_TEMP; - ctx.is_editing_day_profile |= new_slider("Day:", "##tempd", ctx.temperature_day, MIN_TEMP, max_temp, "%d°K"); - ctx.is_editing_night_profile |= new_slider("Night:", "##tempn", ctx.temperature_night, MIN_TEMP, max_temp, "%d°K"); + ctx.is_editing_day_profile |= new_slider("Day:", "##tempd", ctx.profile.day_settings.temperature, MIN_TEMP, max_temp, "%d°K"); + ctx.is_editing_night_profile |= new_slider("Night:", "##tempn", ctx.profile.night_settings.temperature, MIN_TEMP, max_temp, "%d°K"); im::Checkbox("Enable blue temperatures", &enable_extra_hot_temps); im::Separator(); - im::TextUnformatted("Filter"); - ctx.is_editing_day_profile |= new_combo("Day:", "##filterd", ctx.filter_day, filters_names); - ctx.is_editing_night_profile |= new_combo("Night:", "##filtern", ctx.filter_night, filters_names); - // Brightness slider - if (ctx.cur_profile_id != ctx.active_external_profile) { - im::Separator(); - im::TextUnformatted("Screen brightness"); - ctx.is_editing_day_profile |= new_slider("Day:", "##brightd", ctx.brightness_day, MIN_BRIGHTNESS, MAX_BRIGHTNESS, "%.2f"); - ctx.is_editing_night_profile |= new_slider("Night:", "##brightn", ctx.brightness_night, MIN_BRIGHTNESS, MAX_BRIGHTNESS, "%.2f"); - } + // Filter combos + im::TextUnformatted("Filter"); + ctx.is_editing_day_profile |= new_combo("Day:", "##filterd", ctx.profile.day_settings.filter, filters_names); + ctx.is_editing_night_profile |= new_combo("Night:", "##filtern", ctx.profile.night_settings.filter, filters_names); im::EndTabItem(); return 0; } -Result draw_correction_tab(cfg::Config &ctx) { +Result draw_correction_tab(Config &ctx) { if (!im::BeginTabItem("Correction")) return 0; - // Gamma slider + // Gamma sliders im::TextUnformatted("Gamma"); - ctx.is_editing_day_profile |= new_slider("Day:", "##gammad", ctx.gamma_day, MIN_GAMMA, MAX_GAMMA, "%.2f"); - ctx.is_editing_night_profile |= new_slider("Night:", "##gamman", ctx.gamma_night, MIN_GAMMA, MAX_GAMMA, "%.2f"); + ctx.is_editing_day_profile |= new_slider("Day:", "##gammad", ctx.profile.day_settings.gamma, MIN_GAMMA, MAX_GAMMA, "%.2f"); + ctx.is_editing_night_profile |= new_slider("Night:", "##gamman", ctx.profile.night_settings.gamma, MIN_GAMMA, MAX_GAMMA, "%.2f"); + // Saturation sliders im::TextUnformatted("Saturation"); - ctx.is_editing_day_profile |= new_slider("Day:", "##satd", ctx.sat_day, MIN_SAT, MAX_SAT, "%.2f"); - ctx.is_editing_night_profile |= new_slider("Night:", "##satn", ctx.sat_night, MIN_SAT, MAX_SAT, "%.2f"); + ctx.is_editing_day_profile |= new_slider("Day:", "##satd", ctx.profile.day_settings.saturation, MIN_SAT, MAX_SAT, "%.2f"); + ctx.is_editing_night_profile |= new_slider("Night:", "##satn", ctx.profile.night_settings.saturation, MIN_SAT, MAX_SAT, "%.2f"); - // Luminance slider im::Separator(); + + // Luminance sliders im::TextUnformatted("Luminance"); - ctx.is_editing_day_profile |= new_slider("Day:", "##lumad", ctx.luminance_day, MIN_LUMA, MAX_LUMA, "%.2f", true); - ctx.is_editing_night_profile |= new_slider("Night:", "##luman", ctx.luminance_night, MIN_LUMA, MAX_LUMA, "%.2f", true); + ctx.is_editing_day_profile |= new_slider("Day:", "##lumad", ctx.profile.day_settings.luminance, MIN_LUMA, MAX_LUMA, "%.2f", true); + ctx.is_editing_night_profile |= new_slider("Night:", "##luman", ctx.profile.night_settings.luminance, MIN_LUMA, MAX_LUMA, "%.2f", true); - // Color range sliders + // Color range sliderss im::Separator(); im::TextUnformatted("Color range:"); - ctx.is_editing_day_profile |= new_range("Day:", "Full range##d", "##rangeld", "##ranghd", ctx.range_day); - ctx.is_editing_night_profile |= new_range("Night:", "Full range##n", "##rangeln", "##ranghn", ctx.range_night); + ctx.is_editing_day_profile |= new_range("Day:", "Full range##d", "##rangeld", "##ranghd", ctx.profile.day_settings.range); + ctx.is_editing_night_profile |= new_range("Night:", "Full range##n", "##rangeln", "##ranghn", ctx.profile.night_settings.range); im::EndTabItem(); return 0; } -Result draw_time_tab(cfg::Config &ctx) { +Result draw_time_tab(Config &ctx) { if (!im::BeginTabItem("Time")) return 0; @@ -269,12 +272,12 @@ Result draw_time_tab(cfg::Config &ctx) { // Dusk im::Separator(); im::TextUnformatted("Dusk:"); - has_changed |= new_times("Start:", "##dush", "##dusm", ctx.dusk_begin); - has_changed |= new_times("End:", "##dueh", "##duem", ctx.dusk_end); + has_changed |= new_times("Start:", "##dush", "##dusm", ctx.profile.dusk_begin); + has_changed |= new_times("End:", "##dueh", "##duem", ctx.profile.dusk_end); - if (ctx.dusk_end >= ctx.dusk_begin) { - auto diff = ctx.dusk_end - ctx.dusk_begin; - im::Text("Dusk will begin at %02u:%02u and last for %02uh%02um", ctx.dusk_begin.h, ctx.dusk_begin.m, diff.h, diff.m); + if (ctx.profile.dusk_end >= ctx.profile.dusk_begin) { + auto diff = ctx.profile.dusk_end - ctx.profile.dusk_begin; + im::Text("Dusk will begin at %02u:%02u and last for %02uh%02um", ctx.profile.dusk_begin.h, ctx.profile.dusk_begin.m, diff.h, diff.m); } else { im::TextColored({ 1.00f, 0.33f, 0.33f, 1.0f }, "Invalid dusk transition times!"); } @@ -282,12 +285,12 @@ Result draw_time_tab(cfg::Config &ctx) { // Dawn im::Separator(); im::TextUnformatted("Dawn:"); - has_changed |= new_times("Start:", "##dash", "##dasm", ctx.dawn_begin); - has_changed |= new_times("End:", "##daeh", "##daem", ctx.dawn_end); + has_changed |= new_times("Start:", "##dash", "##dasm", ctx.profile.dawn_begin); + has_changed |= new_times("End:", "##daeh", "##daem", ctx.profile.dawn_end); - if (ctx.dawn_end >= ctx.dawn_begin) { - auto diff = ctx.dawn_end - ctx.dawn_begin; - im::Text("Dawn will begin at %02u:%02u and last for %02uh%02um", ctx.dawn_begin.h, ctx.dawn_begin.m, diff.h, diff.m); + if (ctx.profile.dawn_end >= ctx.profile.dawn_begin) { + auto diff = ctx.profile.dawn_end - ctx.profile.dawn_begin; + im::Text("Dawn will begin at %02u:%02u and last for %02uh%02um", ctx.profile.dawn_begin.h, ctx.profile.dawn_begin.m, diff.h, diff.m); } else { im::TextColored({ 1.00f, 0.33f, 0.33f, 1.0f }, "Invalid dawn transition times!"); } @@ -300,24 +303,24 @@ Result draw_time_tab(cfg::Config &ctx) { im::Separator(); im::TextUnformatted("Dimming timeout:"); im::PushItemWidth(im::GetWindowWidth() * 0.2f); - ON_SCOPE_EXIT { im::PopItemWidth(); }; + FZ_SCOPEGUARD([] { im::PopItemWidth(); }); im::SetCursorPosX(150.0f); - int int_m = ctx.dimming_timeout.m, int_s = ctx.dimming_timeout.s; + int int_m = ctx.profile.dimming_timeout.m, int_s = ctx.profile.dimming_timeout.s; im::DragInt("##dimm", &int_m, 0.05f, 0, 59, "%02dm"); swkbd::handle("##dimm", &int_m, 0, 59); im::SameLine(); im::DragInt("##dims", &int_s, 0.05f, 0, 59, "%02ds"); swkbd::handle("##dims", &int_s, 0, 59); - ctx.dimming_timeout.m = static_cast(int_m), ctx.dimming_timeout.s = static_cast(int_s); + ctx.profile.dimming_timeout.m = static_cast(int_m), ctx.profile.dimming_timeout.s = static_cast(int_s); } im::EndTabItem(); return 0; } -Result draw_help_tab(cfg::Config &ctx) { +Result draw_help_tab(Config &ctx) { if (!im::BeginTabItem("Help")) return 0; @@ -365,15 +368,15 @@ setting.)"); } // namespace -void draw_background(cfg::Config &ctx, DkResHandle background_handle) { +void draw_background(Config &ctx, DkResHandle background_handle) { im::GetBackgroundDrawList()->AddImage(im::deko3d::makeTextureID(background_handle), { 0, 0 }, im::GetIO().DisplaySize); } -Result draw_main_window(cfg::Config &ctx) { +Result draw_main_window(Config &ctx) { if (!im::Begin("Fizeau, version " VERSION "-" COMMIT, nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove)) return 0; - ON_SCOPE_EXIT { im::End(); }; + FZ_SCOPEGUARD([] { im::End(); }); auto [width, height] = im::GetIO().DisplaySize; im::SetWindowPos( { 0.03f * width, 0.09f * height }, ImGuiCond_Always); @@ -384,7 +387,8 @@ Result draw_main_window(cfg::Config &ctx) { // Active checkbox if (im::Checkbox("Correction active", &ctx.active)) { - R_TRY(fizeauSetIsActive(ctx.active)); + if (auto rc = fizeauSetIsActive(ctx.active); R_FAILED(rc)) + return rc; ctx.has_active_override = true; } @@ -395,17 +399,27 @@ Result draw_main_window(cfg::Config &ctx) { im::Text("Time: %02d:%02d:%02d - Fps: %.2f", time.h, time.m, time.s, im::GetIO().Framerate); im::BeginTabBar("##tab_bar", ImGuiTabBarFlags_NoTooltip); - ON_SCOPE_EXIT { im::EndTabBar(); }; - R_TRY(draw_profile_tab(ctx)); - R_TRY(draw_color_tab(ctx)); - R_TRY(draw_correction_tab(ctx)); - R_TRY(draw_time_tab(ctx)); - R_TRY(draw_help_tab(ctx)); + FZ_SCOPEGUARD([] { im::EndTabBar(); }); + + if (auto rc = draw_profile_tab(ctx); R_FAILED(rc)) + return rc; + + if (auto rc = draw_color_tab(ctx); R_FAILED(rc)) + return rc; + + if (auto rc = draw_correction_tab(ctx); R_FAILED(rc)) + return rc; + + if (auto rc = draw_time_tab(ctx); R_FAILED(rc)) + return rc; + + if (auto rc = draw_help_tab(ctx); R_FAILED(rc)) + return rc; return 0; } -void draw_preview_window(cfg::Config &ctx, DkResHandle preview_handle) { +void draw_preview_window(Config &ctx, DkResHandle preview_handle) { std::array buf; std::snprintf(buf.data(), buf.size(), "Preview (%s)###preview", ctx.is_editing_day_profile ? "day" : ctx.is_editing_night_profile ? "night" : "none"); @@ -413,7 +427,7 @@ void draw_preview_window(cfg::Config &ctx, DkResHandle preview_handle) { if (!im::Begin(buf.data(), nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove)) return; - ON_SCOPE_EXIT { im::End(); }; + FZ_SCOPEGUARD([] { im::End(); }); auto [width, height] = im::GetIO().DisplaySize; im::SetWindowPos( { 0.47f * width, 0.05f * height }, ImGuiCond_Always); @@ -424,9 +438,9 @@ void draw_preview_window(cfg::Config &ctx, DkResHandle preview_handle) { float r = 1.0f, g = 1.0f, b = 1.0f; if (ctx.is_editing_day_profile) - std::tie(r, g, b) = whitepoint(ctx.temperature_day); + std::tie(r, g, b) = whitepoint(ctx.profile.day_settings.temperature); else if (ctx.is_editing_night_profile) - std::tie(r, g, b) = whitepoint(ctx.temperature_night); + std::tie(r, g, b) = whitepoint(ctx.profile.night_settings.temperature); im::Image(im::deko3d::makeTextureID(preview_handle), { 0.23f * width, 0.23f * width }); im::SameLine(); @@ -434,7 +448,7 @@ void draw_preview_window(cfg::Config &ctx, DkResHandle preview_handle) { { 0, 0 }, { 1, 1 }, { r, g, b, 1.0f }); } -void draw_graph_window(cfg::Config &ctx) { +void draw_graph_window(Config &ctx) { std::array buf; std::snprintf(buf.data(), buf.size(), "Gamma ramps (%s)###gammaramp", ctx.is_editing_day_profile ? "day" : ctx.is_editing_night_profile ? "night" : "none"); @@ -442,7 +456,7 @@ void draw_graph_window(cfg::Config &ctx) { if (!im::Begin(buf.data(), nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove)) return; - ON_SCOPE_EXIT { im::End(); }; + FZ_SCOPEGUARD([] { im::End(); }); auto [width, height] = im::GetIO().DisplaySize; im::SetWindowPos( { 0.53f * width, 0.60f * height }, ImGuiCond_Always); @@ -450,9 +464,9 @@ void draw_graph_window(cfg::Config &ctx) { Gamma gamma = DEFAULT_GAMMA; Luminance luma = DEFAULT_LUMA; ColorRange range = DEFAULT_RANGE; if (ctx.is_editing_day_profile) - gamma = ctx.gamma_day, luma = ctx.luminance_day, range = ctx.range_day; + gamma = ctx.profile.day_settings.gamma, luma = ctx.profile.day_settings.luminance, range = ctx.profile.day_settings.range; else if (ctx.is_editing_night_profile) - gamma = ctx.gamma_night, luma = ctx.luminance_night, range = ctx.range_night; + gamma = ctx.profile.night_settings.gamma, luma = ctx.profile.night_settings.luminance, range = ctx.profile.night_settings.range; // Calculate ramps std::array lut1; @@ -500,11 +514,11 @@ void draw_graph_window(cfg::Config &ctx) { new_plot(lut2_float.data(), lut2_float.size(), { 0, 1 }, { 56.0f, 255.0f, 128.0f, 255.0f }, inner_bb); } -void draw_error_window(cfg::Config &ctx, Result error) { +void draw_error_window(Config &ctx, Result error) { if (!im::Begin("Fizeau, version " VERSION "-" COMMIT, nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove)) return; - ON_SCOPE_EXIT { im::End(); }; + FZ_SCOPEGUARD([] { im::End(); }); im::Text("Error: %#x (%04d-%04d)", error, R_MODULE(error) + 2000, R_DESCRIPTION(error)); im::TextUnformatted( diff --git a/application/src/gui.hpp b/application/src/gui.hpp index aaf8cf2..d52b98b 100644 --- a/application/src/gui.hpp +++ b/application/src/gui.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -28,10 +28,10 @@ namespace im = ImGui; void init(); void exit(); -void draw_background(cfg::Config &ctx, DkResHandle background_handle); -Result draw_main_window(cfg::Config &ctx); -void draw_preview_window(cfg::Config &ctx, DkResHandle preview_handle); -void draw_graph_window(cfg::Config &ctx); -void draw_error_window(cfg::Config &ctx, Result error); +void draw_background(Config &ctx, DkResHandle background_handle); +Result draw_main_window(Config &ctx); +void draw_preview_window(Config &ctx, DkResHandle preview_handle); +void draw_graph_window(Config &ctx); +void draw_error_window(Config &ctx, Result error); } // namespace fz::gui diff --git a/application/src/main.cpp b/application/src/main.cpp index 8232f3a..10437c9 100644 --- a/application/src/main.cpp +++ b/application/src/main.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -55,7 +54,7 @@ extern "C" void userAppExit(void) { appletUnlockExit(); } -fz::cfg::Config config; +fz::Config config; int main(int argc, char **argv) { LOG("Starting Fizeau\n"); @@ -117,10 +116,19 @@ int main(int argc, char **argv) { rc = fizeauInitialize(); if (R_SUCCEEDED(rc)) - config = fz::cfg::read(); + config.read(); if (R_SUCCEEDED(rc)) - rc = fz::cfg::open_profile(config, FizeauProfileId_Profile1); + rc = fizeauSetIsActive(config.active); + + if (R_SUCCEEDED(rc)) + rc = fizeauSetActiveProfileId(false, config.internal_profile); + + if (R_SUCCEEDED(rc)) + rc = fizeauSetActiveProfileId(true, config.external_profile); + + if (R_SUCCEEDED(rc)) + rc = config.open_profile(config.internal_profile); if (R_SUCCEEDED(rc)) rc = fz::Clock::initialize(); @@ -148,10 +156,9 @@ int main(int argc, char **argv) { fz::gfx::render(); } - fz::cfg::dump(config); + config.write(); LOG("Exiting Fizeau\n"); - fizeauProfileClose(&config.cur_profile); fizeauExit(); fz::gui::exit(); diff --git a/application/src/swkbd.cpp b/application/src/swkbd.cpp index 537818b..6a66a20 100644 --- a/application/src/swkbd.cpp +++ b/application/src/swkbd.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // diff --git a/application/src/swkbd.hpp b/application/src/swkbd.hpp index cf64849..7573766 100644 --- a/application/src/swkbd.hpp +++ b/application/src/swkbd.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // diff --git a/chainloader/Makefile b/chainloader/Makefile deleted file mode 100644 index 7ae8cea..0000000 --- a/chainloader/Makefile +++ /dev/null @@ -1,141 +0,0 @@ -ifeq ($(strip $(DEVKITPRO)),) - $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") -endif - -TOPDIR ?= $(CURDIR) - -# ----------------------------------------------- - -APP_TITLE = Fizeau-chl -APP_TITLEID = - -TARGET = Fizeau-chl -EXTENSION = nsp -OUT = out -BUILD = build -SOURCES = src -INCLUDES = include ../lib/libstratosphere/libstratosphere/include -CUSTOM_LIBS = ../common/ ../lib/inih ../lib/libstratosphere -NPDM_JSON = config.json - -DEFINES = __SWITCH__ ATMOSPHERE_IS_STRATOSPHERE ATMOSPHERE_BOARD_NINTENDO_NX \ - ATMOSPHERE_ARCH_ARM64 ATMOSPHERE_OS_HORIZON SYSMODULE TWILI -ARCH = -march=armv8-a+crc+crypto+simd -mtune=cortex-a57 -mtp=soft -fpie -FLAGS = -Wall -pipe -g -Os -ffunction-sections -fdata-sections -CFLAGS = -std=gnu11 -fno-stack-protector -fno-common -flto -CXXFLAGS = -std=gnu++20 -fno-rtti -fno-exceptions -fno-non-call-exceptions \ - -fno-threadsafe-statics -fno-use-cxa-atexit \ - -fno-asynchronous-unwind-tables -fno-unwind-tables -ASFLAGS = -LDFLAGS = -Wl,--wrap,__cxa_pure_virtual \ - -Wl,--wrap,__cxa_throw \ - -Wl,--wrap,__cxa_rethrow \ - -Wl,--wrap,__cxa_allocate_exception \ - -Wl,--wrap,__cxa_free_exception \ - -Wl,--wrap,__cxa_begin_catch \ - -Wl,--wrap,__cxa_end_catch \ - -Wl,--wrap,__cxa_call_unexpected \ - -Wl,--wrap,__cxa_call_terminate \ - -Wl,--wrap,__gxx_personality_v0 \ - -Wl,--wrap,_Unwind_Resume \ - -Wl,--wrap,_ZSt19__throw_logic_errorPKc \ - -Wl,--wrap,_ZSt20__throw_length_errorPKc \ - -Wl,--wrap,_ZNSt11logic_errorC2EPKc \ - -Wl,-pie -specs=$(DEVKITPRO)/libnx/switch.specs -g -Os \ - -flto -fuse-linker-plugin -LINKS = -lcommon -linih -lstratosphere -lnx - -PREFIX = aarch64-none-elf- -CC = $(PREFIX)gcc -CXX = $(PREFIX)g++ -AS = $(PREFIX)as -LD = $(PREFIX)g++ -NM = $(PREFIX)gcc-nm - -# ----------------------------------------------- - -export PATH := $(DEVKITPRO)/tools/bin:$(DEVKITPRO)/devkitA64/bin:$(PORTLIBS)/bin:$(PATH) - -PORTLIBS = $(DEVKITPRO)/portlibs/switch -LIBNX = $(DEVKITPRO)/libnx -LIBS = $(CUSTOM_LIBS) $(LIBNX) $(PORTLIBS) - -# ----------------------------------------------- - -CFILES = $(shell find $(SOURCES) -name *.c) -CPPFILES = $(shell find $(SOURCES) -name *.cpp) -SFILES = $(shell find $(SOURCES) -name *.s -or -name *.S) -OFILES = $(CFILES:%=$(BUILD)/%.o) $(CPPFILES:%=$(BUILD)/%.o) $(SFILES:%=$(BUILD)/%.o) -DFILES = $(OFILES:.o=.d) - -LIBS_TARGET = $(shell find $(addsuffix /lib,$(CUSTOM_LIBS)) -name "*.a" 2>/dev/null) -NX_TARGET = $(if $(OUT:=), $(OUT)/$(TARGET).$(EXTENSION), .$(OUT)/$(TARGET).$(EXTENSION)) -ELF_TARGET = $(if $(OUT:=), $(OUT)/$(TARGET).elf, .$(OUT)/$(TARGET).elf) -NSO_TARGET = $(if $(BUILD:=), $(BUILD)/$(TARGET).nso, .$(BUILD)/$(TARGET).nso) -NPDM_TARGET = $(if $(OUT:=), $(OUT)/$(TARGET).npdm, .$(OUT)/$(TARGET).npdm) - -DEFINE_FLAGS = $(addprefix -D,$(DEFINES)) -INCLUDE_FLAGS = $(addprefix -I$(CURDIR)/,$(INCLUDES)) $(foreach dir,$(CUSTOM_LIBS),-I$(CURDIR)/$(dir)/include) \ - $(foreach dir,$(filter-out $(CUSTOM_LIBS),$(LIBS)),-I$(dir)/include) -LIB_FLAGS = $(foreach dir,$(LIBS),-L$(dir)/lib) - -# ----------------------------------------------- - -.SUFFIXES: - -.PHONY: all libs clean mrproper $(CUSTOM_LIBS) - -all: $(NX_TARGET) - -libs: $(CUSTOM_LIBS) - -$(CUSTOM_LIBS): - @$(MAKE) -s --no-print-directory -C $@ - -$(NX_TARGET): $(NSO_TARGET) $(NPDM_TARGET) - @echo " NSP " $@ - @mkdir -p $(BUILD)/exefs - @cp $(NSO_TARGET) $(BUILD)/exefs/main - @cp $(NPDM_TARGET) $(BUILD)/exefs/main.npdm - @build_pfs0 $(BUILD)/exefs $@ - @echo Built $(notdir $@) - -$(NSO_TARGET): $(ELF_TARGET) - @echo " NSO " $@ - @mkdir -p $(dir $@) - @elf2nso $< $@ - -$(ELF_TARGET): $(OFILES) | libs - @echo " LD " $@ - @mkdir -p $(dir $@) - @$(LD) $(ARCH) $(LDFLAGS) -Wl,-Map,$(BUILD)/$(TARGET).map $(LIB_FLAGS) $(OFILES) $(LINKS) -o $@ - @$(NM) -CSn $@ > $(BUILD)/$(TARGET).lst - -$(BUILD)/%.c.o: %.c - @echo " CC " $@ - @mkdir -p $(dir $@) - @$(CC) -MMD -MP $(ARCH) $(FLAGS) $(CFLAGS) $(DEFINE_FLAGS) $(INCLUDE_FLAGS) -c $(CURDIR)/$< -o $@ - -$(BUILD)/%.cpp.o: %.cpp - @echo " CXX " $@ - @mkdir -p $(dir $@) - @$(CXX) -MMD -MP $(ARCH) $(FLAGS) $(CXXFLAGS) $(DEFINE_FLAGS) $(INCLUDE_FLAGS) -c $(CURDIR)/$< -o $@ - -$(BUILD)/%.s.o: %.s %.S - @echo " AS " $@ - @mkdir -p $(dir $@) - @$(AS) -MMD -MP -x assembler-with-cpp $(ARCH) $(FLAGS) $(ASFLAGS) $(INCLUDE_FLAGS) -c $(CURDIR)/$< -o $@ - -%.npdm: $(NPDM_JSON) - @echo " NPDM" $@ - @mkdir -p $(dir $@) - @npdmtool $(NPDM_JSON) $@ - -clean: - @echo Cleaning... - @rm -rf $(BUILD) $(OUT) - -mrproper: clean - @for dir in $(CUSTOM_LIBS); do $(MAKE) --no-print-directory -C $$dir clean; done - --include $(DFILES) diff --git a/chainloader/config.json b/chainloader/config.json deleted file mode 100644 index a421fa3..0000000 --- a/chainloader/config.json +++ /dev/null @@ -1,131 +0,0 @@ -{ - "name" : "Fizeau-chl", - "title_id" : "0x010000000000cf12", - "title_id_range_min" : "0x010000000000cf12", - "title_id_range_max" : "0x010000000000cf12", - "main_thread_stack_size": "0x0002000", - "main_thread_priority" : 49, - "default_cpu_id" : 3, - "process_category" : 0, - "is_retail" : true, - "pool_partition" : 2, - "is_64_bit" : true, - "address_space_type" : 1, - "filesystem_access" : { - "permissions": "0xffffffffffffffff" - }, - "service_host" : [ "*" ], - "service_access" : [ "*" ], - "kernel_capabilities": [ - { - "type" : "kernel_flags", - "value": { - "highest_thread_priority": 63, - "lowest_thread_priority" : 16, - "lowest_cpu_id" : 3, - "highest_cpu_id" : 3 - } - }, - { - "type" : "syscalls", - "value": { - "svcSetHeapSize" : "0x01", - "svcSetMemoryPermission" : "0x02", - "svcSetMemoryAttribute" : "0x03", - "svcMapMemory" : "0x04", - "svcUnmapMemory" : "0x05", - "svcQueryMemory" : "0x06", - "svcExitProcess" : "0x07", - "svcCreateThread" : "0x08", - "svcStartThread" : "0x09", - "svcExitThread" : "0x0a", - "svcSleepThread" : "0x0b", - "svcGetThreadPriority" : "0x0c", - "svcSetThreadPriority" : "0x0d", - "svcGetThreadCoreMask" : "0x0e", - "svcSetThreadCoreMask" : "0x0f", - "svcGetCurrentProcessorNumber" : "0x10", - "svcSignalEvent" : "0x11", - "svcClearEvent" : "0x12", - "svcMapSharedMemory" : "0x13", - "svcUnmapSharedMemory" : "0x14", - "svcCreateTransferMemory" : "0x15", - "svcCloseHandle" : "0x16", - "svcResetSignal" : "0x17", - "svcWaitSynchronization" : "0x18", - "svcCancelSynchronization" : "0x19", - "svcArbitrateLock" : "0x1a", - "svcArbitrateUnlock" : "0x1b", - "svcWaitProcessWideKeyAtomic" : "0x1c", - "svcSignalProcessWideKey" : "0x1d", - "svcGetSystemTick" : "0x1e", - "svcConnectToNamedPort" : "0x1f", - "svcSendSyncRequestLight" : "0x20", - "svcSendSyncRequest" : "0x21", - "svcSendSyncRequestWithUserBuffer" : "0x22", - "svcSendAsyncRequestWithUserBuffer": "0x23", - "svcGetProcessId" : "0x24", - "svcGetThreadId" : "0x25", - "svcBreak" : "0x26", - "svcOutputDebugString" : "0x27", - "svcReturnFromException" : "0x28", - "svcGetInfo" : "0x29", - "svcWaitForAddress" : "0x34", - "svcSignalToAddress" : "0x35", - "svcCreateSession" : "0x40", - "svcAcceptSession" : "0x41", - "svcReplyAndReceiveLight" : "0x42", - "svcReplyAndReceive" : "0x43", - "svcReplyAndReceiveWithUserBuffer" : "0x44", - "svcCreateEvent" : "0x45", - "svcCreateInterruptEvent" : "0x53", - "svcReadWriteRegister" : "0x4e", - "svcQueryIoMapping" : "0x55", - "svcCreateDeviceAddressSpace" : "0x56", - "svcAttachDeviceAddressSpace" : "0x57", - "svcDetachDeviceAddressSpace" : "0x58", - "svcMapDeviceAddressSpaceAligned" : "0x5a", - "svcUnmapDeviceAddressSpace" : "0x5c", - "svcGetSystemInfo" : "0x6f", - "svcCallSecureMonitor" : "0x7f", - "svcUnknown46" : "0x46", - "svcUnknown47" : "0x47", - "svcMapPhysicalMemoryUnsafe" : "0x48", - "svcUnmapPhysicalMemoryUnsafe" : "0x49", - "svcSetUnsafeLimit" : "0x4a", - "svcCreateCodeMemory" : "0x4b", - "svcControlCodeMemory" : "0x4c", - "svcSleepSystem" : "0x4d", - "svcSetProcessActivity" : "0x4f", - "svcCreateSharedMemory" : "0x50", - "svcMapTransferMemory" : "0x51", - "svcUnmapTransferMemory" : "0x52", - "svcDebugActiveProcess" : "0x60", - "svcBreakDebugProcess" : "0x61", - "svcTerminateDebugProcess" : "0x62", - "svcGetDebugEvent" : "0x63", - "svcContinueDebugEvent" : "0x64", - "svcGetProcessList" : "0x65", - "svcGetThreadList" : "0x66", - "svcGetDebugThreadContext" : "0x67", - "svcSetDebugThreadContext" : "0x68", - "svcQueryDebugProcessMemory" : "0x69", - "svcReadDebugProcessMemory" : "0x6a", - "svcWriteDebugProcessMemory" : "0x6b", - "svcSetHardwareBreakPoint" : "0x6c", - "svcGetDebugThreadParam" : "0x6d", - "svcConnectToPort" : "0x72", - "svcSetProcessMemoryPermission" : "0x73", - "svcMapProcessMemory" : "0x74", - "svcUnmapProcessMemory" : "0x75", - "svcQueryProcessMemory" : "0x76", - "svcMapProcessCodeMemory" : "0x77", - "svcUnmapProcessCodeMemory" : "0x78" - } - }, - { - "type" : "min_kernel_version", - "value": "0x0030" - } - ] -} diff --git a/chainloader/src/main.cpp b/chainloader/src/main.cpp deleted file mode 100644 index 717253a..0000000 --- a/chainloader/src/main.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include -#include - -#include - -extern "C" { - u32 __nx_applet_type = AppletType_None; - - #define INNER_HEAP_SIZE (0x2 * ams::os::MemoryPageSize) - size_t nx_inner_heap_size = INNER_HEAP_SIZE; - char nx_inner_heap[INNER_HEAP_SIZE]; - - alignas(16) u8 __nx_exception_stack[ams::os::MemoryPageSize]; - u64 __nx_exception_stack_size = sizeof(__nx_exception_stack); -} - -namespace ams { - ncm::ProgramId CurrentProgramId = { 0x010000000000cf12 }; - namespace result { bool CallFatalOnResultAssertion = false; } -} // namespace ams - -#ifdef DEBUG -TwiliPipe g_twlPipe; -#endif - -extern "C" void __libnx_initheap(void) { - // Newlib - extern char *fake_heap_start; - extern char *fake_heap_end; - - fake_heap_start = nx_inner_heap; - fake_heap_end = nx_inner_heap + nx_inner_heap_size; -} - -extern "C" void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); -} - -extern "C" void __appInit(void) { - ams::hos::InitializeForStratosphere(); - - R_ABORT_UNLESS(smInitialize()); - R_ABORT_UNLESS(pmshellInitialize()); - R_ABORT_UNLESS(fsInitialize()); - R_ABORT_UNLESS(fsdevMountSdmc()); - -#ifdef DEBUG - R_ABORT_UNLESS(twiliInitialize()); - R_ABORT_UNLESS(twiliCreateNamedOutputPipe(&g_twlPipe, "fzout")); -#endif -} - -extern "C" void __appExit(void) { -#ifdef DEBUG - twiliClosePipe(&g_twlPipe); - twiliExit(); -#endif - - fsdevUnmountAll(); - fsExit(); - pmshellExit(); - smExit(); -} - -int main() { - LOG("Launching program\n"); - constexpr NcmProgramLocation fizeau_program_location = { 0x0100000000000f12ul, NcmStorageId_None }; - R_ABORT_UNLESS(pmshellLaunchProgram(PmLaunchFlag_None, &fizeau_program_location, nullptr)); - - LOG("Initializing service\n"); - R_ABORT_UNLESS(fizeauInitialize()); - ON_SCOPE_EXIT { fizeauExit(); }; - - LOG("Applying settings\n"); - auto config = fz::cfg::read(); - if (config.has_active_override) - R_ABORT_UNLESS(fizeauSetIsActive(config.active)); - fizeauProfileClose(&config.cur_profile); - - LOG("Done, exiting\n"); - return 0; -} diff --git a/chainloader/toolbox.json b/chainloader/toolbox.json deleted file mode 100644 index 1fa437f..0000000 --- a/chainloader/toolbox.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name" : "Fizeau chainloader", - "tid" : "010000000000CF12", - "requires_reboot": true -} diff --git a/common/Makefile b/common/Makefile index a391cf4..0aaaf50 100644 --- a/common/Makefile +++ b/common/Makefile @@ -12,8 +12,7 @@ SOURCES = src INCLUDES = include ../lib/libstratosphere/libstratosphere/include LIBS = ../lib/inih -DEFINES = __SWITCH__ ATMOSPHERE_IS_STRATOSPHERE ATMOSPHERE_BOARD_NINTENDO_NX \ - ATMOSPHERE_ARCH_ARM64 ATMOSPHERE_OS_HORIZON +DEFINES = __SWITCH__ NXLINK ARCH = -march=armv8-a+crc+crypto+simd -mtune=cortex-a57 -mtp=soft -fpie FLAGS = -Wall -pipe -g -O2 -ffunction-sections -fdata-sections \ -fno-stack-protector -fno-common diff --git a/common/include/color.hpp b/common/include/color.hpp index cdc102f..de17451 100644 --- a/common/include/color.hpp +++ b/common/include/color.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // diff --git a/common/include/common.hpp b/common/include/common.hpp index af73086..8d31f6a 100644 --- a/common/include/common.hpp +++ b/common/include/common.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // diff --git a/common/include/config.hpp b/common/include/config.hpp index 0313b0f..2d2b3a1 100644 --- a/common/include/config.hpp +++ b/common/include/config.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -17,44 +17,49 @@ #pragma once +#include #include #include #include "fizeau.h" #include "types.h" -namespace fz::cfg { +namespace fz { -struct Config { - bool active = true, has_active_override = false; +class Config { + public: + constinit static inline std::array config_locations = { + std::string_view("/switch/Fizeau/config.ini"), + std::string_view("/config/Fizeau/config.ini"), + }; - FizeauProfile cur_profile = {}; - FizeauProfileId cur_profile_id = FizeauProfileId_Invalid, - active_internal_profile = FizeauProfileId_Invalid, active_external_profile = FizeauProfileId_Invalid; - bool is_editing_day_profile = false, is_editing_night_profile = false; + public: + bool active = true, has_active_override = false; - Time dusk_begin, dusk_end; - Time dawn_begin, dawn_end; + FizeauProfileId cur_profile_id = FizeauProfileId_Invalid, + internal_profile = FizeauProfileId_Invalid, external_profile = FizeauProfileId_Invalid; + bool is_editing_day_profile = false, is_editing_night_profile = false; - Temperature temperature_day, temperature_night; - ColorFilter filter_day, filter_night; - Gamma gamma_day, gamma_night; - Saturation sat_day, sat_night; - Luminance luminance_day, luminance_night; - ColorRange range_day, range_night; - Brightness brightness_day, brightness_night; + FizeauProfile profile = {}; - Time dimming_timeout; -}; + void (*parse_profile_switch_action)(Config *, FizeauProfileId) = nullptr; + + public: + static int ini_handler(void *user, const char *section, const char *name, const char *value); + static std::string_view find_config(); -std::string_view find_config(); -Config read(); -std::string make(Config &config); -void dump(Config &config); + public: + void read(); + void write(); + std::string make(); -Result update(Config &config); -Result apply(Config &config); -Result reset(Config &config); -Result open_profile(Config &cfg, FizeauProfileId id); + Result update(); + Result apply(); + Result reset(); + Result open_profile(FizeauProfileId id); + + private: + bool validate(); +}; -} // namespace fz::cfg +} // namespace fz diff --git a/common/include/fizeau.h b/common/include/fizeau.h index 8af2a5a..14b7a20 100644 --- a/common/include/fizeau.h +++ b/common/include/fizeau.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2020 averne + * Copyright (c) 2024 averne * * This file is part of Fizeau. * @@ -29,6 +29,15 @@ extern "C" { #endif +typedef enum { + FizeauCommandId_GetIsActive, + FizeauCommandId_SetIsActive, + FizeauCommandId_GetProfile, + FizeauCommandId_SetProfile, + FizeauCommandId_GetActiveProfileId, + FizeauCommandId_SetActiveProfileId, +} FizeauCommandId; + typedef enum { FizeauProfileId_Profile1, FizeauProfileId_Profile2, @@ -38,8 +47,27 @@ typedef enum { FizeauProfileId_Invalid = 0xffff, } FizeauProfileId; +#define FIZEAU_RC_MODULE 0xf12 +#define FIZEAU_RC_INVALID_PROFILEID 1 + +#define FIZEAU_MAKERESULT(r) MAKERESULT(FIZEAU_RC_MODULE, FIZEAU_RC_ ## r) + +typedef struct { + Temperature temperature; + Gamma gamma; + Saturation saturation; + Luminance luminance; + ColorRange range; + ColorFilter filter; +} FizeauSettings; + typedef struct { - Service s; + FizeauSettings day_settings, night_settings; + + Time dusk_begin, dusk_end; + Time dawn_begin, dawn_end; + + Time dimming_timeout; } FizeauProfile; Result fizeauIsServiceActive(bool *out); @@ -50,33 +78,12 @@ Service *fizeauGetServiceSession(); Result fizeauGetIsActive(bool *is_active); Result fizeauSetIsActive(bool is_active); -Result fizeauOpenProfile(FizeauProfile *out, FizeauProfileId id); -Result fizeauGetActiveInternalProfileId(FizeauProfileId *id); -Result fizeauSetActiveInternalProfileId(FizeauProfileId id); -Result fizeauGetActiveExternalProfileId(FizeauProfileId *id); -Result fizeauSetActiveExternalProfileId(FizeauProfileId id); - -void fizeauProfileClose(FizeauProfile *p); -Result fizeauProfileGetDawnTime(FizeauProfile *p, Time *time_begin, Time *time_end); -Result fizeauProfileSetDawnTime(FizeauProfile *p, Time time_begin, Time time_end); -Result fizeauProfileGetDuskTime(FizeauProfile *p, Time *time_begin, Time *time_end); -Result fizeauProfileSetDuskTime(FizeauProfile *p, Time time_begin, Time time_end); -Result fizeauProfileGetCmuTemperature(FizeauProfile *p, Temperature *temp_day, Temperature *temp_night); -Result fizeauProfileSetCmuTemperature(FizeauProfile *p, Temperature temp_day, Temperature temp_night); -Result fizeauProfileGetCmuColorFilter(FizeauProfile *p, ColorFilter *filter_day, ColorFilter *filter_night); -Result fizeauProfileSetCmuColorFilter(FizeauProfile *p, ColorFilter filter_day, ColorFilter filter_night); -Result fizeauProfileGetCmuGamma(FizeauProfile *p, Gamma *gamma_day, Gamma *gamma_night); -Result fizeauProfileSetCmuGamma(FizeauProfile *p, Gamma gamma_day, Gamma gamma_night); -Result fizeauProfileGetCmuSaturation(FizeauProfile *p, Saturation *sat_day, Saturation *sat_night); -Result fizeauProfileSetCmuSaturation(FizeauProfile *p, Saturation sat_day, Saturation sat_night); -Result fizeauProfileGetCmuLuminance(FizeauProfile *p, Luminance *luma_day, Luminance *luma_night); -Result fizeauProfileSetCmuLuminance(FizeauProfile *p, Luminance luma_day, Luminance luma_night); -Result fizeauProfileGetCmuColorRange(FizeauProfile *p, ColorRange *range_day, ColorRange *range_night); -Result fizeauProfileSetCmuColorRange(FizeauProfile *p, ColorRange range_day, ColorRange range_night); -Result fizeauProfileGetScreenBrightness(FizeauProfile *p, Brightness *brightness_day, Brightness *brightness_night); -Result fizeauProfileSetScreenBrightness(FizeauProfile *p, Brightness brightness_day, Brightness brightness_night); -Result fizeauProfileGetDimmingTimeout(FizeauProfile *p, Time *timeout); -Result fizeauProfileSetDimmingTimeout(FizeauProfile *p, Time timeout); + +Result fizeauGetProfile(FizeauProfileId id, FizeauProfile *profile); +Result fizeauSetProfile(FizeauProfileId id, FizeauProfile *profile); + +Result fizeauGetActiveProfileId(bool is_external, FizeauProfileId *id); +Result fizeauSetActiveProfileId(bool is_external, FizeauProfileId id); #ifdef __cplusplus } diff --git a/common/include/omm.h b/common/include/omm.h index a6d1e53..b786e57 100644 --- a/common/include/omm.h +++ b/common/include/omm.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2020 averne + * Copyright (c) 2024 averne * * This file is part of Fizeau. * diff --git a/common/include/time.hpp b/common/include/time.hpp index d768967..9412efc 100644 --- a/common/include/time.hpp +++ b/common/include/time.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -19,7 +19,6 @@ #include #include -#include #include "types.h" @@ -28,27 +27,35 @@ namespace fz { class Clock { public: static Result initialize() { - R_TRY(smInitialize()); - ON_SCOPE_EXIT { smExit(); }; - R_TRY(timeInitialize()); - ON_SCOPE_EXIT { timeExit(); }; + Result rc; + if (rc = timeInitialize(); R_FAILED(rc)) + goto exit; + + Clock::tick = armGetSystemTick(); std::uint64_t time; + if (rc = timeGetCurrentTime(TimeType_Default, &time); R_FAILED(rc)) + goto exit; + TimeCalendarTime caltime; - Clock::tick = armGetSystemTick(); - R_TRY(timeGetCurrentTime(TimeType_Default, &time)); - R_TRY(timeToCalendarTimeWithMyRule(time, &caltime, nullptr)); - Clock::timestamp = ams::TimeSpan::FromSeconds(60 * 60 * caltime.hour + 60 * caltime.minute + caltime.second); - return 0; + if (rc = timeToCalendarTimeWithMyRule(time, &caltime, nullptr); R_FAILED(rc)) + goto exit; + + Clock::timestamp = 1'000'000'000ull * (60 * 60 * caltime.hour + 60 * caltime.minute + caltime.second); + + rc = 0; + +exit: + timeExit(); + return rc; } static Time get_current_time() { - auto ts = Clock::timestamp + ams::TimeSpan::FromNanoSeconds(armTicksToNs(armGetSystemTick() - Clock::tick)); - return {static_cast(ts.GetHours() % 24), - static_cast(ts.GetMinutes() % 60), static_cast(ts.GetSeconds() % 60)}; + auto ts = Clock::timestamp + armTicksToNs(armGetSystemTick() - Clock::tick); + return from_timestamp(ts / 1'000'000'000); } - static bool is_in_interval(const Time &cur, const Time &lo, const Time &hi) { + static constexpr bool is_in_interval(const Time &cur, const Time &lo, const Time &hi) { return (lo <= cur) && (cur < hi); } @@ -58,7 +65,7 @@ class Clock { private: static inline std::uint64_t tick = 0; - static inline ams::TimeSpan timestamp = 0; + static inline std::uint64_t timestamp = 0; }; } // namespace fz diff --git a/common/include/types.h b/common/include/types.h index 87988e1..8ec9871 100644 --- a/common/include/types.h +++ b/common/include/types.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2020 averne + * Copyright (c) 2024 averne * * This file is part of Fizeau. * @@ -61,10 +61,6 @@ typedef struct { #define DEFAULT_RANGE { MIN_RANGE, MAX_RANGE } #define DEFAULT_LIMITED_RANGE { MIN_LIMITED_RANGE, MAX_LIMITED_RANGE} -typedef float Brightness; -#define MIN_BRIGHTNESS 0.0f -#define MAX_BRIGHTNESS 1.0f - typedef uint64_t Timestamp; typedef struct { uint8_t h, m, s; @@ -80,6 +76,8 @@ NX_CONSTEXPR Time from_timestamp(Timestamp s) { #ifdef __cplusplus +#include + constexpr auto operator <=>(const Time &l, const Time &r) { return to_timestamp(l) <=> to_timestamp(r); } diff --git a/common/include/utils.h b/common/include/utils.h index 30e033d..2a9ca1e 100644 --- a/common/include/utils.h +++ b/common/include/utils.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2020 averne + * Copyright (c) 2024 averne * * This file is part of Fizeau. * @@ -21,6 +21,14 @@ #include + +#define _FZ_CAT(x, y) x ## y +#define FZ_CAT(x, y) _FZ_CAT(x, y) +#define _FZ_STR(x) #x +#define FZ_STR(x) _FZ_STR(x) + +#define FZ_ANONYMOUS FZ_CAT(var, __COUNTER__) + #define ASSERT_SIZE(x, sz) static_assert(sizeof(x) == (sz), "Wrong size in " #x) #define ASSERT_STANDARD_LAYOUT(x) static_assert(std::is_standard_layout_v, #x " is not standard layout") @@ -78,3 +86,34 @@ __attribute__((unused)) static void hexdump(void *mem, unsigned int len) { } } } + +#ifdef __cplusplus + +#define FZ_SCOPEGUARD(f) auto FZ_ANONYMOUS = ::fz::ScopeGuard(f) + +namespace fz { + +template +struct ScopeGuard { + [[nodiscard]] ScopeGuard(F &&f): f(std::move(f)) { } + + ScopeGuard(const ScopeGuard &) = delete; + ScopeGuard &operator =(const ScopeGuard &) = delete; + + ~ScopeGuard() { + if (this->want_run) + this->f(); + } + + void cancel() { + this->want_run = false; + } + + private: + bool want_run = true; + F f; +}; + +} // namespace fz + +#endif // __cplusplus diff --git a/common/src/color.cpp b/common/src/color.cpp index b6f02f3..7143d4b 100644 --- a/common/src/color.cpp +++ b/common/src/color.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // diff --git a/common/src/fizeau.c b/common/src/fizeau.c index dd0e616..473bb15 100644 --- a/common/src/fizeau.c +++ b/common/src/fizeau.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2020 averne + * Copyright (c) 2024 averne * * This file is part of Fizeau. * @@ -25,39 +25,6 @@ #include -typedef enum { - FizeauCmdId_GetIsActive = 0, - FizeauCmdId_SetIsActive = 1, - FizeauCmdId_OpenProfile = 2, - FizeauCmdId_GetActiveInternalProfileId = 3, - FizeauCmdId_SetActiveInternalProfileId = 4, - FizeauCmdId_GetActiveExternalProfileId = 5, - FizeauCmdId_SetActiveExternalProfileId = 6, -} FizeauCmdId; - -typedef enum { - FizeauProfileCmdId_GetDuskTime = 0, - FizeauProfileCmdId_SetDuskTime = 1, - FizeauProfileCmdId_GetDawnTime = 2, - FizeauProfileCmdId_SetDawnTime = 3, - FizeauProfileCmdId_GetCmuTemperature = 4, - FizeauProfileCmdId_SetCmuTemperature = 5, - FizeauProfileCmdId_GetCmuColorFilter = 6, - FizeauProfileCmdId_SetCmuColorFilter = 7, - FizeauProfileCmdId_GetCmuGamma = 8, - FizeauProfileCmdId_SetCmuGamma = 9, - FizeauProfileCmdId_GetCmuSaturation = 10, - FizeauProfileCmdId_SetCmuSaturation = 11, - FizeauProfileCmdId_GetCmuLuminance = 12, - FizeauProfileCmdId_SetCmuLuminance = 13, - FizeauProfileCmdId_GetCmuColorRange = 14, - FizeauProfileCmdId_SetCmuColorRange = 15, - FizeauProfileCmdId_GetScreenBrightness = 16, - FizeauProfileCmdId_SetScreenBrightness = 17, - FizeauProfileCmdId_GetDimmingTimeout = 18, - FizeauProfileCmdId_SetDimmingTimeout = 19, -} FizeauProfileCmdId; - static Service g_fizeau_srv; NX_GENERATE_SERVICE_GUARD(fizeau); @@ -85,261 +52,53 @@ Service *fizeauGetServiceSession(void) { Result fizeauGetIsActive(bool *is_active) { u8 tmp; - Result rc = serviceDispatchOut(&g_fizeau_srv, FizeauCmdId_GetIsActive, tmp); + Result rc = serviceDispatchOut(&g_fizeau_srv, FizeauCommandId_GetIsActive, tmp); if (R_SUCCEEDED(rc) && is_active) *is_active = !!tmp; - return rc; -} - -Result fizeauSetIsActive(bool is_active) { - return serviceDispatchIn(&g_fizeau_srv, FizeauCmdId_SetIsActive, is_active); -} - -Result fizeauOpenProfile(FizeauProfile *out, FizeauProfileId id) { - return serviceDispatchIn(&g_fizeau_srv, FizeauCmdId_OpenProfile, id, - .out_num_objects = 1, - .out_objects = &out->s, - ); -} - -Result fizeauGetActiveInternalProfileId(FizeauProfileId *id) { - u32 tmp; - Result rc = serviceDispatchOut(&g_fizeau_srv, FizeauCmdId_GetActiveInternalProfileId, tmp); - - if (R_SUCCEEDED(rc) && id) - *id = tmp; - return rc; -} - -Result fizeauSetActiveInternalProfileId(FizeauProfileId id) { - return serviceDispatchIn(&g_fizeau_srv, FizeauCmdId_SetActiveInternalProfileId, id); -} - -Result fizeauGetActiveExternalProfileId(FizeauProfileId *id) { - u32 tmp; - Result rc = serviceDispatchOut(&g_fizeau_srv, FizeauCmdId_GetActiveExternalProfileId, tmp); - - if (R_SUCCEEDED(rc) && id) - *id = tmp; - return rc; -} -Result fizeauSetActiveExternalProfileId(FizeauProfileId id) { - return serviceDispatchIn(&g_fizeau_srv, FizeauCmdId_SetActiveExternalProfileId, id); -} - -void fizeauProfileClose(FizeauProfile *p) { - serviceClose(&p->s); -} - -Result fizeauProfileGetDuskTime(FizeauProfile *p, Time *time_begin, Time *time_end) { - struct { - Time begin, end; - } tmp; - Result rc = serviceDispatchOut(&p->s, FizeauProfileCmdId_GetDuskTime, tmp); - - if (R_SUCCEEDED(rc)) { - if (time_begin) - *time_begin = tmp.begin; - if (time_end) - *time_end = tmp.end; - } return rc; } -Result fizeauProfileSetDuskTime(FizeauProfile *p, Time time_begin, Time time_end) { - struct { - Time begin, end; - } in = { time_begin, time_end }; - return serviceDispatchIn(&p->s, FizeauProfileCmdId_SetDuskTime, in); -} - -Result fizeauProfileGetDawnTime(FizeauProfile *p, Time *time_begin, Time *time_end) { - struct { - Time begin, end; - } tmp; - Result rc = serviceDispatchOut(&p->s, FizeauProfileCmdId_GetDawnTime, tmp); - - if (R_SUCCEEDED(rc)) { - if (time_begin) - *time_begin = tmp.begin; - if (time_end) - *time_end = tmp.end; - } - return rc; -} - -Result fizeauProfileSetDawnTime(FizeauProfile *p, Time time_begin, Time time_end) { - struct { - Time begin, end; - } in = { time_begin, time_end }; - return serviceDispatchIn(&p->s, FizeauProfileCmdId_SetDawnTime, in); -} - -Result fizeauProfileGetCmuTemperature(FizeauProfile *p, Temperature *temp_day, Temperature *temp_night) { - struct { - Temperature temp_day, temp_night; - } tmp; - Result rc = serviceDispatchOut(&p->s, FizeauProfileCmdId_GetCmuTemperature, tmp); - - if (R_SUCCEEDED(rc)) { - if (temp_day) - *temp_day = tmp.temp_day; - if (temp_night) - *temp_night = tmp.temp_night; - } - return rc; -} - -Result fizeauProfileSetCmuTemperature(FizeauProfile *p, Temperature temp_day, Temperature temp_night) { - struct { - Temperature temp_day, temp_night; - } in = { temp_day, temp_night }; - return serviceDispatchIn(&p->s, FizeauProfileCmdId_SetCmuTemperature, in); -} - -Result fizeauProfileGetCmuColorFilter(FizeauProfile *p, ColorFilter *filter_day, ColorFilter *filter_night) { - struct { - ColorFilter filter_day, filter_night; - } tmp; - Result rc = serviceDispatchOut(&p->s, FizeauProfileCmdId_GetCmuColorFilter, tmp); - - if (R_SUCCEEDED(rc)) { - if (filter_day) - *filter_day = tmp.filter_day; - if (filter_night) - *filter_night = tmp.filter_night; - } - return rc; -} - -Result fizeauProfileSetCmuColorFilter(FizeauProfile *p, ColorFilter filter_day, ColorFilter filter_night) { - struct { - ColorFilter filter_day, filter_night; - } in = { filter_day, filter_night }; - return serviceDispatchIn(&p->s, FizeauProfileCmdId_SetCmuColorFilter, in); -} - -Result fizeauProfileGetCmuGamma(FizeauProfile *p, Gamma *gamma_day, Gamma *gamma_night) { - struct { - Gamma gamma_day, gamma_night; - } tmp; - Result rc = serviceDispatchOut(&p->s, FizeauProfileCmdId_GetCmuGamma, tmp); - - if (R_SUCCEEDED(rc)) { - if (gamma_day) - *gamma_day = tmp.gamma_day; - if (gamma_night) - *gamma_night = tmp.gamma_night; - } - return rc; -} - -Result fizeauProfileSetCmuGamma(FizeauProfile *p, Gamma gamma_day, Gamma gamma_night) { - struct { - Gamma gamma_day, gamma_night; - } in = { gamma_day, gamma_night }; - return serviceDispatchIn(&p->s, FizeauProfileCmdId_SetCmuGamma, in); -} - -Result fizeauProfileGetCmuSaturation(FizeauProfile *p, Saturation *sat_day, Saturation *sat_night) { - struct { - Saturation sat_day, sat_night; - } tmp; - Result rc = serviceDispatchOut(&p->s, FizeauProfileCmdId_GetCmuSaturation, tmp); - - if (R_SUCCEEDED(rc)) { - if (sat_day) - *sat_day = tmp.sat_day; - if (sat_night) - *sat_night = tmp.sat_night; - } - return rc; +Result fizeauSetIsActive(bool is_active) { + return serviceDispatchIn(&g_fizeau_srv, FizeauCommandId_SetIsActive, is_active); } -Result fizeauProfileSetCmuSaturation(FizeauProfile *p, Saturation sat_day, Saturation sat_night) { - struct { - Saturation sat_day, sat_night; - } in = { sat_day, sat_night }; - return serviceDispatchIn(&p->s, FizeauProfileCmdId_SetCmuSaturation, in);} +Result fizeauGetProfile(FizeauProfileId id, FizeauProfile *profile) { + FizeauProfile tmp; + Result rc = serviceDispatchInOut(&g_fizeau_srv, FizeauCommandId_GetProfile, id, tmp); -Result fizeauProfileGetCmuLuminance(FizeauProfile *p, Luminance *luma_day, Luminance *luma_night) { - struct { - Luminance luma_day, luma_night; - } tmp; - Result rc = serviceDispatchOut(&p->s, FizeauProfileCmdId_GetCmuLuminance, tmp); + if (R_SUCCEEDED(rc) && profile) + *profile = tmp; - if (R_SUCCEEDED(rc)) { - if (luma_day) - *luma_day = tmp.luma_day; - if (luma_night) - *luma_night = tmp.luma_night; - } return rc; } -Result fizeauProfileSetCmuLuminance(FizeauProfile *p, Luminance luma_day, Luminance luma_night) { +Result fizeauSetProfile(FizeauProfileId id, FizeauProfile *profile) { struct { - Luminance luma_day, luma_night; - } in = { luma_day, luma_night }; - return serviceDispatchIn(&p->s, FizeauProfileCmdId_SetCmuLuminance, in); -} - -Result fizeauProfileGetCmuColorRange(FizeauProfile *p, ColorRange *range_day, ColorRange *range_night) { - struct { - ColorRange range_day, range_night; - } tmp; - Result rc = serviceDispatchOut(&p->s, FizeauProfileCmdId_GetCmuColorRange, tmp); - - if (R_SUCCEEDED(rc)) { - if (range_day) - *range_day = tmp.range_day; - if (range_night) - *range_night = tmp.range_night; - } - return rc; + FizeauProfileId id; + FizeauProfile profile; + } tmp = { id, *profile }; + return serviceDispatchIn(&g_fizeau_srv, FizeauCommandId_SetProfile, tmp); } -Result fizeauProfileSetCmuColorRange(FizeauProfile *p, ColorRange range_day, ColorRange range_night) { +Result fizeauGetActiveProfileId(bool is_external, FizeauProfileId *id) { struct { - ColorRange range_day, range_night; - } in = { range_day, range_night }; - return serviceDispatchIn(&p->s, FizeauProfileCmdId_SetCmuColorRange, in); -} + bool is_external; + FizeauProfileId id; + } tmp = { is_external }; + Result rc = serviceDispatchOut(&g_fizeau_srv, FizeauCommandId_GetActiveProfileId, tmp); -Result fizeauProfileGetScreenBrightness(FizeauProfile *p, Brightness *brightness_day, Brightness *brightness_night) { - struct { - Brightness brightness_day, brightness_night; - } tmp; - Result rc = serviceDispatchOut(&p->s, FizeauProfileCmdId_GetScreenBrightness, tmp); + if (R_SUCCEEDED(rc) && id) + *id = tmp.id; - if (R_SUCCEEDED(rc)) { - if (brightness_day) - *brightness_day = tmp.brightness_day; - if (brightness_night) - *brightness_night = tmp.brightness_night; - } return rc; } -Result fizeauProfileSetScreenBrightness(FizeauProfile *p, Brightness brightness_day, Brightness brightness_night) { +Result fizeauSetActiveProfileId(bool is_external, FizeauProfileId id) { struct { - Brightness brightness_day, brightness_night; - } in = { brightness_day, brightness_night }; - return serviceDispatchIn(&p->s, FizeauProfileCmdId_SetScreenBrightness, in); -} - -Result fizeauProfileGetDimmingTimeout(FizeauProfile *p, Time *timeout) { - Time tmp; - Result rc = serviceDispatchOut(&p->s, FizeauProfileCmdId_GetDimmingTimeout, tmp); - - if (R_SUCCEEDED(rc) && timeout) - *timeout = tmp; - - return rc; -} - -Result fizeauProfileSetDimmingTimeout(FizeauProfile *p, Time timeout) { - return serviceDispatchIn(&p->s, FizeauProfileCmdId_SetDimmingTimeout, timeout); + bool is_external; + FizeauProfileId id; + } tmp = { is_external, id }; + return serviceDispatchIn(&g_fizeau_srv, FizeauCommandId_SetActiveProfileId, tmp); } diff --git a/common/src/omm.c b/common/src/omm.c index bb1836f..f9d1209 100644 --- a/common/src/omm.c +++ b/common/src/omm.c @@ -1,5 +1,5 @@ /** - * Copyright (C) 2020 averne + * Copyright (c) 2024 averne * * This file is part of Fizeau. * diff --git a/lib/inih/Makefile b/lib/inih/Makefile index fa6d744..44aca9e 100644 --- a/lib/inih/Makefile +++ b/lib/inih/Makefile @@ -12,7 +12,7 @@ SOURCES = inih -maxdepth 1 INCLUDES = include LIBS = -DEFINES = __SWITCH__ +DEFINES = __SWITCH__ INI_USE_STACK ARCH = -march=armv8-a+crc+crypto+simd -mtune=cortex-a57 -mtp=soft -fpie FLAGS = -Wall -Wno-stringop-truncation -pipe -g -O2 -ffunction-sections -fdata-sections CFLAGS = -std=gnu11 diff --git a/lib/libstratosphere/Makefile b/lib/libstratosphere/Makefile deleted file mode 100644 index eabf660..0000000 --- a/lib/libstratosphere/Makefile +++ /dev/null @@ -1,95 +0,0 @@ -ifeq ($(strip $(DEVKITPRO)),) - $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") -endif - -# ----------------------------------------------- - -TARGET = $(notdir $(CURDIR)) -EXTENSION = a -OUT = lib -BUILD = build -SOURCES = libstratosphere/source -INCLUDES = libstratosphere/include -LIBS = - -DEFINES = __SWITCH__ ATMOSPHERE_IS_STRATOSPHERE ATMOSPHERE_BOARD_NINTENDO_NX ATMOSPHERE_ARCH_ARM64 \ - ATMOSPHERE_OS_HORIZON -ARCH = -march=armv8-a+crc+crypto+simd -mtune=cortex-a57 -mtp=soft -fpie -FLAGS = -Wall -pipe -g -Os -ffunction-sections -fdata-sections \ - -fno-stack-protector -fno-common -flto -CFLAGS = -std=gnu11 -CXXFLAGS = -std=gnu++20 -fno-rtti -fno-exceptions -fno-non-call-exceptions -fno-threadsafe-statics \ - -fno-use-cxa-atexit -fno-asynchronous-unwind-tables -fno-unwind-tables -ASFLAGS = -ARFLAGS = -rc - -PREFIX = aarch64-none-elf- -CC = $(PREFIX)gcc -CXX = $(PREFIX)g++ -AS = $(PREFIX)as -AR = $(PREFIX)gcc-ar -RANLIB = $(PREFIX)gcc-ranlib - -# ----------------------------------------------- - -export PATH := $(DEVKITPRO)/tools/bin:$(DEVKITPRO)/devkitA64/bin:$(PORTLIBS)/bin:$(PATH) - -PORTLIBS = $(DEVKITPRO)/portlibs/switch -LIBNX = $(DEVKITPRO)/libnx -LIBS := $(LIBS) $(LIBNX) $(PORTLIBS) - -# ----------------------------------------------- - -CFILES = $(shell find $(SOURCES) -name *.c) -CPPFILES = $(shell find $(SOURCES) -name *.cpp) -SFILES = $(shell find $(SOURCES) -name *.s -or -name *.S) -OFILES = $(CFILES:%=$(BUILD)/%.o) $(CPPFILES:%=$(BUILD)/%.o) $(SFILES:%=$(BUILD)/%.o) -DFILES = $(addprefix $(BUILD)/,$(GCHFILES:.gch=.d)) $(OFILES:.o=.d) -GCHFILES = include/stratosphere.gch - -LIB_TARGET = $(if $(OUT:=), $(OUT)/$(TARGET).$(EXTENSION), .$(OUT)/$(TARGET).$(EXTENSION)) - -DEFINE_FLAGS = $(addprefix -D,$(DEFINES)) -INCLUDE_FLAGS = $(addprefix -I$(CURDIR)/,$(INCLUDES)) $(foreach dir,$(CUSTOM_LIBS),-I$(CURDIR)/$(dir)/include) \ - $(foreach dir,$(filter-out $(CUSTOM_LIBS),$(LIBS)),-I$(dir)/include) - -# ----------------------------------------------- - -.SUFFIXES: - -.PHONY: all clean - -all: $(LIB_TARGET) - -$(LIB_TARGET): $(OFILES) - @echo " AR " $@ - @mkdir -p $(dir $@) - @rm -f $@ - @$(AR) $(ARFLAGS) $@ $^ - @echo "Built" $(notdir $@) - -%.gch: %.hpp - @echo " GCH " $@ - @mkdir -p $(dir $@) $(dir $(BUILD)/$*.d) - @$(CXX) -w -x c++-header -MMD -MP -MF $(BUILD)/$*.d $(ARCH) $(FLAGS) $(CXXFLAGS) $(DEFINE_FLAGS) $(INCLUDE_FLAGS) -c $(CURDIR)/$< -o $@ - -$(BUILD)/%.c.o: %.c - @echo " CC " $@ - @mkdir -p $(dir $@) - @$(CC) -MMD -MP $(ARCH) $(FLAGS) $(CFLAGS) $(DEFINE_FLAGS) $(INCLUDE_FLAGS) -c $(CURDIR)/$< -o $@ - -$(BUILD)/%.cpp.o: %.cpp - @echo " CXX " $@ - @mkdir -p $(dir $@) - @$(CXX) -MMD -MP $(ARCH) $(FLAGS) $(CXXFLAGS) $(DEFINE_FLAGS) $(INCLUDE_FLAGS) -c $(CURDIR)/$< -o $@ - -$(BUILD)/%.s.o: %.s %.S - @echo " AS " $@ - @mkdir -p $(dir $@) - @$(AS) -MMD -MP -x assembler-with-cpp $(ARCH) $(FLAGS) $(ASFLAGS) $(INCLUDE_FLAGS) -c $(CURDIR)/$< -o $@ - -clean: - @echo Cleaning... - @rm -rf $(BUILD) $(OUT) $(GCHFILES) - --include $(DFILES) diff --git a/lib/libstratosphere/include/stratosphere.hpp b/lib/libstratosphere/include/stratosphere.hpp deleted file mode 100644 index 67e1ab0..0000000 --- a/lib/libstratosphere/include/stratosphere.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include "../libstratosphere/include/stratosphere.hpp" diff --git a/lib/libstratosphere/include/vapours.hpp b/lib/libstratosphere/include/vapours.hpp deleted file mode 100644 index f2b5f3c..0000000 --- a/lib/libstratosphere/include/vapours.hpp +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include "../libstratosphere/include/vapours.hpp" diff --git a/lib/libstratosphere/libstratosphere b/lib/libstratosphere/libstratosphere deleted file mode 160000 index 91aff5c..0000000 --- a/lib/libstratosphere/libstratosphere +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 91aff5c4e2772f3a6fbfec185557087578230b97 diff --git a/overlay/Makefile b/overlay/Makefile index b8a4c0a..5a3e53c 100644 --- a/overlay/Makefile +++ b/overlay/Makefile @@ -17,13 +17,11 @@ EXTENSION = ovl OUT = out BUILD = build SOURCES = src -INCLUDES = include ../lib/libtesla/include ../lib/libstratosphere/libstratosphere/include +INCLUDES = include ../lib/libtesla/include CUSTOM_LIBS = ../common ../lib/inih ROMFS = -DEFINES = __SWITCH__ VERSION=\"$(FZ_VERSION)\" COMMIT=\"$(FZ_COMMIT)\" \ - ATMOSPHERE_IS_STRATOSPHERE ATMOSPHERE_BOARD_NINTENDO_NX \ - ATMOSPHERE_ARCH_ARM64 ATMOSPHERE_OS_HORIZON +DEFINES = __SWITCH__ VERSION=\"$(FZ_VERSION)\" COMMIT=\"$(FZ_COMMIT)\" ARCH = -march=armv8-a+crc+crypto+simd -mtune=cortex-a57 -mtp=soft -fpie FLAGS = -Wall -pipe -g -O2 -ffunction-sections -fdata-sections CFLAGS = -std=gnu11 diff --git a/overlay/src/gui.cpp b/overlay/src/gui.cpp index af52ba4..7fe17d9 100644 --- a/overlay/src/gui.cpp +++ b/overlay/src/gui.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -58,36 +58,28 @@ FizeauOverlayGui::FizeauOverlayGui() { if (R_FAILED(rc)) return; - tsl::hlp::doWithSDCardHandle([this] { *this->config = cfg::read(); }); + tsl::hlp::doWithSDCardHandle([this] { this->config.read(); }); ApmPerformanceMode perf_mode; if (this->rc = apmGetPerformanceMode(&perf_mode); R_FAILED(this->rc)) return; FizeauProfileId id; - if (perf_mode == ApmPerformanceMode_Normal) { - this->rc = fizeauGetActiveInternalProfileId(&id); - } else { - this->rc = fizeauGetActiveExternalProfileId(&id); - } - if (R_FAILED(this->rc)) + if (this->rc = fizeauGetActiveProfileId(perf_mode != ApmPerformanceMode_Normal, &id); R_FAILED(this->rc)) return; - if (this->rc = cfg::open_profile(*this->config, id); R_FAILED(this->rc)) + if (this->rc = this->config.open_profile(id); R_FAILED(this->rc)) return; - - this->is_day = Clock::is_in_interval(this->config->dawn_begin, this->config->dusk_begin); } FizeauOverlayGui::~FizeauOverlayGui() { - tsl::hlp::doWithSDCardHandle([this] { cfg::dump(*this->config); }); - fizeauProfileClose(&this->config->cur_profile); + tsl::hlp::doWithSDCardHandle([this] { this->config.write(); }); fizeauExit(); } tsl::elm::Element *FizeauOverlayGui::createUI() { this->info_header = new tsl::elm::CustomDrawer([this](tsl::gfx::Renderer *renderer, s32 x, s32 y, s32 w, s32 h) { - renderer->drawString(format("Editing profile: %u", static_cast(this->config->cur_profile_id) + 1).c_str(), + renderer->drawString(format("Editing profile: %u", static_cast(this->config.cur_profile_id) + 1).c_str(), false, x, y + 20, 20, renderer->a(0xffff)); renderer->drawString(format("In period: %s", this->is_day ? "day" : "night").c_str(), false, x, y + 45, 20, renderer->a(0xffff)); @@ -96,118 +88,110 @@ tsl::elm::Element *FizeauOverlayGui::createUI() { this->active_button = new tsl::elm::ListItem("Correction active"); this->active_button->setClickListener([this](std::uint64_t keys) { if (keys & HidNpadButton_A) { - this->config->active ^= 1; - this->rc = fizeauSetIsActive(this->config->active); - this->active_button->setValue(this->config->active ? "Active": "Inactive"); + this->config.active ^= 1; + this->rc = fizeauSetIsActive(this->config.active); + this->active_button->setValue(this->config.active ? "Active": "Inactive"); return true; } return false; }); - this->active_button->setValue(this->config->active ? "Active": "Inactive"); + this->active_button->setValue(this->config.active ? "Active": "Inactive"); this->apply_button = new tsl::elm::ListItem("Apply settings"); this->apply_button->setClickListener([this](std::uint64_t keys) { if (keys & HidNpadButton_A) { - this->rc = cfg::apply(*this->config); + this->rc = this->config.apply(); return true; } return false; }); static bool enable_extra_hot_temps = false; - if ((this->is_day ? this->config->temperature_day : this->config->temperature_night) > D65_TEMP) + if ((this->is_day ? this->config.profile.day_settings.temperature : this->config.profile.night_settings.temperature) > D65_TEMP) enable_extra_hot_temps = true; this->temp_slider = new tsl::elm::TrackBar(""); - this->temp_slider->setProgress(((this->is_day ? this->config->temperature_day : this->config->temperature_night) - MIN_TEMP) + this->temp_slider->setProgress(((this->is_day ? this->config.profile.day_settings.temperature : this->config.profile.night_settings.temperature) - MIN_TEMP) * 100 / ((enable_extra_hot_temps ? MAX_TEMP : D65_TEMP) - MIN_TEMP)); this->temp_slider->setClickListener([&, this](std::uint64_t keys) { if (keys & HidNpadButton_Y) { this->temp_slider->setProgress((DEFAULT_TEMP - MIN_TEMP) * 100 / ((enable_extra_hot_temps ? MAX_TEMP : D65_TEMP) - MIN_TEMP)); - (this->is_day ? this->config->temperature_day : this->config->temperature_night) = DEFAULT_TEMP; + (this->is_day ? this->config.profile.day_settings.temperature : this->config.profile.night_settings.temperature) = DEFAULT_TEMP; return true; } return false; }); this->temp_slider->setValueChangedListener([this](std::uint8_t val) { - (this->is_day ? this->config->temperature_day : this->config->temperature_night) = + (this->is_day ? this->config.profile.day_settings.temperature : this->config.profile.night_settings.temperature) = val * ((enable_extra_hot_temps ? MAX_TEMP : D65_TEMP) - MIN_TEMP) / 100 + MIN_TEMP; }); - this->brightness_slider = new tsl::elm::TrackBar(""); - this->brightness_slider->setProgress(((this->is_day ? this->config->brightness_day : this->config->brightness_night) - MIN_BRIGHTNESS) - * 100 / (MAX_BRIGHTNESS - MIN_BRIGHTNESS)); - this->brightness_slider->setValueChangedListener([this](std::uint8_t val) { - (this->is_day ? this->config->brightness_day : this->config->brightness_night) = - val * (MAX_BRIGHTNESS - MIN_BRIGHTNESS) / 100 + MIN_BRIGHTNESS; - }); - this->gamma_slider = new tsl::elm::TrackBar(""); - this->gamma_slider->setProgress(((this->is_day ? this->config->gamma_day : this->config->gamma_night) - MIN_GAMMA) + this->gamma_slider->setProgress(((this->is_day ? this->config.profile.day_settings.gamma : this->config.profile.night_settings.gamma) - MIN_GAMMA) * 100 / (MAX_GAMMA - MIN_GAMMA)); this->gamma_slider->setClickListener([this](std::uint64_t keys) { if (keys & HidNpadButton_Y) { this->gamma_slider->setProgress((DEFAULT_GAMMA - MIN_GAMMA) * 100 / (MAX_GAMMA - MIN_GAMMA)); - (this->is_day ? this->config->gamma_day : this->config->gamma_night) = DEFAULT_GAMMA; + (this->is_day ? this->config.profile.day_settings.gamma : this->config.profile.night_settings.gamma) = DEFAULT_GAMMA; return true; } return false; }); this->gamma_slider->setValueChangedListener([this](std::uint8_t val) { - (this->is_day ? this->config->gamma_day : this->config->gamma_night) = + (this->is_day ? this->config.profile.day_settings.gamma : this->config.profile.night_settings.gamma) = val * (MAX_GAMMA - MIN_GAMMA) / 100 + MIN_GAMMA; }); this->sat_slider = new tsl::elm::TrackBar(""); - this->sat_slider->setProgress(((this->is_day ? this->config->sat_day : this->config->sat_night) - MIN_SAT) + this->sat_slider->setProgress(((this->is_day ? this->config.profile.day_settings.saturation : this->config.profile.night_settings.saturation) - MIN_SAT) * 100 / (MAX_SAT - MIN_SAT)); this->sat_slider->setClickListener([this](std::uint64_t keys) { if (keys & HidNpadButton_Y) { this->sat_slider->setProgress((DEFAULT_SAT - MIN_SAT) * 100 / (MAX_SAT - MIN_SAT)); - (this->is_day ? this->config->sat_day : this->config->sat_night) = DEFAULT_SAT; + (this->is_day ? this->config.profile.day_settings.saturation : this->config.profile.night_settings.saturation) = DEFAULT_SAT; return true; } return false; }); this->sat_slider->setValueChangedListener([this](std::uint8_t val) { - (this->is_day ? this->config->sat_day : this->config->sat_night) = + (this->is_day ? this->config.profile.day_settings.saturation : this->config.profile.night_settings.saturation) = val * (MAX_SAT - MIN_SAT) / 100 + MIN_SAT; }); this->luma_slider = new tsl::elm::TrackBar(""); - this->luma_slider->setProgress(((this->is_day ? this->config->luminance_day : this->config->luminance_night) - MIN_LUMA) + this->luma_slider->setProgress(((this->is_day ? this->config.profile.day_settings.luminance : this->config.profile.night_settings.luminance) - MIN_LUMA) * 100 / (MAX_LUMA - MIN_LUMA)); this->luma_slider->setClickListener([this](std::uint64_t keys) { if (keys & HidNpadButton_Y) { this->luma_slider->setProgress((DEFAULT_LUMA - MIN_LUMA) * 100 / (MAX_LUMA - MIN_LUMA)); - (this->is_day ? this->config->luminance_day : this->config->luminance_night) = DEFAULT_LUMA; + (this->is_day ? this->config.profile.day_settings.luminance : this->config.profile.night_settings.luminance) = DEFAULT_LUMA; return true; } return false; }); this->luma_slider->setValueChangedListener([this](std::uint8_t val) { - (this->is_day ? this->config->luminance_day : this->config->luminance_night) = + (this->is_day ? this->config.profile.day_settings.luminance : this->config.profile.night_settings.luminance) = val * (MAX_LUMA - MIN_LUMA) / 100 + MIN_LUMA; }); this->filter_bar = new tsl::elm::NamedStepTrackBar("", { "None", "Red", "Green", "Blue" }); - this->filter_bar->setProgress(static_cast(this->is_day ? this->config->filter_day : this->config->filter_night)); + this->filter_bar->setProgress(static_cast(this->is_day ? this->config.profile.day_settings.filter : this->config.profile.night_settings.filter)); this->filter_bar->setClickListener([this](std::uint64_t keys) { if (keys & HidNpadButton_Y) { this->filter_bar->setProgress(0); - (this->is_day ? this->config->filter_day : this->config->filter_night) = ColorFilter_None; + (this->is_day ? this->config.profile.day_settings.filter : this->config.profile.night_settings.filter) = ColorFilter_None; return true; } return false; }); this->filter_bar->setValueChangedListener([this](u8 val) { - (this->is_day ? this->config->filter_day : this->config->filter_night) = static_cast(val); + (this->is_day ? this->config.profile.day_settings.filter : this->config.profile.night_settings.filter) = static_cast(val); }); this->range_button = new tsl::elm::ListItem("Color range"); this->range_button->setClickListener([this](std::uint64_t keys) { if (keys & HidNpadButton_A) { - auto &range = (this->is_day ? this->config->range_day : this->config->range_night); + auto &range = (this->is_day ? this->config.profile.day_settings.range : this->config.profile.night_settings.range); if (is_full(range)) range = DEFAULT_LIMITED_RANGE; else @@ -217,11 +201,10 @@ tsl::elm::Element *FizeauOverlayGui::createUI() { } return false; }); - this->range_button->setValue(is_full(this->is_day ? this->config->range_day : this->config->range_night) ? "Full" : "Limited"); + this->range_button->setValue(is_full(this->is_day ? this->config.profile.day_settings.range : this->config.profile.night_settings.range) ? "Full" : "Limited"); this->temp_header = new tsl::elm::CategoryHeader(""); this->filter_header = new tsl::elm::CategoryHeader("Filter"); - this->brightness_header = new tsl::elm::CategoryHeader(""); this->gamma_header = new tsl::elm::CategoryHeader(""); this->sat_header = new tsl::elm::CategoryHeader(""); this->luma_header = new tsl::elm::CategoryHeader(""); @@ -234,11 +217,6 @@ tsl::elm::Element *FizeauOverlayGui::createUI() { list->addItem(this->temp_header); list->addItem(this->temp_slider); - if (config->cur_profile_id != config->active_external_profile) { - list->addItem(this->brightness_header); - list->addItem(this->brightness_slider); - } - list->addItem(this->gamma_header); list->addItem(this->gamma_slider); list->addItem(this->sat_header); @@ -250,23 +228,22 @@ tsl::elm::Element *FizeauOverlayGui::createUI() { list->addItem(this->range_button); frame->setContent(list); return frame; - } void FizeauOverlayGui::update() { if (R_FAILED(this->rc)) tsl::changeTo(this->rc); + this->is_day = Clock::is_in_interval(this->config.profile.dawn_begin, this->config.profile.dusk_begin); + this->temp_header->setText(format("Temperature: %u°K", - this->is_day ? this->config->temperature_day : this->config->temperature_night)); - this->brightness_header->setText(format("Brightness: %.2f", - this->is_day ? this->config->brightness_day : this->config->brightness_night)); + this->is_day ? this->config.profile.day_settings.temperature : this->config.profile.night_settings.temperature)); this->gamma_header->setText(format("Gamma: %.2f", - this->is_day ? this->config->gamma_day : this->config->gamma_night)); + this->is_day ? this->config.profile.day_settings.gamma : this->config.profile.night_settings.gamma)); this->sat_header->setText(format("Saturation: %.2f", - this->is_day ? this->config->sat_day : this->config->sat_night)); + this->is_day ? this->config.profile.day_settings.saturation : this->config.profile.night_settings.saturation)); this->luma_header->setText(format("Luminance: %.2f", - this->is_day ? this->config->luminance_day : this->config->luminance_night)); + this->is_day ? this->config.profile.day_settings.luminance : this->config.profile.night_settings.luminance)); } } // namespace fz diff --git a/overlay/src/gui.hpp b/overlay/src/gui.hpp index b2e0b03..b8af028 100644 --- a/overlay/src/gui.hpp +++ b/overlay/src/gui.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -47,14 +47,14 @@ class FizeauOverlayGui: public tsl::Gui { virtual void update() final override; - cfg::Config &get_config() { - return *this->config; + Config &get_config() { + return this->config; } private: Result rc; bool is_day; - std::unique_ptr config = std::make_unique(); + Config config = {}; tsl::elm::CustomDrawer *info_header; tsl::elm::ListItem *active_button; diff --git a/overlay/src/main.cpp b/overlay/src/main.cpp index b65f6b4..35c867e 100644 --- a/overlay/src/main.cpp +++ b/overlay/src/main.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // diff --git a/sysmodule/Makefile b/sysmodule/Makefile index 0fb5dd3..d217634 100644 --- a/sysmodule/Makefile +++ b/sysmodule/Makefile @@ -14,37 +14,21 @@ EXTENSION = nsp OUT = out BUILD = build SOURCES = src -INCLUDES = include ../lib/libstratosphere/libstratosphere/include -CUSTOM_LIBS = ../common ../lib/libstratosphere +INCLUDES = include +CUSTOM_LIBS = ../common ../lib/inih NPDM_JSON = config.json -DEFINES = __SWITCH__ ATMOSPHERE_IS_STRATOSPHERE ATMOSPHERE_BOARD_NINTENDO_NX \ - ATMOSPHERE_ARCH_ARM64 ATMOSPHERE_OS_HORIZON SYSMODULE +DEFINES = __SWITCH__ SYSMODULE ARCH = -march=armv8-a+crc+crypto+simd -mtune=cortex-a57 -mtp=soft -fpie -FLAGS = -Wall -pipe -g -Os -ffunction-sections -fdata-sections \ +FLAGS = -Wall -pipe -g -Os -ffunction-sections -fdata-sections \ -fno-stack-protector -fno-common CFLAGS = -std=gnu11 CXXFLAGS = -std=gnu++20 -fno-rtti -fno-exceptions -fno-non-call-exceptions \ -fno-threadsafe-statics -fno-use-cxa-atexit \ -fno-asynchronous-unwind-tables -fno-unwind-tables ASFLAGS = -LDFLAGS = -Wl,--wrap,__cxa_pure_virtual \ - -Wl,--wrap,__cxa_throw \ - -Wl,--wrap,__cxa_rethrow \ - -Wl,--wrap,__cxa_allocate_exception \ - -Wl,--wrap,__cxa_free_exception \ - -Wl,--wrap,__cxa_begin_catch \ - -Wl,--wrap,__cxa_end_catch \ - -Wl,--wrap,__cxa_call_unexpected \ - -Wl,--wrap,__cxa_call_terminate \ - -Wl,--wrap,__gxx_personality_v0 \ - -Wl,--wrap,_Unwind_Resume \ - -Wl,--wrap,_ZSt19__throw_logic_errorPKc \ - -Wl,--wrap,_ZSt20__throw_length_errorPKc \ - -Wl,--wrap,_ZNSt11logic_errorC2EPKc \ - -Wl,-pie -specs=$(DEVKITPRO)/libnx/switch.specs -g -Os \ - -flto -fuse-linker-plugin -LINKS = -lcommon -lstratosphere -lnx +LDFLAGS = -Wl,-pie -g -Os -specs=$(DEVKITPRO)/libnx/switch.specs +LINKS = -lcommon -linih -lnx PREFIX = aarch64-none-elf- CC = $(PREFIX)gcc diff --git a/sysmodule/src/brightness.cpp b/sysmodule/src/brightness.cpp deleted file mode 100644 index 47b4cf0..0000000 --- a/sysmodule/src/brightness.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2020 averne -// -// This file is part of Fizeau. -// -// Fizeau is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 2 of the License, or -// (at your option) any later version. -// -// Fizeau is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Fizeau. If not, see . - -#include - -#include "brightness.hpp" - -namespace fz { - -ams::Result BrightnessManager::initialize() { - return BrightnessManager::get_brightness(BrightnessManager::saved_brightness); -} - -ams::Result BrightnessManager::finalize() { - return ams::ResultSuccess(); -} - -ams::Result BrightnessManager::get_brightness(Brightness &brightness) { - return lblGetCurrentBrightnessSetting(&brightness); -} - -ams::Result BrightnessManager::set_brightness(Brightness brightness) { - R_TRY(BrightnessManager::get_brightness(BrightnessManager::saved_brightness)); - return lblSetCurrentBrightnessSetting(brightness); -} - -ams::Result BrightnessManager::disable() { - return lblSetCurrentBrightnessSetting(BrightnessManager::saved_brightness); -} - -} // namespace fz diff --git a/sysmodule/src/brightness.hpp b/sysmodule/src/context.hpp similarity index 50% rename from sysmodule/src/brightness.hpp rename to sysmodule/src/context.hpp index af31f03..050105f 100644 --- a/sysmodule/src/brightness.hpp +++ b/sysmodule/src/context.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -17,35 +17,26 @@ #pragma once -#include -#include +#include + #include -namespace fz { +#include "nvdisp.hpp" -class BrightnessManager { - public: - static ams::Result initialize(); - static ams::Result finalize(); +namespace fz { - static ams::Result get_brightness(Brightness &brightness); - static ams::Result set_brightness(Brightness brightness); - static ams::Result disable(); +struct Context { + bool is_lite = false; - static ams::Result enable_dimming() { - return lblEnableDimming(); - } + bool has_config_init = false, is_active = false; - static ams::Result disable_dimming() { - return lblDisableDimming(); - } + FizeauProfileId internal_profile = FizeauProfileId_Invalid, + external_profile = FizeauProfileId_Invalid; - static ams::Result is_dimming(bool &is_dimming) { - return lblIsDimmingEnabled(&is_dimming); - } + std::array profiles = {}; - private: - static inline Brightness saved_brightness; + DisplayController::Csc saved_internal_csc = {}, + saved_external_csc = {}; }; } // namespace fz diff --git a/sysmodule/src/disp1_regs.hpp b/sysmodule/src/disp1_regs.hpp index ad21396..02ab35b 100644 --- a/sysmodule/src/disp1_regs.hpp +++ b/sysmodule/src/disp1_regs.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2021 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -16,7 +16,6 @@ // along with Fizeau. If not, see . #include -#include #define DISP_IO_BASE 0x54200000 #define DISP_IO_SIZE (0x80000) diff --git a/sysmodule/src/ipc_server.c b/sysmodule/src/ipc_server.c new file mode 100644 index 0000000..d894d2e --- /dev/null +++ b/sysmodule/src/ipc_server.c @@ -0,0 +1,204 @@ +/* + * -------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * , , + * wrote this file. As long as you retain this notice you can do whatever you + * want with this stuff. If you meet any of us some day, and you think this + * stuff is worth it, you can buy us a beer in return. - The sys-clk authors + * -------------------------------------------------------------------------- + */ + +#include "ipc_server.h" +#include + +Result ipcServerInit(IpcServer* server, const char* name, u32 max_sessions) +{ + if(max_sessions < 1 || max_sessions > (MAX_WAIT_OBJECTS - 1)) + { + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + } + + server->srvName = smEncodeName(name); + server->max = max_sessions + 1; + server->count = 0; + + Result rc = smRegisterService(&server->handles[0], server->srvName, false, max_sessions); + if(R_SUCCEEDED(rc)) + { + server->count = 1; + } + return rc; +} + +Result ipcServerExit(IpcServer* server) +{ + for(u32 i = 0; i < server->count; i++) + { + svcCloseHandle(server->handles[i]); + } + server->count = 0; + return smUnregisterService(server->srvName); +} + +static Result _ipcServerAddSession(IpcServer* server, Handle session) +{ + if(server->count >= server->max) + { + return MAKERESULT(Module_Libnx, LibnxError_OutOfMemory); + } + + server->handles[server->count] = session; + server->count++; + return 0; +} + +static Result _ipcServerDeleteSession(IpcServer* server, u32 index) +{ + if(!index || index >= server->count) + { + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + } + + svcCloseHandle(server->handles[index]); + + for(u32 j = index; j < (server->count - 1); j++) + { + server->handles[j] = server->handles[j + 1]; + } + server->count--; + return 0; +} + +static Result _ipcServerParseRequest(IpcServerRequest* r) +{ + u8* base = armGetTls(); + + r->hipc = hipcParseRequest(base); + r->data.cmdId = 0; + r->data.size = 0; + r->data.ptr = NULL; + + if(r->hipc.meta.type == CmifCommandType_Request) + { + IpcServerRawHeader* header = cmifGetAlignedDataStart(r->hipc.data.data_words, base); + size_t dataSize = r->hipc.meta.num_data_words * 4; + + if(!header || dataSize < sizeof(IpcServerRawHeader) || header->magic != CMIF_IN_HEADER_MAGIC) + { + return MAKERESULT(Module_Libnx, LibnxError_BadInput); + } + + r->data.cmdId = header->cmdId; + if(dataSize > sizeof(IpcServerRawHeader)) + { + r->data.size = dataSize - sizeof(IpcServerRawHeader); + r->data.ptr = ((u8*)header) + sizeof(IpcServerRawHeader); + } + } + + return 0; +} + +static void _ipcServerPrepareResponse(Result rc, void* data, size_t dataSize) +{ + u8* base = armGetTls(); + HipcRequest hipc = hipcMakeRequestInline(base, + .type = CmifCommandType_Request, + .num_data_words = (sizeof(IpcServerRawHeader) + dataSize + 0x10) / 4, + ); + + IpcServerRawHeader* rawHeader = cmifGetAlignedDataStart(hipc.data_words, base); + rawHeader->magic = CMIF_OUT_HEADER_MAGIC; + rawHeader->result = rc; + + if(R_SUCCEEDED(rc)) + { + memcpy(((u8*)rawHeader) + sizeof(IpcServerRawHeader), data, dataSize); + } +} + +static Result _ipcServerProcessNewSession(IpcServer* server) +{ + Handle session; + Result rc = svcAcceptSession(&session, server->handles[0]); + if(R_SUCCEEDED(rc) && R_FAILED(rc = _ipcServerAddSession(server, session))) + { + svcCloseHandle(session); + } + return rc; +} + +static Result _ipcServerProcessSession(IpcServer* server, IpcServerRequestHandler handler, void* userdata, u32 handleIndex) +{ + s32 unusedIndex; + IpcServerRequest r; + size_t dataSize = 0; + u8 data[IPC_SERVER_EXT_RESPONSE_MAX_DATA_SIZE]; + bool close = false; + + Result rc = svcReplyAndReceive(&unusedIndex, &server->handles[handleIndex], 1, 0, UINT64_MAX); + if(R_SUCCEEDED(rc)) + { + rc = _ipcServerParseRequest(&r); + } + + if(R_SUCCEEDED(rc)) + { + switch(r.hipc.meta.type) + { + case CmifCommandType_Request: + _ipcServerPrepareResponse( + handler(userdata, &r, data, &dataSize), + data, + dataSize + ); + break; + case CmifCommandType_Close: + _ipcServerPrepareResponse(0, NULL, 0); + close = true; + break; + default: + _ipcServerPrepareResponse(MAKERESULT(11, 403), NULL, 0); + break; + } + + rc = svcReplyAndReceive(&unusedIndex, &server->handles[handleIndex], 0, server->handles[handleIndex], 0); + if(rc == KERNELRESULT(TimedOut)) + { + rc = 0; + } + } + + if(R_FAILED(rc) || close) + { + _ipcServerDeleteSession(server, handleIndex); + } + + return rc; +} + +Result ipcServerProcess(IpcServer* server, IpcServerRequestHandler handler, void* userdata) +{ + s32 handleIndex = -1; + Result rc = svcWaitSynchronization(&handleIndex, server->handles, server->count, UINT64_MAX); + + if(R_SUCCEEDED(rc) && (handleIndex < 0 || handleIndex >= server->count)) + { + rc = MAKERESULT(Module_Libnx, LibnxError_NotFound); + } + + if(R_SUCCEEDED(rc)) + { + if(handleIndex) + { + rc = _ipcServerProcessSession(server, handler, userdata, handleIndex); + } + else + { + rc = _ipcServerProcessNewSession(server); + } + } + + return rc; +} + diff --git a/sysmodule/src/ipc_server.h b/sysmodule/src/ipc_server.h new file mode 100644 index 0000000..4dd8f88 --- /dev/null +++ b/sysmodule/src/ipc_server.h @@ -0,0 +1,62 @@ +/* + * -------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * , , + * wrote this file. As long as you retain this notice you can do whatever you + * want with this stuff. If you meet any of us some day, and you think this + * stuff is worth it, you can buy us a beer in return. - The sys-clk authors + * -------------------------------------------------------------------------- + */ + +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#define IPC_SERVER_EXT_RESPONSE_MAX_DATA_SIZE (0x100 - 0x10 - sizeof(IpcServerRawHeader)) + +typedef struct +{ + u64 magic; + union + { + u64 cmdId; + u64 result; + }; +} IpcServerRawHeader; + +typedef struct +{ + SmServiceName srvName; + Handle handles[MAX_WAIT_OBJECTS]; + u32 max; + u32 count; +} IpcServer; + +typedef struct +{ + u64 cmdId; + void* ptr; + size_t size; +} IpcServerRequestData; + +typedef struct +{ + HipcParsedRequest hipc; + IpcServerRequestData data; +} IpcServerRequest; + +typedef Result (*IpcServerRequestHandler)(void* userdata, const IpcServerRequest* r, u8* out_data, size_t* out_dataSize); + +Result ipcServerInit(IpcServer* server, const char* name, u32 max_sessions); +Result ipcServerExit(IpcServer* server); +Result ipcServerProcess(IpcServer* server, IpcServerRequestHandler handler, void* userdata); +Result ipcServerParseCommand(const IpcServerRequest* r, size_t* out_datasize, void** out_data, u64* out_cmd); + +#ifdef __cplusplus +} +#endif diff --git a/sysmodule/src/main.cpp b/sysmodule/src/main.cpp index 35f5a0a..799673c 100644 --- a/sysmodule/src/main.cpp +++ b/sysmodule/src/main.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -15,127 +15,141 @@ // You should have received a copy of the GNU General Public License // along with Fizeau. If not, see . -#include +#include #include +#include #include -#include + +#include #include -#include "brightness.hpp" +#include "context.hpp" +#include "profile.hpp" #include "nvdisp.hpp" -#include "service.hpp" +#include "server.hpp" + +#if defined(DEBUG) && defined(TWILI) +TwiliPipe g_twlPipe; +#endif // libnx tweaking extern "C" { - u32 __nx_applet_type = AppletType_None; - - #define INNER_HEAP_SIZE (12 * ams::os::MemoryPageSize) - size_t nx_inner_heap_size = INNER_HEAP_SIZE; - char nx_inner_heap[INNER_HEAP_SIZE]; - - // 32kib is the smallest possible transfer memory size - u32 __nx_nv_transfermem_size = 8 * ams::os::MemoryPageSize; - - alignas(16) u8 __nx_exception_stack[ams::os::MemoryPageSize]; - u64 __nx_exception_stack_size = sizeof(__nx_exception_stack); -} -// libstratosphere tweaking -namespace ams { - ncm::ProgramId CurrentProgramId = { 0x0100000000000f12 }; - namespace result { - bool CallFatalOnResultAssertion = false; - } -} +u32 __nx_applet_type = AppletType_None; -#if defined(DEBUG) && defined(TWILI) -TwiliPipe g_twlPipe; -#endif +// 32kiB is the smallest possible transfer memory size (nvnflinger uses 400kiB) +#define NVDRV_TMEM_SIZE (8 * 0x1000) +char nvdrv_tmem_data[NVDRV_TMEM_SIZE] alignas(0x1000); -extern "C" void __libnx_initheap(void) { - // Newlib - extern char *fake_heap_start; - extern char *fake_heap_end; +void __libnx_initheap(void) { } +void *__libnx_alloc(size_t size) { return nullptr; } +void *__libnx_aligned_alloc(size_t alignment, size_t size) { return nullptr; } +void __libnx_free(void* p) { } - fake_heap_start = nx_inner_heap; - fake_heap_end = nx_inner_heap + nx_inner_heap_size; +Result __nx_nv_create_tmem(TransferMemory *t, u32 *out_size, Permission perm) { + *out_size = NVDRV_TMEM_SIZE; + return tmemCreateFromMemory(t, nvdrv_tmem_data, NVDRV_TMEM_SIZE, perm); } extern "C" void __libnx_exception_handler(ThreadExceptionDump *ctx) { - ams::CrashHandler(ctx); + diagAbortWithResult(ctx->error_desc); } extern "C" void __appInit(void) { #if defined(DEBUG) && !defined(TWILI) u64 has_debugger = 0; while (!has_debugger) { - R_ABORT_UNLESS(svcGetInfo(&has_debugger, InfoType_DebuggerAttached, INVALID_HANDLE, 0)); + if (auto rc = svcGetInfo(&has_debugger, InfoType_DebuggerAttached, INVALID_HANDLE, 0); R_FAILED(rc)) + diagAbortWithResult(rc); + if (has_debugger) break; svcSleepThread(1e6); } #endif - ams::hos::InitializeForStratosphere(); + if (auto rc = smInitialize(); R_FAILED(rc)) + diagAbortWithResult(rc); + + if (auto rc = splInitialize(); R_FAILED(rc)) + diagAbortWithResult(rc); - ams::sm::DoWithSession([] { - R_ABORT_UNLESS(nvInitialize()); - R_ABORT_UNLESS(pscmInitialize()); - if (hosversionBefore(14, 0, 0)) - R_ABORT_UNLESS(lblInitialize()); + u64 exo_api_ver; + if (auto rc = splGetConfig(static_cast(65000), &exo_api_ver); R_FAILED(rc)) + diagAbortWithResult(rc); - if (hosversionAtLeast(9, 0, 0)) - R_ABORT_UNLESS(insrInitialize()); + hosversionSet(BIT(31) | ((exo_api_ver >> 8) & 0xffffff)); + + if (auto rc = nvInitialize(); R_FAILED(rc)) + diagAbortWithResult(rc); + + if (auto rc = pscmInitialize(); R_FAILED(rc)) + diagAbortWithResult(rc); + + if (auto rc = ommInitialize(); R_FAILED(rc)) + diagAbortWithResult(rc); + + if (auto rc = insrInitialize(); R_FAILED(rc)) + diagAbortWithResult(rc); #if defined(DEBUG) && defined(TWILI) - R_ABORT_UNLESS(twiliInitialize()); - R_ABORT_UNLESS(twiliCreateNamedOutputPipe(&g_twlPipe, "fzout")); -#endif - }); + if (auto rc = twiliInitialize(); R_FAILED(rc)) + diagAbortWithResult(rc); - // ams::CheckApiVersion(); + if (auto rc = twiliCreateNamedOutputPipe(&g_twlPipe, "fzout"); R_FAILED(rc)) + diagAbortWithResult(rc); +#endif } extern "C" void __appExit(void) { nvExit(); pscmExit(); - if (hosversionBefore(14, 0, 0)) - lblExit(); - - if (hosversionAtLeast(9, 0, 0)) - insrExit(); + ommExit(); + insrExit(); #if defined(DEBUG) && defined(TWILI) twiliClosePipe(&g_twlPipe); twiliExit(); #endif -} -namespace { + splExit(); + smExit(); +} -constexpr auto service_name = ams::sm::ServiceName::Encode("fizeau"); -constexpr std::size_t num_servers = 1; -constexpr std::size_t max_sessions = 2; -ams::sf::hipc::ServerManager server_manager; +} // extern "C" -} // namespace +static fz::Context context; +static fz::DisplayController disp; +static fz::ProfileManager profile(context, disp); +static fz::Server server (context, profile); int main(int argc, char **argv) { LOG("Initializing\n"); - R_ABORT_UNLESS(fz::DispControlManager::initialize()); - if (hosversionBefore(14, 0, 0)) - R_ABORT_UNLESS(fz::BrightnessManager::initialize()); - R_ABORT_UNLESS(fz::ProfileManager::initialize()); - R_ABORT_UNLESS(fz::Clock::initialize()); + + u64 hw_type; + if (auto rc = splGetConfig(SplConfigItem_HardwareType, reinterpret_cast(&hw_type)); R_FAILED(rc)) + diagAbortWithResult(rc); + context.is_lite = hw_type == 2; // Hoag + + if (auto rc = fz::Clock::initialize(); R_FAILED(rc)) + diagAbortWithResult(rc); + + if (auto rc = disp.initialize(); R_FAILED(rc)) + diagAbortWithResult(rc); + + if (auto rc = profile.initialize(); R_FAILED(rc)) + diagAbortWithResult(rc); LOG("Starting server\n"); - R_ABORT_UNLESS(server_manager.RegisterServer(service_name, max_sessions)); - server_manager.LoopProcess(); + if (auto rc = server.initialize(); R_FAILED(rc)) + diagAbortWithResult(rc); + + server.loop(); + + server .finalize(); + profile.finalize(); + disp .finalize(); LOG("Exiting\n"); - fz::ProfileManager::finalize(); - fz::DispControlManager::finalize(); - if (hosversionBefore(14, 0, 0)) - fz::BrightnessManager::finalize(); return 0; } diff --git a/sysmodule/src/nvdisp.cpp b/sysmodule/src/nvdisp.cpp index 727d8f5..3dc2a83 100644 --- a/sysmodule/src/nvdisp.cpp +++ b/sysmodule/src/nvdisp.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -25,61 +25,94 @@ namespace fz { -using Man = DispControlManager; +namespace { -ams::Result Man::set_cmu(std::uint32_t fd, Temperature temp, ColorFilter filter, Gamma gamma, - Saturation sat, Luminance luma, ColorRange range, std::array &saved_csc) { - auto &cmu = Man::cmu; - cmu.reset(); +Cmu calculate_cmu(FizeauSettings &settings) { + Cmu cmu; // Calculate initial coefficients - auto coeffs = filter_matrix(filter); + auto coeffs = filter_matrix(settings.filter); // Apply temperature color correction - auto [krr, kgg, kbb] = whitepoint(temp); - krr = degamma(krr, 2.4f), kgg = degamma(kgg, 2.4f), kbb = degamma(kbb, 2.4f); - coeffs[0] *= krr, coeffs[4] *= kgg, coeffs[8] *= kbb; + ColorMatrix wp = {}; + std::tie(wp[0], wp[4], wp[8]) = whitepoint(settings.temperature); + wp[0] = degamma(wp[0], 2.4f), wp[4] = degamma(wp[4], 2.4f), wp[8] = degamma(wp[8], 2.4f); + coeffs = dot(coeffs, wp); - coeffs = dot(coeffs, saturation_matrix(sat)); + // Apply saturation + coeffs = dot(coeffs, saturation_matrix(settings.saturation)); + // Copy color matrix to cmu format std::transform(coeffs.begin(), coeffs.end(), &cmu.krr, [](float c) -> QS18 { return c; }); - // Copy calculated color matrix, masking only the meaningful bits - std::transform(&cmu.krr, &cmu.krr + 9, saved_csc.begin(), - [](QS18 c) -> std::uint16_t { return static_cast(c) & QS18::BitMask; }); - // Calculate gamma ramps - degamma_ramp(cmu.lut_1.data(), cmu.lut_1.size(), DEFAULT_GAMMA, 12); // Set the LUT1 with a fixed gamma corresponding to the incoming data - regamma_ramp(cmu.lut_2.data(), 512, gamma, 8, 0.0f, 0.125f); // Set the first part of LUT2 (more precision in darker components) - regamma_ramp(cmu.lut_2.data() + 512, cmu.lut_2.size() - 512, gamma, 8, 0.125f, 1.0f); // Set the second part of LUT2 (less precision in brighter components) + degamma_ramp(cmu.lut_1.data(), cmu.lut_1.size(), DEFAULT_GAMMA, 12); // Set the LUT1 with a fixed gamma corresponding to the incoming data + regamma_ramp(cmu.lut_2.data(), 512, settings.gamma, 8, 0.0f, 0.125f); // Set the first part of LUT2 (more precision in darker components) + regamma_ramp(cmu.lut_2.data() + 512, cmu.lut_2.size() - 512, settings.gamma, 8, 0.125f, 1.0f); // Set the second part of LUT2 (less precision in brighter components) // Apply luminance - apply_luma(cmu.lut_2.data(), cmu.lut_2.size(), luma); + apply_luma(cmu.lut_2.data(), cmu.lut_2.size(), settings.luminance); // Apply color range - apply_range(cmu.lut_2.data(), cmu.lut_2.size(), range.lo, std::min(range.hi, cmu.lut_2.back() / 255.0f)); // Adjust max for luma + apply_range(cmu.lut_2.data(), cmu.lut_2.size(), + settings.range.lo, std::min(settings.range.hi, cmu.lut_2.back() / 255.0f)); // Adjust max for luma + + return cmu; +} + +} // namespace + +Result DisplayController::disable(bool external) const { + Cmu cmu(false); + + if (auto rc = nvioctlNvDisp_SetCmu(!external ? this->disp0_fd : this->disp1_fd, &cmu)) + return rc; + + if (external) + return 0; + + AviInfoframe infoframe; + if (auto rc = nvioctlNvDisp_GetAviInfoframe(this->disp1_fd, &infoframe); R_FAILED(rc)) + return rc; + + infoframe.rgb_quant = RgbQuantRange::Default; + if (auto rc = nvioctlNvDisp_SetAviInfoframe(this->disp1_fd, &infoframe); R_FAILED(rc)) + return rc; - return nvioctlNvDisp_SetCmu(fd, cmu); + return 0; } -ams::Result Man::set_hdmi_color_range(ColorRange range, bool disable) { +Result DisplayController::apply_color_profile(bool external, FizeauSettings &settings, Csc &saved_csc) const { + Cmu cmu = calculate_cmu(settings); + + if (auto rc = nvioctlNvDisp_SetCmu(!external ? this->disp0_fd : this->disp1_fd, &cmu); R_FAILED(rc)) + return rc; + + // Save csc matrix, to be used for change detection + std::transform(&cmu.krr, &cmu.krr + 9, saved_csc.begin(), + [](QS18 c) -> std::uint16_t { return static_cast(c) & QS18::BitMask; }); + + return 0; +} + +Result DisplayController::set_hdmi_color_range(bool external, ColorRange range) const { + if (external) + return 0; + auto is_limited = [](const ColorRange &range) { return (range.lo >= MIN_LIMITED_RANGE) && (range.hi <= MAX_LIMITED_RANGE); }; - R_TRY(nvioctlNvDisp_GetAviInfoframe(Man::disp1_fd, Man::infoframe)); - Man::infoframe.rgb_quant = static_cast(disable ? RgbQuantRange::Default : - (is_limited(range) ? RgbQuantRange::Limited : RgbQuantRange::Full)); + AviInfoframe infoframe; + if (auto rc = nvioctlNvDisp_GetAviInfoframe(this->disp1_fd, &infoframe); R_FAILED(rc)) + return rc; - R_TRY(nvioctlNvDisp_SetAviInfoframe(Man::disp1_fd, Man::infoframe)); - return ams::ResultSuccess(); -} + infoframe.rgb_quant = is_limited(range) ? RgbQuantRange::Limited : RgbQuantRange::Full; + + if (auto rc = nvioctlNvDisp_SetAviInfoframe(this->disp1_fd, &infoframe); R_FAILED(rc)) + return rc; -ams::Result Man::disable(bool internal) { - Man::cmu.reset(false); - R_TRY(nvioctlNvDisp_SetCmu(internal ? Man::disp0_fd : Man::disp1_fd, Man::cmu)); - R_TRY(set_hdmi_color_range(DEFAULT_LIMITED_RANGE, true)); - return ams::ResultSuccess(); + return 0; } } // namespace fz diff --git a/sysmodule/src/nvdisp.hpp b/sysmodule/src/nvdisp.hpp index 635016e..74d2008 100644 --- a/sysmodule/src/nvdisp.hpp +++ b/sysmodule/src/nvdisp.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -23,7 +23,9 @@ #include #include #include + #include + #include namespace fz { @@ -96,12 +98,12 @@ struct Cmu { }; ASSERT_SIZE(Cmu, 2458); -static inline Result nvioctlNvDisp_SetCmu(u32 fd, Cmu &cmu) { - return nvIoctl(fd, _NV_IOWR(2, 14, Cmu), &cmu); +static inline Result nvioctlNvDisp_SetCmu(u32 fd, Cmu *cmu) { + return nvIoctl(fd, _NV_IOWR(2, 14, Cmu), cmu); } // Defined in CEA-861-D table 11 -enum class RgbQuantRange { +enum RgbQuantRange { Default = 0, Limited = 1, Full = 2, @@ -132,46 +134,33 @@ struct AviInfoframe { }; ASSERT_SIZE(AviInfoframe, 96); -static inline Result nvioctlNvDisp_GetAviInfoframe(u32 fd, AviInfoframe &infoframe) { - return nvIoctl(fd, _NV_IOR(2, 16, AviInfoframe), &infoframe); +static inline Result nvioctlNvDisp_GetAviInfoframe(u32 fd, AviInfoframe *infoframe) { + return nvIoctl(fd, _NV_IOR(2, 16, AviInfoframe), infoframe); } -static inline Result nvioctlNvDisp_SetAviInfoframe(u32 fd, AviInfoframe &infoframe) { - return nvIoctl(fd, _NV_IOW(2, 17, AviInfoframe), &infoframe); +static inline Result nvioctlNvDisp_SetAviInfoframe(u32 fd, AviInfoframe *infoframe) { + return nvIoctl(fd, _NV_IOW(2, 17, AviInfoframe), infoframe); } -class DispControlManager { +class DisplayController { public: - static ams::Result initialize() { - return nvOpen(&DispControlManager::disp0_fd, "/dev/nvdisp-disp0") | nvOpen(&DispControlManager::disp1_fd, "/dev/nvdisp-disp1"); - } - - static ams::Result finalize() { - return nvClose(DispControlManager::disp0_fd) | nvClose(DispControlManager::disp1_fd); - } - - static ams::Result set_cmu(std::uint32_t fd, Temperature temp, ColorFilter filter, Gamma gamma, - Saturation sat, Luminance luma, ColorRange range, std::array &saved_csc); + using Csc = std::array; - static inline ams::Result set_cmu_internal(Temperature temp, ColorFilter filter, Gamma gamma, - Saturation sat, Luminance luma, ColorRange range, std::array &saved_csc) { - return DispControlManager::set_cmu(DispControlManager::disp0_fd, temp, filter, gamma, sat, luma, range, saved_csc); + public: + Result initialize() { + return nvOpen(&this->disp0_fd, "/dev/nvdisp-disp0") || nvOpen(&this->disp1_fd, "/dev/nvdisp-disp1"); } - static inline ams::Result set_cmu_external(Temperature temp, ColorFilter filter, Gamma gamma, - Saturation sat, Luminance luma, ColorRange range, std::array &saved_csc) { - return DispControlManager::set_cmu(DispControlManager::disp1_fd, temp, filter, gamma, sat, luma, range, saved_csc); + Result finalize() const { + return nvClose(this->disp0_fd) || nvClose(this->disp1_fd); } - static ams::Result set_hdmi_color_range(ColorRange range, bool disable = false); - - static ams::Result disable(bool internal); + Result disable(bool external) const; + Result apply_color_profile(bool external, FizeauSettings &settings, Csc &saved_csc) const; + Result set_hdmi_color_range(bool external, ColorRange range) const; private: - static inline Cmu cmu; - static inline AviInfoframe infoframe; - static inline std::uint32_t disp0_fd; - static inline std::uint32_t disp1_fd; + std::uint32_t disp0_fd, disp1_fd; }; } // namespace fz diff --git a/sysmodule/src/profile.cpp b/sysmodule/src/profile.cpp index d4add41..34707e7 100644 --- a/sysmodule/src/profile.cpp +++ b/sysmodule/src/profile.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -16,14 +16,15 @@ // along with Fizeau. If not, see . #include -#include -#include +#include +#include + #include #include -#include "brightness.hpp" #include "disp1_regs.hpp" #include "nvdisp.hpp" + #include "profile.hpp" using namespace std::chrono_literals; @@ -33,287 +34,277 @@ namespace fz { namespace { constexpr std::uint32_t ins_evt_id = 0; -std::uint64_t g_disp_va_base; -} // namespace +FizeauSettings interpolate_profile(FizeauProfile &in, float factor, bool from_day) { + FizeauSettings out, + &from = from_day ? in.day_settings : in.night_settings, + &to = !from_day ? in.day_settings : in.night_settings; + + out = { + .temperature = static_cast(std::lerp(from.temperature, to.temperature, factor)), + .gamma = std::lerp(from.gamma, to.gamma, factor), + .saturation = std::lerp(from.saturation, to.saturation, factor), + .luminance = std::lerp(from.luminance, to.luminance, factor), + .range = { + std::lerp(from.range.lo, to.range.lo, factor), + std::lerp(from.range.hi, to.range.hi, factor), + }, + .filter = from.filter, + }; -using Man = ProfileManager; - -Profile Profile::interpolate(float factor, bool from_day) { - Profile p; - if (from_day) { - p.temperature_day = std::lerp(this->temperature_day, this->temperature_night, factor); - p.gamma_day = std::lerp(this->gamma_day, this->gamma_night, factor); - p.sat_day = std::lerp(this->sat_day, this->sat_night, factor); - p.luminance_day = std::lerp(this->luminance_day, this->luminance_night, factor); - p.brightness_day = std::lerp(this->brightness_day, this->brightness_night, factor); - p.range_day = { std::lerp(this->range_day.lo, this->range_night.lo, factor), - std::lerp(this->range_day.hi, this->range_night.hi, factor) }; - } else { - p.temperature_night = std::lerp(this->temperature_night, this->temperature_day, factor); - p.gamma_night = std::lerp(this->gamma_night, this->gamma_day, factor); - p.sat_night = std::lerp(this->sat_day, this->sat_night, factor); - p.luminance_night = std::lerp(this->luminance_night, this->luminance_day, factor); - p.brightness_night = std::lerp(this->brightness_night, this->brightness_day, factor); - p.range_night = { std::lerp(this->range_night.lo, this->range_day.lo, factor), - std::lerp(this->range_night.hi, this->range_day.hi, factor) }; - } - p.dusk_begin = this->dusk_begin, p.dusk_end = this->dusk_end; - p.dawn_begin = this->dawn_begin, p.dawn_end = this->dawn_end; - p.filter_day = this->filter_day, p.filter_night = this->filter_night; - return p; + return out; } -void ProfileManager::transition_thread_func([[maybe_unused]] void *args) { - while (!Man::stop.stop_requested()) { - std::this_thread::sleep_for(50ms); +} // namespace - std::scoped_lock lk(Man::mmio_mutex); - if (!Man::is_active || !Man::should_poll_mmio) - continue; +void ProfileManager::transition_thread_func(void *args) { + auto *self = static_cast(args); - bool need_apply = false, is_handheld = Man::operation_mode == AppletOperationMode_Handheld; + UTimer timer; + utimerCreate(&timer, std::chrono::nanoseconds(100ms).count(), TimerType_Repeating); + utimerStart(&timer); - // Poll DISPLAY_A in handheld mode, DISPLAY_B in docked mode - std::uint64_t iobase = g_disp_va_base + (is_handheld ? 0 : 0x40000); + while (true) { + int idx; + auto rc = waitMulti(&idx, UINT64_MAX, + waiterForUTimer(&timer), + waiterForUEvent(&self->thread_exit_event)); + if (R_FAILED(rc)) + return; - { - std::scoped_lock lk(Man::commit_mutex); + switch (idx) { + case 0: + break; + case 1: + default: + return; + } + + if (!self->context.is_active) + continue; - auto &csc = is_handheld ? Man::saved_internal_csc : Man::saved_external_csc; + bool need_apply = false, is_handheld = self->operation_mode == AppletOperationMode_Handheld; - for (std::size_t i = 0; i < csc.size(); ++i) { - if (csc[i] != READ(iobase + DC_COM_CMU_CSC_KRR + i * sizeof(std::uint32_t))) { - need_apply = true; - break; + { + mutexLock(&self->commit_mutex); + FZ_SCOPEGUARD([self] { mutexUnlock(&self->commit_mutex); }); + + if (self->mmio_available) { + // Poll DISPLAY_A in handheld mode, DISPLAY_B in docked mode + std::uint64_t iobase = self->disp_va_base + (is_handheld ? 0 : 0x40000); + + auto &csc = is_handheld ? self->context.saved_internal_csc : self->context.saved_external_csc; + for (std::size_t i = 0; i < csc.size(); ++i) { + if (csc[i] != READ(iobase + DC_COM_CMU_CSC_KRR + i * sizeof(std::uint32_t))) { + need_apply = true; + break; + } } } } - auto &profile = is_handheld ? Man::get_active_internal_profile() : Man::get_active_external_profile(); - auto time = Clock::get_current_time(); - if (!need_apply && (profile.is_transitionning || Clock::is_in_interval(time, profile.dusk_begin, profile.dusk_end) || - Clock::is_in_interval(time, profile.dawn_begin, profile.dawn_end))) { - // First wait a second to avoid calculating/applying the coefficients too much - std::this_thread::sleep_for(1s); - need_apply = true; - } + auto profile_id = is_handheld ? self->context.internal_profile : self->context.external_profile; + if (!need_apply && profile_id != FizeauProfileId_Invalid) { + auto &profile = self->context.profiles[profile_id]; + + auto time = Clock::get_current_time(); + if (Clock::is_in_interval(time, profile.dusk_begin, profile.dusk_end) || + Clock::is_in_interval(time, profile.dawn_begin, profile.dawn_end)) + need_apply = true; - if (!need_apply) { std::uint64_t timeout = armNsToTicks(to_timestamp(profile.dimming_timeout) * 1e9), - delta = armGetSystemTick() - Man::activity_tick; + delta = armGetSystemTick() - self->activity_tick; - if (!Man::is_dimming && delta > timeout) - need_apply = true, Man::is_dimming = true; - else if (Man::is_dimming && delta <= timeout) - need_apply = true, Man::is_dimming = false; + if (!self->is_dimming && delta > timeout) + need_apply = true, self->is_dimming = true; + else if (self->is_dimming && delta <= timeout) + need_apply = true, self->is_dimming = false; } - if (need_apply) - Man::commit(false); + if (need_apply) { + self->apply(); + + // Wait a second to avoid calculating/applying the coefficients too frequently + svcSleepThread(std::chrono::nanoseconds(1s).count()); + } } } -void ProfileManager::event_monitor_thread_func([[maybe_unused]] void *args) { - while (!Man::stop.stop_requested()) { +void ProfileManager::event_monitor_thread_func(void *args) { + auto *self = static_cast(args); + + while (true) { int idx; auto rc = waitMulti(&idx, UINT64_MAX, - waiterForEvent(&Man::psc_module.event), - waiterForEvent(&Man::operation_mode_event), - waiterForEvent(&Man::activity_event)); + waiterForEvent(&self->operation_mode_event), + waiterForEvent(&self->activity_event), + waiterForEvent(&self->psc_module.event), + waiterForUEvent(&self->thread_exit_event)); if (R_FAILED(rc)) - continue; - - std::scoped_lock lk(Man::mmio_mutex); + return; switch (idx) { - case 0: - PscPmState state; - if (R_SUCCEEDED(pscPmModuleGetRequest(&Man::psc_module, &state, nullptr))) - Man::should_poll_mmio = state == PscPmState_Awake; - - pscPmModuleAcknowledge(&Man::psc_module, state); + case 0: { + ommGetOperationMode(&self->operation_mode); break; - case 1: - ommGetOperationMode(&Man::operation_mode); + } + case 1: { + insrGetLastTick(ins_evt_id, &self->activity_tick); break; - case 2: - insrGetLastTick(ins_evt_id, &Man::activity_tick); + } + case 2: { + PscPmState state; + if (R_SUCCEEDED(pscPmModuleGetRequest(&self->psc_module, &state, nullptr))) + self->mmio_available = state == PscPmState_Awake; + + pscPmModuleAcknowledge(&self->psc_module, state); break; + } + case 3: default: - break; + return; } } } -ams::Result ProfileManager::initialize() { - ams::sm::DoWithSession([]() { - if (auto rc = splInitialize(); R_FAILED(rc)) - Man::is_lite = false; - ON_SCOPE_EXIT { splExit(); }; +Result ProfileManager::initialize() { + std::uint64_t size; + if (auto rc = svcQueryMemoryMapping(&this->disp_va_base, &size, DISP_IO_BASE, DISP_IO_SIZE); R_FAILED(rc)) + diagAbortWithResult(rc); - ams::spl::HardwareType type; - if (auto rc = splGetConfig(SplConfigItem_HardwareType, reinterpret_cast(&type)); R_FAILED(rc)) - Man::is_lite = false; + std::array deps = { u32(PscPmModuleId_Display) }; + if (auto rc = pscmGetPmModule(&this->psc_module, PscPmModuleId(125), deps.data(), deps.size(), true); R_FAILED(rc)) + diagAbortWithResult(rc); - Man::is_lite = type == ams::spl::HardwareType::Hoag; + if (auto rc = ommGetOperationModeChangeEvent(&this->operation_mode_event, false); R_FAILED(rc)) + diagAbortWithResult(rc); - R_ABORT_UNLESS(ommInitialize()); - }); + if (auto rc = ommGetOperationMode(&this->operation_mode); R_FAILED(rc)) + diagAbortWithResult(rc); - std::uint64_t size; - R_TRY(svcQueryIoMapping(reinterpret_cast(&g_disp_va_base), &size, DISP_IO_BASE, DISP_IO_SIZE)); + if (auto rc = insrGetReadableEvent(ins_evt_id, &this->activity_event); R_FAILED(rc)) + diagAbortWithResult(rc); - std::array deps = {u32(PscPmModuleId_Display)}; - R_TRY(pscmGetPmModule(&Man::psc_module, PscPmModuleId(125), deps.data(), deps.size(), true)); + if (auto rc = insrGetLastTick(ins_evt_id, &this->activity_tick); R_FAILED(rc)) + diagAbortWithResult(rc); - R_TRY(ommGetOperationMode(&Man::operation_mode)); - R_TRY(ommGetOperationModeChangeEvent(&Man::operation_mode_event, false)); + ueventCreate(&this->thread_exit_event, true); - R_TRY(insrGetReadableEvent(ins_evt_id, &Man::activity_event)); - R_TRY(insrGetLastTick(ins_evt_id, &Man::activity_tick)); + // The event monitor thread should have a higher priority than the transition thread to ensure it wins on mutex races + if (auto rc = threadCreate(&this->event_monitor_thread, &ProfileManager::event_monitor_thread_func, this, + this->event_monitor_thread_stack, sizeof(this->event_monitor_thread_stack), 0x3d, -2); R_FAILED(rc)) + diagAbortWithResult(rc); - R_TRY(Man::transition_thread.Initialize(Man::transition_thread_func, nullptr, 0x3f)); - R_TRY(Man::transition_thread.Start()); + if (auto rc = threadStart(&this->event_monitor_thread); R_FAILED(rc)) + diagAbortWithResult(rc); - R_TRY(Man::event_monitor_thread.Initialize(Man::event_monitor_thread_func, nullptr, 0x3f)); - R_TRY(Man::event_monitor_thread.Start()); + if (auto rc = threadCreate(&this->transition_thread, &ProfileManager::transition_thread_func, this, + this->transition_thread_stack, sizeof(this->transition_thread_stack), 0x3e, -2); R_FAILED(rc)) + diagAbortWithResult(rc); + + if (auto rc = threadStart(&this->transition_thread); R_FAILED(rc)) + diagAbortWithResult(rc); return 0; } -ams::Result ProfileManager::finalize() { - ommExit(); - pscPmModuleFinalize(&Man::psc_module); - pscPmModuleClose(&Man::psc_module); - eventClose(&Man::psc_module.event); - eventClose(&Man::operation_mode_event); +Result ProfileManager::finalize() { + ueventSignal(&this->thread_exit_event); + threadWaitForExit(&this->event_monitor_thread); + threadClose(&this->event_monitor_thread); - Man::stop.request_stop(); - R_TRY(Man::transition_thread.Join()); - R_TRY(Man::event_monitor_thread.Join()); + ueventSignal(&this->thread_exit_event); + threadWaitForExit(&this->transition_thread); + threadClose(&this->transition_thread); - return 0; -} + pscPmModuleFinalize(&this->psc_module); + pscPmModuleClose(&this->psc_module); + eventClose(&this->psc_module.event); -bool ProfileManager::get_is_active() { - return Man::is_active; -} + eventClose(&this->operation_mode_event); -ams::Result ProfileManager::set_is_active(bool active) { - Man::is_active = active; - if (active) { - R_TRY(Man::commit()); - } else { - R_TRY(DispControlManager::disable(true)); - if (!Man::is_lite) - R_TRY(DispControlManager::disable(false)); - if (hosversionBefore(14, 0, 0)) - R_TRY(BrightnessManager::disable()); - } - return ams::ResultSuccess(); + return 0; } -ams::Result ProfileManager::commit(bool force_brightness) { - std::scoped_lock lk(Man::commit_mutex); +Result ProfileManager::apply() { + if (!this->context.is_active) + return 0; + + auto apply_profile = [this](FizeauProfileId profile_id, bool dim, bool external) -> Result { + auto &profile = this->context.profiles[profile_id]; - auto apply_profile = [&force_brightness](Profile profile, bool dim, bool internal) -> ams::Result { auto time = Clock::get_current_time(); - bool apply_brightness = true; - Luminance luminance_day = profile.luminance_day, luminance_night = profile.luminance_night; + FizeauSettings settings; if (Clock::is_in_interval(time, profile.dusk_begin, profile.dusk_end)) { - if (!profile.is_transitionning) { - if (hosversionBefore(14, 0, 0)) - R_TRY(BrightnessManager::get_brightness(profile.brightness_day)); - profile.is_transitionning = true; - } float factor = static_cast(to_timestamp(profile.dusk_end - time)) / static_cast(to_timestamp(profile.dusk_end - profile.dusk_begin)); - profile = profile.interpolate(factor, false); + settings = interpolate_profile(profile, factor, false); } else if (Clock::is_in_interval(time, profile.dawn_begin, profile.dawn_end)) { - if (!profile.is_transitionning) { - if (hosversionBefore(14, 0, 0)) - R_TRY(BrightnessManager::get_brightness(profile.brightness_night)); - profile.is_transitionning = true; - } float factor = static_cast(to_timestamp(profile.dawn_end - time)) / static_cast(to_timestamp(profile.dawn_end - profile.dawn_begin)); - profile = profile.interpolate(factor, true); + settings = interpolate_profile(profile, factor, true); + } else if (Clock::is_in_interval(time, profile.dawn_end, profile.dusk_begin)) { + settings = profile.day_settings; } else { - profile.is_transitionning = false; - apply_brightness = force_brightness; + settings = profile.night_settings; } - if (dim) { - luminance_day = luminance_night = - internal ? dimmed_luma_internal : dimmed_luma_external; + if (dim) + settings.luminance = !external ? dimmed_luma_internal : dimmed_luma_external; - apply_brightness = false; - if (internal && hosversionBefore(14, 0, 0)) - R_TRY(BrightnessManager::enable_dimming()); - } else if (internal && hosversionBefore(14, 0, 0)) { - bool is_dimming; - R_TRY(BrightnessManager::is_dimming(is_dimming)); + auto &csc = !external ? this->context.saved_internal_csc : this->context.saved_external_csc; + if (auto rc = this->disp.apply_color_profile(external, settings, csc); R_FAILED(rc)) + return rc; - if (is_dimming) - R_TRY(BrightnessManager::disable_dimming()); - } + if (auto rc = this->disp.set_hdmi_color_range(external, settings.range); R_FAILED(rc)) + return rc; - if (Clock::is_in_interval(profile.dawn_begin, profile.dusk_begin)) { - if (internal) { - R_TRY(DispControlManager::set_cmu_internal(profile.temperature_day, profile.filter_day, - profile.gamma_day, profile.sat_day, luminance_day, profile.range_day, - Man::saved_internal_csc)); - } else { - R_TRY(DispControlManager::set_cmu_external(profile.temperature_day, profile.filter_day, - profile.gamma_day, profile.sat_day, luminance_day, profile.range_day, - Man::saved_external_csc)); - R_TRY(DispControlManager::set_hdmi_color_range(profile.range_day)); - } - if (internal && apply_brightness && hosversionBefore(14, 0, 0)) - R_TRY(BrightnessManager::set_brightness(profile.brightness_day)); - } else { - if (internal) { - R_TRY(DispControlManager::set_cmu_internal(profile.temperature_night, profile.filter_night, - profile.gamma_night, profile.sat_night, luminance_night, profile.range_night, - Man::saved_internal_csc)); - } else { - R_TRY(DispControlManager::set_cmu_external(profile.temperature_night, profile.filter_night, - profile.gamma_night, profile.sat_night, luminance_night, profile.range_night, - Man::saved_external_csc)); - R_TRY(DispControlManager::set_hdmi_color_range(profile.range_night)); - } - if (internal && apply_brightness && hosversionBefore(14, 0, 0)) - R_TRY(BrightnessManager::set_brightness(profile.brightness_night)); - } - return ams::ResultSuccess(); + return 0; + }; + + auto should_dim = [this](auto profile_id, auto timeout) { + if (profile_id == FizeauProfileId_Invalid) + return false; + + auto ts = to_timestamp(this->context.profiles[profile_id].dimming_timeout); + return ts && (timeout >= ts); }; - bool should_dim_internal = false, should_dim_external = false; - if (hosversionAtLeast(9, 0, 0)) { - auto timeout = armTicksToNs(armGetSystemTick() - Man::activity_tick) / static_cast(1e9); + auto timeout = armTicksToNs(armGetSystemTick() - this->activity_tick) / 1'000'000'000; + bool should_dim_internal = should_dim(this->context.internal_profile, timeout); + bool should_dim_external = should_dim(this->context.external_profile, timeout); - auto should_dim = [](auto profile, auto timeout) { - auto ts = to_timestamp(profile.dimming_timeout); - return ts && (timeout >= ts); - }; + mutexLock(&this->commit_mutex); + FZ_SCOPEGUARD([this] { mutexUnlock(&this->commit_mutex); }); - should_dim_internal = should_dim(Man::get_active_internal_profile(), timeout); - should_dim_external = should_dim(Man::get_active_external_profile(), timeout); + if (this->context.internal_profile != FizeauProfileId_Invalid) { + if (auto rc = apply_profile(this->context.internal_profile, should_dim_internal, false); R_FAILED(rc)) + return rc; } - R_TRY(apply_profile(Man::get_active_internal_profile(), should_dim_internal, true)); - if (!Man::is_lite) - R_TRY(apply_profile(Man::get_active_external_profile(), should_dim_external, false)); + if (this->context.external_profile != FizeauProfileId_Invalid && !this->context.is_lite) { + if (auto rc = apply_profile(this->context.external_profile, should_dim_external, true); R_FAILED(rc)) + return rc; + } - return ams::ResultSuccess(); + return 0; } -ams::Result ProfileManager::on_profile_updated(ProfileId id) { - if (!Man::is_active || ((id != Man::active_internal_profile) && (id != Man::active_external_profile))) - return ams::ResultSuccess(); - return Man::commit(); +Result ProfileManager::update_active() { + if (this->context.is_active) { + return this->apply(); + } else { + if (auto rc = this->disp.disable(false); R_FAILED(rc)) + return rc; + + if (!this->context.is_lite) { + if (auto rc = this->disp.disable(true); R_FAILED(rc)) + return rc; + } + } + + return 0; } } // namespace fz diff --git a/sysmodule/src/profile.hpp b/sysmodule/src/profile.hpp index 6797159..b35d8ab 100644 --- a/sysmodule/src/profile.hpp +++ b/sysmodule/src/profile.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2020 averne +// Copyright (c) 2024 averne // // This file is part of Fizeau. // @@ -19,103 +19,51 @@ #include #include -#include - -namespace fz { - -enum class ProfileId: std::uint32_t { - Profile1, - Profile2, - Profile3, - Profile4, - Total, - Invalid = 0xffff, -}; -struct Profile { - Temperature temperature_day = DEFAULT_TEMP, temperature_night = DEFAULT_TEMP; - ColorFilter filter_day = ColorFilter_None, filter_night = ColorFilter_None; - Gamma gamma_day = DEFAULT_GAMMA, gamma_night = DEFAULT_GAMMA; - Saturation sat_day = DEFAULT_SAT, sat_night = DEFAULT_SAT; - Luminance luminance_day = DEFAULT_LUMA, luminance_night = DEFAULT_LUMA; - ColorRange range_day = DEFAULT_RANGE, range_night = DEFAULT_RANGE; - Brightness brightness_day = 1.0f, brightness_night = 1.0f; - - Time dusk_begin = { 21, 00, 00 }, dusk_end = { 21, 30, 00 }; - Time dawn_begin = { 07, 00, 00 }, dawn_end = { 07, 30, 00 }; - - Time dimming_timeout = { 00, 05, 00 }; +#include - bool is_transitionning = false; +#include "context.hpp" +#include "nvdisp.hpp" - Profile interpolate(float factor, bool from_day); -}; +namespace fz { constexpr float dimmed_luma_internal = -0.1f, dimmed_luma_external = -0.7f; // Official values used in 6.0.0 am class ProfileManager { public: - static ams::Result initialize(); - static ams::Result finalize(); + ProfileManager(Context &context, DisplayController &disp): context(context), disp(disp) { } - static ams::Result commit(bool force_apply_brightness = true); - static ams::Result on_profile_updated(ProfileId id); + Result initialize(); + Result finalize(); - static bool get_is_active(); - static ams::Result set_is_active(bool active); + Result apply(); + Result update_active(); - static Profile &get_profile(ProfileId id) { - return ProfileManager::profiles[static_cast(id)]; - } - - static Profile &get_active_internal_profile() { - return get_profile(ProfileManager::active_internal_profile); - } - - static Profile &get_active_external_profile() { - return get_profile(ProfileManager::active_external_profile); - } + private: + static void transition_thread_func(void *args); + static void event_monitor_thread_func(void *args); - static ProfileId get_active_internal_profile_id() { - return ProfileManager::active_internal_profile; - } + private: + Context &context; + DisplayController &disp; - static void set_active_internal_profile_id(ProfileId id) { - ProfileManager::active_internal_profile = id; - } + UEvent thread_exit_event = {}; + Thread transition_thread, event_monitor_thread; + std::uint8_t transition_thread_stack[0x2000] alignas(0x1000), + event_monitor_thread_stack[0x1000] alignas(0x1000); - static ProfileId get_active_external_profile_id() { - return ProfileManager::active_external_profile; - } + PscPmModule psc_module; + bool mmio_available = true; + std::uint64_t disp_va_base = 0; - static void set_active_external_profile_id(ProfileId id) { - ProfileManager::active_external_profile = id; - } + Event operation_mode_event; + AppletOperationMode operation_mode; - private: - static void transition_thread_func(void *args); - static void event_monitor_thread_func(void *args); + Event activity_event; + std::uint64_t activity_tick; + bool is_dimming = false; - private: - static inline bool is_lite = false; - static inline bool is_active = false; - static inline bool should_poll_mmio = true; - - static inline ams::os::StaticThread<2 * ams::os::MemoryPageSize> transition_thread; - static inline ams::os::StaticThread event_monitor_thread; - static inline std::stop_source stop; - static inline PscPmModule psc_module; - static inline Event operation_mode_event; - static inline AppletOperationMode operation_mode; - static inline Event activity_event; - static inline std::uint64_t activity_tick; - static inline bool is_dimming = false; - - static inline ProfileId active_internal_profile = ProfileId::Profile1, active_external_profile = ProfileId::Profile2; - static inline std::array(ProfileId::Total)> profiles; - static inline std::array saved_internal_csc, saved_external_csc; - - static inline ams::os::Mutex commit_mutex, mmio_mutex; + Mutex commit_mutex = {}; }; } // namespace fz diff --git a/sysmodule/src/server.cpp b/sysmodule/src/server.cpp new file mode 100644 index 0000000..47e4aaf --- /dev/null +++ b/sysmodule/src/server.cpp @@ -0,0 +1,96 @@ +// Copyright (c) 2024 averne +// +// This file is part of Fizeau. +// +// Fizeau is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Fizeau is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Fizeau. If not, see . + +#include +#include +#include + +#include + +#include "server.hpp" + +namespace fz { + +#define SET_OUTDATA(v) ({ \ + *(std::remove_cvref_t *)out_data = v; \ + *out_datasize = sizeof(v); \ +}) + +Result Server::command_handler(void *userdata, const IpcServerRequest *r, u8 *out_data, size_t *out_datasize) { + auto *self = static_cast(userdata); + + switch (r->data.cmdId) { + case FizeauCommandId_GetIsActive: { + SET_OUTDATA(self->context.is_active); + break; + } + case FizeauCommandId_SetIsActive: { + auto prev_active = std::exchange(self->context.is_active, *(bool *)r->data.ptr); + + if (prev_active != self->context.is_active) + self->profile.update_active(); + + break; + } + case FizeauCommandId_GetProfile: { + auto id = *(FizeauProfileId *)r->data.ptr; + if (id < FizeauProfileId_Profile1 || id > FizeauProfileId_Profile4) + return FIZEAU_MAKERESULT(INVALID_PROFILEID); + + SET_OUTDATA(self->context.profiles[id]); + break; + } + case FizeauCommandId_SetProfile: { + auto id = *(FizeauProfileId *)r->data.ptr; + if (id < FizeauProfileId_Profile1 || id > FizeauProfileId_Profile4) + return FIZEAU_MAKERESULT(INVALID_PROFILEID); + + self->context.profiles[id] = *(FizeauProfile *)((std::uint8_t *)r->data.ptr + std::max(alignof(bool), alignof(FizeauProfile))); + + if (id == self->context.internal_profile || id == self->context.external_profile) { + if (auto rc = self->profile.apply(); R_FAILED(rc)) + return rc; + } + + break; + } + case FizeauCommandId_GetActiveProfileId: { + auto external = *(bool *)r->data.ptr; + SET_OUTDATA(!external ? self->context.internal_profile : self->context.external_profile); + break; + } + case FizeauCommandId_SetActiveProfileId: { + auto external = *(bool *)r->data.ptr; + auto id = *(FizeauProfileId *)((std::uint8_t *)r->data.ptr + std::max(alignof(bool), alignof(FizeauProfileId))); + if (id < FizeauProfileId_Profile1 || id > FizeauProfileId_Profile4) + return FIZEAU_MAKERESULT(INVALID_PROFILEID); + + (!external ? self->context.internal_profile : self->context.external_profile) = id; + + if (auto rc = self->profile.apply(); R_FAILED(rc)) + return rc; + + break; + } + default: + return MAKERESULT(10, 221); + } + + return 0; +} + +} // namespace fz diff --git a/sysmodule/src/server.hpp b/sysmodule/src/server.hpp new file mode 100644 index 0000000..4564744 --- /dev/null +++ b/sysmodule/src/server.hpp @@ -0,0 +1,63 @@ +// Copyright (c) 2024 averne +// +// This file is part of Fizeau. +// +// Fizeau is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Fizeau is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Fizeau. If not, see . + +#include + +#include "context.hpp" +#include "ipc_server.h" +#include "profile.hpp" + +namespace fz { + +class Server: public IpcServer { + public: + constexpr static inline std::string_view ServiceName = "fizeau"; + constexpr static inline int ServiceNumSessions = 2; + + public: + Server(Context &context, ProfileManager &profile): context(context), profile(profile) { } + + Result initialize() { + return ipcServerInit(this, Server::ServiceName.data(), Server::ServiceNumSessions); + } + + Result finalize() { + return ipcServerExit(this); + } + + Result process() { + return ipcServerProcess(this, &command_handler, this); + } + + Result loop() { + while (true) { + if (auto rc = this->process(); R_FAILED(rc)) + return rc; + } + } + + private: + static Result command_handler(void *userdata, const IpcServerRequest *r, u8 *out_data, size_t *out_datasize); + + private: + Context &context; + ProfileManager &profile; + + bool running = false; +}; + +} // namespace fz diff --git a/sysmodule/src/service.cpp b/sysmodule/src/service.cpp deleted file mode 100644 index a02811a..0000000 --- a/sysmodule/src/service.cpp +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (C) 2020 averne -// -// This file is part of Fizeau. -// -// Fizeau is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 2 of the License, or -// (at your option) any later version. -// -// Fizeau is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Fizeau. If not, see . - -#include -#include - -#include "service.hpp" - -namespace fz { - -ams::Result FizeauService::GetIsActive(ams::sf::Out is_active) { - is_active.SetValue(ProfileManager::get_is_active()); - return ams::ResultSuccess(); -} - -ams::Result FizeauService::SetIsActive(bool is_active) { - return ProfileManager::set_is_active(is_active); -} - -ams::Result FizeauService::OpenProfile(ams::sf::Out> out, ProfileId profile) { - out.SetValue(std::make_shared(profile, ProfileManager::get_profile(profile))); - return ams::ResultSuccess(); -} - -ams::Result FizeauService::GetActiveInternalProfileId(ams::sf::Out id) { - id.SetValue(ProfileManager::get_active_internal_profile_id()); - return ams::ResultSuccess(); -} - -ams::Result FizeauService::SetActiveInternalProfileId(ProfileId id) { - ProfileManager::set_active_internal_profile_id(id); - return ams::ResultSuccess(); -} - -ams::Result FizeauService::GetActiveExternalProfileId(ams::sf::Out id) { - id.SetValue(ProfileManager::get_active_external_profile_id()); - return ams::ResultSuccess(); -} - -ams::Result FizeauService::SetActiveExternalProfileId(ProfileId id) { - ProfileManager::set_active_external_profile_id(id); - return ams::ResultSuccess(); -} - -ams::Result IProfile::GetDuskTime(ams::sf::Out