Initial setup of sokol_gfx to replace the raylib impl for rendering.

Next I need to setup sokol_gp
This commit is contained in:
2024-05-24 16:31:22 -04:00
parent cf81d3f9bd
commit 13c3032dba
11 changed files with 593 additions and 70 deletions

View File

@ -11,7 +11,10 @@ import "core:strings"
import "core:time"
import "core:prof/spall"
import sokol_app "thirdparty:sokol/app"
import sokol_app "thirdparty:sokol/app"
import sokol_gfx "thirdparty:sokol/gfx"
import sokol_app_gfx_glue "thirdparty:sokol/glue"
import rl "vendor:raylib"
Path_Assets :: "../assets/"
@ -188,6 +191,79 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
}
}
// Setup sokol_gfx
{
glue_env := sokol_app_gfx_glue.environment()
desc := sokol_gfx.Desc {
buffer_pool_size = 128,
image_pool_size = 128,
sampler_pool_size = 64,
shader_pool_size = 32,
pipeline_pool_size = 64,
// pass_pool_size = 16, // (No longer exists)
attachments_pool_size = 16,
uniform_buffer_size = 4 * Megabyte,
max_commit_listeners = Kilo,
allocator = { sokol_gfx_alloc, sokol_gfx_free, nil },
logger = { sokol_gfx_log_callback, nil },
environment = glue_env,
}
sokol_gfx.setup(desc)
backend := sokol_gfx.query_backend()
switch backend
{
case .D3D11: logf("sokol_gfx: using D3D11 backend")
case .GLCORE, .GLES3: logf("sokol_gfx: using GL backend")
case .METAL_MACOS, .METAL_IOS, .METAL_SIMULATOR:
logf("sokol_gfx: using Metal backend")
case .WGPU: logf("sokol_gfx: using WebGPU backend")
case .DUMMY: logf("sokol_gfx: using dummy backend")
}
// Learning examples
{
debug.gfx_clear_demo_pass_action.colors[0] = {
load_action = .CLEAR,
clear_value = { 1, 0, 0, 1 }
}
vertices := [?]f32 {
// positions // colors
0.0, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0,
0.5, -0.5, 0.5, 0.0, 1.0, 0.0, 1.0,
-0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0,
}
tri_shader_attr_vs_position :: 0
tri_shader_attr_vs_color0 :: 1
using debug.gfx_tri_demo_state
bindings.vertex_buffers[0] = sokol_gfx.make_buffer( sokol_gfx.Buffer_Desc {
data = {
ptr = & vertices,
size = size_of(vertices)
}
})
pipeline = sokol_gfx.make_pipeline( sokol_gfx.Pipeline_Desc {
shader = sokol_gfx.make_shader( triangle_shader_desc(backend)),
layout = sokol_gfx.Vertex_Layout_State {
attrs = {
tri_shader_attr_vs_position = { format = .FLOAT3 },
tri_shader_attr_vs_color0 = { format = .FLOAT4 },
}
}
})
pass_action.colors[0] = {
load_action = .CLEAR,
clear_value = { 0, 0, 0, 1 }
}
}
}
// Basic Font Setup
if false
{
@ -205,7 +281,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
}
// Setup the screen ui state
if false
if true
{
ui_startup( & screen_ui.base, cache_allocator = persistent_slab_allocator() )
ui_floating_startup( & screen_ui.floating, persistent_slab_allocator(), 1 * Kilobyte, 1 * Kilobyte, "screen ui floating manager" )
@ -220,7 +296,7 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
// Demo project setup
// TODO(Ed): This will eventually have to occur when the user either creates or loads a workspace. I don't know
if false
if true
{
using project
path = str_intern("./")
@ -345,48 +421,55 @@ tick :: proc( host_delta_time_ms : f64, host_delta_ns : Duration ) -> b32
state := get_state(); using state
client_tick := time.tick_now()
tick_work_frame()
should_close |= tick_work_frame( host_delta_time_ms)
tick_frametime( & client_tick, host_delta_time_ms, host_delta_ns )
profile_begin("sokol_app: post_client_tick")
sokol_app.post_client_frame()
profile_end()
return ! should_close
}
// Lifted out of tick so that sokol_app_frame_callback can do it as well.
tick_work_frame :: #force_inline proc()
tick_work_frame :: #force_inline proc( host_delta_time_ms : f64 ) -> b32
{
context.logger = to_odin_logger( & Memory_App.logger )
state := get_state(); using state
profile("Work frame")
context.logger = to_odin_logger( & Memory_App.logger )
state := get_state(); using state
profile("Work frame")
// Setup Frame Slab
{
alloc_error : AllocatorError
frame_slab, alloc_error = slab_init( & default_slab_policy, bucket_reserve_num = 0,
allocator = frame_allocator(),
dbg_name = Frame_Slab_DBG_Name,
should_zero_buckets = true )
verify( alloc_error == .None, "Failed to allocate frame slab" )
}
should_close : b32
// The policy for the work tick is that the default allocator is the frame's slab.
// Transient's is the temp allocator.
context.allocator = frame_slab_allocator()
context.temp_allocator = transient_allocator()
// Setup Frame Slab
{
alloc_error : AllocatorError
frame_slab, alloc_error = slab_init( & default_slab_policy, bucket_reserve_num = 0,
allocator = frame_allocator(),
dbg_name = Frame_Slab_DBG_Name,
should_zero_buckets = true )
verify( alloc_error == .None, "Failed to allocate frame slab" )
}
// rl.PollInputEvents()
// The policy for the work tick is that the default allocator is the frame's slab.
// Transient's is the temp allocator.
context.allocator = frame_slab_allocator()
context.temp_allocator = transient_allocator()
debug.draw_ui_box_bounds_points = false
debug.draw_UI_padding_bounds = false
debug.draw_ui_content_bounds = false
// rl.PollInputEvents()
// config.color_theme = App_Thm_Light
// config.color_theme = App_Thm_Dusk
config.color_theme = App_Thm_Dark
debug.draw_ui_box_bounds_points = false
debug.draw_UI_padding_bounds = false
debug.draw_ui_content_bounds = false
// should_close |= update( host_delta_time )
// render()
// config.color_theme = App_Thm_Light
// config.color_theme = App_Thm_Dusk
config.color_theme = App_Thm_Dark
// rl.SwapScreenBuffer()
should_close |= update( host_delta_time_ms )
render()
// rl.SwapScreenBuffer()
return should_close
}
// Lifted out of tick so that sokol_app_frame_callback can do it as well.
@ -440,10 +523,6 @@ tick_frametime :: #force_inline proc( client_tick : ^time.Tick, host_delta_time_
if frametime_elapsed_ms > 60.0 {
log( str_fmt("Big tick! %v ms", frametime_elapsed_ms), LogLevel.Warning )
}
profile_begin("sokol_app: post_client_tick")
sokol_app.post_client_frame()
profile_end()
}
@export

