Skip to main content

Overview

The GPU module provides NVIDIA Tegra GPU emulation using Vulkan. It includes support for SM86 instruction decoding and SPIR-V shader compilation.

State

Main GPU state structure that holds all GPU-related state including Vulkan context.

Structure

#[derive(Default)]
pub struct State {
    pub shared_memory: *mut u8,
    pub global_memory: *mut u8,
    pub pc: u64,
    pub vk: VkState,
}
shared_memory
*mut u8
Pointer to GPU shared memory region (accessible by all shader threads)
global_memory
*mut u8
Pointer to GPU global memory region
pc
u64
Program counter for GPU execution
vk
VkState
Vulkan state and context

Methods

new()

Create a new uninitialized GPU state.
pub fn new() -> Self
return
State
Returns a new GPU state with null pointers and default values
Example:
use oboromi_core::gpu::State;

let mut gpu = State::new();
assert_eq!(gpu.pc, 0);
assert!(gpu.shared_memory.is_null());

init()

Initialize the Vulkan context and create the Vulkan instance.
pub fn init(&mut self) -> ash::prelude::VkResult<()>
return
VkResult<()>
Returns Ok(()) on success, or a Vulkan error on failure
Example:
let mut gpu = State::new();
gpu.init().expect("Failed to initialize Vulkan");

VkState

Vulkan-specific state including the entry point and instance.

Structure

pub struct VkState {
    pub entry: ash::Entry,
    pub instance: ash::Instance,
}
entry
ash::Entry
Vulkan library entry point (loaded dynamically)
instance
ash::Instance
Vulkan instance handle

Methods

new()

Create an uninitialized Vulkan state.
pub fn new() -> Self
This creates uninitialized memory. You must call init() before use.

init()

Load the Vulkan library and create a Vulkan instance.
pub fn init(&mut self) -> ash::prelude::VkResult<()>
return
VkResult<()>
Returns Ok(()) on success, or a Vulkan error if initialization fails
Configuration:
  • API Version: Vulkan 1.0.0
  • Application Info: Uses default values
  • Instance Extensions: None (can be extended)
Example:
use oboromi_core::gpu::VkState;

let mut vk = VkState::new();
vk.init().expect("Failed to initialize Vulkan");

// Now vk.entry and vk.instance are ready to use

SM86 Module

Provides SM86 (NVIDIA Ampere architecture) instruction decoding and execution.
SM86 is the shader microarchitecture used by NVIDIA’s Ampere GPUs, which includes the Tegra chips in the Nintendo Switch 2.

Features

  • Instruction decoding for SM86 ISA
  • Support for common GPU operations:
    • Arithmetic operations (ADD, SUB, MUL, etc.)
    • Memory loads and stores
    • Thread synchronization
    • Texture sampling
    • Control flow (branches, predicates)

Usage

use oboromi_core::gpu::sm86;

// Decode and execute SM86 instructions
// (Implementation details in sm86_decoder_generated.rs)
The SM86 decoder is auto-generated from NVIDIA’s instruction set specifications.

SPIR-V Module

Handles SPIR-V shader compilation and integration with Vulkan.

Overview

The SPIR-V module translates GPU shader code into SPIR-V intermediate representation for execution on Vulkan. Key responsibilities:
  • Parse shader binaries
  • Translate to SPIR-V format
  • Interface with Vulkan shader modules
  • Handle shader resource bindings

Usage

use oboromi_core::gpu::spirv;

// Compile and load shaders
// (Module provides utilities for SPIR-V manipulation)

Complete Example

use oboromi_core::gpu::State;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create GPU state
    let mut gpu = State::new();
    
    // Initialize Vulkan
    gpu.init()?;
    
    println!("Vulkan initialized successfully");
    println!("GPU PC: {}", gpu.pc);
    
    // Allocate shader memory
    let shared_mem = vec![0u8; 64 * 1024].into_boxed_slice(); // 64KB
    gpu.shared_memory = Box::leak(shared_mem).as_mut_ptr();
    
    // GPU is now ready for shader execution
    Ok(())
}
use oboromi_core::gpu::VkState;
use ash::vk;

fn enumerate_devices(vk_state: &VkState) -> Result<(), Box<dyn std::error::Error>> {
    // Use the initialized Vulkan instance
    let physical_devices = unsafe {
        vk_state.instance.enumerate_physical_devices()?
    };
    
    println!("Found {} physical device(s)", physical_devices.len());
    
    for (i, device) in physical_devices.iter().enumerate() {
        let props = unsafe {
            vk_state.instance.get_physical_device_properties(*device)
        };
        
        let device_name = unsafe {
            std::ffi::CStr::from_ptr(props.device_name.as_ptr())
        };
        
        println!("Device {}: {:?}", i, device_name);
    }
    
    Ok(())
}

Architecture Notes

Memory Layout

The GPU state maintains separate memory regions:
Shared Memory is accessible by all threads in a shader work group.
  • Low latency
  • Limited size (typically 48-64KB)
  • Used for thread cooperation
  • Explicit synchronization required

Execution Model

The GPU executes shaders in parallel:
  1. Shader Compilation: SM86 code → SPIR-V → Vulkan shader module
  2. Dispatch: Launch shader with work group configuration
  3. Execution: Threads execute in parallel on GPU
  4. Synchronization: Barriers and memory fences coordinate threads
  5. Results: Output written to global memory or frame buffer

Implementation Status

The GPU module is under active development. Current status:
  • Vulkan initialization: ✓ Complete
  • SM86 decoder: ✓ Generated from specs
  • SPIR-V compilation: 🚧 In progress
  • Shader execution: 🚧 In progress
  • Texture support: 📋 Planned
  • Compute shaders: 📋 Planned

See Also

Build docs developers (and LLMs) love