# How sceVideoOut Is Implemented in SharpEmu: PS5 Video-Out Emulation Explained

> Explore the sceVideoOut implementation in SharpEmu. Learn how this C# HLE layer handles PS5 video ports and Vulkan frame presentation via the SharpEmu.Libs.VideoOut namespace.

- Repository: [Berk/sharpemu](https://github.com/par274/sharpemu)
- Tags: internals
- Published: 2026-07-16

---

**SharpEmu implements the PlayStation 5's sceVideoOut API as a high-level emulation (HLE) layer in C#, using the `SharpEmu.Libs.VideoOut` namespace to manage video ports, buffer registration, and Vulkan-based frame presentation.**

The `par274/sharpemu` repository provides a complete software implementation of the PlayStation 5's video output subsystem, enabling games to render frames through the **sceVideoOut** system call interface. This implementation bridges guest GPU memory to the host display using Vulkan, while accurately simulating vblank timing and flip events to maintain compatibility with commercial titles.

## Core Components of the sceVideoOut Implementation

SharpEmu's video output system consists of three architectural layers defined in the `SharpEmu.Libs.VideoOut` namespace:

- **API Entry Points**: Exported functions marked with `[SysAbiExport]` in [`src/SharpEmu.Libs/VideoOut/VideoOutExports.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Libs/VideoOut/VideoOutExports.cs) expose `sceVideoOutOpen`, `sceVideoOutSubmitFlip`, and `sceVideoOutAddVblankEvent` to the emulator's HLE dispatcher.
- **Port State Management**: The `VideoOutPortState` class tracks per-handle data including buffer groups, flip counters, and timing parameters, protected by the static `_stateGate` lock.
- **Presentation Layer**: `VulkanVideoPresenter` in [`src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Libs/VideoOut/VulkanVideoPresenter.cs) consumes frames from `GuestGpu` and displays them to the host window.

## Opening and Configuring Video Ports

The initialization sequence begins with `sceVideoOutOpen`, which validates that the `busType` equals `SceVideoOutBusTypeMain`, the `index` is 0, and the `userId` is 0 or 255. Upon validation, it instantiates a `VideoOutPortState` object, stores it in the static `_ports` dictionary, and returns a unique handle to the guest application.

Configuration continues through `sceVideoOutSetFlipRate`, `sceVideoOutSetBufferAttribute`, and `sceVideoOutRegisterBuffers`. These methods populate the `VideoOutPortState` fields:

- `FlipRate`: Set to 30 Hz, 20 Hz, or 60 Hz
- `OutputWidth`, `OutputHeight`, and `RefreshRate`: Define display dimensions
- `Groups` and `BufferSlots`: Store metadata and guest memory addresses for registered buffers

## Submitting Flips and Managing Frame Delivery

The `sceVideoOutSubmitFlip` syscall triggers the frame presentation pipeline. Internally, this calls `SubmitFlip`, which performs several critical operations:

1. Validates the port handle and buffer index against registered slots.
2. Updates `CurrentBuffer` and increments `FlipCount`.
3. Constructs a `SceVideoOutInternalEventFlip` hint for event notification.
4. Invokes `GuestGpu.Current.TrySubmitGuestImage` to upload the guest display buffer to the host GPU, converting pixel formats via `MapPixelFormatToGuestTextureFormat`.
5. Optionally dumps the frame if `_dumpVideoOut` is enabled.
6. Calls `PaceFlip` to enforce the requested flip rate unless `SHARPEMU_NO_FLIP_PACING=1` is set.
7. Triggers flip events directly or through `VulkanVideoPresenter.SubmitOrderedGuestAction` to maintain GPU work ordering.

## Vblank Timing and Event Handling

SharpEmu simulates hardware vblank signals through a dedicated background thread. The `StartVblankThreadOnce` method initializes `VblankTickLoop`, which runs at the port's refresh cadence and increments `VblankCount` each cycle.

Event registration works through `sceVideoOutAddFlipEvent` and `sceVideoOutAddVblankEvent`, which add entries to the port's `FlipEvents` and `VblankEvents` lists. When vblank occurs, the loop triggers events via `KernelEventQueueCompatExports.TriggerDisplayEvent`.

For precise timing, `sceVideoOutWaitVblank` uses `HostTiming.SleepUntil` with a high-resolution `Stopwatch` to calculate the next vblank deadline, avoiding scheduler quantum overshoot that would disrupt frame pacing.

## Vulkan Integration and Pixel Format Validation

The presentation layer relies on `VulkanVideoPresenter` to consume frames from `GuestGpu` and display them in a host window. This class handles ordering of GPU work and maintains performance counters.

During initialization, the static constructor in [`VideoOutExports.cs`](https://github.com/par274/sharpemu/blob/main/VideoOutExports.cs) invokes `RunPixelFormatSelfChecks()` to verify that PS5 pixel-format constants correctly map to the emulator's internal texture formats, preventing display corruption before the first frame renders.

## Shutdown Coordination and Lifecycle Management

When the presentation window closes or the host requests termination, `NotifyPresentationWindowClosed` and `NotifyHostInterrupt` initiate a graceful shutdown sequence. These methods shut down the Vulkan presenter, coordinate with [`AudioOutExports.cs`](https://github.com/par274/sharpemu/blob/main/AudioOutExports.cs) to stop audio output, and terminate the process cleanly.

## Practical Usage Example

```csharp
// Open a video-out port (equivalent to sceVideoOutOpen)
int handle = VideoOutExports.VideoOutOpen(ctx);

// Configure 30 Hz output (sceVideoOutSetFlipRate)
VideoOutExports.VideoOutSetFlipRate(ctx);

// Register display buffers (sceVideoOutRegisterBuffers)
ulong bufferAddr = 0x1234_5678_9000;
VideoOutExports.VideoOutSetBufferAttribute(ctx);
VideoOutExports.VideoOutRegisterBuffers(ctx);

// Submit a frame (sceVideoOutSubmitFlip)
VideoOutExports.VideoOutSubmitFlip(ctx);

// Wait for vblank (sceVideoOutWaitVblank)
VideoOutExports.VideoOutWaitVblank(ctx);

```

Each function receives a `CpuContext ctx` containing guest registers and memory, with arguments extracted from `ctx[CpuRegister.*]`.

## Summary

- SharpEmu implements **sceVideoOut** as a high-level emulation layer in the `SharpEmu.Libs.VideoOut` namespace.
- **VideoOutExports.cs** contains the syscall implementations and `VideoOutPortState` management logic.
- **VulkanVideoPresenter.cs** handles the actual frame display using the host GPU.
- The implementation supports configurable flip rates (20/30/60 Hz), precise vblank timing via `HostTiming.SleepUntil`, and pixel format validation.
- Frame submission coordinates with `GuestGpu` to copy guest memory to Vulkan textures while respecting flip pacing settings.

## Frequently Asked Questions

### How does SharpEmu handle the PS5's video output without actual hardware?

SharpEmu uses high-level emulation (HLE) where the `sceVideoOut` syscalls are intercepted and implemented in C# rather than passed to physical hardware. The [`VideoOutExports.cs`](https://github.com/par274/sharpemu/blob/main/VideoOutExports.cs) file provides software implementations that translate guest GPU commands into Vulkan API calls on the host, effectively simulating the video-out bus in software.

### What determines the frame rate in SharpEmu's sceVideoOut implementation?

The frame rate is controlled by `sceVideoOutSetFlipRate`, which configures the `VideoOutPortState.FlipRate` field to 20 Hz, 30 Hz, or 60 Hz. The `PaceFlip` method enforces this timing unless the `SHARPEMU_NO_FLIP_PACING` environment variable is set to 1, which disables pacing for debugging or performance analysis.

### Where does the actual image rendering happen in the sceVideoOut pipeline?

While `sceVideoOutSubmitFlip` initiates the process, the actual host-side rendering occurs in [`VulkanVideoPresenter.cs`](https://github.com/par274/sharpemu/blob/main/VulkanVideoPresenter.cs). This class receives the guest image via `GuestGpu.Current.TrySubmitGuestImage`, handles pixel format conversion through `MapPixelFormatToGuestTextureFormat`, and presents the final frame to the host display using Vulkan.

### How does the emulator maintain accurate vblank timing for games?

A dedicated background thread started by `StartVblankThreadOnce` runs `VblankTickLoop` at the port's refresh rate. For synchronous waits, `sceVideoOutWaitVblank` uses `HostTiming.SleepUntil` with high-resolution timer calculations to sleep precisely until the next vblank deadline, minimizing timing drift that could cause frame stuttering.