View File

@ -6,17 +6,20 @@ import str "core:strings"
import sokol_app "thirdparty:sokol/app"
#region("Sokol App")
sokol_app_init_callback :: proc "c" () {
context = get_state().sokol_context
log("sokol_app: Confirmed initialization")
}
// This is being filled in but we're directly controlling the lifetime of sokol_app's execution.
// So this will only get called during resize events (on Win32 at least)
// So this will only get called during window pan or resize events (on Win32 at least)
sokol_app_frame_callback :: proc "c" () {
context = get_state().sokol_context
state := get_state()
state := get_state()
should_close : b32
sokol_width := sokol_app.widthf()
sokol_height := sokol_app.heightf()
@ -33,7 +36,7 @@ sokol_app_frame_callback :: proc "c" () {
sokol_delta_ns := transmute(Duration) sokol_delta_ms * MS_To_NS
client_tick := time.tick_now()
tick_work_frame()
should_close |= tick_work_frame( sokol_delta_ms )
tick_frametime( & client_tick, sokol_delta_ms, sokol_delta_ns )
}
@ -45,7 +48,7 @@ sokol_app_cleanup_callback :: proc "c" () {
sokol_app_alloc :: proc "c" ( size : u64, user_data : rawptr ) -> rawptr {
context = get_state().sokol_context
block, error := alloc( int(size), allocator = persistent_slab_allocator() )
ensure(error != AllocatorError.None, "sokol_app allocation failed")
ensure(error == AllocatorError.None, "sokol_app allocation failed")
return block
}
@ -95,3 +98,52 @@ sokol_app_event_callback :: proc "c" (event : ^sokol_app.Event)
monitor_refresh_hz := sokol_app.refresh_rate()
}
}
#endregion("Sokol App")
#region("Sokol GFX")
sokol_gfx_alloc :: proc "c" ( size : u64, user_data : rawptr ) -> rawptr {
context = get_state().sokol_context
block, error := alloc( int(size), allocator = persistent_slab_allocator() )
ensure(error == AllocatorError.None, "sokol_gfx allocation failed")
return block
}
sokol_gfx_free :: proc "c" ( data : rawptr, user_data : rawptr ) {
context = get_state().sokol_context
free(data, allocator = persistent_slab_allocator() )
}
sokol_gfx_log_callback :: proc "c" (
tag: cstring,
log_level: u32,
log_item_id: u32,
message_or_null: cstring,
line_nr: u32,
filename_or_null: cstring,
user_data: rawptr) {
context = get_state().sokol_context
odin_level : LogLevel
switch log_level {
case 0: odin_level = .Fatal
case 1: odin_level = .Error
case 2: odin_level = .Warning
case 3: odin_level = .Info
}
cloned_msg : string = ""
if message_or_null != nil {
cloned_msg = str.clone_from_cstring(message_or_null, context.temp_allocator)
}
cloned_fname : string = ""
if filename_or_null != nil {
cloned_fname = str.clone_from_cstring(filename_or_null, context.temp_allocator)
}
cloned_tag := str.clone_from_cstring(tag, context.temp_allocator)
logf( "%-80s %s::%v", cloned_msg, cloned_tag, line_nr, level = odin_level )
}
#endregion("Sokol GFX")

