Skip to content

Initial splash screen implementation#1957

Merged
nicolasnoble merged 7 commits intogrumpycoders:mainfrom
wheremyfoodat:splash
Nov 18, 2025
Merged

Initial splash screen implementation#1957
nicolasnoble merged 7 commits intogrumpycoders:mainfrom
wheremyfoodat:splash

Conversation

@wheremyfoodat
Copy link
Copy Markdown
Collaborator

@wheremyfoodat wheremyfoodat commented Aug 15, 2025

  • Displays a static splash screen with usage instructions when the emulator starts
  • Adds a Python script for generating splash screen data from an image file
  • Fixes glTexParameteri usage. The UI offscreen textures are no longer written to before min/mag filters are set, which would make Apple's drivers error.

The current splash screen is a sample and not necessarily final. This code will also likely be replaced when nanovg/nanosvg are replaced. Also worth noting that this relies on stb-image-resize2 for resizing the splash image to the render resolution. This can be avoided, but might require adding a fair bit of code.

Screen.Recording.2025-08-15.at.2.54.46.PM.mov

Image used for the splash screen in the video (Made in Canva, so I sadly can't share the project files easily)
redux-splash

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Aug 15, 2025

Walkthrough

Adds a splash-screen path: a private m_enableSplashScreen flag and getSplashScreen helper; uploads generated RGBA splash into both offscreen textures with NEAREST filtering (unique_ptr-managed data); disables splash on ExecutionFlow::Run; adds splash generator script and integrates splash.cc into the VS project; adjusts Nix submodule handling for stb.

Changes

Cohort / File(s) Summary
GUI splash implementation
src/gui/gui.cc, src/gui/gui.h
Add private bool m_enableSplashScreen (default true) and getSplashScreen(uint32_t,uint32_t) returning std::unique_ptr<uint32_t[]>; on startFrame upload splash via glTexSubImage2D when clearing or splash enabled; set GL_TEXTURE_MIN/MAG_FILTER = GL_NEAREST during splash upload; remove per-frame NEAREST setup from flip(); disable splash at ExecutionFlow::Run; replace raw buffer/new-delete with unique_ptr.
Splash source & build
src/gui/splash.cc, vsprojects/gui/gui.vcxproj, vsprojects/gui/gui.vcxproj.filters
Add new translation unit src/gui/splash.cc and include it in the Visual Studio GUI project and filters.
Tooling for splash data
tools/splash-generator/splash.py
New Python script using Pillow to convert an image to little-endian RGBA8888 uint32_t array with width/height first and emit a formatted C array; CLI expects one argument.
Nix submodules
pcsx-redux.nix
Remove stb from top-level package list/buildInputs and add stb as a dedicated submodule entry with rev and hash.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant App
    participant ExecutionFlow
    participant GUI
    participant GL as Textures

    App->>ExecutionFlow: Run()
    ExecutionFlow->>GUI: StartFrame()/Init()
    alt first frame & m_enableSplashScreen == true
        GUI->>GUI: getSplashScreen(w,h) -> unique_ptr(data)
        GUI->>GL: bind(offscreen tex A)
        GUI->>GL: glTexSubImage2D(data)
        GUI->>GL: set TEXTURE_MIN/MAG_FILTER = NEAREST
        GUI->>GL: bind(offscreen tex B)
        GUI->>GL: glTexSubImage2D(data)
        GUI->>App: flip() (present)
    else subsequent frames
        GUI->>GL: render normal frame content to offscreen textures
        GUI->>App: flip()
    end
    ExecutionFlow->>ExecutionFlow: m_enableSplashScreen = false
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15–20 minutes

Areas to review closely:

  • src/gui/gui.cc splash upload GL calls (formats, alignment, texture binding/state).
  • Ownership/lifetime of splash data returned by getSplashScreen.
  • src/gui/splash.cc platform build implications and correct inclusion in VS project.
  • pcsx-redux.nix submodule entry correctness (rev/hash).

Suggested reviewers

  • NotExactlySiev

Poem

I painted dawn on two small panes,
Pixels neat, no smeared remains.
A hop, a flip, the splash appears,
Then steady frames for all frontiers.
— Rabbit, with a tiny cheer 🐇

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the primary change: implementing an initial splash screen feature for the emulator, which is clearly reflected in the file modifications.
Description check ✅ Passed The description is directly related to the changeset, covering the splash screen implementation, the Python script for generating splash data, and the glTexParameteri fix mentioned in the code changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eec812e and 33adecd.

📒 Files selected for processing (1)
  • src/gui/gui.cc (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/gui/gui.cc (1)
src/gui/splash.cc (2)
  • getSplashScreen (38411-38424)
  • getSplashScreen (38411-38411)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: pcsx-redux (x86_64-linux)
  • GitHub Check: pcsx-redux (aarch64-linux)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: cross-arm64
  • GitHub Check: build
  • GitHub Check: toolchain
  • GitHub Check: coverage
  • GitHub Check: aur-build
🔇 Additional comments (2)
src/gui/gui.cc (2)

556-557: LGTM: Splash screen correctly disabled when emulation starts.

The splash screen is appropriately disabled once emulation begins running, ensuring it only appears during the initial startup phase.


956-969: Verify texture parameters are always initialized before first use.

The fix correctly sets texture parameters before glTexSubImage2D, addressing the Apple driver issue. However, texture parameters are only set when m_clearTextures || m_enableSplashScreen is true.

Since texture storage is reallocated on lines 951-954, consider whether texture parameters should be set unconditionally after reallocation to ensure they're always defined, rather than relying on the splash screen path. While OpenGL texture parameters are "sticky" and persist across glTexImage2D calls, this assumes m_enableSplashScreen is true at least once during initialization.

Please verify:

  1. Is m_enableSplashScreen guaranteed to be true during the first startFrame() call in init()?
  2. Are there any code paths (e.g., command-line flags) that could disable the splash screen before texture parameters are set?

If there's any uncertainty, consider setting texture parameters unconditionally:

     glBindTexture(GL_TEXTURE_2D, m_offscreenTextures[1]);
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_renderSize.x, m_renderSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);

+    // Always set texture parameters after reallocation
+    for (int i = 0; i < 2; i++) {
+        glBindTexture(GL_TEXTURE_2D, m_offscreenTextures[i]);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    }
+
     if (m_clearTextures || m_enableSplashScreen) {
         m_clearTextures = false;
         std::unique_ptr<uint32_t[]> splashImageData = getSplashScreen(m_renderSize.x, m_renderSize.y);

         // Upload to both textures
         for (int i = 0; i < 2; i++) {
             glBindTexture(GL_TEXTURE_2D, m_offscreenTextures[i]);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

             glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_renderSize.x, m_renderSize.y, GL_RGBA, GL_UNSIGNED_BYTE,
                             splashImageData.get());
         }
     }

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (5)
src/gui/gui.h (1)

