blob: 08b39335551fb8beb3dd03e176ca1f0d7e01f491 [file] [log] [blame]
# 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])