Initial pipeline work
This commit is contained in:
+240
-13
@@ -3,9 +3,29 @@ package engine
|
||||
import "core:fmt"
|
||||
import sdl "vendor:sdl3"
|
||||
|
||||
Vertex :: struct {
|
||||
pos: [2]f32, // clip space, -1..1
|
||||
uv: [2]f32, // 0..1 atlas coords (used later in draw_sprite)
|
||||
}
|
||||
|
||||
SPRITE_VERT_COUNT :: 6
|
||||
VERTEX_BUFFER_SIZE :: SPRITE_VERT_COUNT * size_of(Vertex)
|
||||
|
||||
VERT_SPV := #load("../shaders/sprite.vert.spv")
|
||||
FRAG_SPV := #load("../shaders/sprite.frag.spv")
|
||||
|
||||
App :: struct {
|
||||
window: ^sdl.Window,
|
||||
renderer: ^sdl.Renderer,
|
||||
window: ^sdl.Window,
|
||||
device: ^sdl.GPUDevice,
|
||||
pipeline: ^sdl.GPUGraphicsPipeline,
|
||||
sampler: ^sdl.GPUSampler,
|
||||
cmd: ^sdl.GPUCommandBuffer,
|
||||
render_pass: ^sdl.GPURenderPass,
|
||||
swapchain_texture: ^sdl.GPUTexture,
|
||||
swapchain_w: u32,
|
||||
swapchain_h: u32,
|
||||
vertex_buffer: ^sdl.GPUBuffer,
|
||||
transfer_buffer: ^sdl.GPUTransferBuffer,
|
||||
}
|
||||
|
||||
init :: proc(app: ^App, title: cstring, width, height: i32) -> bool {
|
||||
@@ -14,8 +34,64 @@ init :: proc(app: ^App, title: cstring, width, height: i32) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if !sdl.CreateWindowAndRenderer(title, width, height, {}, &app.window, &app.renderer) {
|
||||
fmt.eprintfln("CreateWindowAndRenderer failed: %s", sdl.GetError())
|
||||
app.window = sdl.CreateWindow(title, width, height, {})
|
||||
|
||||
if app.window == nil {
|
||||
fmt.eprintfln("CreateWindow failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
app.device = sdl.CreateGPUDevice({.SPIRV}, true, nil)
|
||||
if app.device == nil {
|
||||
fmt.eprintfln("CreateGPUDevice failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
if !sdl.ClaimWindowForGPUDevice(app.device, app.window) {
|
||||
fmt.eprintfln("ClaimWindowForGPUDevice failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
app.pipeline = create_sprite_pipeline(app.device, app.window)
|
||||
if app.pipeline == nil {
|
||||
fmt.eprintfln("create_sprite_pipeline failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
app.sampler = sdl.CreateGPUSampler(
|
||||
app.device,
|
||||
{
|
||||
min_filter = .NEAREST,
|
||||
mag_filter = .NEAREST,
|
||||
mipmap_mode = .NEAREST,
|
||||
address_mode_u = .CLAMP_TO_EDGE,
|
||||
address_mode_v = .CLAMP_TO_EDGE,
|
||||
address_mode_w = .CLAMP_TO_EDGE,
|
||||
},
|
||||
)
|
||||
|
||||
if app.sampler == nil {
|
||||
fmt.eprintfln("CreateGPUSampler failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
app.vertex_buffer = sdl.CreateGPUBuffer(
|
||||
app.device,
|
||||
{usage = {.VERTEX}, size = VERTEX_BUFFER_SIZE},
|
||||
)
|
||||
|
||||
if app.vertex_buffer == nil {
|
||||
fmt.eprintfln("CreateGPUBuffer failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
app.transfer_buffer = sdl.CreateGPUTransferBuffer(
|
||||
app.device,
|
||||
{usage = .UPLOAD, size = VERTEX_BUFFER_SIZE},
|
||||
)
|
||||
|
||||
if app.transfer_buffer == nil {
|
||||
fmt.eprintfln("CreateGPUTransferBuffer failed: %s", sdl.GetError())
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -23,14 +99,43 @@ init :: proc(app: ^App, title: cstring, width, height: i32) -> bool {
|
||||
}
|
||||
|
||||
shutdown :: proc(app: ^App) {
|
||||
if app.renderer != nil do sdl.DestroyRenderer(app.renderer)
|
||||
if app.window != nil do sdl.DestroyWindow(app.window)
|
||||
if app.device != nil {
|
||||
ok := sdl.WaitForGPUIdle(app.device)
|
||||
if !ok {
|
||||
fmt.eprintfln("WaitForGPUIdle failed")
|
||||
}
|
||||
|
||||
if app.transfer_buffer != nil {
|
||||
sdl.ReleaseGPUTransferBuffer(app.device, app.transfer_buffer)
|
||||
}
|
||||
|
||||
if app.vertex_buffer != nil {
|
||||
sdl.ReleaseGPUBuffer(app.device, app.vertex_buffer)
|
||||
}
|
||||
|
||||
if app.sampler != nil {
|
||||
sdl.ReleaseGPUSampler(app.device, app.sampler)
|
||||
}
|
||||
|
||||
if app.pipeline != nil {
|
||||
sdl.ReleaseGPUGraphicsPipeline(app.device, app.pipeline)
|
||||
}
|
||||
|
||||
if app.window != nil {
|
||||
sdl.ReleaseWindowFromGPUDevice(app.device, app.window)
|
||||
}
|
||||
sdl.DestroyGPUDevice(app.device)
|
||||
}
|
||||
|
||||
if app.window != nil {
|
||||
sdl.DestroyWindow(app.window)
|
||||
}
|
||||
|
||||
sdl.Quit()
|
||||
app^ = {}
|
||||
}
|
||||
|
||||
pump_events :: proc() -> bool {
|
||||
events :: proc() -> bool {
|
||||
event: sdl.Event
|
||||
|
||||
for sdl.PollEvent(&event) {
|
||||
@@ -42,15 +147,137 @@ pump_events :: proc() -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
begin_frame :: proc(app: ^App, r: u8 = 30, g: u8 = 30, b: u8 = 40, a: u8 = 255) {
|
||||
sdl.SetRenderDrawColor(app.renderer, r, g, b, a)
|
||||
sdl.RenderClear(app.renderer)
|
||||
begin_frame :: proc(app: ^App, clear: sdl.FColor = {0.12, 0.12, 0.16, 1}) {
|
||||
app.cmd = sdl.AcquireGPUCommandBuffer(app.device)
|
||||
|
||||
if app.cmd == nil {
|
||||
fmt.eprintfln("AcquireGPUCommandBuffer failed: %s", sdl.GetError())
|
||||
return
|
||||
}
|
||||
|
||||
ok := sdl.WaitAndAcquireGPUSwapchainTexture(
|
||||
app.cmd,
|
||||
app.window,
|
||||
&app.swapchain_texture,
|
||||
&app.swapchain_w,
|
||||
&app.swapchain_h,
|
||||
)
|
||||
|
||||
if !ok || app.swapchain_texture == nil {
|
||||
return
|
||||
}
|
||||
|
||||
color_info := sdl.GPUColorTargetInfo {
|
||||
texture = app.swapchain_texture,
|
||||
clear_color = clear,
|
||||
load_op = .CLEAR,
|
||||
store_op = .STORE,
|
||||
}
|
||||
|
||||
app.render_pass = sdl.BeginGPURenderPass(app.cmd, &color_info, 1, nil)
|
||||
|
||||
sdl.BindGPUGraphicsPipeline(app.render_pass, app.pipeline)
|
||||
}
|
||||
|
||||
end_frame :: proc(app: ^App) {
|
||||
sdl.RenderPresent(app.renderer)
|
||||
if app.render_pass != nil {
|
||||
sdl.EndGPURenderPass(app.render_pass)
|
||||
app.render_pass = nil
|
||||
}
|
||||
|
||||
if app.cmd != nil {
|
||||
ok := sdl.SubmitGPUCommandBuffer(app.cmd)
|
||||
if !ok {
|
||||
fmt.eprintfln("SubmitGPUCommandBuffer failed")
|
||||
}
|
||||
app.cmd = nil
|
||||
}
|
||||
|
||||
app.swapchain_texture = nil
|
||||
}
|
||||
|
||||
renderer :: proc(app: ^App) -> ^sdl.Renderer {
|
||||
return app.renderer
|
||||
load_spirv_shader :: proc(
|
||||
device: ^sdl.GPUDevice,
|
||||
code: []u8,
|
||||
stage: sdl.GPUShaderStage,
|
||||
num_samplers: u32,
|
||||
) -> ^sdl.GPUShader {
|
||||
return sdl.CreateGPUShader(
|
||||
device,
|
||||
{
|
||||
code_size = len(code),
|
||||
code = raw_data(code),
|
||||
entrypoint = "main",
|
||||
format = {.SPIRV},
|
||||
stage = stage,
|
||||
num_samplers = num_samplers,
|
||||
num_storage_textures = 0,
|
||||
num_storage_buffers = 0,
|
||||
num_uniform_buffers = 0,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
create_sprite_pipeline :: proc(
|
||||
device: ^sdl.GPUDevice,
|
||||
window: ^sdl.Window,
|
||||
) -> ^sdl.GPUGraphicsPipeline {
|
||||
vert := load_spirv_shader(device, VERT_SPV[:], .VERTEX, 0)
|
||||
if vert == nil do return nil
|
||||
|
||||
frag := load_spirv_shader(device, FRAG_SPV[:], .FRAGMENT, 1)
|
||||
if frag == nil {
|
||||
sdl.ReleaseGPUShader(device, vert)
|
||||
return nil
|
||||
}
|
||||
|
||||
swap_format := sdl.GetGPUSwapchainTextureFormat(device, window)
|
||||
|
||||
|
||||
blend := sdl.GPUColorTargetBlendState {
|
||||
src_color_blendfactor = .SRC_ALPHA,
|
||||
dst_color_blendfactor = .ONE_MINUS_SRC_ALPHA,
|
||||
color_blend_op = .ADD,
|
||||
src_alpha_blendfactor = .ONE,
|
||||
dst_alpha_blendfactor = .ONE_MINUS_SRC_ALPHA,
|
||||
alpha_blend_op = .ADD,
|
||||
enable_blend = true,
|
||||
}
|
||||
|
||||
color_target := sdl.GPUColorTargetDescription {
|
||||
format = swap_format,
|
||||
blend_state = blend,
|
||||
}
|
||||
|
||||
vb_desc := sdl.GPUVertexBufferDescription {
|
||||
slot = 0,
|
||||
pitch = u32(size_of(Vertex)),
|
||||
input_rate = .VERTEX,
|
||||
}
|
||||
|
||||
attrs := [2]sdl.GPUVertexAttribute {
|
||||
{location = 0, buffer_slot = 0, format = .FLOAT2, offset = 0},
|
||||
{location = 1, buffer_slot = 0, format = .FLOAT2, offset = u32(offset_of(Vertex, uv))},
|
||||
}
|
||||
|
||||
pipeline_info := sdl.GPUGraphicsPipelineCreateInfo {
|
||||
vertex_shader = vert,
|
||||
fragment_shader = frag,
|
||||
vertex_input_state = {
|
||||
vertex_buffer_descriptions = &vb_desc,
|
||||
num_vertex_buffers = 1,
|
||||
vertex_attributes = raw_data(attrs[:]),
|
||||
num_vertex_attributes = 2,
|
||||
},
|
||||
primitive_type = .TRIANGLELIST,
|
||||
rasterizer_state = {fill_mode = .FILL},
|
||||
target_info = {color_target_descriptions = &color_target, num_color_targets = 1},
|
||||
}
|
||||
|
||||
pipeline := sdl.CreateGPUGraphicsPipeline(device, pipeline_info)
|
||||
|
||||
sdl.ReleaseGPUShader(device, vert)
|
||||
sdl.ReleaseGPUShader(device, frag)
|
||||
|
||||
return pipeline
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user