render3d: a command buffer holds at most 512 draws, and that many are drawn at start-up
Metal pools the command storage a command buffer grew to and grows it only when one encodes more than any before (IOGPU under vkQueueSubmit < fn_gvk_once_end: +2-7 KB a window while a frame's draws climbed, 192 KB in the trail scene). gvk_draw submits the frame's command buffer after gvk_cb_cap_of draws (R3D_CB_DRAWS, 0 = none) and r3d_warm_commands draws that many through the normal path once r3d is ready. steady: a frame drawing 20 to 200 actors grows 0 (was 2.7-7.5 KB). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
404ee2ee3b
commit
22c104f766
4 changed files with 47 additions and 0 deletions
|
|
@ -448,3 +448,31 @@ function actor_release(render3d_st: mut Render3dState, a: Actor) -> void {
|
|||
if render3d_st.ac_spare == null { render3d_st.ac_spare = new []Actor }
|
||||
push(render3d_st.ac_spare, a)
|
||||
}
|
||||
|
||||
# One command buffer's worth of draws at start-up, through the path every draw takes (pipeline, set,
|
||||
# buffers, draw), so Metal's pooled command storage is already the size a frame can need: a bigger
|
||||
# frame than any before once grew it in play (IOGPU, under vkQueueSubmit). Drawn into the screen
|
||||
# image before the first frame clears it.
|
||||
function r3d_warm_commands(render3d_st: mut Render3dState) -> void {
|
||||
let n = gvk_cb_cap_of(render3d_st)
|
||||
if Os.platform() != "macos" or n <= 0 or render3d_st.ac_lit == null { return }
|
||||
let m = gpu_mesh_new(render3d_st)
|
||||
let v = floats(24)
|
||||
for k in 0 .. 3 { v[k * 8 + k] = 0.01; v[k * 8 + 4] = 1.0 }
|
||||
gpu_mesh_vertices(render3d_st, m, data_of(v), 96, GPU_STATIC)
|
||||
gpu_mesh_attr(render3d_st, m, 0, 3, GPU_F32, 32, 0, false)
|
||||
gpu_mesh_attr(render3d_st, m, 1, 3, GPU_F32, 32, 12, false)
|
||||
gpu_mesh_attr(render3d_st, m, 2, 2, GPU_F32, 32, 24, false)
|
||||
let ix = words(3)
|
||||
ix[0] = 0; ix[1] = 1; ix[2] = 2
|
||||
gpu_mesh_indices(render3d_st, m, data_of(ix), 12, 4)
|
||||
m.count = 3
|
||||
gpu_mesh_done(render3d_st, m)
|
||||
gpu_fb_bind(render3d_st, 0)
|
||||
gpu_use_program(render3d_st, render3d_st.ac_lit.prog)
|
||||
for i in 0 .. n { gpu_draw_mesh(render3d_st, m) }
|
||||
gvk_flush(render3d_st)
|
||||
mesh_release(render3d_st, m)
|
||||
free(v)
|
||||
free(ix)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -339,6 +339,8 @@ export state Render3dState {
|
|||
gvk_us_set: long = 0
|
||||
gvk_us_draw: long = 0
|
||||
gvk_n_draws: int = 0
|
||||
gvk_cb_draws: int = 0 # draws recorded into the frame's command buffer so far
|
||||
gvk_cb_cap: int = -1 # a command buffer is submitted after this many (0 = never; -1 unread)
|
||||
gvk_n_asked: int = 0 # draws that reached gvk_draw_now: every one the renderer asked for
|
||||
gvk_n_flush: int = 0
|
||||
gvk_prof_frames: int = 0
|
||||
|
|
|
|||
|
|
@ -1248,6 +1248,10 @@ function gvk_set_view(render3d_st: mut Render3dState, cb: pointer) -> void {
|
|||
# first / count select vertices or indices; count 0 means the mesh's own count. instances >= 1.
|
||||
function gvk_draw(render3d_st: mut Render3dState, p: int, m: Mesh, st: GvkState, first: int, count: int, instances: int, tx: words, tx_w: int, tx_cap: int, rec: words, rec_o: int) -> void {
|
||||
if render3d_st.gvk_prog_var == null or p <= 0 or p >= len(render3d_st.gvk_prog_var) or render3d_st.gvk_prog_var[p] == null { return }
|
||||
let cap = gvk_cb_cap_of(render3d_st)
|
||||
if cap > 0 and render3d_st.gvk_cb_draws >= cap { gvk_flush(render3d_st) }
|
||||
if render3d_st.gvk_cb == null { render3d_st.gvk_cb_draws = 0 }
|
||||
render3d_st.gvk_cb_draws += 1
|
||||
let prof = gvk_prof(render3d_st)
|
||||
var t0: long = 0
|
||||
if prof { t0 = gl_now_us() }
|
||||
|
|
@ -1974,3 +1978,15 @@ function gvk_pipeline_fast(render3d_st: mut Render3dState, p: int, m: Mesh, st:
|
|||
if p < 4096 { render3d_st.gvk_pc_last[p] = len(render3d_st.gvk_pc_prog) - 1 }
|
||||
return pipe
|
||||
}
|
||||
|
||||
# Draws a command buffer holds before it is submitted and the frame goes on in the next. Metal pools
|
||||
# the storage a command buffer grew to and grows it only when one encodes more than any before, so
|
||||
# with a bound and that many drawn at start-up (r3d_warm_commands) play never grows it. 0: no bound.
|
||||
const GVK_CB_DRAWS: int = 512
|
||||
function gvk_cb_cap_of(render3d_st: mut Render3dState) -> int {
|
||||
if render3d_st.gvk_cb_cap < 0 {
|
||||
render3d_st.gvk_cb_cap = GVK_CB_DRAWS
|
||||
if r3d_env_has(render3d_st, "R3D_CB_DRAWS") { render3d_st.gvk_cb_cap = Text.to_int(r3d_env(render3d_st, "R3D_CB_DRAWS")) }
|
||||
}
|
||||
return render3d_st.gvk_cb_cap
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ function r3d_load_step(render3d_st: mut Render3dState, i: int) -> bool {
|
|||
render3d_st.r3d_fog_density = 0.00024
|
||||
render3d_st.r3d_fog_falloff = 0.002
|
||||
render3d_st.r3d_ready = true
|
||||
r3d_warm_commands(render3d_st)
|
||||
gpu_check(render3d_st, "r3d init")
|
||||
}
|
||||
return true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue