Merge branch 'r3d/skin-own' into lang/foundations
This commit is contained in:
commit
14140e26cd
6 changed files with 69 additions and 29 deletions
|
|
@ -34,6 +34,7 @@ property Actor {
|
|||
cutout: bool = false, # alpha-tested (a flame's cards)
|
||||
emissive: float = 0.0, # float bits: self-lit strength
|
||||
skin: Skin, # this instance's own pose (skin_clone); null: the model's
|
||||
skin_owned: bool = false, # made by actor_own_skin: actor_release frees it
|
||||
ptint: words, # 4 per primitive: on flag, r, g, b (a part's own colour)
|
||||
hide: words, # 1 per primitive: skip it (a cap taken off)
|
||||
radius: float = 0.0, # float bits: bounding radius for culling (0 = never culled)
|
||||
|
|
@ -443,7 +444,7 @@ function actor_fresh(render3d_st: mut Render3dState) -> Actor {
|
|||
m4_identity(a.mat)
|
||||
a.visible = true; a.cast_hidden = false; a.casts = true; a.row = -1
|
||||
a.cutout = false; a.emissive = 0.0; a.radius = 0.0; a.cull = 0.0; a.outline = 0.0
|
||||
a.skin = null; a.ocol = null
|
||||
a.skin = null; a.skin_owned = false; a.ocol = null
|
||||
return a
|
||||
}
|
||||
|
||||
|
|
@ -455,8 +456,21 @@ function actor_release(render3d_st: mut Render3dState, a: Actor) -> void {
|
|||
actor_remove(render3d_st, a)
|
||||
if a.ptint != null { free(a.ptint); a.ptint = null }
|
||||
if a.hide != null { free(a.hide); a.hide = null }
|
||||
if a.skin_owned and a.skin != null { skin_clone_free(a.skin) }
|
||||
a.skin_owned = false
|
||||
a.model = null; a.skin = null; a.ocol = null
|
||||
a.id = 0
|
||||
if render3d_st.ac_spare == null { render3d_st.ac_spare = new []Actor }
|
||||
push(render3d_st.ac_spare, a)
|
||||
}
|
||||
|
||||
# The actor poses on its own copy of its model's skeleton (a person, an animal), which it keeps until
|
||||
# actor_release gives it back with the record: a clone made by the caller and dropped with the actor
|
||||
# was one kept skeleton per figure ever placed.
|
||||
function actor_own_skin(a: Actor) -> Skin {
|
||||
if a == null or a.model == null or a.model.skin == null { return null }
|
||||
if a.skin_owned and a.skin != null { skin_clone_free(a.skin) }
|
||||
a.skin = skin_clone(a.model.skin)
|
||||
a.skin_owned = true
|
||||
return a.skin
|
||||
}
|
||||
|
|
|
|||
|
|
@ -279,6 +279,7 @@ function gvk_init(render3d_st: mut Render3dState) -> bool {
|
|||
|
||||
if not gvk_cmd_init(render3d_st) { return false }
|
||||
render3d_st.gvk_ready = true
|
||||
gvk_startup_state(render3d_st)
|
||||
print(`r3d: vulkan on {render3d_st.gvk_device_name}, anisotropy up to {gvk_aniso_x(render3d_st.gvk_max_aniso)}x, multi-draw indirect {render3d_st.gvk_has_mdi}, indirect count {render3d_st.gvk_has_dic}, mesh shaders {render3d_st.gvk_has_mesh}`)
|
||||
return true
|
||||
}
|
||||
|
|
@ -543,7 +544,6 @@ function gvk_cmd_init(render3d_st: mut Render3dState) -> bool {
|
|||
const GVK_TMP_BYTES: int = 1048576
|
||||
|
||||
function gvk_tmp(render3d_st: mut Render3dState, n: int) -> pointer {
|
||||
if render3d_st.gvk_tmp_buf == null { render3d_st.gvk_tmp_buf = bytes(GVK_TMP_BYTES) }
|
||||
let sz = (n + 15) / 16 * 16
|
||||
if sz > GVK_TMP_BYTES { print(`r3d: vulkan: {n} bytes of scratch asked for at once`); return null }
|
||||
if render3d_st.gvk_tmp_off + sz > GVK_TMP_BYTES { render3d_st.gvk_tmp_off = 0 }
|
||||
|
|
@ -726,3 +726,43 @@ function gvk_labels_close(render3d_st: mut Render3dState) -> void {
|
|||
render3d_st.gvk_label_depth -= 1
|
||||
}
|
||||
}
|
||||
|
||||
# Everything a frame's draws use as scratch or as a table, made once the device is up: each was made
|
||||
# on the first draw that needed it, which put an allocation in whichever frame that was (plan 25.2)
|
||||
const GVK_PROGS_MAX: int = 4096
|
||||
function gvk_startup_state(render3d_st: mut Render3dState) -> void {
|
||||
let zero: long = 0
|
||||
render3d_st.gvk_tmp_buf = bytes(GVK_TMP_BYTES)
|
||||
render3d_st.gvk_skip_said = words(4096)
|
||||
for i in 0 .. 4096 { render3d_st.gvk_skip_said[i] = 0 }
|
||||
render3d_st.gvk_seen = words(GPU_MAX_VBUFS)
|
||||
if render3d_st.gvk_state == null { render3d_st.gvk_state = new GvkState }
|
||||
render3d_st.gvk_size_buf = words(4)
|
||||
if render3d_st.gvk_tex_spare == null { render3d_st.gvk_tex_spare = new []int }
|
||||
if render3d_st.gvk_buf_spare == null { render3d_st.gvk_buf_spare = new []int }
|
||||
if render3d_st.gvk_retired_frame == null { render3d_st.gvk_retired_frame = new []int }
|
||||
if render3d_st.gvk_buf_gpu == null { render3d_st.gvk_buf_gpu = new []int }
|
||||
render3d_st.gvk_sc_tmp = new []long
|
||||
let sct = render3d_st.gvk_sc_tmp
|
||||
for i in 0 .. 130 { push(sct, zero) }
|
||||
render3d_st.gvk_set_offs = bytes(16)
|
||||
render3d_st.gvk_ub_frame = new []int; render3d_st.gvk_ub_offv = new []int; render3d_st.gvk_ub_offf = new []int
|
||||
let ubf = render3d_st.gvk_ub_frame
|
||||
let ubv = render3d_st.gvk_ub_offv
|
||||
let ubo = render3d_st.gvk_ub_offf
|
||||
for i in 0 .. GVK_PROGS_MAX {
|
||||
push(ubf, 0); push(ubv, 0); push(ubo, 0)
|
||||
}
|
||||
render3d_st.gvk_pc_prog = new []int; render3d_st.gvk_pc_layout = new []int; render3d_st.gvk_pc_state = new []int; render3d_st.gvk_pc_bias = new []int
|
||||
render3d_st.gvk_pc_pass = new []int; render3d_st.gvk_pc_pipe = new []long
|
||||
render3d_st.gvk_pc_last = words(4096)
|
||||
for i in 0 .. 4096 { render3d_st.gvk_pc_last[i] = -1 }
|
||||
render3d_st.gg_rb = words(4); render3d_st.gg_cb = words(1); render3d_st.gg_bufs = words(3)
|
||||
render3d_st.gg_texs = words(3); render3d_st.gg_pr = words(48)
|
||||
if render3d_st.gpu_u_tmp == null { render3d_st.gpu_u_tmp = words(4) }
|
||||
if render3d_st.gpu_unit_2d == null {
|
||||
render3d_st.gpu_unit_2d = words(32)
|
||||
for i in 0 .. 32 { render3d_st.gpu_unit_2d[i] = -1 }
|
||||
}
|
||||
if render3d_st.cam_planes == null { render3d_st.cam_planes = floats(16) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -799,11 +799,6 @@ function gvk_draw_set(render3d_st: mut Render3dState, p: int, tx: words, tx_w: i
|
|||
let zero: long = 0
|
||||
let v = render3d_st.gvk_prog_var[p]
|
||||
gvk_uniform_blocks(render3d_st, p)
|
||||
if render3d_st.gvk_sc_tmp == null {
|
||||
render3d_st.gvk_sc_tmp = new []long
|
||||
render3d_st.gvk_set_offs = bytes(16)
|
||||
render3d_st.gvk_ub_frame = new []int; render3d_st.gvk_ub_offv = new []int; render3d_st.gvk_ub_offf = new []int
|
||||
}
|
||||
while len(render3d_st.gvk_ub_frame) <= p { push(render3d_st.gvk_ub_frame, 0); push(render3d_st.gvk_ub_offv, 0); push(render3d_st.gvk_ub_offf, 0) }
|
||||
let nt = len(v.t_name)
|
||||
# the key: every texture as this draw resolves it, and its sampler
|
||||
|
|
@ -1268,7 +1263,6 @@ function gvk_draw(render3d_st: mut Render3dState, p: int, m: Mesh, st: GvkState,
|
|||
if pipe == 0 {
|
||||
# Say so, once per program: a driver that refuses a pipeline other drivers accept (MoltenVK
|
||||
# rejected every skinned one) otherwise leaves a whole layer missing from the frame in silence.
|
||||
if render3d_st.gvk_skip_said == null { render3d_st.gvk_skip_said = words(4096); for i in 0 .. 4096 { render3d_st.gvk_skip_said[i] = 0 } }
|
||||
if p < 4096 and render3d_st.gvk_skip_said[p] == 0 {
|
||||
render3d_st.gvk_skip_said[p] = 1
|
||||
print(`r3d: vulkan: no pipeline for {gpu_program_key(render3d_st, p)}; its draws are skipped`)
|
||||
|
|
@ -1291,7 +1285,6 @@ function gvk_draw(render3d_st: mut Render3dState, p: int, m: Mesh, st: GvkState,
|
|||
let bufs = gvk_tmp(render3d_st, 8 * (GPU_MAX_VBUFS + 1))
|
||||
let offs = gvk_tmp(render3d_st, 8 * (GPU_MAX_VBUFS + 1))
|
||||
Vk.zero(offs, 8 * (GPU_MAX_VBUFS + 1))
|
||||
if render3d_st.gvk_seen == null { render3d_st.gvk_seen = words(GPU_MAX_VBUFS) }
|
||||
let seen = render3d_st.gvk_seen
|
||||
var nbd = 0
|
||||
for i in 0 .. m.n_attrs {
|
||||
|
|
@ -1435,8 +1428,7 @@ function gvk_open(render3d_st: mut Render3dState, w: int, h: int, title: string)
|
|||
win_gl_resize(w, h)
|
||||
# macOS: the Metal layer sets the backing scale, so it exists before the drawable is measured
|
||||
if Os.platform() == "macos" and win_metal_layer() == null { render3d_st.gvk_why = "no Metal layer on the window"; return false }
|
||||
if render3d_st.gvk_size_buf == null { render3d_st.gvk_size_buf = words(4) }
|
||||
win_gl_drawable(render3d_st.gvk_size_buf)
|
||||
win_gl_drawable(render3d_st.gvk_size_buf)
|
||||
if render3d_st.gvk_size_buf[0] > 0 and render3d_st.gvk_size_buf[1] > 0 { gl_set_drawable(render3d_st.gvk_size_buf[0], render3d_st.gvk_size_buf[1]) }
|
||||
gl_set_pixel_scale(win_gl_scale())
|
||||
}
|
||||
|
|
@ -1508,7 +1500,6 @@ function gvk_fb_forget(render3d_st: mut Render3dState, fb: int) -> void {
|
|||
|
||||
# the render state gpu.ludic has cached, with OpenGL's defaults where nothing was set yet
|
||||
function gvk_state_now(render3d_st: mut Render3dState) -> GvkState {
|
||||
if render3d_st.gvk_state == null { render3d_st.gvk_state = new GvkState }
|
||||
let st = render3d_st.gvk_state
|
||||
st.depth_test = 0; if render3d_st.gpu_s_depth_test == 1 { st.depth_test = 1 }
|
||||
st.depth_write = 1; if render3d_st.gpu_s_depth_write == 0 { st.depth_write = 0 }
|
||||
|
|
@ -1833,7 +1824,6 @@ function gvk_present_window(render3d_st: mut Render3dState) -> void {
|
|||
# a window's client area changed: the screen images and the swapchain follow it
|
||||
function gvk_resize_check(render3d_st: mut Render3dState) -> bool {
|
||||
if render3d_st.gvk_swap == 0 { return false }
|
||||
if render3d_st.gvk_size_buf == null { render3d_st.gvk_size_buf = words(4) }
|
||||
win_gl_drawable(render3d_st.gvk_size_buf)
|
||||
let w = render3d_st.gvk_size_buf[0]
|
||||
let h = render3d_st.gvk_size_buf[1]
|
||||
|
|
@ -1967,12 +1957,6 @@ function gvk_pipeline_fast(render3d_st: mut Render3dState, p: int, m: Mesh, st:
|
|||
state = state | ((st.depth_func & 15) << 8) | ((st.cull_face & 15) << 12) | (gvk_blend_index(st.blend_src) << 16) | (gvk_blend_index(st.blend_dst) << 20)
|
||||
let bias = st.bias_factor * 31 + st.bias_units
|
||||
let pass = ((n_color * 1000 + color_fmt) * 1000 + depth_fmt) * 64 + samples
|
||||
if render3d_st.gvk_pc_prog == null {
|
||||
render3d_st.gvk_pc_prog = new []int; render3d_st.gvk_pc_layout = new []int; render3d_st.gvk_pc_state = new []int; render3d_st.gvk_pc_bias = new []int
|
||||
render3d_st.gvk_pc_pass = new []int; render3d_st.gvk_pc_pipe = new []long
|
||||
render3d_st.gvk_pc_last = words(4096)
|
||||
for i in 0 .. 4096 { render3d_st.gvk_pc_last[i] = -1 }
|
||||
}
|
||||
if p < 4096 {
|
||||
let k = render3d_st.gvk_pc_last[p]
|
||||
if k >= 0 and render3d_st.gvk_pc_layout[k] == layout and render3d_st.gvk_pc_state[k] == state and render3d_st.gvk_pc_pass[k] == pass and render3d_st.gvk_pc_bias[k] == bias { return render3d_st.gvk_pc_pipe[k] }
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ function gvk_channel_bytes(ifmt: int) -> int {
|
|||
function gvk_tex_give_back(render3d_st: mut Render3dState, tex: int) -> void {
|
||||
if tex <= 0 or tex >= len(render3d_st.gvk_tex_image) or render3d_st.gvk_tex_image[tex] == 0 { return }
|
||||
gvk_tex_release(render3d_st, tex)
|
||||
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)")
|
||||
|
|
@ -660,7 +659,6 @@ function gvk_buf_delete(render3d_st: mut Render3dState, b: int) -> void {
|
|||
if b <= 0 or b >= len(render3d_st.gvk_buf) { return }
|
||||
gvk_buf_release(render3d_st, b)
|
||||
if render3d_st.gvk_buf_gpu != null and b < len(render3d_st.gvk_buf_gpu) { render3d_st.gvk_buf_gpu[b] = 0 }
|
||||
if render3d_st.gvk_buf_spare == null { render3d_st.gvk_buf_spare = new []int }
|
||||
let sp = render3d_st.gvk_buf_spare
|
||||
for i in 0 .. len(sp) { if sp[i] == b { return } }
|
||||
push(sp, b)
|
||||
|
|
@ -672,7 +670,6 @@ function gvk_buf_release(render3d_st: mut Render3dState, b: int) -> void {
|
|||
if gvk_buf_busy(render3d_st, b) {
|
||||
# a draw recorded this frame (or the frame in flight) still reads it: destroy it once the frame has been submitted
|
||||
push(render3d_st.gvk_retired_buf, render3d_st.gvk_buf[b]); push(render3d_st.gvk_retired_mem, render3d_st.gvk_buf_mem[b])
|
||||
if render3d_st.gvk_retired_frame == null { render3d_st.gvk_retired_frame = new []int }
|
||||
while len(render3d_st.gvk_retired_frame) < len(render3d_st.gvk_retired_buf) - 1 { push(render3d_st.gvk_retired_frame, 0) }
|
||||
push(render3d_st.gvk_retired_frame, render3d_st.gvk_buf_used[b])
|
||||
} else {
|
||||
|
|
@ -695,7 +692,6 @@ function gvk_retire_flush(render3d_st: mut Render3dState) -> void { gvk_retire_u
|
|||
# the frame being recorded read stays
|
||||
function gvk_retire_upto(render3d_st: mut Render3dState, done: int) -> void {
|
||||
if render3d_st.gvk_retired_buf == null { return }
|
||||
if render3d_st.gvk_retired_frame == null { render3d_st.gvk_retired_frame = new []int }
|
||||
while len(render3d_st.gvk_retired_frame) < len(render3d_st.gvk_retired_buf) { push(render3d_st.gvk_retired_frame, 0) }
|
||||
# compacted in place: three fresh lists a frame were never given back
|
||||
var w = 0
|
||||
|
|
@ -721,7 +717,6 @@ function gvk_retire_upto(render3d_st: mut Render3dState, done: int) -> void {
|
|||
# A buffer a compute pass writes: a draw later in the same frame reads what the GPU put there,
|
||||
# so it is never swapped for fresh storage because it was used this frame (gvk_buf_reserve).
|
||||
function gvk_buf_gpu_owned(render3d_st: mut Render3dState, b: int) -> void {
|
||||
if render3d_st.gvk_buf_gpu == null { render3d_st.gvk_buf_gpu = new []int }
|
||||
while len(render3d_st.gvk_buf_gpu) <= b { push(render3d_st.gvk_buf_gpu, 0) }
|
||||
render3d_st.gvk_buf_gpu[b] = 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,11 +102,7 @@ function gg_cull_frame(render3d_st: mut Render3dState) -> void {
|
|||
gg_tiles(render3d_st, 4, 0.0, 16.0)
|
||||
gg_tiles(render3d_st, 8, 16.0, 40.0)
|
||||
gg_tiles(render3d_st, 16, 40.0, render3d_st.grass_radius)
|
||||
# made once: a words() a frame is a calloc nothing frees
|
||||
if render3d_st.gg_rb == null {
|
||||
render3d_st.gg_rb = words(4); render3d_st.gg_cb = words(1); render3d_st.gg_bufs = words(3)
|
||||
render3d_st.gg_texs = words(3); render3d_st.gg_pr = words(48)
|
||||
}
|
||||
# made once, with the device (gvk_startup_state)
|
||||
let rb = render3d_st.gg_rb
|
||||
rb[0] = GG_BANDS; rb[1] = 0; rb[2] = 0; rb[3] = 0
|
||||
let cb = render3d_st.gg_cb
|
||||
|
|
|
|||
|
|
@ -246,3 +246,14 @@ function skin_free(sk: Skin) -> void {
|
|||
if sk.bones_v != null { free(sk.bones_v) }
|
||||
free(sk)
|
||||
}
|
||||
|
||||
# A skin_clone given back: what the clone made for itself (its pose, its matrices and their views, its
|
||||
# scratch). The rest data, the joints and the names are its source's and stay.
|
||||
function skin_clone_free(sk: Skin) -> void {
|
||||
if sk == null { return }
|
||||
free(sk.pose_r); free(sk.pose_t); free(sk.gmat); free(sk.bones)
|
||||
if sk.gmat_v != null { free(sk.gmat_v) }
|
||||
if sk.bones_v != null { free(sk.bones_v) }
|
||||
free(sk.tmp_l); free(sk.tmp_q); free(sk.tmp_a); free(sk.tmp_b); free(sk.tmp_c); free(sk.tmp_v)
|
||||
free(sk)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue