Merge commit '6289564' into lang/foundations
This commit is contained in:
commit
5f6277a74c
17 changed files with 315 additions and 15 deletions
|
|
@ -196,6 +196,9 @@ export state Render3dState {
|
|||
gvk_al_off: []int = null
|
||||
gvk_al_len: []int = 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
|
||||
gvk_pool: long = 0
|
||||
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.
|
||||
# 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)")
|
||||
@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
|
||||
let at = dir + "/" + file
|
||||
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_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_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)
|
||||
}
|
||||
|
||||
|
|
@ -483,10 +484,15 @@ function gvk_mem_new(render3d_st: mut Render3dState, req: bytes, want: int, imag
|
|||
List.pop(spare)
|
||||
} 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_tag, 0)
|
||||
a = len(render3d_st.gvk_al_blk) - 1
|
||||
}
|
||||
var len_ = size
|
||||
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
|
||||
return a
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,8 +87,15 @@ function grass_blade_mesh(render3d_st: mut Render3dState, rows: int) -> Mesh {
|
|||
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 {
|
||||
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")
|
||||
var defs = "#define FOLIAGE\n#define BLADE\n#define GBLADE\n"
|
||||
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
|
||||
@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 {
|
||||
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 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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
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
|
||||
# the exposure's two 1x1 targets: made once, here, rather than by the first frame that measured
|
||||
if render3d_st.post_adapt_t == null {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import "fmath.ludic"
|
|||
import "gpu.ludic"
|
||||
import "gpu_manifest.ludic"
|
||||
import "gpu_vk.ludic"
|
||||
import "vkmem_report.ludic"
|
||||
import "gpu_vk_res.ludic"
|
||||
import "gpu_vk_bc.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) }
|
||||
|
||||
# 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 {
|
||||
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())
|
||||
cam_update(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 }
|
||||
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 {
|
||||
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)
|
||||
if not render3d_st.r3d_ready { return }
|
||||
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
|
||||
# a stale attachment or a texture freed twice shows up.
|
||||
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")) }
|
||||
# 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.
|
||||
|
|
|
|||
|
|
@ -248,8 +248,16 @@ function scatter_attach(render3d_st: Render3dState, m: Mesh, buf: int) -> void {
|
|||
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 {
|
||||
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
|
||||
l.model = model
|
||||
l.cap = cap
|
||||
|
|
@ -301,8 +309,16 @@ function layer_add(l: Layer, x: float, y: float, z: float, scale: float, yaw: fl
|
|||
}
|
||||
|
||||
# ---- 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 {
|
||||
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
|
||||
im.tiles = tiles
|
||||
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
|
||||
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 {
|
||||
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 fbo = gpu_fb_new(render3d_st)
|
||||
gpu_fb_bind(render3d_st, fbo)
|
||||
|
|
|
|||
|
|
@ -8,8 +8,15 @@
|
|||
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 {
|
||||
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)
|
||||
render3d_st.sh_fbo = gpu_fb_new(render3d_st)
|
||||
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)))
|
||||
}
|
||||
|
||||
@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 {
|
||||
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)
|
||||
if render3d_st.sky_tex == 0 { return false }
|
||||
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)
|
||||
|
||||
@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 {
|
||||
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 {
|
||||
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")) }
|
||||
|
|
|
|||
|
|
@ -142,7 +142,14 @@ function terrain_ortho_forest(render3d_st: mut Render3dState, x: float, z: float
|
|||
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 {
|
||||
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)
|
||||
if px == null { return }
|
||||
# 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_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 {
|
||||
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) }
|
||||
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
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
||||
# the GPU memory it makes is counted as VKM_TERRAIN (R3D_VKMEM)
|
||||
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 = ""
|
||||
if render3d_st.ter_dem_tex != 0 { defs = "#define DEM\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
|
||||
}
|
||||
|
||||
@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 {
|
||||
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)
|
||||
let a = render3d_st.r3d_assets + "/textures/"
|
||||
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])}`) } }
|
||||
}
|
||||
|
||||
# the GPU memory it makes is counted as VKM_TERRAIN (R3D_VKMEM)
|
||||
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) }
|
||||
}
|
||||
|
||||
|
|
@ -361,8 +396,15 @@ function terrain_init_step(render3d_st: mut Render3dState, i: int) -> void {
|
|||
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 {
|
||||
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)
|
||||
render3d_st.ter_wire = r3d_env_has(render3d_st, "R3D_WIRE")
|
||||
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)")
|
||||
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)
|
||||
@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 {
|
||||
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
|
||||
# (not for a cut-out atlas: its edge padding is made here, from the .png)
|
||||
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).
|
||||
# the GPU memory it makes is counted as VKM_TEXTURE (R3D_VKMEM)
|
||||
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)
|
||||
if px == null { return 0 }
|
||||
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
|
||||
# `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 {
|
||||
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)
|
||||
if d == null { return 0 }
|
||||
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
|
||||
@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 {
|
||||
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)
|
||||
if b == null { return 0 }
|
||||
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
|
||||
}
|
||||
|
||||
# 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 {
|
||||
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 b[84] != 68 or b[85] != 88 or b[86] != 49 or b[87] != 48 { return 0 } # "DX10"
|
||||
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
|
||||
# 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 {
|
||||
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_body_add(render3d_st, level, cx, cz, ex, ez, true)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue