adding new files

This commit is contained in:
Richard Geldreich
2026-01-19 01:59:35 -05:00
parent 9d87991078
commit ea6778b2b5
72 changed files with 31686 additions and 0 deletions

View File

@@ -0,0 +1 @@
# __init__.py

View File

@@ -0,0 +1,58 @@
import wasmtime
import ctypes
# --- Engine ---
engine = wasmtime.Engine()
# --- Store ---
store = wasmtime.Store(engine)
# --- WASI config ---
wasi = wasmtime.WasiConfig()
wasi.argv = ["basisu_module_st"]
wasi.inherit_stdout() # <-- tell WASI to use the host stdout
wasi.inherit_stderr()
store.set_wasi(wasi)
# --- Load module ---
module = wasmtime.Module.from_file(engine, "basisu_py/wasm/basisu_module_st.wasm")
# --- Linker + WASI ---
linker = wasmtime.Linker(engine)
linker.define_wasi()
# --- Instantiate ---
instance = linker.instantiate(store, module)
print("Single-threaded WASM instantiated OK")
# --- Exports ---
exports = instance.exports(store)
get_version = exports["bu_get_version"]
alloc = exports["bu_alloc"]
free = exports["bu_free"]
memory = exports["memory"]
# --- Version ---
version = get_version(store)
print("Version =", version)
# --- Alloc ---
ptr = alloc(store, 64)
print("Allocated ptr =", ptr)
# --- Access WASM memory properly ---
data_len = memory.data_len(store)
raw_ptr = memory.data_ptr(store) # ctypes pointer
addr = ctypes.addressof(raw_ptr.contents) # convert to integer pointer
# Create a byte array view into WASM memory
buf = (ctypes.c_ubyte * data_len).from_address(addr)
# Write TEST at allocated ptr
buf[ptr : ptr + 4] = b"TEST"
print("Wrote TEST into WASM memory.")
# --- Free ---
free(store, ptr)
print("Memory free OK.")

View File

@@ -0,0 +1,148 @@
# basisu_wasm.py
import wasmtime
import ctypes
import sys
sys.path.append("basisu_py") # our shared .py files
from constants import *
class BasisuWasm:
def __init__(self, path):
self.path = path
self.engine = None
self.store = None
self.memory = None
self.exports = None
# -----------------------------------------------
# Internal helper: build WASI + Wasmtime engine
# -----------------------------------------------
def _init_engine(self):
self.engine = wasmtime.Engine()
self.store = wasmtime.Store(self.engine)
wasi = wasmtime.WasiConfig()
wasi.argv = ["basisu"]
wasi.inherit_stdout()
wasi.inherit_stderr()
self.store.set_wasi(wasi)
return wasi
# -----------------------------------------------
# Create linker and instantiate WASM module
# -----------------------------------------------
def load(self):
self._init_engine()
module = wasmtime.Module.from_file(self.engine, self.path)
linker = wasmtime.Linker(self.engine)
linker.define_wasi()
instance = linker.instantiate(self.store, module)
self.exports = instance.exports(self.store)
self.memory = self.exports["memory"]
if "bu_init" in self.exports:
self.exports["bu_init"](self.store)
print("WASM loaded:", self.path)
# -----------------------------------------------
# Read/write WASM linear memory via ctypes
# -----------------------------------------------
def _wasm_buf(self):
raw_ptr = self.memory.data_ptr(self.store)
length = self.memory.data_len(self.store)
addr = ctypes.addressof(raw_ptr.contents)
return (ctypes.c_ubyte * length).from_address(addr)
# -----------------------------------------------
# Exported API accessors
# -----------------------------------------------
def init(self):
return self.exports["bu_init"](self.store)
def version(self):
return self.exports["bu_get_version"](self.store)
def alloc(self, size):
return self.exports["bu_alloc"](self.store, size)
def free(self, ptr):
return self.exports["bu_free"](self.store, ptr)
def new_params(self):
return self.exports["bu_new_comp_params"](self.store)
def delete_params(self, ptr):
return self.exports["bu_delete_comp_params"](self.store, ptr)
def set_image_rgba32(self, params, image_index, img_ptr, w, h, pitch):
return self.exports["bu_comp_params_set_image_rgba32"](
self.store, params, image_index, img_ptr, w, h, pitch
)
def set_image_float_rgba(self, params, image_index, img_ptr, w, h, pitch):
return self.exports["bu_comp_params_set_image_float_rgba"](
self.store, params, image_index, img_ptr, w, h, pitch
)
# Normally quality_level controls the quality.
# If quality_level==-1, then rdo_quality (a low-level parameter) directly
# controls each codec's quality setting. Normally set to 0.
def compress_texture_lowlevel(self, params,
tex_format,
quality_level,
effort_level,
flags_and_quality,
rdo_quality):
return self.exports["bu_compress_texture"](
self.store,
params,
tex_format,
quality_level,
effort_level,
flags_and_quality,
rdo_quality
)
def compress(self, params,
tex_format=BasisTexFormat.cUASTC_LDR_4x4,
quality=BasisQuality.MAX,
effort=BasisEffort.DEFAULT,
flags=BasisFlags.NONE,
rdo_quality=0.0):
return bool(self.compress_texture_lowlevel(
params,
tex_format,
quality,
effort,
flags,
rdo_quality
))
def get_comp_data_ofs(self, params):
return self.exports["bu_comp_params_get_comp_data_ofs"](self.store, params)
def get_comp_data_size(self, params):
return self.exports["bu_comp_params_get_comp_data_size"](self.store, params)
# -----------------------------------------------
# Copy bytes into WASM memory
# -----------------------------------------------
def write_bytes(self, wasm_ptr, data: bytes):
buf = self._wasm_buf()
buf[wasm_ptr:wasm_ptr+len(data)] = data
# -----------------------------------------------
# Read bytes from WASM memory
# -----------------------------------------------
def read_bytes(self, wasm_ptr, size):
buf = self._wasm_buf()
return bytes(buf[wasm_ptr:wasm_ptr+size])

