webgl: Add bindings, fix Tex*Image*D

This commit is contained in:
fendevel
2026-02-28 00:37:34 +00:00
parent 4581f57953
commit eeb7e775f3
3 changed files with 92 additions and 23 deletions

View File

@@ -10,7 +10,7 @@ function getElement(name) {
}
function stripNewline(str) {
return str.replace(/\n/, ' ')
return str.replace(/\n/, ' ')
}
class WasmMemoryInterface {
@@ -40,22 +40,14 @@ class WasmMemoryInterface {
}
loadF32Array(addr, len) {
let array = new Float32Array(this.memory.buffer, addr, len);
return array;
}
loadF64Array(addr, len) {
let array = new Float64Array(this.memory.buffer, addr, len);
return array;
}
loadU32Array(addr, len) {
let array = new Uint32Array(this.memory.buffer, addr, len);
return array;
}
loadI32Array(addr, len) {
let array = new Int32Array(this.memory.buffer, addr, len);
return array;
}
loadF32Array(addr, len) { return new Float32Array(this.memory.buffer, addr, len); }
loadF64Array(addr, len) { return new Float64Array(this.memory.buffer, addr, len); }
loadU32Array(addr, len) { return new Uint32Array(this.memory.buffer, addr, len); }
loadI32Array(addr, len) { return new Int32Array(this.memory.buffer, addr, len); }
loadU16Array(addr, len) { return new Uint16Array(this.memory.buffer, addr, len); }
loadI16Array(addr, len) { return new Int16Array(this.memory.buffer, addr, len); }
loadU8Array(addr, len) { return new Uint8Array(this.memory.buffer, addr, len); }
loadI8Array(addr, len) { return new Int8Array(this.memory.buffer, addr, len); }
loadU8(addr) { return this.mem.getUint8 (addr); }
@@ -200,6 +192,7 @@ class WebGLInterface {
this.transformFeedbacks = [];
this.syncs = [];
this.programInfos = {};
this.extensions = [];
}
get mem() {
@@ -225,6 +218,9 @@ class WebGLInterface {
} else {
this.ctxVersion = 1.0;
}
this.extensions = this.ctx.getSupportedExtensions();
return true;
}
@@ -281,6 +277,30 @@ class WebGLInterface {
return source;
}
loadTypedArrayFromTexelType(type, size, data) {
switch (type) {
case this.ctx.SHORT: return this.mem.loadI16Array(data, size/2);
case this.ctx.UNSIGNED_SHORT_5_5_5_1:
case this.ctx.UNSIGNED_SHORT_5_6_5:
case this.ctx.UNSIGNED_SHORT_4_4_4_4:
case this.ctx.UNSIGNED_SHORT:
case this.ctx.HALF_FLOAT: return this.mem.loadU16Array(data, size/2);
case this.ctx.FLOAT: return this.mem.loadF32Array(data, size/4);
case this.ctx.INT: return this.mem.loadI32Array(data, size/4)
case this.ctx.UNSIGNED_INT_24_8:
case this.ctx.UNSIGNED_INT_5_9_9_9_REV:
case this.ctx.UNSIGNED_INT_10F_11F_11F_REV:
case this.ctx.UNSIGNED_INT_2_10_10_10_REV:
case this.ctx.UNSIGNED_INT: return this.mem.loadU32Array(data, size/4)
case this.ctx.BYTE: return this.mem.loadI8Array(data, size);
case this.ctx.UNSIGNED_BYTE: return this.mem.loadU8Array(data, size);
case this.ctx.FLOAT_32_UNSIGNED_INT_24_8_REV:
throw new Error("Source data of type FLOAT_32_UNSIGNED_INT_24_8_REV must be null");
}
throw new Error(`Unsupported texture data type: 0x${type.toString(16)}`);
}
getWebGL1Interface() {
return {
SetCurrentContextById: (name_ptr, name_len) => {
@@ -327,10 +347,30 @@ class WebGLInterface {
IsExtensionSupported: (name_ptr, name_len) => {
let name = this.mem.loadString(name_ptr, name_len);
let extensions = this.ctx.getSupportedExtensions();
let extensions = this.extensions;
return extensions.indexOf(name) !== -1
},
GetSupportedExtensionFromIndex: (index, buf_ptr, buf_len, length_ptr) => {
let extensions = this.extensions;
if (index < 0 || index >= extensions.length) {
return false;
}
let ext = extensions[index];
const n = Math.min(buf_len, ext.length);
ext = ext.substring(0, n);
this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder().encode(ext));
this.mem.storeInt(length_ptr, n);
return true;
},
GetExtension: (name_ptr, name_len) => {
let name = this.mem.loadString(name_ptr, name_len);
this.ctx.getExtension(name);
},
GetError: () => {
let err = this.lastError;
@@ -628,6 +668,11 @@ class WebGLInterface {
this.ctx.generateMipmap(target);
},
GetBufferParameter: (target, pname) => {
return this.ctx.getBufferParameter(target, pname);
},
GetActiveAttrib: (program, index, size_ptr, type_ptr, name_buf_ptr, name_buf_len, name_len_ptr) => {
const info = this.ctx.getActiveAttrib(this.programs[program], index);
@@ -830,7 +875,8 @@ class WebGLInterface {
TexImage2D: (target, level, internalformat, width, height, border, format, type, size, data) => {
if (data) {
this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, this.mem.loadBytes(data, size));
const texelData = this.loadTypedArrayFromTexelType(type, size, data);
this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, texelData);
} else {
this.ctx.texImage2D(target, level, internalformat, width, height, border, format, type, null);
}
@@ -842,7 +888,8 @@ class WebGLInterface {
this.ctx.texParameteri(target, pname, param);
},
TexSubImage2D: (target, level, xoffset, yoffset, width, height, format, type, size, data) => {
this.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, this.mem.loadBytes(data, size));
const texelData = this.loadTypedArrayFromTexelType(type, size, data);
this.ctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, texelData);
},
@@ -976,7 +1023,10 @@ class WebGLInterface {
},
/* Texture objects */
TexStorage2D: (target, levels, internalformat, width, height) => {
this.assertWebGL2();
this.ctx.texStorage2D(target, levels, internalformat, width, height);
},
TexStorage3D: (target, levels, internalformat, width, height, depth) => {
this.assertWebGL2();
this.ctx.texStorage3D(target, levels, internalformat, width, height, depth);
@@ -984,14 +1034,16 @@ class WebGLInterface {
TexImage3D: (target, level, internalformat, width, height, depth, border, format, type, size, data) => {
this.assertWebGL2();
if (data) {
this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, this.mem.loadBytes(data, size));
const texelData = this.loadTypedArrayFromTexelType(type, size, data);
this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, texelData);
} else {
this.ctx.texImage3D(target, level, internalformat, width, height, depth, border, format, type, null);
}
},
TexSubImage3D: (target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, size, data) => {
this.assertWebGL2();
this.ctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, this.mem.loadBytes(data, size));
const texelData = this.loadTypedArrayFromTexelType(type, size, data);
this.ctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texelData);
},
CompressedTexImage3D: (target, level, internalformat, width, height, depth, border, imageSize, data) => {
this.assertWebGL2();

View File

@@ -52,6 +52,7 @@ foreign webgl {
GetError :: proc() -> Enum ---
IsExtensionSupported :: proc(name: string) -> bool ---
GetExtension :: proc(name: string) ---
ActiveTexture :: proc(x: Enum) ---
AttachShader :: proc(program: Program, shader: Shader) ---
@@ -118,6 +119,7 @@ foreign webgl {
GenerateMipmap :: proc(target: Enum) ---
GetBufferParameter :: proc(target, name: Enum) -> int ---
GetAttribLocation :: proc(program: Program, name: string) -> i32 ---
GetUniformLocation :: proc(program: Program, name: string) -> i32 ---
GetVertexAttribOffset :: proc(index: i32, pname: Enum) -> uintptr ---
@@ -373,7 +375,21 @@ GetShaderInfoLog :: proc "contextless" (shader: Shader, buf: []byte) -> string {
return string(buf[:length])
}
IterateSupportedExtensions :: proc(index: ^int, buf: []byte) -> (string, bool) {
foreign webgl {
@(link_name="GetSupportedExtensionFromIndex")
_GetSupportedExtensionFromIndex :: proc "contextless" (index: int, buf: []byte, length: ^int) -> bool ---
}
length: int
if !_GetSupportedExtensionFromIndex(index^, buf[:], &length) {
return "", false
}
index^ += 1
return string(buf[:length]), true
}
BufferDataSlice :: proc "contextless" (target: Enum, slice: $S/[]$E, usage: Enum) {
BufferData(target, len(slice)*size_of(E), raw_data(slice), usage)

View File

@@ -35,6 +35,7 @@ foreign webgl2 {
RenderbufferStorageMultisample :: proc(target: Enum, samples: i32, internalformat: Enum, width, height: i32) ---
/* Texture objects */
TexStorage2D :: proc(target: Enum, levels: i32, internalformat: Enum, width, height: i32) ---
TexStorage3D :: proc(target: Enum, levels: i32, internalformat: Enum, width, height, depth: i32) ---
TexImage3D :: proc(target: Enum, level: i32, internalformat: Enum, width, height, depth: i32, border: i32, format, type: Enum, size: int, data: rawptr) ---
TexSubImage3D :: proc(target: Enum, level: i32, xoffset, yoffset, zoffset, width, height, depth: i32, format, type: Enum, size: int, data: rawptr) ---