shdrlib 0.1.4

A three-tiered Vulkan shader compilation and rendering framework built in pure Rust
Documentation
# Migration Guide


**Moving between shdrlib's three tiers.**

## Quick Reference


| From | To | Reason | Difficulty |
|------|----|----|------------|
| EZ → EX | Need more control | Easy |
| EZ → CORE | Maximum control | Medium |
| EX → CORE | Specific customization | Easy |
| CORE → EX | Want safety | Easy |
| CORE → EZ | Want simplicity | Easy |
| EX → EZ | Simplify prototype | Easy |

---

## EZ → EX


**Why:** Need explicit control, type-safe IDs, custom configurations

### Access EX Components


```rust
// Start with EZ
let mut renderer = EzRenderer::new()?;

// Access EX managers
let runtime = renderer.runtime();
let shaders = renderer.shader_manager();
```

### Full Migration


**Before (EZ):**
```rust
let mut renderer = EzRenderer::new()?;
let pipeline = renderer.quick_pipeline(VERT, FRAG)?;
renderer.render_frame(|frame| { /* ... */ })?;
```

**After (EX):**
```rust
let mut runtime = RuntimeManager::new(RuntimeConfig::default())?;
let mut shaders = ShaderManager::new(runtime.device())?;

let vert_id = shaders.add_shader(VERT, ShaderStage::Vertex, "vert")?;
let frag_id = shaders.add_shader(FRAG, ShaderStage::Fragment, "frag")?;

let pipeline_id = shaders.build_pipeline(
    PipelineBuilder::new()
        .vertex_shader(shaders.get_shader(vert_id)?.handle(), "main")
        .fragment_shader(shaders.get_shader(frag_id)?.handle(), "main")
        .color_attachment_formats(vec![Format::R8G8B8A8_UNORM]),
    "pipeline"
)?;

loop {
    let frame = runtime.begin_frame()?;
    // ... record commands ...
    runtime.end_frame(&SubmitInfo::default())?;
}
```

**What changed:**
- Explicit RuntimeManager and ShaderManager
- Type-safe ShaderId and PipelineId
- Manual frame loop
- More control over pipeline config

---

## EX → CORE


**Why:** Need custom resource creation, specific Vulkan features

### Access CORE Objects


```rust
// Start with EX
let mut runtime = RuntimeManager::new(RuntimeConfig::default())?;
let device = runtime.device();

// Use CORE directly
let custom_shader = core::Shader::from_glsl(&device, glsl, stage)?;
let custom_buffer = core::Buffer::new(&device, size, usage, properties)?;
```

### Full Migration (Rare)


**Before (EX):**
```rust
let mut runtime = RuntimeManager::new(RuntimeConfig::default())?;
let device = runtime.device();
```

**After (CORE):**
```rust
let entry = ash::Entry::linked();
let instance = Instance::new(&entry, &InstanceCreateInfo::default())?;
let physical_devices = instance.enumerate_physical_devices()?;
let device = Device::new(&instance, physical_devices[0], &DeviceCreateInfo::default())?;
```

**What changed:**
- Manual instance/device creation
- No automatic resource management
- Must destroy resources manually in correct order

⚠️ **Usually not needed** - Use CORE for specific resources, keep EX for management.

---

## CORE → EX


**Why:** Want safety, tired of manual lifetime management

### Wrap in EX Managers


**Before (CORE):**
```rust
let device = Device::new(...)?;
let shader = Shader::from_glsl(&device, glsl, stage)?;
// ... later ...
shader.destroy(&device);
```

**After (EX):**
```rust
let device = Arc::new(Device::new(...)?);
let mut shaders = ShaderManager::new(device)?;
let shader_id = shaders.add_shader(glsl, stage, "name")?;
// No manual cleanup needed - ShaderManager handles it
```

**Benefits:**
- Automatic cleanup
- Type-safe IDs
- Can't accidentally use destroyed resources

---

## EZ → CORE


**Why:** Learning Vulkan internals, maximum control

**Before (EZ):**
```rust
let mut renderer = EzRenderer::new()?;
// Everything automatic
```

**After (CORE):**
```rust
// 80+ lines of setup
let entry = ash::Entry::linked();
let instance = Instance::new(...)?;
let device = Device::new(...)?;
let pool = CommandPool::new(...)?;
// ... etc
```

**Consider:** Use EX tier instead - gets you 90% of the control with 10% of the complexity.

---

## CORE → EZ


**Why:** Rapid prototyping, teaching

Simple wrapper:

