Skip to content

psyqo: add selectable framebuffer Layout - #2051

Open
nicolasnoble wants to merge 2 commits into
grumpycoders:mainfrom
nicolasnoble:psyqo-gpu-layout
Open

psyqo: add selectable framebuffer Layout#2051
nicolasnoble wants to merge 2 commits into
grumpycoders:mainfrom
nicolasnoble:psyqo-gpu-layout

Conversation

@nicolasnoble

Copy link
Copy Markdown
Member

Add a compile-time GPU::Layout (Default, VerticalSwitch, Horizontal) selecting
where the two display buffers sit in VRAM, routed through a new setDisplayArea()
helper plus the scissor/clear paths. Default is the existing vertically-stacked
pair (0,0)/(0,256) and is behaviorally unchanged. VerticalSwitch offsets the
first buffer down by 16 lines; Horizontal places the buffers side by side.
Selected via PSYQO_USE_VERTICAL_SWITCH_LAYOUT / PSYQO_USE_HORIZONTAL_LAYOUT.

Stacked on #2050 (the reinitialize() split); rebase once that merges.

Add a compile-time GPU::Layout (Default, VerticalSwitch, Horizontal) selecting
where the two display buffers sit in VRAM, routed through a new setDisplayArea()
helper plus the scissor/clear paths. Default is the existing vertically-stacked
pair (0,0)/(0,256) and is behaviorally unchanged. VerticalSwitch offsets the
first buffer down by 16 lines; Horizontal places the buffers side by side.
Selected via PSYQO_USE_VERTICAL_SWITCH_LAYOUT / PSYQO_USE_HORIZONTAL_LAYOUT.

Co-authored-by: Elias Daler <eliasdaler@protonmail.com>
Signed-off-by: Nicolas 'Pixel' Noble <nicolas@nobis-crew.org>
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d44ca6dd-4335-4338-b2b5-da86ea7c5108

📥 Commits

Reviewing files that changed from the base of the PR and between 9b71308 and f5bea32.

📒 Files selected for processing (2)
  • src/mips/psyqo/gpu.hh
  • src/mips/psyqo/src/gpu.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/mips/psyqo/src/gpu.cpp

📝 Walkthrough

Walkthrough

Adds compile-time selectable GPU layouts, separates register setup into reinitialize, centralizes display-area updates in setDisplayArea, and applies layout-specific coordinate calculations to scissor and clear regions.

Changes

GPU Layout Support

Layer / File(s) Summary
GPU layout contract
src/mips/psyqo/gpu.hh
Adds Layout, compile-time c_layout, and the private setDisplayArea declaration.
Initialization and display-area flow
src/mips/psyqo/src/gpu.cpp
Moves GPU setup into reinitialize, delegates to it from initialize, and uses setDisplayArea(firstBuffer) from flip().
Layout-aware region calculations
src/mips/psyqo/src/gpu.cpp
Updates current and next scissor and fast-fill clear calculations for the selected layout.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant GPU
  participant Hardware_GPU_Ctrl

  Caller->>GPU: initialize(config)
  GPU->>GPU: initialize COUNTERS[1]
  GPU->>GPU: reinitialize(config)
  GPU->>Hardware_GPU_Ctrl: write GPU setup registers

  Caller->>GPU: flip()
  GPU->>GPU: setDisplayArea(firstBuffer)
  GPU->>Hardware_GPU_Ctrl: write display-area offsets based on c_layout
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title concisely describes the main change: adding a selectable framebuffer layout.
Description check ✅ Passed The description matches the changes and explains the new GPU::Layout options and helpers.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/mips/psyqo/src/gpu.cpp (2)

73-74: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Initialize the display area using the selected layout.

VerticalSwitch puts the first buffer at y=16, but reinitialize() still resets the display area to (0,0), so the initial display/reinitialize path points at a region that is not one of the configured buffers.