View File

@ -4,6 +4,7 @@ import "core:fmt"
import rl "vendor:raylib"
when false {
range2_to_rl_rect :: #force_inline proc "contextless"( range : Range2 ) -> rl.Rectangle
{
rect := rl.Rectangle {
@ -399,3 +400,4 @@ render_screen_ui :: proc()
}
//endregion App UI
}
} // when false

View File

@ -1,2 +1,37 @@
package sectr
import sokol_gfx "thirdparty:sokol/gfx"
import sokol_glue "thirdparty:sokol/glue"
render :: proc()
{
state := get_state(); using state
// Clear Demo
if false
{
green_value := debug.gfx_clear_demo_pass_action.colors[0].clear_value.g + 0.01
debug.gfx_clear_demo_pass_action.colors[0].clear_value.g = green_value > 1.0 ? 0.0 : green_value
sokol_gfx.begin_pass( sokol_gfx.Pass {
action = debug.gfx_clear_demo_pass_action,
swapchain = sokol_glue.swapchain()
})
sokol_gfx.end_pass()
sokol_gfx.commit()
}
// Triangle Demo
if true
{
using debug.gfx_tri_demo_state
sokol_gfx.begin_pass(sokol_gfx.Pass { action = pass_action, swapchain = sokol_glue.swapchain() })
sokol_gfx.apply_pipeline( pipeline )
sokol_gfx.apply_bindings( bindings )
sokol_gfx.draw( 0, 3, 1 )
sokol_gfx.end_pass()
sokol_gfx.commit()
}
}

View File

@ -5,6 +5,7 @@ import "core:strings"
import "core:unicode/utf8"
import rl "vendor:raylib"
when false {
debug_draw_text :: proc( content : string, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : FontID = Font_Default )
{
// profile(#procedure)
@ -222,3 +223,4 @@ measure_text_size_raylib :: proc( text : string, font : FontID, font_size := Fon
return text_size
}
} // when false

View File

@ -66,6 +66,7 @@ frametime_delta32 :: #force_inline proc "contextless" () -> f32 {
return cast(f32) get_state().frametime_avg_ms
}
//TODO(Ed): Just use avg delta not this.
update :: proc( delta_time : f64 ) -> b32
{
profile(#procedure)