render3d: R3D_VKMEM=<frame> says where the GPU memory is, by owner, and the renderer's big CPU arrays
Every allocation carries the owner its maker was wrapped in (models, terrain, impostor atlases, scatter, grass, shadow maps, frame targets, sky, water, game textures, made in a frame), and the report prints each owner's images and buffers, the 25 largest images and the scatter layers', streams' and terrain's CPU copies. Nothing drawn changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f65bd1aca1
commit
6289564382
17 changed files with 315 additions and 15 deletions
|
|
@ -196,6 +196,9 @@ export state Render3dState {
|
||||||
gvk_al_off: []int = null
|
gvk_al_off: []int = null
|
||||||
gvk_al_len: []int = null
|
gvk_al_len: []int = null
|
||||||
gvk_al_map: []pointer = null
|
gvk_al_map: []pointer = null
|
||||||
|
gvk_al_tag: []int = null # per allocation id: owner * 4 + image * 2 + host (vkmem_report.ludic)
|
||||||
|
gvk_tag: int = 0 # the owner allocations are made for now (VKM_*)
|
||||||
|
vkmem_at: int = 0 # R3D_VKMEM=<frame>: the report is printed at that frame
|
||||||
@max(4096) gvk_al_spare: []int = null # ids to reuse
|
@max(4096) gvk_al_spare: []int = null # ids to reuse
|
||||||
gvk_pool: long = 0
|
gvk_pool: long = 0
|
||||||
gvk_fence: bytes = null
|
gvk_fence: bytes = null
|
||||||
|
|
|
||||||
|
|
@ -175,9 +175,17 @@ function gltf_prim(render3d_st: mut Render3dState, p: Val) -> Prim {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Load the mesh of the node called `node_name` from dir/file.
|
# Load the mesh of the node called `node_name` from dir/file.
|
||||||
|
# the GPU memory it makes is counted as VKM_MODEL (R3D_VKMEM)
|
||||||
|
function gltf_load(render3d_st: mut Render3dState, dir: string, file: string, node_name: string) -> Model {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_MODEL
|
||||||
|
let r = gltf_load__t(render3d_st, dir, file, node_name)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
return r
|
||||||
|
}
|
||||||
@alloc_ok("loading a model, a texture or a font: a load, not a frame (a guest loading a teammate's look is one)")
|
@alloc_ok("loading a model, a texture or a font: a load, not a frame (a guest loading a teammate's look is one)")
|
||||||
@creates(Model)
|
@creates(Model)
|
||||||
function gltf_load(render3d_st: mut Render3dState, dir: string, file: string, node_name: string) -> Model {
|
function gltf_load__t(render3d_st: mut Render3dState, dir: string, file: string, node_name: string) -> Model {
|
||||||
render3d_st.gltf_dir = dir
|
render3d_st.gltf_dir = dir
|
||||||
let at = dir + "/" + file
|
let at = dir + "/" + file
|
||||||
let text = Fs.read_text(at)
|
let text = Fs.read_text(at)
|
||||||
|
|
|
||||||
|
|
@ -358,7 +358,8 @@ function gvk_mem_init(render3d_st: mut Render3dState) -> void {
|
||||||
render3d_st.gvk_blk_mem = new []long; render3d_st.gvk_blk_kind = new []int; render3d_st.gvk_blk_size = new []int; render3d_st.gvk_blk_map = new []pointer
|
render3d_st.gvk_blk_mem = new []long; render3d_st.gvk_blk_kind = new []int; render3d_st.gvk_blk_size = new []int; render3d_st.gvk_blk_map = new []pointer
|
||||||
render3d_st.gvk_fr_blk = new []int; render3d_st.gvk_fr_off = new []int; render3d_st.gvk_fr_len = new []int
|
render3d_st.gvk_fr_blk = new []int; render3d_st.gvk_fr_off = new []int; render3d_st.gvk_fr_len = new []int
|
||||||
render3d_st.gvk_al_blk = new []int; render3d_st.gvk_al_mem = new []long; render3d_st.gvk_al_off = new []int; render3d_st.gvk_al_len = new []int
|
render3d_st.gvk_al_blk = new []int; render3d_st.gvk_al_mem = new []long; render3d_st.gvk_al_off = new []int; render3d_st.gvk_al_len = new []int
|
||||||
render3d_st.gvk_al_map = new []pointer; render3d_st.gvk_al_spare = new []int
|
render3d_st.gvk_al_map = new []pointer; render3d_st.gvk_al_spare = new []int; render3d_st.gvk_al_tag = new []int
|
||||||
|
push(render3d_st.gvk_al_tag, 0)
|
||||||
push(render3d_st.gvk_al_blk, -1); push(render3d_st.gvk_al_mem, zero); push(render3d_st.gvk_al_off, 0); push(render3d_st.gvk_al_len, 0); push(render3d_st.gvk_al_map, null)
|
push(render3d_st.gvk_al_blk, -1); push(render3d_st.gvk_al_mem, zero); push(render3d_st.gvk_al_off, 0); push(render3d_st.gvk_al_len, 0); push(render3d_st.gvk_al_map, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -483,10 +484,15 @@ function gvk_mem_new(render3d_st: mut Render3dState, req: bytes, want: int, imag
|
||||||
List.pop(spare)
|
List.pop(spare)
|
||||||
} else {
|
} else {
|
||||||
push(render3d_st.gvk_al_blk, -1); push(render3d_st.gvk_al_mem, zero); push(render3d_st.gvk_al_off, 0); push(render3d_st.gvk_al_len, 0); push(render3d_st.gvk_al_map, null)
|
push(render3d_st.gvk_al_blk, -1); push(render3d_st.gvk_al_mem, zero); push(render3d_st.gvk_al_off, 0); push(render3d_st.gvk_al_len, 0); push(render3d_st.gvk_al_map, null)
|
||||||
|
push(render3d_st.gvk_al_tag, 0)
|
||||||
a = len(render3d_st.gvk_al_blk) - 1
|
a = len(render3d_st.gvk_al_blk) - 1
|
||||||
}
|
}
|
||||||
var len_ = size
|
var len_ = size
|
||||||
if blk >= 0 { len_ = span } # what the block gives back when it is freed
|
if blk >= 0 { len_ = span } # what the block gives back when it is freed
|
||||||
|
var tg = render3d_st.gvk_tag * 4
|
||||||
|
if image { tg += 2 }
|
||||||
|
if host { tg += 1 }
|
||||||
|
render3d_st.gvk_al_tag[a] = tg
|
||||||
render3d_st.gvk_al_blk[a] = blk; render3d_st.gvk_al_mem[a] = own; render3d_st.gvk_al_off[a] = off; render3d_st.gvk_al_len[a] = len_; render3d_st.gvk_al_map[a] = map
|
render3d_st.gvk_al_blk[a] = blk; render3d_st.gvk_al_mem[a] = own; render3d_st.gvk_al_off[a] = off; render3d_st.gvk_al_len[a] = len_; render3d_st.gvk_al_map[a] = map
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,8 +87,15 @@ function grass_blade_mesh(render3d_st: mut Render3dState, rows: int) -> Mesh {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
@alloc_ok("start-up: the device, its tables, the programs, the passes and the world's first textures are made once, before play")
|
# the GPU memory it makes is counted as VKM_GRASS (R3D_VKMEM)
|
||||||
function grass_init(render3d_st: mut Render3dState) -> void {
|
function grass_init(render3d_st: mut Render3dState) -> void {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_GRASS
|
||||||
|
grass_init__t(render3d_st)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
}
|
||||||
|
@alloc_ok("start-up: the device, its tables, the programs, the passes and the world's first textures are made once, before play")
|
||||||
|
function grass_init__t(render3d_st: mut Render3dState) -> void {
|
||||||
render3d_st.grass_merge = gpu_has_mdi(render3d_st) and not r3d_env_has(render3d_st, "R3D_GRASS_TILES")
|
render3d_st.grass_merge = gpu_has_mdi(render3d_st) and not r3d_env_has(render3d_st, "R3D_GRASS_TILES")
|
||||||
var defs = "#define FOLIAGE\n#define BLADE\n#define GBLADE\n"
|
var defs = "#define FOLIAGE\n#define BLADE\n#define GBLADE\n"
|
||||||
if render3d_st.grass_merge {
|
if render3d_st.grass_merge {
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,15 @@ function gg_base(b: int) -> int {
|
||||||
}
|
}
|
||||||
|
|
||||||
# once, after grass_init: the programs, the buffers and the three instanced blades
|
# once, after grass_init: the programs, the buffers and the three instanced blades
|
||||||
@alloc_ok("start-up: the device, its tables, the programs, the passes and the world's first textures are made once, before play")
|
# the GPU memory it makes is counted as VKM_GRASS (R3D_VKMEM)
|
||||||
function gg_init(render3d_st: mut Render3dState) -> void {
|
function gg_init(render3d_st: mut Render3dState) -> void {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_GRASS
|
||||||
|
gg_init__t(render3d_st)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
}
|
||||||
|
@alloc_ok("start-up: the device, its tables, the programs, the passes and the world's first textures are made once, before play")
|
||||||
|
function gg_init__t(render3d_st: mut Render3dState) -> void {
|
||||||
if not gpu_has_compute(render3d_st) or render3d_st.grass_prog == 0 { return }
|
if not gpu_has_compute(render3d_st) or render3d_st.grass_prog == 0 { return }
|
||||||
if r3d_env_has(render3d_st, "R3D_GRASS_GPU") and r3d_env(render3d_st, "R3D_GRASS_GPU") == "0" { return }
|
if r3d_env_has(render3d_st, "R3D_GRASS_GPU") and r3d_env(render3d_st, "R3D_GRASS_GPU") == "0" { return }
|
||||||
render3d_st.gg_reset = gpu_compute(render3d_st, "grass_reset", 1)
|
render3d_st.gg_reset = gpu_compute(render3d_st, "grass_reset", 1)
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,15 @@ function post_set_msaa(render3d_st: mut Render3dState, n: int) -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@alloc_ok("a world being set up (a stream, a layer, water, post, a bake): the map loading or swapping, not a frame")
|
# the GPU memory it makes is counted as VKM_TARGET (R3D_VKMEM)
|
||||||
function post_init(render3d_st: mut Render3dState, w: int, h: int) -> void {
|
function post_init(render3d_st: mut Render3dState, w: int, h: int) -> void {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_TARGET
|
||||||
|
post_init__t(render3d_st, w, h)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
}
|
||||||
|
@alloc_ok("a world being set up (a stream, a layer, water, post, a bake): the map loading or swapping, not a frame")
|
||||||
|
function post_init__t(render3d_st: mut Render3dState, w: int, h: int) -> void {
|
||||||
render3d_st.post_w = w; render3d_st.post_h = h
|
render3d_st.post_w = w; render3d_st.post_h = h
|
||||||
# the exposure's two 1x1 targets: made once, here, rather than by the first frame that measured
|
# the exposure's two 1x1 targets: made once, here, rather than by the first frame that measured
|
||||||
if render3d_st.post_adapt_t == null {
|
if render3d_st.post_adapt_t == null {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import "fmath.ludic"
|
||||||
import "gpu.ludic"
|
import "gpu.ludic"
|
||||||
import "gpu_manifest.ludic"
|
import "gpu_manifest.ludic"
|
||||||
import "gpu_vk.ludic"
|
import "gpu_vk.ludic"
|
||||||
|
import "vkmem_report.ludic"
|
||||||
import "gpu_vk_res.ludic"
|
import "gpu_vk_res.ludic"
|
||||||
import "gpu_vk_bc.ludic"
|
import "gpu_vk_bc.ludic"
|
||||||
import "texture_dds.ludic"
|
import "texture_dds.ludic"
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,14 @@ function r3d_screenshot(render3d_st: mut Render3dState, path: string) -> bool {
|
||||||
function r3d_present(render3d_st: mut Render3dState) -> void { gpu_present(render3d_st) }
|
function r3d_present(render3d_st: mut Render3dState) -> void { gpu_present(render3d_st) }
|
||||||
|
|
||||||
# the drawable changed size: the camera's aspect and every screen-sized target follow
|
# the drawable changed size: the camera's aspect and every screen-sized target follow
|
||||||
|
# the GPU memory it makes is counted as VKM_TARGET (R3D_VKMEM)
|
||||||
function r3d_resize(render3d_st: mut Render3dState) -> void {
|
function r3d_resize(render3d_st: mut Render3dState) -> void {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_TARGET
|
||||||
|
r3d_resize__t(render3d_st)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
}
|
||||||
|
function r3d_resize__t(render3d_st: mut Render3dState) -> void {
|
||||||
render3d_st.cam_aspect = float(gl_width()) / float(gl_height())
|
render3d_st.cam_aspect = float(gl_width()) / float(gl_height())
|
||||||
cam_update(render3d_st)
|
cam_update(render3d_st)
|
||||||
post_free(render3d_st)
|
post_free(render3d_st)
|
||||||
|
|
@ -198,7 +205,14 @@ function r3d_resize(render3d_st: mut Render3dState) -> void {
|
||||||
if render3d_st.water_refl != null { target_free(render3d_st, render3d_st.water_refl); render3d_st.water_refl = null }
|
if render3d_st.water_refl != null { target_free(render3d_st, render3d_st.water_refl); render3d_st.water_refl = null }
|
||||||
r3d_say_resized()
|
r3d_say_resized()
|
||||||
}
|
}
|
||||||
|
# the GPU memory it makes is counted as VKM_FRAME (R3D_VKMEM)
|
||||||
function r3d_frame(render3d_st: mut Render3dState, time: float) -> void {
|
function r3d_frame(render3d_st: mut Render3dState, time: float) -> void {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_FRAME
|
||||||
|
r3d_frame__t(render3d_st, time)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
}
|
||||||
|
function r3d_frame__t(render3d_st: mut Render3dState, time: float) -> void {
|
||||||
outline_frame(render3d_st)
|
outline_frame(render3d_st)
|
||||||
if not render3d_st.r3d_ready { return }
|
if not render3d_st.r3d_ready { return }
|
||||||
if gpu_resize_check(render3d_st) { r3d_resize(render3d_st) }
|
if gpu_resize_check(render3d_st) { r3d_resize(render3d_st) }
|
||||||
|
|
@ -206,6 +220,7 @@ function r3d_frame(render3d_st: mut Render3dState, time: float) -> void {
|
||||||
# or a fullscreen change does. Headless has no window to resize, and this path is where
|
# or a fullscreen change does. Headless has no window to resize, and this path is where
|
||||||
# a stale attachment or a texture freed twice shows up.
|
# a stale attachment or a texture freed twice shows up.
|
||||||
render3d_st.r3d_test_frame += 1
|
render3d_st.r3d_test_frame += 1
|
||||||
|
vkmem_tick(render3d_st)
|
||||||
if render3d_st.r3d_test_resize == 0 and r3d_env_has(render3d_st, "R3D_RESIZE_AT") { render3d_st.r3d_test_resize = Text.to_int(r3d_env(render3d_st, "R3D_RESIZE_AT")) }
|
if render3d_st.r3d_test_resize == 0 and r3d_env_has(render3d_st, "R3D_RESIZE_AT") { render3d_st.r3d_test_resize = Text.to_int(r3d_env(render3d_st, "R3D_RESIZE_AT")) }
|
||||||
# R3D_RESIZE_AT=<n>: from frame n on, rebuild every screen-sized buffer every few
|
# R3D_RESIZE_AT=<n>: from frame n on, rebuild every screen-sized buffer every few
|
||||||
# frames at a different size, as dragging a window edge or entering fullscreen does.
|
# frames at a different size, as dragging a window edge or entering fullscreen does.
|
||||||
|
|
|
||||||
|
|
@ -248,8 +248,16 @@ function scatter_attach(render3d_st: Render3dState, m: Mesh, buf: int) -> void {
|
||||||
gpu_mesh_done(render3d_st, m)
|
gpu_mesh_done(render3d_st, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
@alloc_ok("a world being set up (a stream, a layer, water, post, a bake): the map loading or swapping, not a frame")
|
# the GPU memory it makes is counted as VKM_SCATTER (R3D_VKMEM)
|
||||||
function layer_new(render3d_st: mut Render3dState, model: Model, cap: int, foliage: bool, wind: float, near: float, cull: float) -> Layer {
|
function layer_new(render3d_st: mut Render3dState, model: Model, cap: int, foliage: bool, wind: float, near: float, cull: float) -> Layer {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_SCATTER
|
||||||
|
let r = layer_new__t(render3d_st, model, cap, foliage, wind, near, cull)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
@alloc_ok("a world being set up (a stream, a layer, water, post, a bake): the map loading or swapping, not a frame")
|
||||||
|
function layer_new__t(render3d_st: mut Render3dState, model: Model, cap: int, foliage: bool, wind: float, near: float, cull: float) -> Layer {
|
||||||
let l = new Layer
|
let l = new Layer
|
||||||
l.model = model
|
l.model = model
|
||||||
l.cap = cap
|
l.cap = cap
|
||||||
|
|
@ -301,8 +309,16 @@ function layer_add(l: Layer, x: float, y: float, z: float, scale: float, yaw: fl
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---- impostors ---------------------------------------------------------------------
|
# ---- impostors ---------------------------------------------------------------------
|
||||||
@alloc_ok("a world being set up (a stream, a layer, water, post, a bake): the map loading or swapping, not a frame")
|
# the GPU memory it makes is counted as VKM_IMPOSTOR (R3D_VKMEM)
|
||||||
function impostor_bake(render3d_st: mut Render3dState, model: Model, tiles: int, tw: int, th: int) -> Impostor {
|
function impostor_bake(render3d_st: mut Render3dState, model: Model, tiles: int, tw: int, th: int) -> Impostor {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_IMPOSTOR
|
||||||
|
let r = impostor_bake__t(render3d_st, model, tiles, tw, th)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
@alloc_ok("a world being set up (a stream, a layer, water, post, a bake): the map loading or swapping, not a frame")
|
||||||
|
function impostor_bake__t(render3d_st: mut Render3dState, model: Model, tiles: int, tw: int, th: int) -> Impostor {
|
||||||
let im = new Impostor
|
let im = new Impostor
|
||||||
im.tiles = tiles
|
im.tiles = tiles
|
||||||
im.radius = model.radius * 1.02
|
im.radius = model.radius * 1.02
|
||||||
|
|
@ -1113,7 +1129,15 @@ function cb_rnd(render3d_st: mut Render3dState) -> float {
|
||||||
render3d_st.cb_state = (render3d_st.cb_state * 1103515245 + 12345) & 0x7FFFFFFF
|
render3d_st.cb_state = (render3d_st.cb_state * 1103515245 + 12345) & 0x7FFFFFFF
|
||||||
return float((render3d_st.cb_state >> 8) & 0xFFFF) / 65536.0
|
return float((render3d_st.cb_state >> 8) & 0xFFFF) / 65536.0
|
||||||
}
|
}
|
||||||
|
# the GPU memory it makes is counted as VKM_SCATTER (R3D_VKMEM)
|
||||||
function carpet_bake(render3d_st: mut Render3dState, layers: []Layer, count: int, tile: float, res: int) -> int {
|
function carpet_bake(render3d_st: mut Render3dState, layers: []Layer, count: int, tile: float, res: int) -> int {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_SCATTER
|
||||||
|
let r = carpet_bake__t(render3d_st, layers, count, tile, res)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
function carpet_bake__t(render3d_st: mut Render3dState, layers: []Layer, count: int, tile: float, res: int) -> int {
|
||||||
let tex = tex_target(render3d_st, res, res, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR)
|
let tex = tex_target(render3d_st, res, res, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR)
|
||||||
let fbo = gpu_fb_new(render3d_st)
|
let fbo = gpu_fb_new(render3d_st)
|
||||||
gpu_fb_bind(render3d_st, fbo)
|
gpu_fb_bind(render3d_st, fbo)
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,15 @@
|
||||||
const SHADOW_CASCADES: int = 5
|
const SHADOW_CASCADES: int = 5
|
||||||
|
|
||||||
|
|
||||||
@alloc_ok("start-up: the device, its tables, the programs, the passes and the world's first textures are made once, before play")
|
# the GPU memory it makes is counted as VKM_SHADOW (R3D_VKMEM)
|
||||||
function shadow_init(render3d_st: mut Render3dState) -> void {
|
function shadow_init(render3d_st: mut Render3dState) -> void {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_SHADOW
|
||||||
|
shadow_init__t(render3d_st)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
}
|
||||||
|
@alloc_ok("start-up: the device, its tables, the programs, the passes and the world's first textures are made once, before play")
|
||||||
|
function shadow_init__t(render3d_st: mut Render3dState) -> void {
|
||||||
shadow_make_tex(render3d_st)
|
shadow_make_tex(render3d_st)
|
||||||
render3d_st.sh_fbo = gpu_fb_new(render3d_st)
|
render3d_st.sh_fbo = gpu_fb_new(render3d_st)
|
||||||
gpu_fb_bind(render3d_st, render3d_st.sh_fbo)
|
gpu_fb_bind(render3d_st, render3d_st.sh_fbo)
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,16 @@ function sky_dir_from_uv(o: floats, u: float, v: float) -> void {
|
||||||
v3_set(o, st * Math.sin(phi), Math.cos(theta), -(st * Math.cos(phi)))
|
v3_set(o, st * Math.sin(phi), Math.cos(theta), -(st * Math.cos(phi)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@alloc_ok("start-up: the device, its tables, the programs, the passes and the world's first textures are made once, before play")
|
# the GPU memory it makes is counted as VKM_SKY (R3D_VKMEM)
|
||||||
function sky_load(render3d_st: mut Render3dState, path: string) -> bool {
|
function sky_load(render3d_st: mut Render3dState, path: string) -> bool {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_SKY
|
||||||
|
let r = sky_load__t(render3d_st, path)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
@alloc_ok("start-up: the device, its tables, the programs, the passes and the world's first textures are made once, before play")
|
||||||
|
function sky_load__t(render3d_st: mut Render3dState, path: string) -> bool {
|
||||||
render3d_st.sky_tex = tex_load_hdr(render3d_st, path)
|
render3d_st.sky_tex = tex_load_hdr(render3d_st, path)
|
||||||
if render3d_st.sky_tex == 0 { return false }
|
if render3d_st.sky_tex == 0 { return false }
|
||||||
render3d_st.sky_w = render3d_st.tex_w; render3d_st.sky_h = render3d_st.tex_h
|
render3d_st.sky_w = render3d_st.tex_w; render3d_st.sky_h = render3d_st.tex_h
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,16 @@ property Stream {
|
||||||
|
|
||||||
# microseconds spent per frame, split so the hitch can be attributed (R3D_PROF=1)
|
# microseconds spent per frame, split so the hitch can be attributed (R3D_PROF=1)
|
||||||
|
|
||||||
@alloc_ok("a world being set up (a stream, a layer, water, post, a bake): the map loading or swapping, not a frame")
|
# the GPU memory it makes is counted as VKM_SCATTER (R3D_VKMEM)
|
||||||
function stream_new(render3d_st: mut Render3dState, layer: Layer, size: float, reach: float, b0: float, b1: float, b2: float, b3: float) -> Stream {
|
function stream_new(render3d_st: mut Render3dState, layer: Layer, size: float, reach: float, b0: float, b1: float, b2: float, b3: float) -> Stream {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_SCATTER
|
||||||
|
let r = stream_new__t(render3d_st, layer, size, reach, b0, b1, b2, b3)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
@alloc_ok("a world being set up (a stream, a layer, water, post, a bake): the map loading or swapping, not a frame")
|
||||||
|
function stream_new__t(render3d_st: mut Render3dState, layer: Layer, size: float, reach: float, b0: float, b1: float, b2: float, b3: float) -> Stream {
|
||||||
if not render3d_st.stream_cap_read {
|
if not render3d_st.stream_cap_read {
|
||||||
render3d_st.stream_cap_read = true
|
render3d_st.stream_cap_read = true
|
||||||
if r3d_env_has(render3d_st, "R3D_STREAM_CAP") { render3d_st.STREAM_MAX_CHUNKS = Text.to_int(r3d_env(render3d_st, "R3D_STREAM_CAP")) }
|
if r3d_env_has(render3d_st, "R3D_STREAM_CAP") { render3d_st.STREAM_MAX_CHUNKS = Text.to_int(r3d_env(render3d_st, "R3D_STREAM_CAP")) }
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,14 @@ function terrain_ortho_forest(render3d_st: mut Render3dState, x: float, z: float
|
||||||
return 0.0
|
return 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# the GPU memory it makes is counted as VKM_TERRAIN (R3D_VKMEM)
|
||||||
function terrain_use_ortho(render3d_st: mut Render3dState, path: string) -> void {
|
function terrain_use_ortho(render3d_st: mut Render3dState, path: string) -> void {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_TERRAIN
|
||||||
|
terrain_use_ortho__t(render3d_st, path)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
}
|
||||||
|
function terrain_use_ortho__t(render3d_st: mut Render3dState, path: string) -> void {
|
||||||
let px = png_decode(render3d_st, path)
|
let px = png_decode(render3d_st, path)
|
||||||
if px == null { return }
|
if px == null { return }
|
||||||
# a map set up over another lets go of the last one's photograph first
|
# a map set up over another lets go of the last one's photograph first
|
||||||
|
|
@ -156,7 +163,14 @@ function terrain_use_ortho(render3d_st: mut Render3dState, path: string) -> void
|
||||||
gpu_tex_param(render3d_st, GPU_TEX2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
|
gpu_tex_param(render3d_st, GPU_TEX2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
|
||||||
gpu_tex_param(render3d_st, GPU_TEX2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
|
gpu_tex_param(render3d_st, GPU_TEX2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
|
||||||
}
|
}
|
||||||
|
# the GPU memory it makes is counted as VKM_TERRAIN (R3D_VKMEM)
|
||||||
function terrain_use_dem(render3d_st: mut Render3dState, path: string, emin: float, emax: float, base: float, ox: float, oz: float) -> void {
|
function terrain_use_dem(render3d_st: mut Render3dState, path: string, emin: float, emax: float, base: float, ox: float, oz: float) -> void {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_TERRAIN
|
||||||
|
terrain_use_dem__t(render3d_st, path, emin, emax, base, ox, oz)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
}
|
||||||
|
function terrain_use_dem__t(render3d_st: mut Render3dState, path: string, emin: float, emax: float, base: float, ox: float, oz: float) -> void {
|
||||||
if render3d_st.ter_dem_tex != 0 { gpu_tex_free(render3d_st, render3d_st.ter_dem_tex) }
|
if render3d_st.ter_dem_tex != 0 { gpu_tex_free(render3d_st, render3d_st.ter_dem_tex) }
|
||||||
render3d_st.ter_dem_tex = tex_load(render3d_st, path, false)
|
render3d_st.ter_dem_tex = tex_load(render3d_st, path, false)
|
||||||
render3d_st.ter_dem_min = emin; render3d_st.ter_dem_max = emax; render3d_st.ter_dem_base = base
|
render3d_st.ter_dem_min = emin; render3d_st.ter_dem_max = emax; render3d_st.ter_dem_base = base
|
||||||
|
|
@ -166,7 +180,14 @@ function terrain_use_dem(render3d_st: mut Render3dState, path: string, emin: flo
|
||||||
gpu_tex_param(render3d_st, GPU_TEX2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
|
gpu_tex_param(render3d_st, GPU_TEX2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# the GPU memory it makes is counted as VKM_TERRAIN (R3D_VKMEM)
|
||||||
function terrain_generate(render3d_st: mut Render3dState) -> void {
|
function terrain_generate(render3d_st: mut Render3dState) -> void {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_TERRAIN
|
||||||
|
terrain_generate__t(render3d_st)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
}
|
||||||
|
function terrain_generate__t(render3d_st: mut Render3dState) -> void {
|
||||||
var defs = ""
|
var defs = ""
|
||||||
if render3d_st.ter_dem_tex != 0 { defs = "#define DEM\n" }
|
if render3d_st.ter_dem_tex != 0 { defs = "#define DEM\n" }
|
||||||
if render3d_st.ter_smooth { defs = "#define SMOOTH\n" }
|
if render3d_st.ter_smooth { defs = "#define SMOOTH\n" }
|
||||||
|
|
@ -324,8 +345,15 @@ function terrain_height_smooth(render3d_st: mut Render3dState, x: float, z: floa
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
@alloc_ok("start-up: the device, its tables, the programs, the passes and the world's first textures are made once, before play")
|
# the GPU memory it makes is counted as VKM_TERRAIN (R3D_VKMEM)
|
||||||
function terrain_load_textures(render3d_st: mut Render3dState) -> void {
|
function terrain_load_textures(render3d_st: mut Render3dState) -> void {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_TERRAIN
|
||||||
|
terrain_load_textures__t(render3d_st)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
}
|
||||||
|
@alloc_ok("start-up: the device, its tables, the programs, the passes and the world's first textures are made once, before play")
|
||||||
|
function terrain_load_textures__t(render3d_st: mut Render3dState) -> void {
|
||||||
render3d_st.ter_tex = words(15)
|
render3d_st.ter_tex = words(15)
|
||||||
let a = render3d_st.r3d_assets + "/textures/"
|
let a = render3d_st.r3d_assets + "/textures/"
|
||||||
render3d_st.ter_tex[0] = tex_load(render3d_st, a + "aerial_grass_rock_diff_2k.png", true)
|
render3d_st.ter_tex[0] = tex_load(render3d_st, a + "aerial_grass_rock_diff_2k.png", true)
|
||||||
|
|
@ -346,7 +374,14 @@ function terrain_load_textures(render3d_st: mut Render3dState) -> void {
|
||||||
if r3d_env_has(render3d_st, "R3D_TEXDBG") { for i in 0 .. 15 { print(`ter_tex[{string(i)}] = {string(render3d_st.ter_tex[i])}`) } }
|
if r3d_env_has(render3d_st, "R3D_TEXDBG") { for i in 0 .. 15 { print(`ter_tex[{string(i)}] = {string(render3d_st.ter_tex[i])}`) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# the GPU memory it makes is counted as VKM_TERRAIN (R3D_VKMEM)
|
||||||
function terrain_init(render3d_st: mut Render3dState) -> void {
|
function terrain_init(render3d_st: mut Render3dState) -> void {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_TERRAIN
|
||||||
|
terrain_init__t(render3d_st)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
}
|
||||||
|
function terrain_init__t(render3d_st: mut Render3dState) -> void {
|
||||||
for i in 0 .. TERRAIN_INIT_STEPS { terrain_init_step(render3d_st, i) }
|
for i in 0 .. TERRAIN_INIT_STEPS { terrain_init_step(render3d_st, i) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -361,8 +396,15 @@ function terrain_init_step(render3d_st: mut Render3dState, i: int) -> void {
|
||||||
terrain_init_finish(render3d_st)
|
terrain_init_finish(render3d_st)
|
||||||
}
|
}
|
||||||
|
|
||||||
@alloc_ok("start-up: the device, its tables, the programs, the passes and the world's first textures are made once, before play")
|
# the GPU memory it makes is counted as VKM_TERRAIN (R3D_VKMEM)
|
||||||
function terrain_init_finish(render3d_st: mut Render3dState) -> void {
|
function terrain_init_finish(render3d_st: mut Render3dState) -> void {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_TERRAIN
|
||||||
|
terrain_init_finish__t(render3d_st)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
}
|
||||||
|
@alloc_ok("start-up: the device, its tables, the programs, the passes and the world's first textures are made once, before play")
|
||||||
|
function terrain_init_finish__t(render3d_st: mut Render3dState) -> void {
|
||||||
cdlod_init(render3d_st)
|
cdlod_init(render3d_st)
|
||||||
render3d_st.ter_wire = r3d_env_has(render3d_st, "R3D_WIRE")
|
render3d_st.ter_wire = r3d_env_has(render3d_st, "R3D_WIRE")
|
||||||
render3d_st.ter_force_far = r3d_env_has(render3d_st, "R3D_TFARONLY")
|
render3d_st.ter_force_far = r3d_env_has(render3d_st, "R3D_TFARONLY")
|
||||||
|
|
|
||||||
|
|
@ -265,8 +265,16 @@ function tex_upload(render3d_st: mut Render3dState, px: pointer, srgb: bool, mip
|
||||||
@alloc_ok("loading a model, a texture or a font: a load, not a frame (a guest loading a teammate's look is one)")
|
@alloc_ok("loading a model, a texture or a font: a load, not a frame (a guest loading a teammate's look is one)")
|
||||||
function tex_load(render3d_st: mut Render3dState, path: pointer, srgb: bool) -> int { return tex_load_ex(render3d_st, path, srgb, 0) }
|
function tex_load(render3d_st: mut Render3dState, path: pointer, srgb: bool) -> int { return tex_load_ex(render3d_st, path, srgb, 0) }
|
||||||
# ... with `dilate` passes of edge padding for a cut-out atlas (0 = none)
|
# ... with `dilate` passes of edge padding for a cut-out atlas (0 = none)
|
||||||
@alloc_ok("loading a model, a texture or a font: a load, not a frame (a guest loading a teammate's look is one)")
|
# the GPU memory it makes is counted as VKM_TEXTURE (R3D_VKMEM)
|
||||||
function tex_load_ex(render3d_st: mut Render3dState, path: pointer, srgb: bool, dilate: int) -> int {
|
function tex_load_ex(render3d_st: mut Render3dState, path: pointer, srgb: bool, dilate: int) -> int {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
if was == VKM_OTHER { render3d_st.gvk_tag = VKM_TEXTURE }
|
||||||
|
let r = tex_load_ex__t(render3d_st, path, srgb, dilate)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
@alloc_ok("loading a model, a texture or a font: a load, not a frame (a guest loading a teammate's look is one)")
|
||||||
|
function tex_load_ex__t(render3d_st: mut Render3dState, path: pointer, srgb: bool, dilate: int) -> int {
|
||||||
# a .dds encoded beside the .png at build time goes to the GPU compressed, its mips included
|
# a .dds encoded beside the .png at build time goes to the GPU compressed, its mips included
|
||||||
# (not for a cut-out atlas: its edge padding is made here, from the .png)
|
# (not for a cut-out atlas: its edge padding is made here, from the .png)
|
||||||
if render3d_st.gvk_has_bc and dilate == 0 {
|
if render3d_st.gvk_has_bc and dilate == 0 {
|
||||||
|
|
@ -410,7 +418,15 @@ function hdr_decode(render3d_st: mut Render3dState, path: pointer) -> floats {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Load an equirectangular .hdr as an RGB16F texture with mips (clamped in v).
|
# Load an equirectangular .hdr as an RGB16F texture with mips (clamped in v).
|
||||||
|
# the GPU memory it makes is counted as VKM_TEXTURE (R3D_VKMEM)
|
||||||
function tex_load_hdr(render3d_st: mut Render3dState, path: pointer) -> int {
|
function tex_load_hdr(render3d_st: mut Render3dState, path: pointer) -> int {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
if was == VKM_OTHER { render3d_st.gvk_tag = VKM_TEXTURE }
|
||||||
|
let r = tex_load_hdr__t(render3d_st, path)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
function tex_load_hdr__t(render3d_st: mut Render3dState, path: pointer) -> int {
|
||||||
let px = hdr_decode(render3d_st, path)
|
let px = hdr_decode(render3d_st, path)
|
||||||
if px == null { return 0 }
|
if px == null { return 0 }
|
||||||
let id = gpu_tex_new(render3d_st)
|
let id = gpu_tex_new(render3d_st)
|
||||||
|
|
@ -484,8 +500,16 @@ function tex_dump(render3d_st: mut Render3dState, tex: int, w: int, h: int, path
|
||||||
|
|
||||||
# A binary PPM (P6, what Gl.screenshot writes) as an RGB8 texture, box-filtered down by
|
# A binary PPM (P6, what Gl.screenshot writes) as an RGB8 texture, box-filtered down by
|
||||||
# `shrink` (a photo thumbnail); 0 when the file is missing.
|
# `shrink` (a photo thumbnail); 0 when the file is missing.
|
||||||
@alloc_ok("a load: an image read from disk")
|
# the GPU memory it makes is counted as VKM_TEXTURE (R3D_VKMEM)
|
||||||
function tex_load_ppm(render3d_st: mut Render3dState, path: pointer, shrink: int) -> int {
|
function tex_load_ppm(render3d_st: mut Render3dState, path: pointer, shrink: int) -> int {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
if was == VKM_OTHER { render3d_st.gvk_tag = VKM_TEXTURE }
|
||||||
|
let r = tex_load_ppm__t(render3d_st, path, shrink)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
@alloc_ok("a load: an image read from disk")
|
||||||
|
function tex_load_ppm__t(render3d_st: mut Render3dState, path: pointer, shrink: int) -> int {
|
||||||
let d = r3d_read_file(render3d_st, path)
|
let d = r3d_read_file(render3d_st, path)
|
||||||
if d == null { return 0 }
|
if d == null { return 0 }
|
||||||
let size = render3d_st.tex_file_len
|
let size = render3d_st.tex_file_len
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,16 @@ function dds_path_of(path: string) -> string {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Load the .dds at `path` as a texture (srgb: colour, sampled as sRGB), or 0
|
# Load the .dds at `path` as a texture (srgb: colour, sampled as sRGB), or 0
|
||||||
@alloc_ok("loading a model, a texture or a font: a load, not a frame (a guest loading a teammate's look is one)")
|
# the GPU memory it makes is counted as VKM_TEXTURE (R3D_VKMEM)
|
||||||
function tex_load_dds(render3d_st: mut Render3dState, path: string, srgb: bool) -> int {
|
function tex_load_dds(render3d_st: mut Render3dState, path: string, srgb: bool) -> int {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
if was == VKM_OTHER { render3d_st.gvk_tag = VKM_TEXTURE }
|
||||||
|
let r = tex_load_dds__t(render3d_st, path, srgb)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
@alloc_ok("loading a model, a texture or a font: a load, not a frame (a guest loading a teammate's look is one)")
|
||||||
|
function tex_load_dds__t(render3d_st: mut Render3dState, path: string, srgb: bool) -> int {
|
||||||
let b = Fs.read_bytes(path)
|
let b = Fs.read_bytes(path)
|
||||||
if b == null { return 0 }
|
if b == null { return 0 }
|
||||||
let id = tex_load_dds_bytes(render3d_st, b, srgb)
|
let id = tex_load_dds_bytes(render3d_st, b, srgb)
|
||||||
|
|
@ -28,7 +36,15 @@ function tex_load_dds(render3d_st: mut Render3dState, path: string, srgb: bool)
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# the GPU memory it makes is counted as VKM_TEXTURE (R3D_VKMEM)
|
||||||
function tex_load_dds_bytes(render3d_st: mut Render3dState, b: []byte, srgb: bool) -> int {
|
function tex_load_dds_bytes(render3d_st: mut Render3dState, b: []byte, srgb: bool) -> int {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
if was == VKM_OTHER { render3d_st.gvk_tag = VKM_TEXTURE }
|
||||||
|
let r = tex_load_dds_bytes__t(render3d_st, b, srgb)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
function tex_load_dds_bytes__t(render3d_st: mut Render3dState, b: []byte, srgb: bool) -> int {
|
||||||
if len(b) < 148 or b[0] != 68 or b[1] != 68 or b[2] != 83 or b[3] != 32 { return 0 }
|
if len(b) < 148 or b[0] != 68 or b[1] != 68 or b[2] != 83 or b[3] != 32 { return 0 }
|
||||||
if b[84] != 68 or b[85] != 88 or b[86] != 49 or b[87] != 48 { return 0 } # "DX10"
|
if b[84] != 68 or b[85] != 88 or b[86] != 49 or b[87] != 48 { return 0 } # "DX10"
|
||||||
let h = dds_u32(b, 12)
|
let h = dds_u32(b, 12)
|
||||||
|
|
|
||||||
110
packages/ludic.render3d/vkmem_report.ludic
Normal file
110
packages/ludic.render3d/vkmem_report.ludic
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
# vkmem_report.ludic — where the GPU memory is, by owner (R3D_VKMEM=<frame>, printed once at that frame).
|
||||||
|
# Every allocation carries the owner its maker was wrapped in (gvk_tag); a block's unused room is
|
||||||
|
# counted apart, since it is memory the driver holds for us whoever it will be given to.
|
||||||
|
|
||||||
|
const VKM_OTHER: int = 0
|
||||||
|
const VKM_MODEL: int = 1
|
||||||
|
const VKM_TERRAIN: int = 2
|
||||||
|
const VKM_SCATTER: int = 3
|
||||||
|
const VKM_GRASS: int = 4
|
||||||
|
const VKM_SHADOW: int = 5
|
||||||
|
const VKM_TARGET: int = 6
|
||||||
|
const VKM_SKY: int = 7
|
||||||
|
const VKM_WATER: int = 8
|
||||||
|
const VKM_TEXTURE: int = 9
|
||||||
|
const VKM_FRAME: int = 10
|
||||||
|
const VKM_IMPOSTOR: int = 11
|
||||||
|
const VKM_N: int = 12
|
||||||
|
|
||||||
|
function vkmem_tick(render3d_st: mut Render3dState) -> void {
|
||||||
|
if render3d_st.vkmem_at == 0 {
|
||||||
|
render3d_st.vkmem_at = -1
|
||||||
|
if r3d_env_has(render3d_st, "R3D_VKMEM") { render3d_st.vkmem_at = Text.to_int(r3d_env(render3d_st, "R3D_VKMEM")) }
|
||||||
|
}
|
||||||
|
if render3d_st.vkmem_at > 0 and render3d_st.r3d_test_frame == render3d_st.vkmem_at { vkmem_report(render3d_st) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@alloc_ok("a report printed once, under R3D_VKMEM")
|
||||||
|
function vkmem_report(render3d_st: Render3dState) -> void {
|
||||||
|
if render3d_st.gvk_al_tag == null { return }
|
||||||
|
let img = words(VKM_N); let buf = words(VKM_N); let host = words(VKM_N); let cnt = words(VKM_N)
|
||||||
|
for k in 0 .. VKM_N { img[k] = 0; buf[k] = 0; host[k] = 0; cnt[k] = 0 }
|
||||||
|
var used = 0
|
||||||
|
var own = 0
|
||||||
|
for a in 1 .. len(render3d_st.gvk_al_len) {
|
||||||
|
let n = render3d_st.gvk_al_len[a]
|
||||||
|
if n <= 0 { continue }
|
||||||
|
let t = render3d_st.gvk_al_tag[a]
|
||||||
|
let who = Math.min(t / 4, VKM_N - 1)
|
||||||
|
if (t & 1) != 0 { host[who] += n } else if (t & 2) != 0 { img[who] += n } else { buf[who] += n }
|
||||||
|
cnt[who] += 1
|
||||||
|
used += n
|
||||||
|
if render3d_st.gvk_al_blk[a] < 0 { own += n }
|
||||||
|
}
|
||||||
|
var blocks = 0
|
||||||
|
for b in 0 .. len(render3d_st.gvk_blk_size) { blocks += render3d_st.gvk_blk_size[b] }
|
||||||
|
vkmem_say_head(used, blocks + own, blocks + own - used)
|
||||||
|
for k in 0 .. VKM_N { if cnt[k] > 0 { vkmem_say_row(vkmem_name(k), img[k], buf[k], host[k], cnt[k]) } }
|
||||||
|
vkmem_big(render3d_st)
|
||||||
|
vkmem_cpu(render3d_st)
|
||||||
|
}
|
||||||
|
|
||||||
|
# the largest images, with their owner, size and format
|
||||||
|
@alloc_ok("a report printed once, under R3D_VKMEM")
|
||||||
|
function vkmem_big(render3d_st: Render3dState) -> void {
|
||||||
|
let n = len(render3d_st.gvk_tex_mem)
|
||||||
|
let done = words(n)
|
||||||
|
for i in 0 .. n { done[i] = 0 }
|
||||||
|
for r in 0 .. 25 {
|
||||||
|
var best = -1
|
||||||
|
var bn = 0
|
||||||
|
for i in 1 .. n {
|
||||||
|
let a = int(render3d_st.gvk_tex_mem[i])
|
||||||
|
if done[i] != 0 or a <= 0 or a >= len(render3d_st.gvk_al_len) { continue }
|
||||||
|
if render3d_st.gvk_al_len[a] > bn { bn = render3d_st.gvk_al_len[a]; best = i }
|
||||||
|
}
|
||||||
|
if best < 0 { return }
|
||||||
|
done[best] = 1
|
||||||
|
let a = int(render3d_st.gvk_tex_mem[best])
|
||||||
|
vkmem_say_img(vkmem_name(render3d_st.gvk_al_tag[a] / 4), bn, render3d_st.gvk_tex_dims_w[best], render3d_st.gvk_tex_dims_h[best], render3d_st.gvk_tex_layers[best], render3d_st.gvk_tex_levels[best], render3d_st.gvk_tex_vkfmt[best])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function vkmem_name(k: int) -> string {
|
||||||
|
if k == VKM_MODEL { return "models (gltf_load)" }
|
||||||
|
if k == VKM_TERRAIN { return "terrain" }
|
||||||
|
if k == VKM_SCATTER { return "scatter + streams" }
|
||||||
|
if k == VKM_GRASS { return "grass" }
|
||||||
|
if k == VKM_SHADOW { return "shadow maps" }
|
||||||
|
if k == VKM_TARGET { return "frame targets" }
|
||||||
|
if k == VKM_SKY { return "sky" }
|
||||||
|
if k == VKM_WATER { return "water" }
|
||||||
|
if k == VKM_TEXTURE { return "textures (game)" }
|
||||||
|
if k == VKM_FRAME { return "made in a frame" }
|
||||||
|
if k == VKM_IMPOSTOR { return "impostor atlases" }
|
||||||
|
return "other"
|
||||||
|
}
|
||||||
|
function vkmem_mb(n: int) -> int { return n / 1048576 }
|
||||||
|
function vkmem_say_head(used: int, held: int, slack: int) -> void { print(`vkmem: {vkmem_mb(used)} MB in use, {vkmem_mb(held)} MB held from the driver, {vkmem_mb(slack)} MB unused room in blocks`) }
|
||||||
|
function vkmem_say_row(name: string, img: int, buf: int, host: int, n: int) -> void { print(`vkmem: {name}: images {vkmem_mb(img)} MB, device buffers {vkmem_mb(buf)} MB, host buffers {vkmem_mb(host)} MB ({n} allocations)`) }
|
||||||
|
function vkmem_say_img(name: string, n: int, w: int, h: int, layers: int, levels: int, fmt: int) -> void { print(`vkmem: image {n / 1024} KB {w}x{h}x{layers} mips {levels} vkformat {fmt} {name}`) }
|
||||||
|
|
||||||
|
# the renderer's own big arrays on the CPU heap
|
||||||
|
function vkmem_cpu(render3d_st: Render3dState) -> void {
|
||||||
|
var lay = 0
|
||||||
|
var cap = 0
|
||||||
|
for i in 0 .. len(render3d_st.sc_layers) {
|
||||||
|
let l = render3d_st.sc_layers[i]
|
||||||
|
lay += vkmem_fl(l.inst) + vkmem_fl(l.scratch) + vkmem_fl(l.gsorted) + vkmem_fl(l.vis)
|
||||||
|
cap += l.cap
|
||||||
|
}
|
||||||
|
var str = 0
|
||||||
|
if render3d_st.stream_all != null { for i in 0 .. len(render3d_st.stream_all) { str += len(render3d_st.stream_all[i].arena) * 4 } }
|
||||||
|
let ter = vkmem_fl(render3d_st.ter_heights) + TERRAIN_RES * TERRAIN_RES * 3
|
||||||
|
vkmem_say_cpu(len(render3d_st.sc_layers), cap, lay, str, ter, vkmem_fl(render3d_st.wb_cells))
|
||||||
|
}
|
||||||
|
function vkmem_fl(f: floats) -> int {
|
||||||
|
if f == null { return 0 }
|
||||||
|
return len(f) * 4
|
||||||
|
}
|
||||||
|
function vkmem_say_cpu(n: int, cap: int, lay: int, str: int, ter: int, water: int) -> void { print(`vkmem: cpu: {n} scatter layers (cap {cap} instances) {vkmem_mb(lay)} MB, stream arenas {vkmem_mb(str)} MB, terrain copies {vkmem_mb(ter)} MB, water cells {vkmem_mb(water)} MB`) }
|
||||||
|
|
@ -294,7 +294,14 @@ function water_body_add(render3d_st: mut Render3dState, level: float, cx: float,
|
||||||
}
|
}
|
||||||
# one reflecting plane: what this function always meant, without a new mesh and program
|
# one reflecting plane: what this function always meant, without a new mesh and program
|
||||||
# every time it is called
|
# every time it is called
|
||||||
|
# the GPU memory it makes is counted as VKM_WATER (R3D_VKMEM)
|
||||||
function water_init(render3d_st: mut Render3dState, level: float, cx: float, cz: float, ex: float, ez: float) -> void {
|
function water_init(render3d_st: mut Render3dState, level: float, cx: float, cz: float, ex: float, ez: float) -> void {
|
||||||
|
let was = render3d_st.gvk_tag
|
||||||
|
render3d_st.gvk_tag = VKM_WATER
|
||||||
|
water_init__t(render3d_st, level, cx, cz, ex, ez)
|
||||||
|
render3d_st.gvk_tag = was
|
||||||
|
}
|
||||||
|
function water_init__t(render3d_st: mut Render3dState, level: float, cx: float, cz: float, ex: float, ez: float) -> void {
|
||||||
water_bodies_clear(render3d_st)
|
water_bodies_clear(render3d_st)
|
||||||
water_body_add(render3d_st, level, cx, cz, ex, ez, true)
|
water_body_add(render3d_st, level, cx, cz, ex, ez, true)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue