mirror of
https://github.com/BinomialLLC/basis_universal.git
synced 2026-06-08 00:23:52 +00:00
149 lines
4.8 KiB
Python
149 lines
4.8 KiB
Python
# 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])
|