🛠️ Proposed fix
-    // Display Area
-    Hardware::GPU::Ctrl = 0x05000000;
+    // Display Area
+    if constexpr (c_layout == Layout::VerticalSwitch) {
+        Hardware::GPU::Ctrl = 0x05000000 | (16 << 10);
+    } else {
+        Hardware::GPU::Ctrl = 0x05000000;
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mips/psyqo/src/gpu.cpp` around lines 73 - 74, The display area setup in
reinitialize() is hardcoded to (0,0) instead of using the active layout, so
VerticalSwitch can point at an unconfigured region. Update the GPU display-area
initialization in gpu.cpp to derive the starting y offset from the selected
layout (the same layout used by the buffer configuration), and make sure the
initial display/reinitialize path selects one of the configured buffers rather
than always resetting to the top-left.

84-101: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Guard Horizontal layout against 640-wide modes.

With m_width = 640, the horizontal layout needs 1280 pixels of VRAM width for two side-by-side buffers, but this file treats VRAM as 1024 pixels wide. That makes the second buffer/scissor/clear region extend past VRAM.

🛠️ Proposed fix
     } else {
         m_width = 368;
     }
+
+    if constexpr (c_layout == Layout::Horizontal) {
+        Kernel::assert(m_width <= 512, "Horizontal GPU layout requires display width <= 512");
+    }
 
     if (config.config.videoMode == Configuration::VM_NTSC) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mips/psyqo/src/gpu.cpp` around lines 84 - 101, The horizontal layout in
the GPU width setup does not account for 640-wide mode exceeding the assumed
1024-pixel VRAM span. Update the logic in the GPU width/layout handling around
the width selection and horizontal buffer placement so that 640-wide modes are
rejected, clamped, or routed to a safe layout before `Horizontal` computes the
two side-by-side buffers, scissor, and clear regions.
🧹 Nitpick comments (1)
src/mips/psyqo/src/gpu.cpp (1)

291-372: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Centralize buffer rectangle calculation.

The same layout/parity mapping is repeated across scissor and clear paths, and it has already diverged from setDisplayArea. A small helper returning the current/next buffer origin would reduce the risk of future layout bugs. As per static analysis, CodeScene flags duplication across getClear, getNextClear, getNextScissor, and getScissor.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mips/psyqo/src/gpu.cpp` around lines 291 - 372, Centralize the
buffer-origin logic used by getScissor, getNextScissor, getClear, and
getNextClear in psyqo::GPU, since the current layout/parity mapping is
duplicated and has already drifted from setDisplayArea. Introduce a small helper
that computes the current/next buffer origin for each Layout variant and parity
state, then reuse it in those methods so the scissor and clear rectangles stay
consistent and future layout changes only need one update.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mips/psyqo/gpu.hh`:
- Around line 112-118: Reject conflicting layout defines at compile time in the
GPU layout selection block by updating the conditional around `c_layout` to
detect when both `PSYQO_USE_VERTICAL_SWITCH_LAYOUT` and
`PSYQO_USE_HORIZONTAL_LAYOUT` are defined and fail the build instead of silently
choosing `Layout::VerticalSwitch`. Keep the existing `c_layout` selection logic
for the valid single-define cases, but add a compile-time guard near the
`Layout` static constant so configuration mistakes are caught immediately.

In `@src/mips/psyqo/src/gpu.cpp`:
- Around line 223-224: The horizontal display-area mapping in flip() is reversed
relative to the vertical/default path, causing firstBuffer to point at the wrong
buffer. Update the Layout::Horizontal branch so it maps the next drawing buffer
to the opposite display buffer, matching the existing behavior in the other
layout case. Refer to flip() and the c_layout/Layout::Horizontal conditional
when making the change.

---

Outside diff comments:
In `@src/mips/psyqo/src/gpu.cpp`:
- Around line 73-74: The display area setup in reinitialize() is hardcoded to
(0,0) instead of using the active layout, so VerticalSwitch can point at an
unconfigured region. Update the GPU display-area initialization in gpu.cpp to
derive the starting y offset from the selected layout (the same layout used by
the buffer configuration), and make sure the initial display/reinitialize path
selects one of the configured buffers rather than always resetting to the
top-left.
- Around line 84-101: The horizontal layout in the GPU width setup does not
account for 640-wide mode exceeding the assumed 1024-pixel VRAM span. Update the
logic in the GPU width/layout handling around the width selection and horizontal
buffer placement so that 640-wide modes are rejected, clamped, or routed to a
safe layout before `Horizontal` computes the two side-by-side buffers, scissor,
and clear regions.

---

Nitpick comments:
In `@src/mips/psyqo/src/gpu.cpp`:
- Around line 291-372: Centralize the buffer-origin logic used by getScissor,
getNextScissor, getClear, and getNextClear in psyqo::GPU, since the current
layout/parity mapping is duplicated and has already drifted from setDisplayArea.
Introduce a small helper that computes the current/next buffer origin for each
Layout variant and parity state, then reuse it in those methods so the scissor
and clear rectangles stay consistent and future layout changes only need one
update.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4f19267a-91c5-4670-8068-7952ccf42e65

📥 Commits

Reviewing files that changed from the base of the PR and between e909cc3 and 9b71308.

📒 Files selected for processing (2)
  • src/mips/psyqo/gpu.hh
  • src/mips/psyqo/src/gpu.cpp

Comment thread src/mips/psyqo/gpu.hh
Comment on lines +112 to +118
#if defined(PSYQO_USE_VERTICAL_SWITCH_LAYOUT)
static constexpr Layout c_layout = Layout::VerticalSwitch;
#elif defined(PSYQO_USE_HORIZONTAL_LAYOUT)
static constexpr Layout c_layout = Layout::Horizontal;
#else
static constexpr Layout c_layout = Layout::Default;
#endif

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reject conflicting layout defines at compile time.

If both PSYQO_USE_VERTICAL_SWITCH_LAYOUT and PSYQO_USE_HORIZONTAL_LAYOUT are defined, this silently selects VerticalSwitch, which can hide a build configuration mistake.

🛠️ Proposed fix
+#if defined(PSYQO_USE_VERTICAL_SWITCH_LAYOUT) && defined(PSYQO_USE_HORIZONTAL_LAYOUT)
+#error "Only one PSYQO GPU layout macro can be defined"
+#endif
+
 `#if` defined(PSYQO_USE_VERTICAL_SWITCH_LAYOUT)
     static constexpr Layout c_layout = Layout::VerticalSwitch;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#if defined(PSYQO_USE_VERTICAL_SWITCH_LAYOUT)
static constexpr Layout c_layout = Layout::VerticalSwitch;
#elif defined(PSYQO_USE_HORIZONTAL_LAYOUT)
static constexpr Layout c_layout = Layout::Horizontal;
#else
static constexpr Layout c_layout = Layout::Default;
#endif
`#if` defined(PSYQO_USE_VERTICAL_SWITCH_LAYOUT) && defined(PSYQO_USE_HORIZONTAL_LAYOUT)
`#error` "Only one PSYQO GPU layout macro can be defined"
`#endif`
`#if` defined(PSYQO_USE_VERTICAL_SWITCH_LAYOUT)
static constexpr Layout c_layout = Layout::VerticalSwitch;
`#elif` defined(PSYQO_USE_HORIZONTAL_LAYOUT)
static constexpr Layout c_layout = Layout::Horizontal;
`#else`
static constexpr Layout c_layout = Layout::Default;
`#endif`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mips/psyqo/gpu.hh` around lines 112 - 118, Reject conflicting layout
defines at compile time in the GPU layout selection block by updating the
conditional around `c_layout` to detect when both
`PSYQO_USE_VERTICAL_SWITCH_LAYOUT` and `PSYQO_USE_HORIZONTAL_LAYOUT` are defined
and fail the build instead of silently choosing `Layout::VerticalSwitch`. Keep
the existing `c_layout` selection logic for the valid single-define cases, but
add a compile-time guard near the `Layout` static constant so configuration
mistakes are caught immediately.

Comment on lines +223 to +224
if constexpr (c_layout == Layout::Horizontal) {
x = firstBuffer ? 0 : m_width;

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.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Flip the horizontal display-area mapping.

flip() passes whether the next drawing buffer is the first buffer; vertical/default map that to the opposite buffer for display, but the horizontal branch maps it to the same buffer. After the first flip, it displays the untouched second buffer instead of the first rendered buffer.

🐛 Proposed fix
     uint32_t y = 0;
     if constexpr (c_layout == Layout::Horizontal) {
-        x = firstBuffer ? 0 : m_width;
+        x = firstBuffer ? m_width : 0;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if constexpr (c_layout == Layout::Horizontal) {
x = firstBuffer ? 0 : m_width;
if constexpr (c_layout == Layout::Horizontal) {
x = firstBuffer ? m_width : 0;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mips/psyqo/src/gpu.cpp` around lines 223 - 224, The horizontal
display-area mapping in flip() is reversed relative to the vertical/default
path, causing firstBuffer to point at the wrong buffer. Update the
Layout::Horizontal branch so it maps the next drawing buffer to the opposite
display buffer, matching the existing behavior in the other layout case. Refer
to flip() and the c_layout/Layout::Horizontal conditional when making the
change.

@pull-request-size pull-request-size Bot added size/M and removed size/L labels Jul 21, 2026
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.

1 participant