Merge branch 'r3d/frame-allocs' into lang/foundations
This commit is contained in:
commit
dec64e8a59
21 changed files with 118 additions and 42 deletions
|
|
@ -245,6 +245,7 @@ property OutlineReq {
|
|||
# on the actor; a queue does not, if the first pass empties it. So a flush CLOSES the
|
||||
# batch rather than clearing it, and the next add opens a new one: every pass in a frame
|
||||
# sees the same requests, and the caller needs no frame hook.
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function outline_model(render3d_st: mut Render3dState, m: Model, mat: floats, width: float, r: float, g: float, b: float) -> void {
|
||||
if m == null or mat == null or width == 0.0 { return }
|
||||
if render3d_st.ac_oq_closed { render3d_st.ac_oq_n = 0; render3d_st.ac_oq_closed = false }
|
||||
|
|
|
|||
|
|
@ -33,10 +33,10 @@ function cam_update(render3d_st: mut Render3dState) -> void {
|
|||
let cp = Math.cos(render3d_st.cam_pitch); let sp = Math.sin(render3d_st.cam_pitch)
|
||||
v3_set(render3d_st.cam_fwd, -(sy * cp), sp, -(cy * cp))
|
||||
v3_set(render3d_st.cam_right, cy, 0.0, -sy)
|
||||
let at = floats(3)
|
||||
v3_add(at, render3d_st.cam_pos, render3d_st.cam_fwd)
|
||||
let up = v3_new(0.0, 1.0, 0.0)
|
||||
m4_look_at(render3d_st.cam_view, render3d_st.cam_pos, at, up)
|
||||
let px = render3d_st.cam_pos[0]
|
||||
let py = render3d_st.cam_pos[1]
|
||||
let pz = render3d_st.cam_pos[2]
|
||||
m4_look_at_xyz(render3d_st.cam_view, px, py, pz, px + render3d_st.cam_fwd[0], py + render3d_st.cam_fwd[1], pz + render3d_st.cam_fwd[2], 0.0, 1.0, 0.0)
|
||||
m4_perspective(render3d_st.cam_proj, render3d_st.cam_fov, render3d_st.cam_aspect, render3d_st.cam_near, render3d_st.cam_far)
|
||||
m4_mul(render3d_st.cam_vp_clean, render3d_st.cam_proj, render3d_st.cam_view)
|
||||
m4_inverse(render3d_st.cam_inv_vp_clean, render3d_st.cam_vp_clean)
|
||||
|
|
@ -49,7 +49,6 @@ function cam_update(render3d_st: mut Render3dState) -> void {
|
|||
m4_mul(render3d_st.cam_vp, render3d_st.cam_proj, render3d_st.cam_view)
|
||||
m4_inverse(render3d_st.cam_inv_vp, render3d_st.cam_vp)
|
||||
m4_inverse(render3d_st.cam_inv_proj, render3d_st.cam_proj)
|
||||
free(at); free(up)
|
||||
cam_planes_update(render3d_st)
|
||||
}
|
||||
function cam_planes_update(render3d_st: mut Render3dState) -> void {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ const DS_KINDS: int = 5
|
|||
|
||||
# rows: (pass, program, kind)
|
||||
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function ds_enabled(render3d_st: mut Render3dState) -> bool {
|
||||
if render3d_st.ds_on < 0 {
|
||||
render3d_st.ds_on = 0
|
||||
|
|
@ -49,6 +50,7 @@ function ds_enabled(render3d_st: mut Render3dState) -> bool {
|
|||
}
|
||||
|
||||
# the profiler's pass boundaries (prof_begin / prof_end), whether or not R3D_PROF is on
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function ds_set_pass(render3d_st: mut Render3dState, name: pointer) -> void {
|
||||
if render3d_st.ds_on != 1 { return }
|
||||
render3d_st.ds_last = -1
|
||||
|
|
@ -76,6 +78,7 @@ function ds_frame(render3d_st: mut Render3dState) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function ds_draw(render3d_st: mut Render3dState, kind: int, instances: int, indices: int) -> void {
|
||||
if render3d_st.ds_on != 1 or not render3d_st.ds_counting { return }
|
||||
let p = render3d_st.gpu_prog_cur
|
||||
|
|
@ -125,6 +128,7 @@ function ds_backend(render3d_st: Render3dState) -> pointer {
|
|||
return "opengl"
|
||||
}
|
||||
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function ds_report(render3d_st: mut Render3dState) -> void {
|
||||
let n_rows = len(render3d_st.ds_row_pass)
|
||||
let n_pass = len(render3d_st.ds_pass_names)
|
||||
|
|
|
|||
|
|
@ -157,45 +157,55 @@ function m4_ortho(m: floats, l: float, r: float, b: float, t: float, n: float, f
|
|||
m[14] = -((f + n) / (f - n))
|
||||
}
|
||||
function m4_look_at(m: floats, eye: floats, at: floats, up: floats) -> void {
|
||||
let fwd = floats(3); let side = floats(3); let u = floats(3); let t = floats(3)
|
||||
v3_sub(t, at, eye)
|
||||
v3_normalize(fwd, t)
|
||||
v3_cross(t, fwd, up)
|
||||
v3_normalize(side, t)
|
||||
v3_cross(u, side, fwd)
|
||||
m4_look_at_xyz(m, eye[0], eye[1], eye[2], at[0], at[1], at[2], up[0], up[1], up[2])
|
||||
}
|
||||
# the same from nine numbers, on scalars: the camera asks it every frame, and four scratch vectors
|
||||
# made and freed per call were churn
|
||||
function m4_look_at_xyz(m: floats, ex: float, ey: float, ez: float, ax: float, ay: float, az: float, ux: float, uy: float, uz: float) -> void {
|
||||
var fx = ax - ex
|
||||
var fy = ay - ey
|
||||
var fz = az - ez
|
||||
var fl = Math.sqrt(fx * fx + fy * fy + fz * fz)
|
||||
if fl > 0.0 { fx = fx / fl; fy = fy / fl; fz = fz / fl }
|
||||
var sx = fy * uz - fz * uy
|
||||
var sy = fz * ux - fx * uz
|
||||
var sz = fx * uy - fy * ux
|
||||
let sl = Math.sqrt(sx * sx + sy * sy + sz * sz)
|
||||
if sl > 0.0 { sx = sx / sl; sy = sy / sl; sz = sz / sl }
|
||||
let vx = sy * fz - sz * fy
|
||||
let vy = sz * fx - sx * fz
|
||||
let vz = sx * fy - sy * fx
|
||||
m4_identity(m)
|
||||
m[0] = side[0]; m[4] = side[1]; m[8] = side[2]
|
||||
m[1] = u[0]; m[5] = u[1]; m[9] = u[2]
|
||||
m[2] = -fwd[0]; m[6] = -fwd[1]; m[10] = -fwd[2]
|
||||
m[12] = -v3_dot(side, eye)
|
||||
m[13] = -v3_dot(u, eye)
|
||||
m[14] = v3_dot(fwd, eye)
|
||||
free(fwd); free(side); free(u); free(t)
|
||||
m[0] = sx; m[4] = sy; m[8] = sz
|
||||
m[1] = vx; m[5] = vy; m[9] = vz
|
||||
m[2] = -fx; m[6] = -fy; m[10] = -fz
|
||||
m[12] = -(sx * ex + sy * ey + sz * ez)
|
||||
m[13] = -(vx * ex + vy * ey + vz * ez)
|
||||
m[14] = fx * ex + fy * ey + fz * ez
|
||||
}
|
||||
# general 4x4 inverse (cofactor expansion); o may not alias a
|
||||
function m4_inverse(o: floats, a: floats) -> bool {
|
||||
let inv = floats(16)
|
||||
inv[0] = a[5] * (a[10] * a[15]) + -(a[5] * (a[11] * a[14])) - a[9] * (a[6] * a[15]) + (a[9] * (a[7] * a[14]) + (a[13] * (a[6] * a[11]) - a[13] * (a[7] * a[10])))
|
||||
inv[4] = -(a[4] * (a[10] * a[15])) + a[4] * (a[11] * a[14]) - a[8] * (a[7] * a[14]) + (a[8] * (a[6] * a[15]) + (a[12] * (a[7] * a[10]) - a[12] * (a[6] * a[11])))
|
||||
inv[8] = a[4] * (a[9] * a[15]) + -(a[4] * (a[11] * a[13])) - a[8] * (a[5] * a[15]) + (a[8] * (a[7] * a[13]) + (a[12] * (a[5] * a[11]) - a[12] * (a[7] * a[9])))
|
||||
inv[12] = -(a[4] * (a[9] * a[14])) + a[4] * (a[10] * a[13]) - a[8] * (a[6] * a[13]) + (a[8] * (a[5] * a[14]) + (a[12] * (a[6] * a[9]) - a[12] * (a[5] * a[10])))
|
||||
inv[1] = -(a[1] * (a[10] * a[15])) + a[1] * (a[11] * a[14]) - a[9] * (a[3] * a[14]) + (a[9] * (a[2] * a[15]) + (a[13] * (a[3] * a[10]) - a[13] * (a[2] * a[11])))
|
||||
inv[5] = a[0] * (a[10] * a[15]) + -(a[0] * (a[11] * a[14])) - a[8] * (a[2] * a[15]) + (a[8] * (a[3] * a[14]) + (a[12] * (a[2] * a[11]) - a[12] * (a[3] * a[10])))
|
||||
inv[9] = -(a[0] * (a[9] * a[15])) + a[0] * (a[11] * a[13]) - a[8] * (a[3] * a[13]) + (a[8] * (a[1] * a[15]) + (a[12] * (a[3] * a[9]) - a[12] * (a[1] * a[11])))
|
||||
inv[13] = a[0] * (a[9] * a[14]) + -(a[0] * (a[10] * a[13])) - a[8] * (a[1] * a[14]) + (a[8] * (a[2] * a[13]) + (a[12] * (a[1] * a[10]) - a[12] * (a[2] * a[9])))
|
||||
inv[2] = a[1] * (a[6] * a[15]) + -(a[1] * (a[7] * a[14])) - a[5] * (a[2] * a[15]) + (a[5] * (a[3] * a[14]) + (a[13] * (a[2] * a[7]) - a[13] * (a[3] * a[6])))
|
||||
inv[6] = -(a[0] * (a[6] * a[15])) + a[0] * (a[7] * a[14]) - a[4] * (a[3] * a[14]) + (a[4] * (a[2] * a[15]) + (a[12] * (a[3] * a[6]) - a[12] * (a[2] * a[7])))
|
||||
inv[10] = a[0] * (a[5] * a[15]) + -(a[0] * (a[7] * a[13])) - a[4] * (a[1] * a[15]) + (a[4] * (a[3] * a[13]) + (a[12] * (a[1] * a[7]) - a[12] * (a[3] * a[5])))
|
||||
inv[14] = -(a[0] * (a[5] * a[14])) + a[0] * (a[6] * a[13]) - a[4] * (a[2] * a[13]) + (a[4] * (a[1] * a[14]) + (a[12] * (a[2] * a[5]) - a[12] * (a[1] * a[6])))
|
||||
inv[3] = -(a[1] * (a[6] * a[11])) + a[1] * (a[7] * a[10]) - a[5] * (a[3] * a[10]) + (a[5] * (a[2] * a[11]) + (a[9] * (a[3] * a[6]) - a[9] * (a[2] * a[7])))
|
||||
inv[7] = a[0] * (a[6] * a[11]) + -(a[0] * (a[7] * a[10])) - a[4] * (a[2] * a[11]) + (a[4] * (a[3] * a[10]) + (a[8] * (a[2] * a[7]) - a[8] * (a[3] * a[6])))
|
||||
inv[11] = -(a[0] * (a[5] * a[11])) + a[0] * (a[7] * a[9]) - a[4] * (a[3] * a[9]) + (a[4] * (a[1] * a[11]) + (a[8] * (a[3] * a[5]) - a[8] * (a[1] * a[7])))
|
||||
inv[15] = a[0] * (a[5] * a[10]) + -(a[0] * (a[6] * a[9])) - a[4] * (a[1] * a[10]) + (a[4] * (a[2] * a[9]) + (a[8] * (a[1] * a[6]) - a[8] * (a[2] * a[5])))
|
||||
let det = a[0] * inv[0] + a[1] * inv[4] + (a[2] * inv[8] + a[3] * inv[12])
|
||||
if det == 0.0 { free(inv); return false }
|
||||
let i0 = a[5] * (a[10] * a[15]) + -(a[5] * (a[11] * a[14])) - a[9] * (a[6] * a[15]) + (a[9] * (a[7] * a[14]) + (a[13] * (a[6] * a[11]) - a[13] * (a[7] * a[10])))
|
||||
let i4 = -(a[4] * (a[10] * a[15])) + a[4] * (a[11] * a[14]) - a[8] * (a[7] * a[14]) + (a[8] * (a[6] * a[15]) + (a[12] * (a[7] * a[10]) - a[12] * (a[6] * a[11])))
|
||||
let i8 = a[4] * (a[9] * a[15]) + -(a[4] * (a[11] * a[13])) - a[8] * (a[5] * a[15]) + (a[8] * (a[7] * a[13]) + (a[12] * (a[5] * a[11]) - a[12] * (a[7] * a[9])))
|
||||
let i12 = -(a[4] * (a[9] * a[14])) + a[4] * (a[10] * a[13]) - a[8] * (a[6] * a[13]) + (a[8] * (a[5] * a[14]) + (a[12] * (a[6] * a[9]) - a[12] * (a[5] * a[10])))
|
||||
let i1 = -(a[1] * (a[10] * a[15])) + a[1] * (a[11] * a[14]) - a[9] * (a[3] * a[14]) + (a[9] * (a[2] * a[15]) + (a[13] * (a[3] * a[10]) - a[13] * (a[2] * a[11])))
|
||||
let i5 = a[0] * (a[10] * a[15]) + -(a[0] * (a[11] * a[14])) - a[8] * (a[2] * a[15]) + (a[8] * (a[3] * a[14]) + (a[12] * (a[2] * a[11]) - a[12] * (a[3] * a[10])))
|
||||
let i9 = -(a[0] * (a[9] * a[15])) + a[0] * (a[11] * a[13]) - a[8] * (a[3] * a[13]) + (a[8] * (a[1] * a[15]) + (a[12] * (a[3] * a[9]) - a[12] * (a[1] * a[11])))
|
||||
let i13 = a[0] * (a[9] * a[14]) + -(a[0] * (a[10] * a[13])) - a[8] * (a[1] * a[14]) + (a[8] * (a[2] * a[13]) + (a[12] * (a[1] * a[10]) - a[12] * (a[2] * a[9])))
|
||||
let i2 = a[1] * (a[6] * a[15]) + -(a[1] * (a[7] * a[14])) - a[5] * (a[2] * a[15]) + (a[5] * (a[3] * a[14]) + (a[13] * (a[2] * a[7]) - a[13] * (a[3] * a[6])))
|
||||
let i6 = -(a[0] * (a[6] * a[15])) + a[0] * (a[7] * a[14]) - a[4] * (a[3] * a[14]) + (a[4] * (a[2] * a[15]) + (a[12] * (a[3] * a[6]) - a[12] * (a[2] * a[7])))
|
||||
let i10 = a[0] * (a[5] * a[15]) + -(a[0] * (a[7] * a[13])) - a[4] * (a[1] * a[15]) + (a[4] * (a[3] * a[13]) + (a[12] * (a[1] * a[7]) - a[12] * (a[3] * a[5])))
|
||||
let i14 = -(a[0] * (a[5] * a[14])) + a[0] * (a[6] * a[13]) - a[4] * (a[2] * a[13]) + (a[4] * (a[1] * a[14]) + (a[12] * (a[2] * a[5]) - a[12] * (a[1] * a[6])))
|
||||
let i3 = -(a[1] * (a[6] * a[11])) + a[1] * (a[7] * a[10]) - a[5] * (a[3] * a[10]) + (a[5] * (a[2] * a[11]) + (a[9] * (a[3] * a[6]) - a[9] * (a[2] * a[7])))
|
||||
let i7 = a[0] * (a[6] * a[11]) + -(a[0] * (a[7] * a[10])) - a[4] * (a[2] * a[11]) + (a[4] * (a[3] * a[10]) + (a[8] * (a[2] * a[7]) - a[8] * (a[3] * a[6])))
|
||||
let i11 = -(a[0] * (a[5] * a[11])) + a[0] * (a[7] * a[9]) - a[4] * (a[3] * a[9]) + (a[4] * (a[1] * a[11]) + (a[8] * (a[3] * a[5]) - a[8] * (a[1] * a[7])))
|
||||
let i15 = a[0] * (a[5] * a[10]) + -(a[0] * (a[6] * a[9])) - a[4] * (a[1] * a[10]) + (a[4] * (a[2] * a[9]) + (a[8] * (a[1] * a[6]) - a[8] * (a[2] * a[5])))
|
||||
let det = a[0] * i0 + a[1] * i4 + (a[2] * i8 + a[3] * i12)
|
||||
if det == 0.0 { return false }
|
||||
let id = 1.0 / det
|
||||
for i in 0 .. 16 { o[i] = inv[i] * id }
|
||||
free(inv)
|
||||
o[0] = i0 * id; o[1] = i1 * id; o[2] = i2 * id; o[3] = i3 * id; o[4] = i4 * id; o[5] = i5 * id; o[6] = i6 * id; o[7] = i7 * id
|
||||
o[8] = i8 * id; o[9] = i9 * id; o[10] = i10 * id; o[11] = i11 * id; o[12] = i12 * id; o[13] = i13 * id; o[14] = i14 * id; o[15] = i15 * id
|
||||
return true
|
||||
}
|
||||
# transform a point (w = 1) by m: o = m * (x, y, z, 1), returns w
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ function gltf_mat_remember(render3d_st: mut Render3dState, name: string, diff: i
|
|||
render3d_st.gltf_mat_n += 1
|
||||
}
|
||||
|
||||
@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 gltf_texture(render3d_st: mut Render3dState, uri: string, srgb: bool) -> int {
|
||||
if render3d_st.gltf_tex_paths == null { render3d_st.gltf_tex_paths = new []pointer; render3d_st.gltf_tex_ids = words(256); render3d_st.gltf_tex_refs = words(256) }
|
||||
var png: string = uri
|
||||
|
|
@ -174,6 +175,7 @@ function gltf_prim(render3d_st: mut Render3dState, p: Val) -> Prim {
|
|||
}
|
||||
|
||||
# Load the mesh of the node called `node_name` from dir/file.
|
||||
@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 gltf_load(render3d_st: mut Render3dState, dir: string, file: string, node_name: string) -> Model {
|
||||
render3d_st.gltf_dir = dir
|
||||
let at = dir + "/" + file
|
||||
|
|
|
|||
|
|
@ -4,15 +4,22 @@
|
|||
# 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
|
||||
}
|
||||
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] }
|
||||
}
|
||||
let m = gltf_load(render3d_st, dir, file, node_name)
|
||||
push(render3d_st.gltf_kept, m)
|
||||
push(render3d_st.gltf_kept_dir, dir)
|
||||
|
|
|
|||
|
|
@ -357,6 +357,7 @@ function gpu_gl_usage(u: int) -> int {
|
|||
}
|
||||
|
||||
# a new mesh, its vertex array bound: the vertex, attribute and index calls below describe it
|
||||
@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 gpu_mesh_new(render3d_st: Render3dState) -> Mesh {
|
||||
let m = new Mesh
|
||||
m.attrs = words(GPU_MAX_ATTRS * GPU_ATTR_W)
|
||||
|
|
|
|||
|
|
@ -336,6 +336,7 @@ const GVK_BLOCK_DEVICE: int = 67108864
|
|||
const GVK_BLOCK_HOST: int = 67108864
|
||||
const GVK_OWN_OVER: int = 16777216
|
||||
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function gvk_mem_init(render3d_st: mut Render3dState) -> void {
|
||||
if render3d_st.gvk_al_blk != null { return }
|
||||
let zero: long = 0
|
||||
|
|
@ -377,6 +378,7 @@ function gvk_fr_put(render3d_st: mut Render3dState, b: int, off: int, len_: int)
|
|||
}
|
||||
|
||||
# Memory for a resource from its requirements (a VkMemoryRequirements): an allocation id, 0 if none.
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function gvk_mem_new(render3d_st: mut Render3dState, req: bytes, want: int, image: bool) -> int {
|
||||
gvk_mem_init(render3d_st)
|
||||
let allowed = Vk.get_i32(req, VkMemoryRequirements_memoryTypeBits)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ function gvk_read_spv(render3d_st: mut Render3dState, path: string) -> bytes {
|
|||
return b
|
||||
}
|
||||
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function gvk_module(render3d_st: mut Render3dState, path: string) -> long {
|
||||
let zero: long = 0
|
||||
let spv = gvk_read_spv(render3d_st, path)
|
||||
|
|
@ -49,6 +50,7 @@ function gvk_stage_first(render3d_st: Render3dState, p: int) -> int {
|
|||
if render3d_st.gvk_prog_mesh != null and p < len(render3d_st.gvk_prog_mesh) and render3d_st.gvk_prog_mesh[p] == 1 { return VK_SHADER_STAGE_MESH_BIT_EXT }
|
||||
return VK_SHADER_STAGE_VERTEX_BIT
|
||||
}
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function gvk_program(render3d_st: mut Render3dState, p: int, key: string, spv_dir: string) -> bool {
|
||||
let zero: long = 0
|
||||
if render3d_st.gvk_prog_var == null {
|
||||
|
|
@ -125,6 +127,7 @@ function gvk_program(render3d_st: mut Render3dState, p: int, key: string, spv_di
|
|||
|
||||
function gvk_compute_new(render3d_st: mut Render3dState, name: string, n_bufs: int) -> int { return gvk_compute_new_tex(render3d_st, name, n_bufs, 0) }
|
||||
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function gvk_compute_new_tex(render3d_st: mut Render3dState, name: string, n_bufs: int, n_tex: int) -> int {
|
||||
let zero: long = 0
|
||||
if render3d_st.gvk_cp_pipe == null {
|
||||
|
|
@ -592,6 +595,7 @@ function gvk_same(a: pointer, b: pointer, n: int) -> bool {
|
|||
return true
|
||||
}
|
||||
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function gvk_uniform_blocks(render3d_st: mut Render3dState, p: int) -> void {
|
||||
if render3d_st.gvk_ublk_v == null {
|
||||
render3d_st.gvk_ublk_v = new []bytes; render3d_st.gvk_ublk_f = new []bytes; render3d_st.gvk_prog_tex = new []words; render3d_st.gvk_prog_unit = new []words
|
||||
|
|
@ -861,6 +865,7 @@ function gvk_draw_set(render3d_st: mut Render3dState, p: int, tx: words, tx_w: i
|
|||
}
|
||||
|
||||
# a new kept set for program p with the textures in gvk_sc_tmp, written and cached
|
||||
@alloc_ok("the window changed size or a surface was lost: the screen, the swapchain and its images are made again")
|
||||
function gvk_sc_make(render3d_st: mut Render3dState, p: int, nt: int) -> long {
|
||||
let zero: long = 0
|
||||
let v = render3d_st.gvk_prog_var[p]
|
||||
|
|
@ -995,6 +1000,7 @@ function gvk_hdr_metadata(render3d_st: Render3dState) -> void {
|
|||
Vk.set_hdr_metadata_ext(render3d_st.gvk_dev, 1, chains, md)
|
||||
}
|
||||
|
||||
@alloc_ok("the window changed size or a surface was lost: the screen, the swapchain and its images are made again")
|
||||
function gvk_screen_make(render3d_st: mut Render3dState, w: int, h: int) -> bool {
|
||||
if render3d_st.gvk_vp == null {
|
||||
render3d_st.gvk_vp = words(4); render3d_st.gvk_sc = words(5); render3d_st.gvk_clear_rgba = floats(4)
|
||||
|
|
@ -1024,6 +1030,7 @@ function gvk_frame_cb(render3d_st: mut Render3dState) -> pointer {
|
|||
# The view a pass draws into: level 0 only (an attachment view has exactly one level, and a target
|
||||
# the exposure measure mipmaps has several), and one layer of an array image for a cascade drawn
|
||||
# on its own. Keyed by the image's generation, so a replaced image never reuses a stale view.
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function gvk_view_of(render3d_st: mut Render3dState, tex: int, layer1: int) -> long {
|
||||
if layer1 == 0 and render3d_st.gvk_tex_levels[tex] <= 1 and render3d_st.gvk_tex_layers[tex] <= 1 { return render3d_st.gvk_tex_view[tex] }
|
||||
# keyed by numbers, not a string built on every call: the texture, its generation and the layer
|
||||
|
|
@ -1383,6 +1390,7 @@ function gvk_present(render3d_st: mut Render3dState) -> void {
|
|||
|
||||
# The screen as a binary PPM, top row first. The frame so far is finished first, then read back;
|
||||
# row 0 of the image is OpenGL's bottom row, so rows are written last to first, as gl_screenshot does.
|
||||
@alloc_ok("asked for by the player or a tool, not by the frame")
|
||||
function gvk_screenshot(render3d_st: mut Render3dState, path: string) -> bool {
|
||||
# the screen image is PQ-encoded 10-bit while HDR is on, which an 8-bit PPM would misread
|
||||
if render3d_st.gvk_hdr_on { print("r3d: vulkan: screenshots are SDR only - turn HDR output off to take one"); return false }
|
||||
|
|
@ -1441,6 +1449,7 @@ function gvk_open(render3d_st: mut Render3dState, w: int, h: int, title: string)
|
|||
|
||||
# A variant is made once and shared: a program is immutable here, so every actor asking for the
|
||||
# one it wants (actor.ludic, one per actor) gets the same handle, not its own modules and pipelines.
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function gvk_program_new(render3d_st: mut Render3dState, vs: string, fs: string, defines: string) -> int {
|
||||
let key = `{vs}|{fs}|{Text.replace(defines, "\n", ";")}`
|
||||
if render3d_st.gpu_prog_ids == null { render3d_st.gpu_prog_ids = new []int; render3d_st.gpu_prog_keys = new []string }
|
||||
|
|
@ -1655,6 +1664,7 @@ function gvk_surface_os(render3d_st: mut Render3dState, out: pointer) -> bool {
|
|||
return true
|
||||
}
|
||||
|
||||
@alloc_ok("the window changed size or a surface was lost: the screen, the swapchain and its images are made again")
|
||||
function gvk_surface_make(render3d_st: mut Render3dState) -> bool {
|
||||
if render3d_st.gvk_surface != 0 { return true }
|
||||
let out = bytes(8)
|
||||
|
|
@ -1672,6 +1682,7 @@ function gvk_surface_make(render3d_st: mut Render3dState) -> bool {
|
|||
}
|
||||
|
||||
# (Re)make the swapchain for a w x h client area. The old one is handed over and then destroyed.
|
||||
@alloc_ok("the window changed size or a surface was lost: the screen, the swapchain and its images are made again")
|
||||
function gvk_swap_make(render3d_st: mut Render3dState, w: int, h: int) -> bool {
|
||||
if not gvk_surface_make(render3d_st) { return false }
|
||||
gvk_frame_wait(render3d_st)
|
||||
|
|
@ -1854,6 +1865,7 @@ function gvk_prof(render3d_st: mut Render3dState) -> bool {
|
|||
if render3d_st.gvk_prof_state < 0 { render3d_st.gvk_prof_state = 0; if r3d_env_has(render3d_st, "R3D_VK_PROF") { render3d_st.gvk_prof_state = 1 } }
|
||||
return render3d_st.gvk_prof_state == 1
|
||||
}
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function gvk_prof_frame(render3d_st: mut Render3dState) -> void {
|
||||
if not gvk_prof(render3d_st) { return }
|
||||
render3d_st.gvk_prof_frames += 1
|
||||
|
|
@ -1876,6 +1888,7 @@ function gvk_prof_frame(render3d_st: mut Render3dState) -> void {
|
|||
|
||||
# what was made and destroyed over those frames, and how long the caches are: a kind made every
|
||||
# frame and never destroyed, or a cache that only grows, is a leak
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function gvk_prof_made(render3d_st: mut Render3dState) -> void {
|
||||
let r = render3d_st
|
||||
print(`r3d: vulkan made/destroyed: images {r.gvk_mk_img}/{r.gvk_mk_x_img}, views {r.gvk_mk_view}/{r.gvk_mk_x_view}, buffers {r.gvk_mk_buf}/{r.gvk_mk_x_buf}, memory {r.gvk_mk_mem}/{r.gvk_mk_x_mem}, samplers {r.gvk_mk_smp}, sets {r.gvk_mk_set}, pools {r.gvk_mk_dpool}, cmds {r.gvk_mk_cmd}`)
|
||||
|
|
@ -1894,6 +1907,7 @@ function gvk_len_l(xs: []long) -> int { if xs == null { return 0 }; return len(
|
|||
# state packs into one int, and the pass's formats into another; the program's last hit is tried
|
||||
# first, then the entries it owns.
|
||||
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function gvk_layout_id(render3d_st: mut Render3dState, m: Mesh) -> int {
|
||||
if m == null or m.attrs == null { return 1 }
|
||||
if m.vk_layout > 0 { return m.vk_layout }
|
||||
|
|
@ -1975,6 +1989,7 @@ function gvk_pipeline_fast(render3d_st: mut Render3dState, p: int, m: Mesh, st:
|
|||
}
|
||||
# The one place the pipeline cache grows: once per variant the game draws (program, vertex layout,
|
||||
# render state, formats), kept for the program's life - the fence's declared warm-up (plan 25.2)
|
||||
@alloc_ok("pipeline cache: one per variant the game draws")
|
||||
function gvk_pipe_build(render3d_st: mut Render3dState, p: int, m: Mesh, st: GvkState, n_color: int, color_fmt: int, depth_fmt: int, samples: int, layout: int, state: int, bias: int, pass: int) -> long {
|
||||
let pipe = gvk_pipeline(render3d_st, p, m, st, n_color, color_fmt, depth_fmt, samples)
|
||||
push(render3d_st.gvk_pc_prog, p); push(render3d_st.gvk_pc_layout, layout); push(render3d_st.gvk_pc_state, state)
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ function gvk_tex_give_back(render3d_st: mut Render3dState, tex: int) -> void {
|
|||
if render3d_st.gvk_tex_spare == null { render3d_st.gvk_tex_spare = new []int }
|
||||
push(render3d_st.gvk_tex_spare, tex)
|
||||
}
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function gvk_tex_new(render3d_st: mut Render3dState) -> int {
|
||||
let zero: long = 0
|
||||
if render3d_st.gvk_tex_image == null {
|
||||
|
|
@ -176,6 +177,7 @@ function gvk_staging_free(render3d_st: mut Render3dState) -> void {
|
|||
}
|
||||
|
||||
# (Re)make the image behind a handle: glTexImage2D on a texture that already has one replaces it.
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function gvk_tex_storage(render3d_st: mut Render3dState, tex: int, array: bool, ifmt: int, w: int, h: int, layers: int, with_mips: bool) -> bool {
|
||||
gvk_frame_wait(render3d_st) # the frame in flight may still read it
|
||||
if tex <= 0 or tex >= len(render3d_st.gvk_tex_image) { return false }
|
||||
|
|
@ -571,6 +573,7 @@ function gvk_tex_sampler(render3d_st: mut Render3dState, tex: int, min_f: int, m
|
|||
if tex > 0 and tex < len(render3d_st.gvk_tex_smp_sig) { render3d_st.gvk_tex_smp_sig[tex] = sig; render3d_st.gvk_tex_smp[tex] = s }
|
||||
return s
|
||||
}
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function gvk_sampler(render3d_st: mut Render3dState, min_f: int, mag_f: int, wrap_s: int, wrap_t: int, compare: int, aniso: int) -> long {
|
||||
let bias = float_bits(gvk_mip_bias(render3d_st))
|
||||
# looked up by the numbers themselves: a key string built on every call (and a texture read two
|
||||
|
|
@ -631,6 +634,7 @@ function gvk_sampler(render3d_st: mut Render3dState, min_f: int, mag_f: int, wra
|
|||
# Storage a buffer was moved off, or freed, while the frame that used it has not been submitted:
|
||||
# destroyed at gvk_retire_flush, after the frame's work is done.
|
||||
|
||||
@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 gvk_buf_new(render3d_st: mut Render3dState) -> int {
|
||||
let zero: long = 0
|
||||
if render3d_st.gvk_buf == null {
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ function overlay_init(render3d_st: mut Render3dState, font_dir: string) -> bool
|
|||
# Load (or swap to) the font atlas in `font_dir`: font.png and font.json. A game calls it
|
||||
# again to change fonts at run time - a language whose script the default atlas does not
|
||||
# carry brings its own. Returns false, and keeps the font it had, if there is none there.
|
||||
@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 overlay_font(render3d_st: mut Render3dState, font_dir: string) -> bool {
|
||||
let meta = Fs.read_text(font_dir + "/font.json")
|
||||
if meta == null { return false }
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ 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")
|
||||
function post_init(render3d_st: mut Render3dState, w: int, h: int) -> void {
|
||||
render3d_st.post_w = w; render3d_st.post_h = h
|
||||
render3d_st.post_hdr = target_new(render3d_st, w, h, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, true, GL_LINEAR)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ function prof_init(render3d_st: mut Render3dState) -> void {
|
|||
}
|
||||
|
||||
# the slot index for `name`, registering it on first sight (order = frame order)
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function prof_slot(render3d_st: mut Render3dState, name: pointer) -> int {
|
||||
var i = 0
|
||||
while i < render3d_st.prof_n {
|
||||
|
|
@ -82,6 +83,7 @@ function prof_collect(render3d_st: mut Render3dState) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function prof_report(render3d_st: Render3dState) -> void {
|
||||
if not render3d_st.prof_on { return }
|
||||
print("")
|
||||
|
|
@ -130,6 +132,7 @@ function prof_before_swap(render3d_st: mut Render3dState) -> void { if render3d_
|
|||
# name it without keeping a timeline.
|
||||
function prof_mark_start(render3d_st: mut Render3dState) -> void { if render3d_st.prof_on { render3d_st.prof_mark_last = gl_now_us(); render3d_st.prof_mark_best = 0; render3d_st.prof_mark_name = null } }
|
||||
# ... and every phase's share of the average frame, past the first eight frames (loading, first fills)
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function prof_cpu_mark(render3d_st: mut Render3dState, name: pointer) -> void {
|
||||
if not render3d_st.prof_on { return }
|
||||
let now = gl_now_us()
|
||||
|
|
@ -158,6 +161,7 @@ function prof_layer_add(render3d_st: mut Render3dState, us: long, bytes: long) -
|
|||
}
|
||||
function prof_bake_add(render3d_st: mut Render3dState, us: long) -> void { if render3d_st.prof_on { render3d_st.prof_bake_us_cur = render3d_st.prof_bake_us_cur + us } }
|
||||
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function prof_chunk(render3d_st: mut Render3dState, kind: int, band: int, count: int, us: long) -> void {
|
||||
if not render3d_st.prof_on { return }
|
||||
if render3d_st.prof_chunk_us == null {
|
||||
|
|
@ -169,6 +173,7 @@ function prof_chunk(render3d_st: mut Render3dState, kind: int, band: int, count:
|
|||
render3d_st.prof_gen_us_cur += us
|
||||
}
|
||||
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function prof_chunk_report(render3d_st: Render3dState) -> void {
|
||||
if not render3d_st.prof_on or render3d_st.prof_chunk_us == null { return }
|
||||
print("")
|
||||
|
|
@ -220,6 +225,7 @@ function prof_chunk_report(render3d_st: Render3dState) -> void {
|
|||
print(` generation per frame (us): p95 {string(sorted[(n * 95) / 100])} p99 {string(sorted[(n * 99) / 100])} worst {string(sorted[n - 1])} frames that generated: {string(busy)} of {string(n)} total {string(t / 1000)} ms`)
|
||||
}
|
||||
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function prof_gen_frame(render3d_st: mut Render3dState) -> void {
|
||||
ds_frame(render3d_st)
|
||||
if not render3d_st.prof_on { return }
|
||||
|
|
@ -256,6 +262,7 @@ function prof_gen_frame(render3d_st: mut Render3dState) -> void {
|
|||
}
|
||||
|
||||
# the distribution of REAL frame times: stutter lives in the tail, not the mean
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function prof_ft_report(render3d_st: Render3dState) -> void {
|
||||
if not render3d_st.prof_on { return }
|
||||
if render3d_st.prof_ft == null or len(render3d_st.prof_ft) < 16 { return }
|
||||
|
|
@ -320,6 +327,7 @@ function prof_ft_report(render3d_st: Render3dState) -> void {
|
|||
|
||||
# The slowest frames of the run, with the once-in-a-while CPU work that landed in them.
|
||||
# An average never shows a hitch; this is the list of the frames you actually felt.
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function prof_hitch_report(render3d_st: Render3dState) -> void {
|
||||
if not render3d_st.prof_on or render3d_st.prof_dt == null or len(render3d_st.prof_dt) < 32 { return }
|
||||
let n = len(render3d_st.prof_dt)
|
||||
|
|
@ -357,6 +365,7 @@ function prof_hitch_report(render3d_st: Render3dState) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function prof_gen_report(render3d_st: Render3dState) -> void {
|
||||
if not render3d_st.prof_on { return }
|
||||
if render3d_st.prof_gen == null or len(render3d_st.prof_gen) < 8 { return }
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ function r3d_find_root(render3d_st: mut Render3dState) -> void {
|
|||
# Build a program from a vertex + fragment file pair (defines apply to both).
|
||||
# R3D_PROGRAMS_LOG=<file>: append every program built (vertex, fragment, defines) - the list a
|
||||
# backend that cannot compile shaders at run time (Vulkan: SPIR-V is built ahead) must cover
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function r3d_program_log(render3d_st: mut Render3dState, vs: string, fs: string, defines: string) -> void {
|
||||
if render3d_st.r3d_prog_log < 0 { render3d_st.r3d_prog_log = 0; if r3d_env_has(render3d_st, "R3D_PROGRAMS_LOG") { render3d_st.r3d_prog_log = 1 } }
|
||||
if render3d_st.r3d_prog_log == 0 { return }
|
||||
|
|
@ -48,6 +49,7 @@ function r3d_program_log(render3d_st: mut Render3dState, vs: string, fs: string,
|
|||
file_write(f, line, len(line))
|
||||
file_close(f)
|
||||
}
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function r3d_program(render3d_st: mut Render3dState, vs: string, fs: string, defines: string) -> int {
|
||||
r3d_program_log(render3d_st, vs, fs, defines)
|
||||
let p = gpu_program(render3d_st, vs, fs, `{render3d_st.r3d_global_defs}{defines}`)
|
||||
|
|
@ -67,6 +69,7 @@ property Target {
|
|||
w: int = 0,
|
||||
h: int = 0
|
||||
}
|
||||
@alloc_ok("made once per resource and kept for its life (a texture, program, sampler, view, layout or memory block is created when first asked for)")
|
||||
function target_new(render3d_st: mut Render3dState, w: int, h: int, ifmt: int, fmt: int, ty: int, with_depth: bool, filter: int) -> Target {
|
||||
let t = new Target
|
||||
t.w = w; t.h = h
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ function sc_model_layout(render3d_st: Render3dState, m: Mesh) -> void {
|
|||
|
||||
# Two crossed unit quads (x in [-0.5, 0.5], y in [0, 1]), attribute 0 = pos,
|
||||
# 1 = the quad's facing normal, 2 = uv. Scaled per layer to the atlas card size.
|
||||
@alloc_ok("a world being set up (a stream, a layer, water, post, a bake): the map loading or swapping, not a frame")
|
||||
function model_cross_card(render3d_st: mut Render3dState) -> Model {
|
||||
let model = new Model
|
||||
model.prims = new []Prim
|
||||
|
|
@ -378,6 +379,7 @@ 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")
|
||||
function layer_new(render3d_st: mut Render3dState, model: Model, cap: int, foliage: bool, wind: float, near: float, cull: float) -> Layer {
|
||||
let l = new Layer
|
||||
l.model = model
|
||||
|
|
@ -428,6 +430,7 @@ 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")
|
||||
function impostor_bake(render3d_st: mut Render3dState, model: Model, tiles: int, tw: int, th: int) -> Impostor {
|
||||
let im = new Impostor
|
||||
im.tiles = tiles
|
||||
|
|
@ -583,6 +586,7 @@ function layer_arena_ok(render3d_st: Render3dState, l: Layer) -> bool {
|
|||
return true
|
||||
}
|
||||
|
||||
@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_arena_build(render3d_st: mut Render3dState, l: Layer) -> void {
|
||||
let n_mat = len(l.lods[0].prims)
|
||||
l.g_arena = new []Prim
|
||||
|
|
@ -706,6 +710,7 @@ function layer_gpu_cull(render3d_st: mut Render3dState, l: Layer) -> void {
|
|||
# Sort a static layer's instances into square cells (call once, after placement; a
|
||||
# large layer that was never gridded gets a 96 m grid on its first update). The
|
||||
# shadow buffer is uploaded here once — casters are never culled by the view.
|
||||
@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_grid_build(render3d_st: mut Render3dState, l: Layer, cell: float) -> void {
|
||||
if l.count == 0 { return }
|
||||
var minx = l.inst[0]; var maxx = minx; var minz = l.inst[2]; var maxz = minz
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@ function shadow_pass(render3d_st: mut Render3dState) -> void {
|
|||
}
|
||||
|
||||
# Debug: cascade depths as grey PPMs (build/dbg_shadow_<c>.ppm)
|
||||
@alloc_ok("asked for by the player or a tool, not by the frame")
|
||||
function shadow_dump(render3d_st: mut Render3dState) -> void {
|
||||
let n = render3d_st.shadow_res * render3d_st.shadow_res
|
||||
let buf = floats(n * SHADOW_CASCADES)
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ function skin_attribs(render3d_st: mut Render3dState, m: Mesh, attrs: Val) -> bo
|
|||
}
|
||||
|
||||
# the skin `idx` of the document being loaded (gltf_load holds gltf_doc / gltf_bin open)
|
||||
@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 skin_load(render3d_st: mut Render3dState, idx: int) -> Skin {
|
||||
let sk = new Skin
|
||||
let nodes = value_get(render3d_st.gltf_doc, "nodes")
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ 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")
|
||||
function stream_new(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
|
||||
|
|
@ -315,6 +316,7 @@ function stream_chunk_visible(render3d_st: Render3dState, s: Stream, cx: int, cz
|
|||
}
|
||||
|
||||
# what the caches hold, and whether they are being churned (R3D_PROF)
|
||||
@alloc_ok("profiling and statistics, only under R3D_PROF / R3D_DRAWSTATS")
|
||||
function stream_census(render3d_st: Render3dState) -> void {
|
||||
if render3d_st.stream_all == null { return }
|
||||
print("")
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ function png_unfilter(raw: pointer, cur: int, prev: int, stride: int, fbpp: int,
|
|||
}
|
||||
}
|
||||
|
||||
@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 png_decode(render3d_st: mut Render3dState, path: pointer) -> pointer {
|
||||
let d = r3d_read_file(render3d_st, path)
|
||||
if d == null { print(`png: cannot read {path}`); return null }
|
||||
|
|
@ -260,8 +261,10 @@ function tex_upload(render3d_st: mut Render3dState, px: pointer, srgb: bool, mip
|
|||
}
|
||||
|
||||
# Load a PNG as a mipmapped, anisotropic texture (0 on failure). srgb for albedo.
|
||||
@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)")
|
||||
function tex_load_ex(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)
|
||||
|
|
@ -306,6 +309,7 @@ function tex_height(render3d_st: Render3dState, id: int) -> int {
|
|||
}
|
||||
|
||||
# A small solid-colour fallback texture (linear rgb 0..255), for missing maps.
|
||||
@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_solid(render3d_st: mut Render3dState, r: int, g: int, b: int, a: int) -> int {
|
||||
let px = bytes(16)
|
||||
for i in 0 .. 4 { px[i * 4] = r; px[i * 4 + 1] = g; px[i * 4 + 2] = b; px[i * 4 + 3] = a }
|
||||
|
|
@ -453,6 +457,7 @@ function tex_max(render3d_st: mut Render3dState, tex: int, w: int, h: int, tag:
|
|||
free(buf)
|
||||
}
|
||||
# Debug: write a 2D texture's level 0 (RGBA8, alpha dropped) as a binary PPM.
|
||||
@alloc_ok("asked for by the player or a tool, not by the frame")
|
||||
function tex_dump(render3d_st: mut Render3dState, tex: int, w: int, h: int, path: pointer) -> void {
|
||||
let f = file_open(path, "wb")
|
||||
if f == null { return }
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ 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)")
|
||||
function tex_load_dds(render3d_st: mut Render3dState, path: string, srgb: bool) -> int {
|
||||
let b = Fs.read_bytes(path)
|
||||
if b == null { return 0 }
|
||||
|
|
|
|||
|
|
@ -196,6 +196,7 @@ function wb_wet(render3d_st: mut Render3dState, x: float, z: float, off: float)
|
|||
# walk of every rectangle, every frame. The body beyond the map (a sea runs far past it) is 64 x 64
|
||||
# coarse rectangles tested at their centre, in one last block, which only ever matter kilometres away.
|
||||
const WB_BLOCK: int = 8
|
||||
@alloc_ok("a world being set up (a stream, a layer, water, post, a bake): the map loading or swapping, not a frame")
|
||||
function water_cells_build(render3d_st: mut Render3dState) -> void {
|
||||
let bx0 = render3d_st.water_cx - render3d_st.water_ex; let bx1 = render3d_st.water_cx + render3d_st.water_ex
|
||||
let bz0 = render3d_st.water_cz - render3d_st.water_ez; let bz1 = render3d_st.water_cz + render3d_st.water_ez
|
||||
|
|
@ -256,6 +257,7 @@ function water_cells_build(render3d_st: mut Render3dState) -> void {
|
|||
}
|
||||
|
||||
# the program and the plane are the process's, built once; the bodies are the map's
|
||||
@alloc_ok("a world being set up (a stream, a layer, water, post, a bake): the map loading or swapping, not a frame")
|
||||
function water_setup(render3d_st: mut Render3dState) -> void {
|
||||
if render3d_st.water_prog != 0 { return }
|
||||
render3d_st.water_mesh = mesh_grid(render3d_st, 2, 0.5)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue