diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ad6c27..52719f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: clang-format: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: clang-format run: | docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./src @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-22.04 needs: clang-format steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: create version.h run: | git_hash=$(git rev-parse --short "$GITHUB_SHA") @@ -48,7 +48,7 @@ jobs: - name: zip artifact run: zip -r ${{ env.REPOSITORY_NAME }}_${{ env.DATETIME }}.zip *.wms - name: Create Release - uses: "softprops/action-gh-release@v1" + uses: "softprops/action-gh-release@v2" with: tag_name: ${{ env.REPOSITORY_NAME }}-${{ env.DATETIME }} draft: false diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 9675ecc..db9e1f3 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -6,7 +6,7 @@ jobs: clang-format: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: clang-format run: | docker run --rm -v ${PWD}:/src ghcr.io/wiiu-env/clang-format:13.0.0-2 -r ./src @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-22.04 needs: clang-format steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: build binary with logging run: | docker build . -t builder @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-22.04 needs: clang-format steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: create version.h run: | git_hash=$(git rev-parse --short "${{ github.event.pull_request.head.sha }}") diff --git a/.gitignore b/.gitignore index ba57c28..98a796f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ build/ cmake-build-debug/ CMakeLists.txt *.wms +*.zip diff --git a/Dockerfile b/Dockerfile index 0a1aac3..017897f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ -FROM ghcr.io/wiiu-env/devkitppc:20230621 +FROM ghcr.io/wiiu-env/devkitppc:20240423 COPY --from=ghcr.io/wiiu-env/libnotifications:20230621 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libmappedmemory:20230621 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO -COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20230719 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20240424 /artifacts $DEVKITPRO WORKDIR project diff --git a/src/export.cpp b/src/export.cpp index 1319232..7ed01c1 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -8,6 +8,8 @@ void ExportCleanUp() { std::lock_guard lock(gNotificationListMutex); gNotificationList.clear(); + std::lock_guard overlay_lock(gOverlayFrameMutex); + gOverlayQueueDuringStartup.clear(); } NotificationModuleStatus NMAddStaticNotification(const char *text, @@ -18,9 +20,6 @@ NotificationModuleStatus NMAddStaticNotification(const char *text, NMColor backgroundColor, void (*finishFunc)(NotificationModuleHandle, void *context), void *context) { - if (!gOverlayFrame) { - return NOTIFICATION_MODULE_RESULT_OVERLAY_NOT_READY; - } NotificationStatus status; switch (type) { @@ -46,7 +45,14 @@ NotificationModuleStatus NMAddStaticNotification(const char *text, return NOTIFICATION_MODULE_RESULT_ALLOCATION_FAILED; } - gOverlayFrame->addNotification(notification); + { + std::lock_guard lock(gOverlayFrameMutex); + if (gOverlayFrame) { + gOverlayFrame->addNotification(std::move(notification)); + } else { + gOverlayQueueDuringStartup.push_back(std::move(notification)); + } + } return NOTIFICATION_MODULE_RESULT_SUCCESS; } @@ -70,9 +76,6 @@ NotificationModuleStatus NMAddDynamicNotification(const char *text, return NOTIFICATION_MODULE_RESULT_INVALID_ARGUMENT; } *outHandle = 0; - if (!gOverlayFrame) { - return NOTIFICATION_MODULE_RESULT_OVERLAY_NOT_READY; - } auto notification = make_shared_nothrow( text, @@ -91,8 +94,15 @@ NotificationModuleStatus NMAddDynamicNotification(const char *text, { std::lock_guard lock(gNotificationListMutex); *outHandle = notification->getHandle(); - gOverlayFrame->addNotification(notification); - gNotificationList.push_front(notification); + { + std::lock_guard overlay_lock(gOverlayFrameMutex); + if (gOverlayFrame) { + gOverlayFrame->addNotification(notification); + } else { + gOverlayQueueDuringStartup.push_back(notification); + } + } + gNotificationList.push_front(std::move(notification)); } return NOTIFICATION_MODULE_RESULT_SUCCESS; diff --git a/src/function_patches.cpp b/src/function_patches.cpp index e86cc51..6d302d5 100644 --- a/src/function_patches.cpp +++ b/src/function_patches.cpp @@ -110,19 +110,30 @@ bool drawScreenshotSavedTexture(const GX2ColorBuffer *colorBuffer, GX2ScanTarget DECL_FUNCTION(void, GX2Init, uint32_t attributes) { real_GX2Init(attributes); if (!gOverlayInitDone) { + std::lock_guard overlay_lock(gOverlayFrameMutex); DEBUG_FUNCTION_LINE_VERBOSE("Init Overlay"); gOverlayFrame = new (std::nothrow) OverlayFrame(1280.0f, 720.0f); if (!gOverlayFrame) { - OSFatal("Failed to alloc gOverlayFrame"); + OSFatal("NotificationModule: Failed to alloc gOverlayFrame"); } + // Add notification that had been called before the overlay was ready + for (const auto ¬ification : gOverlayQueueDuringStartup) { + gOverlayFrame->addNotification(notification); + } + gOverlayQueueDuringStartup.clear(); + // Allocate shader. - ColorShader::instance(); - Texture2DShader::instance(); + if (ColorShader::instance() == nullptr) { + OSFatal("NotificationModule: Failed to alloc ColorShader"); + } + if (Texture2DShader::instance() == nullptr) { + OSFatal("NotificationModule: Failed to alloc Texture2DShader"); + } // has been allocated in WUMS INIT if (!gContextState) { - OSFatal("Failed to alloc gContextState"); + OSFatal("NotificationModule: Failed to alloc gContextState"); } real_GX2SetupContextStateEx(gContextState, GX2_TRUE); DCInvalidateRange(gContextState, sizeof(GX2ContextState)); // Important! diff --git a/src/gui/SchriftGX2.cpp b/src/gui/SchriftGX2.cpp index 7752593..e7daeb6 100644 --- a/src/gui/SchriftGX2.cpp +++ b/src/gui/SchriftGX2.cpp @@ -217,6 +217,7 @@ ftgxCharData *SchriftGX2::cacheGlyphData(wchar_t charCode, int16_t pixelSize) { textureHeight = mtx.minHeight; SFT_Image img = { + .pixels = nullptr, .width = textureWidth, .height = textureHeight, }; @@ -307,7 +308,7 @@ bool SchriftGX2::loadGlyphData(SFT_Image *bmp, ftgxCharData *charData, ftGX2Data auto *src = (uint8_t *) bmp->pixels; auto *dst = (uint32_t *) charData->texture->surface.image; - uint32_t x, y; + int32_t x, y; for (y = 0; y < bmp->height; y++) { for (x = 0; x < bmp->width; x++) { @@ -391,6 +392,7 @@ int16_t SchriftGX2::getStyleOffsetHeight(int16_t format, uint16_t pixelSize) { */ uint16_t SchriftGX2::drawText(int16_t x, int16_t y, int16_t z, const wchar_t *text, int16_t pixelSize, const glm::vec4 &color, uint16_t textStyle, uint16_t textWidth, const float &textBlur, const float &colorBlurIntensity, const glm::vec4 &blurColor) { + (void) textWidth; if (!text) { return 0; } diff --git a/src/main.cpp b/src/main.cpp index 2d5b032..2303cde 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,7 +11,7 @@ WUMS_MODULE_EXPORT_NAME("homebrew_notifications"); -#define VERSION "v0.1.1" +#define VERSION "v0.1.2" WUMS_DEPENDS_ON(homebrew_memorymapping); WUMS_DEPENDS_ON(homebrew_functionpatcher); @@ -20,7 +20,7 @@ WUMS_INITIALIZE() { initLogging(); if (FunctionPatcher_InitLibrary() != FUNCTION_PATCHER_RESULT_SUCCESS) { - OSFatal("homebrew_notifications: FunctionPatcher_InitLibrary failed"); + OSFatal("NotificationModule: FunctionPatcher_InitLibrary failed"); } DEBUG_FUNCTION_LINE("Patch NotificationModule functions"); for (uint32_t i = 0; i < function_replacements_size; i++) { @@ -38,22 +38,22 @@ WUMS_INITIALIZE() { sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT); if (gContextState == nullptr) { - OSFatal("Failed to allocate gContextState"); + OSFatal("NotificationModule: Failed to allocate gContextState"); } else { - DEBUG_FUNCTION_LINE("Allocated %d bytes for gCont extState", sizeof(GX2ContextState)); + DEBUG_FUNCTION_LINE_VERBOSE("Allocated %d bytes for gContextState", sizeof(GX2ContextState)); } void *font = nullptr; uint32_t size = 0; - OSGetSharedData(OS_SHAREDDATATYPE_FONT_STANDARD, 0, &font, &size); - if (font && size) { + if (OSGetSharedData(OS_SHAREDDATATYPE_FONT_STANDARD, 0, &font, &size) && font && size > 0) { gFontSystem = new (std::nothrow) SchriftGX2((uint8_t *) font, (int32_t) size); - if (gFontSystem) { - GuiText::setPresetFont(gFontSystem); - } else { - DEBUG_FUNCTION_LINE_ERR("Failed to init font system"); - } } + if (gFontSystem != nullptr) { + GuiText::setPresetFont(gFontSystem); + } else { + OSFatal("NotificationModule: Failed to init font system"); + } + OSMemoryBarrier(); deinitLogging(); } @@ -65,6 +65,7 @@ WUMS_APPLICATION_STARTS() { } WUMS_APPLICATION_ENDS() { + gDrawReady = false; if (gOverlayFrame) { gOverlayFrame->clearElements(); } @@ -76,3 +77,9 @@ WUMS_APPLICATION_ENDS() { Texture2DShader::destroyInstance(); deinitLogging(); } + +WUMS_DEINITIALIZE() { + delete gOverlayFrame; + delete gFontSystem; + MEMFreeToMappedMemory(gContextState); +} \ No newline at end of file diff --git a/src/retain_vars.cpp b/src/retain_vars.cpp index 43c27de..e189435 100644 --- a/src/retain_vars.cpp +++ b/src/retain_vars.cpp @@ -1,10 +1,12 @@ #include "retain_vars.hpp" -GX2SurfaceFormat gTVSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8; -GX2SurfaceFormat gDRCSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8; -GX2ContextState *gContextState = nullptr; -GX2ContextState *gOriginalContextState = nullptr; -OverlayFrame *gOverlayFrame = nullptr; -SchriftGX2 *gFontSystem = nullptr; -bool gOverlayInitDone = false; -bool gDrawReady = false; \ No newline at end of file +GX2SurfaceFormat gTVSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8; +GX2SurfaceFormat gDRCSurfaceFormat = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8; +GX2ContextState *gContextState = nullptr; +GX2ContextState *gOriginalContextState = nullptr; +std::mutex gOverlayFrameMutex = {}; +std::vector> gOverlayQueueDuringStartup = {}; +OverlayFrame *gOverlayFrame = nullptr; +SchriftGX2 *gFontSystem = nullptr; +bool gOverlayInitDone = false; +bool gDrawReady = false; \ No newline at end of file diff --git a/src/retain_vars.hpp b/src/retain_vars.hpp index 2a3c1d8..3648cb2 100644 --- a/src/retain_vars.hpp +++ b/src/retain_vars.hpp @@ -7,6 +7,8 @@ extern GX2SurfaceFormat gTVSurfaceFormat; extern GX2SurfaceFormat gDRCSurfaceFormat; extern GX2ContextState *gContextState; extern GX2ContextState *gOriginalContextState; +extern std::mutex gOverlayFrameMutex; +extern std::vector> gOverlayQueueDuringStartup; extern OverlayFrame *gOverlayFrame; extern SchriftGX2 *gFontSystem; extern bool gOverlayInitDone;