ludic/packages/ludic.render3d/texture_dds.ludic
Orkuncakilkaya 6289564382 render3d: R3D_VKMEM=<frame> says where the GPU memory is, by owner, and the renderer's big CPU arrays
Every allocation carries the owner its maker was wrapped in (models, terrain, impostor atlases,
scatter, grass, shadow maps, frame targets, sky, water, game textures, made in a frame), and the
report prints each owner's images and buffers, the 25 largest images and the scatter layers',
streams' and terrain's CPU copies. Nothing drawn changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 15:58:59 +03:00

88 lines
3.6 KiB
Text

# texture_dds.ludic - a .dds beside a .png: BC7 (colour, and anything packed into three channels),
# BC5 (a normal's x and y) or BC4 (one channel), every mip level encoded at build time. Only the
# DX10 form with its whole chain is taken; anything else is 0 and the caller loads the .png.
# DXGI's numbers for the formats read here
const DDS_BC4: int = 80
const DDS_BC5: int = 83
const DDS_BC7: int = 98
const DDS_BC7_SRGB: int = 99
function dds_u32(b: []byte, o: int) -> int { return b[o] | (b[o + 1] << 8) | (b[o + 2] << 16) | (b[o + 3] << 24) }
# the .dds a .png may have beside it, or "" when the path is not a .png
function dds_path_of(path: string) -> string {
let n = len(path)
if n < 5 or path[n - 4 .. n] != ".png" { return "" }
return path[0 .. n - 4] + ".dds"
}
# Load the .dds at `path` as a texture (srgb: colour, sampled as sRGB), or 0
# 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)
free(b)
if id == 0 { print(`r3d: {path} is not a DX10 .dds with its whole mip chain; the .png is used`) }
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)
let w = dds_u32(b, 16)
var levels = dds_u32(b, 28)
if levels < 1 { levels = 1 }
let dxgi = dds_u32(b, 128)
var ifmt = 0
var block = 16
if dxgi == DDS_BC7 or dxgi == DDS_BC7_SRGB { ifmt = R3D_BC7; if srgb { ifmt = R3D_BC7_SRGB } }
if dxgi == DDS_BC5 { ifmt = R3D_BC5 }
if dxgi == DDS_BC4 { ifmt = R3D_BC4; block = 8 }
if ifmt == 0 or w < 1 or h < 1 or levels != gvk_mip_levels(w, h) { return 0 }
let offs = words(levels + 1)
var at = 0
for l in 0 .. levels {
offs[l] = at
at += max((max(w >> l, 1) + 3) / 4, 1) * max((max(h >> l, 1) + 3) / 4, 1) * block
}
offs[levels] = at
if 148 + at > len(b) {
free(offs)
return 0
}
let id = gpu_tex_new(render3d_st)
gpu_tex_bind(render3d_st, GPU_TEX2D, id)
let ok = gpu_tex_compressed(render3d_st, ifmt, w, h, levels, mem_off(data_of(b), 148), offs)
free(offs)
if not ok {
gpu_tex_free(render3d_st, id)
return 0
}
gpu_tex_param(render3d_st, GPU_TEX2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
gpu_tex_param(render3d_st, GPU_TEX2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
gpu_tex_param(render3d_st, GPU_TEX2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
gpu_tex_param(render3d_st, GPU_TEX2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
gpu_tex_paramf(render3d_st, GPU_TEX2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, render3d_st.tex_anisotropy)
render3d_st.tex_w = w
render3d_st.tex_h = h
return id
}