461-462: Consider annotating getSplashScreen for intent and misuse prevention

Optional refinements:

  • Mark as [[nodiscard]] to prevent accidental ignoring of the returned buffer.
  • Mark noexcept if you’re confident stbir won’t throw in this context (it shouldn’t).
  • Since it doesn’t depend on object state, consider making it static.
-    std::unique_ptr<uint32_t[]> getSplashScreen(uint32_t destWidth, uint32_t destHeight);
+    [[nodiscard]] static std::unique_ptr<uint32_t[]> getSplashScreen(uint32_t destWidth, uint32_t destHeight) noexcept;
tools/splash-generator/splash.py (3)

1-1: Use python3 in the shebang for portability

Many environments map python to Python 2 or don’t provide it at all. Using python3 avoids ambiguity.

-#!/usr/bin/env python
+#!/usr/bin/env python3

12-15: Use a context manager to ensure the image file is closed and add basic error handling

This avoids leaking file descriptors on exceptions and provides a clearer error if Pillow can’t open the file.

-img = Image.open(filename).convert("RGBA")
-width, height = img.size
-pixels = list(img.getdata())
+try:
+    with Image.open(filename) as img:
+        img = img.convert("RGBA")
+        width, height = img.size
+        pixels = list(img.getdata())
+except Exception as e:
+    print(f"Error: failed to open or process image '{filename}': {e}", file=sys.stderr)
+    sys.exit(2)