```rust
// Keep CORE for custom resources
let device = /* your CORE device */;

// Use EZ for rendering
let mut renderer = EzRenderer::new()?;
let ez_device = renderer.device();

// Mix as needed
let custom_buffer = core::Buffer::new(&device, ...)?;
let ez_buffer = renderer.create_vertex_buffer(&data)?;
```

---

## EX → EZ


**Why:** Simplify prototype, reduce code

**Before (EX):**
```rust
let mut runtime = RuntimeManager::new(...)?;
let mut shaders = ShaderManager::new(...)?;
// ... 100 lines ...
```

**After (EZ):**
```rust
let mut renderer = EzRenderer::new()?;
let pipeline = renderer.quick_pipeline(VERT, FRAG)?;
// ... 30 lines ...
```

**Tradeoffs:**
- ✅ Way less code
- ✅ Faster prototyping
- ❌ Less control
- ❌ Fixed patterns

---

## Mixing Tiers (Recommended)


**Best practice:** Use highest tier that works, drop down when needed.

### Pattern 1: EZ + CORE


```rust
let mut renderer = EzRenderer::new()?;
let device = renderer.device();

// Custom CORE resource
let custom = core::Buffer::new(&device, size, usage, properties)?;

// Back to EZ
let pipeline = renderer.quick_pipeline(VERT, FRAG)?;
```

### Pattern 2: EX + CORE


```rust
let mut runtime = RuntimeManager::new(RuntimeConfig::default())?;
let device = runtime.device();

// Use CORE for specific need
let custom_shader = core::Shader::from_glsl(&device, glsl, stage)?;

// Back to EX
let mut shaders = ShaderManager::new(device)?;
let pipeline_id = shaders.build_pipeline(...)?;
```

### Pattern 3: Framework in CORE, API in EX


```rust
// Internal: CORE for flexibility
mod internal {
    pub fn create_resources() -> core::Device {
        /* ... CORE implementation ... */
    }
}

// Public API: EX for safety
pub struct MyFramework {
    runtime: RuntimeManager,
    shaders: ShaderManager,
}

impl MyFramework {
    pub fn new() -> Self {
        let runtime = RuntimeManager::new(RuntimeConfig::default()).unwrap();
        let shaders = ShaderManager::new(runtime.device()).unwrap();
        Self { runtime, shaders }
    }
}
```

---

## Common Migration Scenarios


### "I need a custom buffer"


Stay in EX, use CORE for that one buffer:

```rust
let device = runtime.device();
let custom_buf = core::Buffer::new(&device, size, usage, properties)?;
```

### "I want type-safe resource IDs"


Move EZ → EX:

```rust
// Before: renderer.quick_pipeline() returns PipelineId but no tracking
// After: shaders.add_shader() returns ShaderId, build_pipeline() returns PipelineId
```

### "Manual cleanup is annoying"


Move CORE → EX:

```rust
// Before: shader.destroy(&device); pipeline.destroy(&device);
// After: ShaderManager drops everything automatically
```

### "I need to learn Vulkan"


Start EZ → Read CORE code:

```rust
// Use EZ to get started
let renderer = EzRenderer::new()?;

// Read CORE source to understand what's happening
// File: src/core/instance.rs, device.rs, etc.
```

---

## API Mapping


### Setup


| EZ | EX | CORE |
|----|----|----|
| `EzRenderer::new()` | `RuntimeManager::new()` | `Instance::new()` + `Device::new()` |

### Shaders


| EZ | EX | CORE |
|----|----|----|
| `quick_pipeline(v,f)` | `add_shader()` + `build_pipeline()` | `Shader::from_glsl()` + `Pipeline::new()` |

### Buffers


| EZ | EX | CORE |
|----|----|----|
| `create_vertex_buffer()` | `create_vertex_buffer()` | `Buffer::new()` |

### Rendering


| EZ | EX | CORE |
|----|----|----|
| `render_frame(\|frame\| ...)` | `begin_frame()` + `end_frame()` | Manual command recording + `queue.submit()` |

---

## Decision Tree


```
Need maximum simplicity?
  YES → Use EZ
  NO ↓

Building production app?
  YES → Use EX
  NO ↓

Building rendering engine/framework?
  YES → Use CORE
  NO ↓

Learning Vulkan?
  Start EZ → Read CORE → Use EX for projects
```

---

## Examples


See `demos/` for examples of each tier in action:
- `demos/ez/` - EZ tier examples
- `demos/ex/` - EX tier examples  
- `demos/core/` - CORE tier examples

---

## Next Steps


- **EZ Guide:** [EZ Tier Guide]ez-tier-guide.md
- **EX Guide:** [EX Tier Guide]ex-tier-guide.md
- **CORE Guide:** [CORE Tier Guide]core-tier-guide.md
- **FAQ:** [Common Questions]../getting-started/faq.md