@alloc_ok with its reason on what is made once per resource and kept (textures, programs, samplers, views, layouts, memory blocks, the pipeline cache in gvk_pipe_build), on resize and swapchain remakes, on screenshots and dumps, on a world being set up (streams, layers, water, post, bakes), on loads (gltf_load, skin_load, tex_load*, png_decode, fonts) and on R3D_PROF / drawstats. gltf_cached's hit path is its own and makes nothing; the miss (gltf_cached_load) is declared. m4_look_at (now over m4_look_at_xyz) and m4_inverse work on scalars, and cam_update makes no scratch. Left: lazy first-use starts, error and debug prints, and scratch made and freed each call (churn, plan 25.3). Compiled (steady, and ludic deps over the game). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
2.4 KiB
Text
51 lines
2.4 KiB
Text
# gltf_cached.ludic - a still model loaded once: the same (dir, file, node) asked again hands back the
|
|
# model the first load made, found by comparing the names in place, so asking allocates nothing. For
|
|
# props a game places while it plays (a fish, a sign an animal leaves); a model whose document is
|
|
# read after the load (ludic.anim's clips) still goes through gltf_load. A model loaded here is shared
|
|
# by every actor drawing it; model_release takes it out of the cache as it lets it go.
|
|
export function gltf_cached(render3d_st: mut Render3dState, dir: string, file: string, node_name: string) -> Model {
|
|
if render3d_st.gltf_kept != null {
|
|
for i in 0 .. len(render3d_st.gltf_kept) {
|
|
if render3d_st.gltf_kept_node[i] == node_name and render3d_st.gltf_kept_file[i] == file and render3d_st.gltf_kept_dir[i] == dir { return render3d_st.gltf_kept[i] }
|
|
}
|
|
}
|
|
return gltf_cached_load(render3d_st, dir, file, node_name)
|
|
}
|
|
# the first ask for a model: loaded, and kept for every ask after it
|
|
@alloc_ok("a model loaded the first time it is asked for, kept for every ask after it")
|
|
function gltf_cached_load(render3d_st: mut Render3dState, dir: string, file: string, node_name: string) -> Model {
|
|
if render3d_st.gltf_kept == null {
|
|
render3d_st.gltf_kept = new []Model
|
|
render3d_st.gltf_kept_dir = new []string
|
|
render3d_st.gltf_kept_file = new []string
|
|
render3d_st.gltf_kept_node = new []string
|
|
}
|
|
let m = gltf_load(render3d_st, dir, file, node_name)
|
|
push(render3d_st.gltf_kept, m)
|
|
push(render3d_st.gltf_kept_dir, dir)
|
|
push(render3d_st.gltf_kept_file, file)
|
|
push(render3d_st.gltf_kept_node, node_name)
|
|
return m
|
|
}
|
|
|
|
# a model let go (model_release) leaves the cache, so the next ask loads it afresh
|
|
function gltf_cached_forget(render3d_st: mut Render3dState, m: Model) -> void {
|
|
if render3d_st.gltf_kept == null { return }
|
|
let kept = render3d_st.gltf_kept
|
|
let dirs = render3d_st.gltf_kept_dir
|
|
let files = render3d_st.gltf_kept_file
|
|
let nodes = render3d_st.gltf_kept_node
|
|
for i in 0 .. len(kept) {
|
|
if kept[i] == m {
|
|
let last = len(kept) - 1
|
|
kept[i] = kept[last]; dirs[i] = dirs[last]; files[i] = files[last]; nodes[i] = nodes[last]
|
|
List.pop(kept); List.pop(dirs); List.pop(files); List.pop(nodes)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
export function gltf_cached_count(render3d_st: Render3dState) -> int {
|
|
if render3d_st.gltf_kept == null { return 0 }
|
|
return len(render3d_st.gltf_kept)
|
|
}
|