25-25: Remove extraneous f-string prefix (Ruff F541)

There are no placeholders; drop the f to satisfy linters and avoid confusion.

-print(f"static const uint32_t s_splashImageData[] = {{")
+print("static const uint32_t s_splashImageData[] = {")
src/gui/gui.cc (1)

956-969: Texture parameterization before data upload fixes the macOS driver issue

Setting GL_TEXTURE_MAG_FILTER/MIN_FILTER to GL_NEAREST before calling glTexSubImage2D addresses the Apple driver error where writes occur before filters are set. Uploading the splash to both offscreen textures is sound.

Two small optional improvements:

  • Avoid recomputing the resized splash if m_setupScreenSize toggles repeatedly (e.g., during window resizing): cache the last (w,h) and the buffer to reuse within a frame or until size changes.
  • Consider documenting that glTexImage2D is used solely to allocate storage (pixels=0), so it’s not considered a “write” in the context of the driver issue.
-            std::unique_ptr<uint32_t[]> splashImageData = getSplashScreen(m_renderSize.x, m_renderSize.y);
+            // Optional: cache the resized splash per (w,h) to avoid recompute storms during resize.
+            std::unique_ptr<uint32_t[]> splashImageData = getSplashScreen(m_renderSize.x, m_renderSize.y);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled
  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4f4a00f and 23ee14c.

