diff --git a/packages/ludic.render3d/env.ludic b/packages/ludic.render3d/env.ludic index 7cb0008a..6ddb84aa 100644 --- a/packages/ludic.render3d/env.ludic +++ b/packages/ludic.render3d/env.ludic @@ -354,7 +354,7 @@ export state Render3dState { gvk_unpack_swap: bool = false # GL_UNPACK_SWAP_BYTES: 16-bit PNG samples arrive big-endian gvk_st_buf: long = 0 gvk_st_mem: long = 0 - gvk_smp_keys: []string = null + gvk_smp_keys: []int = null # 7 numbers per sampler: filters, wraps, compare, anisotropy, bias gvk_smp: []long = null gvk_buf: []long = null gvk_buf_mem: []long = null diff --git a/packages/ludic.render3d/gpu_vk_draw.ludic b/packages/ludic.render3d/gpu_vk_draw.ludic index c8a5b294..5908f633 100644 --- a/packages/ludic.render3d/gpu_vk_draw.ludic +++ b/packages/ludic.render3d/gpu_vk_draw.ludic @@ -1416,15 +1416,26 @@ function gvk_open(render3d_st: mut Render3dState, w: int, h: int, title: string) return true } -# a program handle for a variant; the key is gpu_program's, so gpu_program_key works on both +# 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. function gvk_program_new(render3d_st: mut Render3dState, vs: string, fs: string, defines: string) -> int { - render3d_st.gvk_prog_counter += 1 - let p = render3d_st.gvk_prog_counter 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 } + for i in 0 .. len(render3d_st.gpu_prog_keys) { + if render3d_st.gpu_prog_keys[i] == key { + free(key) + return render3d_st.gpu_prog_ids[i] + } + } + render3d_st.gvk_prog_counter += 1 + let p = render3d_st.gvk_prog_counter push(render3d_st.gpu_prog_ids, p) push(render3d_st.gpu_prog_keys, key) - if not gvk_program(render3d_st, p, key, render3d_st.gvk_spv_dir) { return 0 } + # a variant that cannot be made stays 0 for everyone who asks for it later + if not gvk_program(render3d_st, p, key, render3d_st.gvk_spv_dir) { + render3d_st.gpu_prog_ids[len(render3d_st.gpu_prog_ids) - 1] = 0 + return 0 + } return p } diff --git a/packages/ludic.render3d/gpu_vk_res.ludic b/packages/ludic.render3d/gpu_vk_res.ludic index 2bdccff3..b8357821 100644 --- a/packages/ludic.render3d/gpu_vk_res.ludic +++ b/packages/ludic.render3d/gpu_vk_res.ludic @@ -323,7 +323,7 @@ function gvk_tex_grow_mips(render3d_st: mut Render3dState, tex: int, w: int, h: let cb = gvk_once_begin(render3d_st) gvk_barrier(render3d_st, cb, old_image, false, 0, 1, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) gvk_barrier(render3d_st, cb, render3d_st.gvk_tex_image[tex], false, 0, 1, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - let ic = bytes(VkImageCopy_sizeof) + let ic = gvk_tmp(render3d_st, VkImageCopy_sizeof) Vk.zero(ic, VkImageCopy_sizeof) Vk.put_i32(ic, VkImageCopy_srcSubresource + VkImageSubresourceLayers_aspectMask, VK_IMAGE_ASPECT_COLOR_BIT) Vk.put_i32(ic, VkImageCopy_srcSubresource + VkImageSubresourceLayers_layerCount, layers) @@ -368,7 +368,7 @@ function gvk_tex_mips_into(render3d_st: mut Render3dState, cb: pointer, tex: int if dh < 1 { dh = 1 } gvk_barrier(render3d_st, cb, image, false, lv - 1, 1, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) gvk_barrier(render3d_st, cb, image, false, lv, 1, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) - let blit = bytes(VkImageBlit_sizeof) + let blit = gvk_tmp(render3d_st, VkImageBlit_sizeof) Vk.zero(blit, VkImageBlit_sizeof) Vk.put_i32(blit, VkImageBlit_srcSubresource + VkImageSubresourceLayers_aspectMask, VK_IMAGE_ASPECT_COLOR_BIT) Vk.put_i32(blit, VkImageBlit_srcSubresource + VkImageSubresourceLayers_mipLevel, lv - 1) @@ -525,9 +525,16 @@ function gvk_tex_sampler(render3d_st: mut Render3dState, tex: int, min_f: int, m } 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)) - let key = `{min_f}/{mag_f}/{wrap_s}/{wrap_t}/{compare}/{aniso}/{bias}` - if render3d_st.gvk_smp_keys == null { render3d_st.gvk_smp_keys = new []string; render3d_st.gvk_smp = new []long } - for i in 0 .. len(render3d_st.gvk_smp_keys) { if render3d_st.gvk_smp_keys[i] == key { return render3d_st.gvk_smp[i] } } + # looked up by the numbers themselves: a key string built on every call (and a texture read two + # ways in turn misses its own cache every time) was never given back + if render3d_st.gvk_smp_keys == null { render3d_st.gvk_smp_keys = new []int; render3d_st.gvk_smp = new []long } + let ks = render3d_st.gvk_smp_keys + var i = 0 + while i < len(render3d_st.gvk_smp) { + let o = i * 7 + if ks[o] == min_f and ks[o + 1] == mag_f and ks[o + 2] == wrap_s and ks[o + 3] == wrap_t and ks[o + 4] == compare and ks[o + 5] == aniso and ks[o + 6] == bias { return render3d_st.gvk_smp[i] } + i += 1 + } var mn = min_f if mn == 0 { mn = GL_NEAREST_MIPMAP_LINEAR } var mg = mag_f @@ -563,7 +570,7 @@ function gvk_sampler(render3d_st: mut Render3dState, min_f: int, mag_f: int, wra let r = Vk.create_sampler(render3d_st.gvk_dev, sci, null, out) if r != VK_SUCCESS { gvk_fail(render3d_st, "vkCreateSampler", r); return zero } let s = gvk_handle(out) - push(render3d_st.gvk_smp_keys, key) + push(ks, min_f); push(ks, mag_f); push(ks, wrap_s); push(ks, wrap_t); push(ks, compare); push(ks, aniso); push(ks, bias) push(render3d_st.gvk_smp, s) return s }