View File

@@ -0,0 +1,63 @@
# compress_test.py
from .basisu_wasm import *
# === Load WASM ===
codec = BasisuWasm("basisu_py/wasm/basisu_module_st.wasm")
codec.load()
print("Version =", codec.version())
# === Build test image ===
W, H = 256, 256
BYTES_PER_PIXEL = 4
pitch = W * BYTES_PER_PIXEL
img = bytearray(W * H * 4)
for y in range(H):
for x in range(W):
i = (y * W + x) * 4
img[i + 0] = x & 0xFF # R
img[i + 1] = y & 0xFF # G
img[i + 2] = (x ^ y) & 0xFF # B
img[i + 3] = 255 # A
# === Upload image to WASM memory ===
img_ptr = codec.alloc(len(img))
codec.write_bytes(img_ptr, img)
# === Create comp_params ===
params = codec.new_params()
# === Set image into comp_params ===
ok = codec.set_image_rgba32(params, 0, img_ptr, W, H, pitch)
print("Set image:", ok)
# === Compress ===
ok = codec.compress(
params,
tex_format=BasisTexFormat.cUASTC_LDR_4x4,
quality=100,
effort=BasisEffort.DEFAULT,
flags=BasisFlags.KTX2_OUTPUT | BasisFlags.SRGB,
rdo_quality=0.0
)
print("Compress result:", ok)
# === Retrieve compressed blob ===
ofs = codec.get_comp_data_ofs(params)
size = codec.get_comp_data_size(params)
print("Output size =", size)
comp_data = codec.read_bytes(ofs, size)
print("First 16 bytes:", comp_data[:16])
# === Save to KTX2 ===
with open("test.ktx2", "wb") as f:
f.write(comp_data)
print("File written: test.ktx2")
# === Cleanup ===
codec.delete_params(params)
codec.free(img_ptr)

View File

@@ -0,0 +1,76 @@
# compress_test_float.py
from .basisu_wasm import BasisuWasm, BasisTexFormat, BasisEffort, BasisFlags, BasisQuality
import struct # for packing floats
# === Load WASM ===
codec = BasisuWasm("basisu_py/wasm/basisu_module_st.wasm")
codec.load()
print("Version =", codec.version())
# === Build a 256x256 FLOAT RGBA image ===
W, H = 256, 256
BYTES_PER_PIXEL = 16 # float32 * 4
pitch = W * BYTES_PER_PIXEL
# Float image stored as bytearray of packed floats
img = bytearray(W * H * BYTES_PER_PIXEL)
for y in range(H):
for x in range(W):
# Create some float HDR gradient pattern
r = float(x) / W # 0.0 ? 1.0
g = float(y) / H # 0.0 ? 1.0
b = float(x ^ y) / 255.0 # quirky pattern
a = 1.0
i = (y * W + x) * 4
# pack into img bytearray
struct.pack_into("ffff", img, i*4, r, g, b, a)
print("Created FLOAT RGBA image.")
# === Upload to WASM memory ===
img_ptr = codec.alloc(len(img))
codec.write_bytes(img_ptr, img)
print("Copied float image into WASM heap at", img_ptr)
# === Create params ===
params = codec.new_params()
# === Set FLOAT RGBA image ===
ok = codec.set_image_float_rgba(params, 0, img_ptr, W, H, pitch)
print("Set float RGBA:", ok)
# === Compress using HDR UASTC 4x4 ===
ok = codec.compress(
params,
tex_format=BasisTexFormat.cUASTC_HDR_4x4,
quality=BasisQuality.MAX,
effort=BasisEffort.DEFAULT,
flags=BasisFlags.KTX2_OUTPUT | BasisFlags.REC2020, # optional: HDR color space
rdo_quality=0.0
)
print("Compression result:", ok)
# === Retrieve compressed HDR KTX2 ===
ofs = codec.get_comp_data_ofs(params)
size = codec.get_comp_data_size(params)
print("Output size =", size)
data = codec.read_bytes(ofs, size)
print("First 16 bytes:", data[:16])
# === Save to test_hdr.ktx2 ===
with open("test_hdr.ktx2", "wb") as f:
f.write(data)
print("Wrote test_hdr.ktx2")
# === Cleanup ===
codec.delete_params(params)
codec.free(img_ptr)