📒 Files selected for processing (5)
  • src/gui/gui.cc (3 hunks)
  • src/gui/gui.h (2 hunks)
  • tools/splash-generator/splash.py (1 hunks)
  • vsprojects/gui/gui.vcxproj (1 hunks)
  • vsprojects/gui/gui.vcxproj.filters (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/gui/gui.h (1)
src/gui/splash.cc (2)
  • getSplashScreen (38411-38424)
  • getSplashScreen (38411-38411)
src/gui/gui.cc (1)
src/gui/splash.cc (2)
  • getSplashScreen (38411-38424)
  • getSplashScreen (38411-38411)
🪛 Ruff (0.12.2)
tools/splash-generator/splash.py

25-25: f-string without any placeholders

Remove extraneous f prefix

(F541)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: pcsx-redux (aarch64-linux)
  • GitHub Check: pcsx-redux (x86_64-linux)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: macos-build-and-test-toolchain
  • GitHub Check: coverage
  • GitHub Check: toolchain
  • GitHub Check: build
  • GitHub Check: cross-arm64
  • GitHub Check: asan
🔇 Additional comments (6)
vsprojects/gui/gui.vcxproj.filters (1)

106-108: Include of splash.cc in filters looks correct

The new translation unit is properly categorized under "Source Files". This aligns with the project file change and will make the file show up correctly in the VS Solution Explorer.

src/gui/gui.h (2)

28-28: Include is appropriate for unique_ptr usage

This is needed for the new helper returning std::unique_ptr. No issues here.


458-458: m_enableSplashScreen defaulting to true fits the startup-flow

This keeps the splash visible until emulation starts (disabled on Run). Looks good.

vsprojects/gui/gui.vcxproj (1)

131-131: splash.cc added to the GUI build

This ensures the splash functionality is compiled in all configurations. Good.

tools/splash-generator/splash.py (1)

16-21: Endianness and channel order note (FYI)

Packing as 0xAABBGGRR for each pixel is correct for little-endian RGBA8888 consumption (bytes in memory: R G B A). This matches the downstream use with STBIR_RGBA and GL_RGBA/GL_UNSIGNED_BYTE.

src/gui/gui.cc (1)

556-559: Disable splash on Run event is correct and low-risk

This ensures the splash is only shown prior to execution. Clean, simple, and consistent with the PR description.

nicolasnoble
nicolasnoble previously approved these changes Nov 13, 2025
@nicolasnoble
Copy link
Copy Markdown
Member

Looks like this breaks nix.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cdec82a and eec812e.

📒 Files selected for processing (1)
  • pcsx-redux.nix (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-02-11T16:27:49.966Z
Learnt from: NotExactlySiev
Repo: grumpycoders/pcsx-redux PR: 1853
File: pcsx-redux.nix:162-164
Timestamp: 2025-02-11T16:27:49.966Z
Learning: In pcsx-redux's Nix configuration, zlib will be needed as a runtime dependency for Lua functionality in the future, hence the commented placeholder in runtimeDependencies.

Applied to files:

  • pcsx-redux.nix
📚 Learning: 2025-02-11T16:27:22.888Z
Learnt from: NotExactlySiev
Repo: grumpycoders/pcsx-redux PR: 1853
File: 001-patch.diff:92-97
Timestamp: 2025-02-11T16:27:22.888Z
Learning: Lua initialization is temporarily disabled in the Nix build of pcsx-redux (commented out in src/main/main.cc) and will be fixed in a future update. This is an intentional state during the Nix support implementation.

Applied to files:

  • pcsx-redux.nix
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: macos-arm-build-and-test
  • GitHub Check: macos-intel-build-and-test
  • GitHub Check: pcsx-redux (x86_64-linux)
  • GitHub Check: pcsx-redux (aarch64-linux)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: toolchain
  • GitHub Check: cross-arm64
  • GitHub Check: asan
  • GitHub Check: coverage
  • GitHub Check: macos-build-and-test-toolchain
  • GitHub Check: aur-build
  • GitHub Check: build

Comment thread pcsx-redux.nix
Comment on lines +93 to +98
({
owner = "nothings";
repo = "stb";
rev = "ae721c50eaf761660b4f90cc590453cdb0c2acd0";
hash = "sha256-BIhbhXV7q5vodJ3N14vN9mEVwqrP6z9zqEEQrfLPzvI=";
})
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Nov 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Investigate the Nix build breakage.

The stb submodule entry structure is correct and follows the same pattern as other submodules. However, the PR comment explicitly states "Looks like this breaks nix."

The potential issues could be:

  • Incorrect revision or hash causing a fetch failure
  • Build system not finding stb headers at source/third_party/stb
  • Missing build configuration to integrate the stb submodule

Please run the following script to verify the stb submodule configuration:

Additionally, please check the actual Nix build error logs to identify the specific failure point.


🏁 Script executed:

#!/bin/bash
# Verify the stb revision exists and check Nix build configuration

# Check if the stb revision exists in the repository
echo "Checking stb revision..."
curl -s "https://api.github.com/repos/nothings/stb/commits/ae721c50eaf761660b4f90cc590453cdb0c2acd0" | jq -r '.sha // "NOT FOUND"'

# Search for stb usage in build files
echo -e "\nSearching for stb references in build configuration..."
rg -n "stb" --type=make -C2

# Search for stb includes in source files
echo -e "\nSearching for stb header includes..."
rg -n "#include.*stb" -C2

# Check if there are any Nix-specific build errors or configurations
echo -e "\nSearching for Nix build references to stb..."
rg -n "stb" -g "*.nix" -C3

Length of output: 1602


🏁 Script executed:

#!/bin/bash
# Investigate build configuration and stb integration

# Look for CMakeLists.txt or other build files
echo "=== Looking for build configuration files ==="
fd -e cmake -e "CMakeLists.txt" | head -20

# Search for include_directories or add_include_directories in CMake
echo -e "\n=== Searching for include_directories configuration ==="
rg -n "include_directories|target_include_directories" -C2 | head -40

# Look for third_party in CMakeLists files
echo -e "\n=== Checking third_party references in build files ==="
rg -n "third_party" -g "CMakeLists.txt" -C2

# Check if there's a stb directory already
echo -e "\n=== Checking for stb directory ==="
fd -t d "stb$" 2>/dev/null

# Look at how third_party/clip is configured (since it uses stb)
echo -e "\n=== Checking third_party structure and dependencies ==="
ls -la third_party/ 2>/dev/null | head -20

# Check if there's any stb configuration or build instructions
echo -e "\n=== Looking for stb-related build configuration ==="
rg -n "stb" --type=cmake -C2

Length of output: 4634


🏁 Script executed:

#!/bin/bash
# Deep dive into stb directory and build configuration

# Check what's in the stb directory
echo "=== Contents of third_party/stb/ ==="
ls -la third_party/stb/ 2>/dev/null || echo "Directory not found or empty"

# Check size and file count
echo -e "\n=== stb directory size and file count ==="
find third_party/stb/ -type f 2>/dev/null | wc -l
du -sh third_party/stb/ 2>/dev/null

# Look for any build files at repo root
echo -e "\n=== Looking for root-level build configuration ==="
ls -la | grep -E "CMakeLists|meson|setup|configure|Makefile|build" || echo "No standard build files found"

# Check the pcsx-redux.nix more carefully around fetchSubmodule and postUnpack
echo -e "\n=== Examining pcsx-redux.nix structure (around submodule handling) ==="
sed -n '105,130p' pcsx-redux.nix

# Look for how stb was previously handled (if any history)
echo -e "\n=== Checking if stb is referenced in any other Nix config ==="
rg -n "stb" -g "*.nix" -A2 -B2

# Check if stb headers actually exist in the submodule
echo -e "\n=== Checking for stb header files ==="
find third_party/stb -name "stb_*.h" 2>/dev/null | head -10

Length of output: 1563


🏁 Script executed:

#!/bin/bash
# Check Makefile and build configuration for stb handling

# Search Makefile for stb references
echo "=== Searching Makefile for stb references ==="
rg -n "stb" Makefile -C2

# Check how include paths are configured
echo -e "\n=== Checking include path configuration in Makefile ==="
rg -n "INCLUDE|CFLAGS|CPPFLAGS" Makefile -C1 | head -40

# Look for third_party references in Makefile
echo -e "\n=== Checking third_party references in Makefile ==="
rg -n "third_party" Makefile -C1

# Check if there's a specific build config for headers
echo -e "\n=== Looking for include directory setup ==="
rg -n "source/third_party|third_party" Makefile | head -20

# Verify the hash by checking if repo fetch would work (check GitHub)
echo -e "\n=== Testing GitHub API for stb repo ==="
curl -s "https://api.github.com/repos/nothings/stb/contents/" | jq -r '.[0:3] | .[] | .name' 2>/dev/null || echo "API call failed or no results"

# Look for any errors or comments in the PR/Nix about this change
echo -e "\n=== Full submodules section in pcsx-redux.nix ==="
sed -n '80,105p' pcsx-redux.nix

Length of output: 10991


The stb submodule is not being fetched, causing build failure.

The third_party/stb/ directory is empty despite the Nix submodule entry. The build will fail because the code includes stb headers (third_party/clip/image.cpp, third_party/ImFileDialog/ImFileDialog.cpp, and src/gui/splash.cc all require stb headers), but the files won't exist in the expected location.

The submodule entry structure is correct, but the fetchFromGitHub call is not actually copying files into source/third_party/stb. Verify the hash is correct for the specified revision, or check the actual Nix build logs to see if fetchFromGitHub is failing silently.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shut the hell up

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NotExactlySiev, understood. I'll step back on this issue.


🧠 Learnings used
Learnt from: NotExactlySiev
Repo: grumpycoders/pcsx-redux PR: 1853
File: pcsx-redux.nix:162-164
Timestamp: 2025-02-11T16:27:49.966Z
Learning: In pcsx-redux's Nix configuration, zlib will be needed as a runtime dependency for Lua functionality in the future, hence the commented placeholder in runtimeDependencies.

Learnt from: NotExactlySiev
Repo: grumpycoders/pcsx-redux PR: 1853
File: 001-patch.diff:92-97
Timestamp: 2025-02-11T16:27:22.888Z
Learning: Lua initialization is temporarily disabled in the Nix build of pcsx-redux (commented out in src/main/main.cc) and will be fixed in a future update. This is an intentional state during the Nix support implementation.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lmao

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

@wheremyfoodat
Copy link
Copy Markdown
Collaborator Author

Should be good to go I think

@nicolasnoble nicolasnoble merged commit b745534 into grumpycoders:main Nov 18, 2025
20 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants