load and draw texture
@ -5,6 +5,8 @@ struct Configuration {
|
|||||||
|
|
||||||
@group(0) @binding(0) var<uniform> config: Configuration;
|
@group(0) @binding(0) var<uniform> config: Configuration;
|
||||||
@group(0) @binding(1) var<storage> nodeMatrix: array<mat4x4f>;
|
@group(0) @binding(1) var<storage> nodeMatrix: array<mat4x4f>;
|
||||||
|
@group(0) @binding(2) var linearSampler: sampler;
|
||||||
|
@group(0) @binding(3) var colorTexture: texture_2d<f32>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct Imm {
|
struct Imm {
|
||||||
@ -24,11 +26,13 @@ struct VertexOutput {
|
|||||||
@builtin(position) position: vec4f,
|
@builtin(position) position: vec4f,
|
||||||
@location(0) positionWorld: vec3f,
|
@location(0) positionWorld: vec3f,
|
||||||
@location(1) normal: vec3f,
|
@location(1) normal: vec3f,
|
||||||
|
@location(2) texture: vec2f,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FragmentInput {
|
struct FragmentInput {
|
||||||
@location(0) positionWorld: vec3f,
|
@location(0) positionWorld: vec3f,
|
||||||
@location(1) normal: vec3f,
|
@location(1) normal: vec3f,
|
||||||
|
@location(2) texture: vec2f,
|
||||||
};
|
};
|
||||||
|
|
||||||
@vertex
|
@vertex
|
||||||
@ -41,6 +45,7 @@ fn vertexMain(input: VertexInput) -> VertexOutput
|
|||||||
output.position = config.matrix * position;
|
output.position = config.matrix * position;
|
||||||
output.positionWorld = (config.matrixWorld * position).xyz;
|
output.positionWorld = (config.matrixWorld * position).xyz;
|
||||||
output.normal = (config.matrixWorld * normal).xyz;
|
output.normal = (config.matrixWorld * normal).xyz;
|
||||||
|
output.texture = input.texture;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,5 +93,7 @@ fn lighting(position: vec3f, normal: vec3f) -> vec3f
|
|||||||
fn fragmentMain(input: FragmentInput) -> @location(0) vec4f
|
fn fragmentMain(input: FragmentInput) -> @location(0) vec4f
|
||||||
{
|
{
|
||||||
let intensity = lighting(input.positionWorld, normalize(input.normal));
|
let intensity = lighting(input.positionWorld, normalize(input.normal));
|
||||||
return vec4(intensity, 1.0);
|
let color = textureSample(colorTexture, linearSampler, input.texture);
|
||||||
|
|
||||||
|
return vec4(color.xyz * intensity, 1.0);
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
gltf/Image_0.png
|
Before Width: | Height: | Size: 4.3 MiB After Width: | Height: | Size: 4.1 MiB |
BIN
gltf/Image_1.png
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 1.5 MiB |
BIN
gltf/Image_2.png
|
Before Width: | Height: | Size: 2.5 MiB After Width: | Height: | Size: 2.3 MiB |
BIN
gltf/Image_3.png
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 95 KiB |
14
index.js
@ -256,12 +256,14 @@ const rotate = await WebAssembly.instantiateStreaming(fetch("rotate.wasm"), {
|
|||||||
env: { memory: memory }
|
env: { memory: memory }
|
||||||
});
|
});
|
||||||
|
|
||||||
const memory2 = new WebAssembly.Memory({ initial: 2 });
|
const memory2 = new WebAssembly.Memory({ initial: 258 * 2 });
|
||||||
const mem = await WebAssembly.instantiateStreaming(fetch("memory.wasm"), {
|
const module = await WebAssembly.instantiateStreaming(fetch("src/module.wasm"), {
|
||||||
env: { memory: memory2 }
|
env: {
|
||||||
|
memory: memory2,
|
||||||
|
log: console.log,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
console.log("mem");
|
//document.module = module;
|
||||||
document.mem = mem;
|
|
||||||
|
|
||||||
const uniformBuffer = device.createBuffer({
|
const uniformBuffer = device.createBuffer({
|
||||||
label: "grid uniform",
|
label: "grid uniform",
|
||||||
@ -439,7 +441,7 @@ function render()
|
|||||||
}
|
}
|
||||||
//requestAnimationFrame(render);
|
//requestAnimationFrame(render);
|
||||||
|
|
||||||
const gltfRenderer = await loadGltf(device, canvasFormat, memory2, mem);
|
const gltfRenderer = await loadGltf(device, canvasFormat, memory2, module);
|
||||||
|
|
||||||
function render2()
|
function render2()
|
||||||
{
|
{
|
||||||
|
|||||||
126
index2.js
@ -2,7 +2,7 @@ import { getPath } from "./common.js";
|
|||||||
import { parseGltfChunks, vertexBufferLayouts, primitiveAccessors, splitGltf } from "./gltf.js";
|
import { parseGltfChunks, vertexBufferLayouts, primitiveAccessors, splitGltf } from "./gltf.js";
|
||||||
|
|
||||||
|
|
||||||
function loadGltfNode(mem, handle, gltf, nodeIndex)
|
function loadGltfNode(module, handle, gltf, nodeIndex)
|
||||||
{
|
{
|
||||||
const node = gltf.json.nodes[nodeIndex];
|
const node = gltf.json.nodes[nodeIndex];
|
||||||
var translation = [0, 0, 0];
|
var translation = [0, 0, 0];
|
||||||
@ -10,20 +10,20 @@ function loadGltfNode(mem, handle, gltf, nodeIndex)
|
|||||||
translation = node.translation;
|
translation = node.translation;
|
||||||
}
|
}
|
||||||
console.log("init", nodeIndex, translation);
|
console.log("init", nodeIndex, translation);
|
||||||
mem.instance.exports.node_init_translation(handle, nodeIndex, translation[0], translation[1], translation[2]);
|
module.instance.exports.node_init_translation(handle, nodeIndex, translation[0], translation[1], translation[2]);
|
||||||
|
|
||||||
if ("children" in node) {
|
if ("children" in node) {
|
||||||
for (let childIndex in node.children) {
|
for (let childIndex in node.children) {
|
||||||
loadGltfNode(mem, handle, gltf, childIndex);
|
loadGltfNode(module, handle, gltf, childIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadGltfNodes(mem, gltf)
|
function loadGltfNodes(module, gltf)
|
||||||
{
|
{
|
||||||
const nodesHandle = mem.instance.exports.node_alloc(gltf.json.nodes.length);
|
const nodesHandle = module.instance.exports.node_alloc(gltf.json.nodes.length);
|
||||||
for (let nodeIndex of gltf.json.scenes[0].nodes) {
|
for (let nodeIndex of gltf.json.scenes[0].nodes) {
|
||||||
loadGltfNode(mem, nodesHandle, gltf, nodeIndex);
|
loadGltfNode(module, nodesHandle, gltf, nodeIndex);
|
||||||
}
|
}
|
||||||
return nodesHandle;
|
return nodesHandle;
|
||||||
}
|
}
|
||||||
@ -37,10 +37,17 @@ function printMatrix(m, o)
|
|||||||
}
|
}
|
||||||
|
|
||||||
class GltfRenderer {
|
class GltfRenderer {
|
||||||
constructor(device, canvasFormat, shaderModule, gltf)
|
constructor(device, canvasFormat, shaderModule, gltf, texture)
|
||||||
{
|
{
|
||||||
this.gltf = gltf;
|
this.gltf = gltf;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// textures
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
this.sampler = device.createSampler();
|
||||||
|
this.texture = texture;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// buffer
|
// buffer
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
@ -75,6 +82,14 @@ class GltfRenderer {
|
|||||||
binding: 1,
|
binding: 1,
|
||||||
visibility: GPUShaderStage.VERTEX,
|
visibility: GPUShaderStage.VERTEX,
|
||||||
buffer: { type: "read-only-storage" }
|
buffer: { type: "read-only-storage" }
|
||||||
|
}, {
|
||||||
|
binding: 2,
|
||||||
|
visibility: GPUShaderStage.FRAGMENT,
|
||||||
|
sampler: {}
|
||||||
|
}, {
|
||||||
|
binding: 3,
|
||||||
|
visibility: GPUShaderStage.FRAGMENT,
|
||||||
|
texture: {},
|
||||||
}]
|
}]
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
@ -162,6 +177,12 @@ class GltfRenderer {
|
|||||||
}, {
|
}, {
|
||||||
binding: 1,
|
binding: 1,
|
||||||
resource: { buffer: this.nodeBuffer },
|
resource: { buffer: this.nodeBuffer },
|
||||||
|
}, {
|
||||||
|
binding: 2,
|
||||||
|
resource: this.sampler,
|
||||||
|
}, {
|
||||||
|
binding: 3,
|
||||||
|
resource: this.texture,
|
||||||
}]
|
}]
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
@ -244,17 +265,102 @@ class GltfRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadGltf(device, canvasFormat, memory, mem)
|
function memoryString(memory, offset)
|
||||||
|
{
|
||||||
|
const u8 = new Uint8Array(memory.buffer, offset);
|
||||||
|
|
||||||
|
const s = [];
|
||||||
|
var i = 0;
|
||||||
|
while (u8[i] != 0 && (i - offset) < 256) {
|
||||||
|
s.push(u8[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return new TextDecoder().decode(new Uint8Array(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
function pngComponents(colorType)
|
||||||
|
{
|
||||||
|
if (colorType == 2)
|
||||||
|
return 3;
|
||||||
|
if (colorType == 6)
|
||||||
|
return 4;
|
||||||
|
throw new Error("non-implemented png color type");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadTextures(device, memory, module, gltf)
|
||||||
|
{
|
||||||
|
const tempTable = module.instance.exports.mem_alloc(256 * 4);
|
||||||
|
const tempHeader = module.instance.exports.mem_alloc(7 * 4);
|
||||||
|
|
||||||
|
const tempInputSize = 8 * 1024 * 1024;
|
||||||
|
const tempInput = module.instance.exports.mem_alloc(tempInputSize);
|
||||||
|
|
||||||
|
const tempOutputSize = 2048 * 2048 * 4;
|
||||||
|
const tempOutput = module.instance.exports.mem_alloc(tempOutputSize);
|
||||||
|
|
||||||
|
const tempError = module.instance.exports.mem_alloc(4);
|
||||||
|
|
||||||
|
module.instance.exports.png_build_crc_table(tempTable);
|
||||||
|
|
||||||
|
const tempInputU8 = new Uint8Array(memory.buffer, tempInput);
|
||||||
|
const tempOutputU8 = new Uint8Array(memory.buffer, tempOutput);
|
||||||
|
const tempErrorU32 = new Uint32Array(memory.buffer, tempError);
|
||||||
|
const tempHeaderU32 = new Uint32Array(memory.buffer, tempHeader);
|
||||||
|
|
||||||
|
const textures = [];
|
||||||
|
for (let image of gltf.json.images) {
|
||||||
|
console.log(image.uri);
|
||||||
|
const imageResponse = await fetch(`gltf/${image.uri}`);
|
||||||
|
const imageBuffer = await imageResponse.arrayBuffer();
|
||||||
|
const imageBufferU8 = new Uint8Array(imageBuffer)
|
||||||
|
|
||||||
|
tempInputU8.set(imageBufferU8);
|
||||||
|
const ret = module.instance.exports.png_decode(tempTable, tempInput, imageBuffer.byteLength,
|
||||||
|
tempHeader,
|
||||||
|
tempOutput, tempOutputSize,
|
||||||
|
tempError);
|
||||||
|
if (ret < 0) {
|
||||||
|
console.log("png ret", ret, memoryString(memory, tempErrorU32[0]));
|
||||||
|
throw new Error("png error");
|
||||||
|
}
|
||||||
|
|
||||||
|
const width = tempHeaderU32[0];
|
||||||
|
const height = tempHeaderU32[1];
|
||||||
|
const bitDepth = tempHeaderU32[2];
|
||||||
|
const colorType = tempHeaderU32[3];
|
||||||
|
const components = pngComponents(colorType);
|
||||||
|
console.log(components);
|
||||||
|
|
||||||
|
const texture = device.createTexture({
|
||||||
|
size: [width, height],
|
||||||
|
format: 'rgba8unorm',
|
||||||
|
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,
|
||||||
|
});
|
||||||
|
|
||||||
|
device.queue.writeTexture({ texture: texture },
|
||||||
|
tempOutputU8,
|
||||||
|
{ bytesPerRow: width * components },
|
||||||
|
{ width: width, height: height });
|
||||||
|
|
||||||
|
textures.push(texture);
|
||||||
|
}
|
||||||
|
return textures;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadGltf(device, canvasFormat, memory, module)
|
||||||
{
|
{
|
||||||
const gltf = await splitGltf("gltf/lamp.gltf", "gltf/lamp.bin");
|
const gltf = await splitGltf("gltf/lamp.gltf", "gltf/lamp.bin");
|
||||||
const nodesHandle = loadGltfNodes(mem, gltf);
|
const nodesHandle = loadGltfNodes(module, gltf);
|
||||||
|
|
||||||
|
/*
|
||||||
const nodesM = new Float32Array(memory.buffer, nodesHandle);
|
const nodesM = new Float32Array(memory.buffer, nodesHandle);
|
||||||
for (let i = 0; i < gltf.json.nodes.length; i++) {
|
for (let i = 0; i < gltf.json.nodes.length; i++) {
|
||||||
console.log("[", i, "]");
|
console.log("[", i, "]");
|
||||||
printMatrix(nodesM, i * 16);
|
printMatrix(nodesM, i * 16);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
const textures = await loadTextures(device, memory, module, gltf);
|
||||||
|
|
||||||
const code = await getPath("gltf.wgsl");
|
const code = await getPath("gltf.wgsl");
|
||||||
const shaderModule = device.createShaderModule({
|
const shaderModule = device.createShaderModule({
|
||||||
@ -262,7 +368,7 @@ async function loadGltf(device, canvasFormat, memory, mem)
|
|||||||
code: await code,
|
code: await code,
|
||||||
});
|
});
|
||||||
|
|
||||||
const renderer = new GltfRenderer(device, canvasFormat, shaderModule, gltf, nodesHandle);
|
const renderer = new GltfRenderer(device, canvasFormat, shaderModule, gltf, textures[2]);
|
||||||
console.log(renderer.nodeBuffer);
|
console.log(renderer.nodeBuffer);
|
||||||
device.queue.writeBuffer(renderer.nodeBuffer, 0,
|
device.queue.writeBuffer(renderer.nodeBuffer, 0,
|
||||||
memory.buffer, nodesHandle, (4 * 4 * 4) * gltf.json.nodes.length);
|
memory.buffer, nodesHandle, (4 * 4 * 4) * gltf.json.nodes.length);
|
||||||
|
|||||||
71
memory.cpp
@ -1,71 +0,0 @@
|
|||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "directxmath/directxmath.h"
|
|
||||||
|
|
||||||
//size_t __builtin_wasm_memory_grow(int, size_t);
|
|
||||||
//size_t __builtin_wasm_memory_size(int);
|
|
||||||
|
|
||||||
extern char __heap_base[];
|
|
||||||
extern char __heap_end[];
|
|
||||||
|
|
||||||
static size_t heap_pages = 0;
|
|
||||||
static size_t alloc_index = 0;
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
size_t mem_size();
|
|
||||||
size_t mem_alloc(size_t length);
|
|
||||||
size_t node_alloc(int count);
|
|
||||||
|
|
||||||
void node_init_translation(size_t handle, int index, float x, float y, float z);
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline size_t memory_heap_base()
|
|
||||||
{
|
|
||||||
return (size_t)&__heap_base[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline size_t align(size_t n, size_t m)
|
|
||||||
{
|
|
||||||
return (n + (m - 1)) & (~(m - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void memory_grow(size_t npages)
|
|
||||||
{
|
|
||||||
__builtin_wasm_memory_grow(0, npages);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t mem_size()
|
|
||||||
{
|
|
||||||
return __builtin_wasm_memory_size(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t mem_alloc(size_t length)
|
|
||||||
{
|
|
||||||
size_t base = memory_heap_base();
|
|
||||||
|
|
||||||
size_t heap_end = (heap_pages << 16);
|
|
||||||
|
|
||||||
size_t address = alloc_index;
|
|
||||||
|
|
||||||
alloc_index += align(length, 16);
|
|
||||||
|
|
||||||
if (heap_end < alloc_index) {
|
|
||||||
size_t npages = align(alloc_index - heap_end, 65536) >> 16;
|
|
||||||
memory_grow(npages);
|
|
||||||
heap_pages += npages;
|
|
||||||
}
|
|
||||||
return base + address;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t node_alloc(int count)
|
|
||||||
{
|
|
||||||
return mem_alloc((sizeof (XMFLOAT4X4)) * count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void node_init_translation(size_t handle, int index, float x, float y, float z)
|
|
||||||
{
|
|
||||||
XMFLOAT4X4 * nodes = reinterpret_cast<XMFLOAT4X4 *>(handle);
|
|
||||||
//XMMATRIX XMLoadFloat4x4(&nodes[index]);
|
|
||||||
XMMATRIX mat = XMMatrixTranslation(x, y, z);
|
|
||||||
XMStoreFloat4x4(&nodes[index], mat);
|
|
||||||
}
|
|
||||||
27
src/Makefile
@ -3,14 +3,16 @@ MINIZ = $(HOME)/miniz
|
|||||||
CFLAGS = \
|
CFLAGS = \
|
||||||
--target=wasm32 \
|
--target=wasm32 \
|
||||||
-g \
|
-g \
|
||||||
-O0 \
|
-O3 \
|
||||||
|
-flto \
|
||||||
-nostdlib \
|
-nostdlib \
|
||||||
-I$(MINIZ) \
|
-I$(MINIZ) \
|
||||||
|
-I.. \
|
||||||
-I. \
|
-I. \
|
||||||
-Werror \
|
-Werror \
|
||||||
-Wfatal-errors
|
-Wfatal-errors \
|
||||||
|
-D_XM_NO_INTRINSICS_
|
||||||
|
|
||||||
# -flto \
|
|
||||||
|
|
||||||
MFLAGS = \
|
MFLAGS = \
|
||||||
-DMINIZ_NO_STDIO \
|
-DMINIZ_NO_STDIO \
|
||||||
@ -19,15 +21,18 @@ MFLAGS = \
|
|||||||
-DMINIZ_NO_ZLIB_APIS \
|
-DMINIZ_NO_ZLIB_APIS \
|
||||||
-DMINIZ_NO_MALLOC
|
-DMINIZ_NO_MALLOC
|
||||||
|
|
||||||
# -Wl,--lto-O1 \
|
|
||||||
|
|
||||||
LDFLAGS = \
|
LDFLAGS = \
|
||||||
-Wl,--no-entry \
|
-Wl,--no-entry \
|
||||||
-Wl,--export=build_crc_table \
|
-Wl,--export=mem_size \
|
||||||
-Wl,--export=decode \
|
-Wl,--export=mem_alloc \
|
||||||
|
-Wl,--export=node_alloc \
|
||||||
|
-Wl,--export=node_init_translation \
|
||||||
|
-Wl,--export=png_build_crc_table \
|
||||||
|
-Wl,--export=png_decode \
|
||||||
|
-Wl,--import-undefined \
|
||||||
-Wl,--print-map \
|
-Wl,--print-map \
|
||||||
-Wl,--import-memory \
|
-Wl,--import-memory \
|
||||||
-Wl,-z,stack-size=1048576
|
-Wl,--lto-O3
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
clang $(CFLAGS) $(MFLAGS) -o $@ -c $<
|
clang $(CFLAGS) $(MFLAGS) -o $@ -c $<
|
||||||
@ -38,7 +43,9 @@ LDFLAGS = \
|
|||||||
PNG_OBJ = \
|
PNG_OBJ = \
|
||||||
png.o \
|
png.o \
|
||||||
stdlib.o \
|
stdlib.o \
|
||||||
$(MINIZ)/miniz_tinfl.o
|
$(MINIZ)/miniz_tinfl.o \
|
||||||
|
memory.o \
|
||||||
|
node.o
|
||||||
|
|
||||||
png.wasm: $(PNG_OBJ)
|
module.wasm: $(PNG_OBJ)
|
||||||
clang++ $(CFLAGS) $(LDFLAGS) -o $@ $^
|
clang++ $(CFLAGS) $(LDFLAGS) -o $@ $^
|
||||||
|
|||||||
14
src/index.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>WebGPU</title>
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
<script src="index.js" type="module"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas width="256" height="256"></canvas>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
124
src/index.js
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
const canvas = document.querySelector("canvas");
|
||||||
|
canvas.width = 480;
|
||||||
|
canvas.height = 480;
|
||||||
|
|
||||||
|
const context = canvas.getContext("2d");
|
||||||
|
const imageData = context.createImageData(canvas.width, canvas.height);
|
||||||
|
|
||||||
|
const cstride = canvas.width * 4;
|
||||||
|
|
||||||
|
for (let y = 0; y < canvas.height; y++) {
|
||||||
|
for (let x = 0; x < canvas.width; x++) {
|
||||||
|
imageData.data[y * cstride + x * 4 + 0] = x;
|
||||||
|
imageData.data[y * cstride + x * 4 + 1] = y;
|
||||||
|
imageData.data[y * cstride + x * 4 + 2] = 0;
|
||||||
|
imageData.data[y * cstride + x * 4 + 3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.putImageData(imageData, 0, 0);
|
||||||
|
|
||||||
|
const memoryBlocks = 129 + 128 * 10;
|
||||||
|
const memorySize = memoryBlocks * (64 * 1024);
|
||||||
|
const memory = new WebAssembly.Memory({ initial: memoryBlocks });
|
||||||
|
const memoryU8 = new Uint8Array(memory.buffer);
|
||||||
|
|
||||||
|
function round(n, m)
|
||||||
|
{
|
||||||
|
return (n + (m - 1)) & ~(m - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Allocator {
|
||||||
|
constructor(size) {
|
||||||
|
this.size = size;
|
||||||
|
this.offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
alloc(size) {
|
||||||
|
const address = this.offset;
|
||||||
|
this.offset += round(size, 32);
|
||||||
|
if (this.offset > this.size) {
|
||||||
|
throw new Error(`allocator overflow: ${this.offset} > ${this.size}`);
|
||||||
|
}
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function memoryString(mem, offset)
|
||||||
|
{
|
||||||
|
const s = [];
|
||||||
|
var i = offset;
|
||||||
|
while (mem[i] != 0 && (i - offset) < 256) {
|
||||||
|
s.push(mem[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return new TextDecoder().decode(new Uint8Array(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
const m = new Allocator(memorySize);
|
||||||
|
m.offset = (129 + 64) * 64 * 1024;
|
||||||
|
const crcTableA = m.alloc(256 * 4);
|
||||||
|
|
||||||
|
const png = await WebAssembly.instantiateStreaming(fetch("png.wasm"), {
|
||||||
|
env: { memory: memory }
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
const test = await WebAssembly.instantiateStreaming(fetch("test.wasm"), {
|
||||||
|
env: { memory: memory }
|
||||||
|
});
|
||||||
|
const res = test.instance.exports.test();
|
||||||
|
console.log("res", res);
|
||||||
|
console.log(memoryString(memoryU8, res));
|
||||||
|
*/
|
||||||
|
|
||||||
|
png.instance.exports.build_crc_table(crcTableA);
|
||||||
|
/*
|
||||||
|
const crcTable = new Uint32Array(memory.buffer, crcTableA);
|
||||||
|
for (let i = 0; i < 256; i++) {
|
||||||
|
console.log(crcTable[i].toString(16).padStart(8, '0'));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
const pngResponse = await fetch("../gltf/Image_0.png");
|
||||||
|
const pngBuffer = await pngResponse.arrayBuffer();
|
||||||
|
console.log(pngBuffer.byteLength);
|
||||||
|
|
||||||
|
const pngA = m.alloc(pngBuffer.byteLength);
|
||||||
|
const pngBufferU8 = new Uint8Array(pngBuffer);
|
||||||
|
memoryU8.set(pngBufferU8, pngA);
|
||||||
|
console.log("a0", memoryU8[pngA], pngBufferU8[0]);
|
||||||
|
|
||||||
|
const headerA = m.alloc(7 * 4);
|
||||||
|
|
||||||
|
const obufSize = canvas.width * canvas.height * 3;
|
||||||
|
const obufA = m.alloc(obufSize);
|
||||||
|
console.log("obufA", obufA, obufSize);
|
||||||
|
|
||||||
|
const errorA = m.alloc(4);
|
||||||
|
|
||||||
|
const ret = png.instance.exports.decode(crcTableA, pngA, pngBuffer.byteLength,
|
||||||
|
headerA,
|
||||||
|
obufA, obufSize,
|
||||||
|
errorA);
|
||||||
|
if (ret < 0) {
|
||||||
|
const address = new Uint32Array(memory.buffer, errorA);
|
||||||
|
console.log("error3", ret, crcTableA, address[0], memoryString(memoryU8, address[0]));
|
||||||
|
//for (let i = 0; i < 256; i++) {
|
||||||
|
//console.log(memoryU8[(-ret) + i]);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
console.log(ret);
|
||||||
|
if (ret >= 0) {
|
||||||
|
console.log("ret", ret);
|
||||||
|
const pstride = canvas.width * 3;
|
||||||
|
|
||||||
|
for (let y = 0; y < canvas.height; y++) {
|
||||||
|
for (let x = 0; x < canvas.width; x++) {
|
||||||
|
imageData.data[y * cstride + x * 4 + 0] = memoryU8[obufA + pstride * y + x * 3 + 0];
|
||||||
|
imageData.data[y * cstride + x * 4 + 1] = memoryU8[obufA + pstride * y + x * 3 + 1];
|
||||||
|
imageData.data[y * cstride + x * 4 + 2] = memoryU8[obufA + pstride * y + x * 3 + 2];
|
||||||
|
imageData.data[y * cstride + x * 4 + 3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.putImageData(imageData, 0, 0);
|
||||||
|
}
|
||||||
47
src/memory.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
extern char __heap_base[];
|
||||||
|
extern char __heap_end[];
|
||||||
|
|
||||||
|
static size_t heap_pages = 0;
|
||||||
|
static size_t alloc_index = 0;
|
||||||
|
|
||||||
|
static inline size_t memory_heap_base()
|
||||||
|
{
|
||||||
|
return (size_t)&__heap_end[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t align(size_t n, size_t m)
|
||||||
|
{
|
||||||
|
return (n + (m - 1)) & (~(m - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void memory_grow(size_t npages)
|
||||||
|
{
|
||||||
|
__builtin_wasm_memory_grow(0, npages);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t mem_size()
|
||||||
|
{
|
||||||
|
return __builtin_wasm_memory_size(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t mem_alloc(size_t length)
|
||||||
|
{
|
||||||
|
size_t base = memory_heap_base();
|
||||||
|
|
||||||
|
size_t heap_end = (heap_pages << 16);
|
||||||
|
|
||||||
|
alloc_index = align(alloc_index, 16);
|
||||||
|
size_t address = alloc_index;
|
||||||
|
alloc_index += length;
|
||||||
|
|
||||||
|
if (heap_end < alloc_index) {
|
||||||
|
size_t npages = align(alloc_index - heap_end, 65536) >> 16;
|
||||||
|
memory_grow(npages);
|
||||||
|
heap_pages += npages;
|
||||||
|
}
|
||||||
|
return base + address;
|
||||||
|
}
|
||||||
6
src/memory.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
size_t mem_size();
|
||||||
|
size_t mem_alloc(size_t length);
|
||||||
|
};
|
||||||
19
src/node.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
|
#include "node.h"
|
||||||
|
|
||||||
|
#include "directxmath/directxmath.h"
|
||||||
|
|
||||||
|
size_t node_alloc(int count)
|
||||||
|
{
|
||||||
|
return mem_alloc((sizeof (XMFLOAT4X4)) * count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_init_translation(size_t handle, int index, float x, float y, float z)
|
||||||
|
{
|
||||||
|
XMFLOAT4X4 * nodes = reinterpret_cast<XMFLOAT4X4 *>(handle);
|
||||||
|
//XMMATRIX XMLoadFloat4x4(&nodes[index]);
|
||||||
|
XMMATRIX mat = XMMatrixTranslation(x, y, z);
|
||||||
|
XMStoreFloat4x4(&nodes[index], mat);
|
||||||
|
}
|
||||||
6
src/node.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
size_t node_alloc(int count);
|
||||||
|
void node_init_translation(size_t handle, int index, float x, float y, float z);
|
||||||
|
};
|
||||||
24
src/png.cpp
@ -9,6 +9,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "png.h"
|
||||||
#include "miniz_tinfl.h"
|
#include "miniz_tinfl.h"
|
||||||
|
|
||||||
struct CT {
|
struct CT {
|
||||||
@ -33,7 +34,7 @@ struct Header {
|
|||||||
int interlace_method;
|
int interlace_method;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IBUF_SIZE ((1024 + 1) * 1024 * 4)
|
#define IBUF_SIZE ((2048 + 1) * 2048 * 4)
|
||||||
|
|
||||||
struct png_state {
|
struct png_state {
|
||||||
tinfl_decompressor decomp;
|
tinfl_decompressor decomp;
|
||||||
@ -45,9 +46,7 @@ struct png_state {
|
|||||||
|
|
||||||
static png_state _png_state;
|
static png_state _png_state;
|
||||||
|
|
||||||
extern "C" void build_crc_table(uint32_t * crc_table);
|
void png_build_crc_table(uint32_t * crc_table)
|
||||||
|
|
||||||
void build_crc_table(uint32_t * crc_table)
|
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < 256; i++) {
|
for (uint32_t i = 0; i < 256; i++) {
|
||||||
uint32_t c = i;
|
uint32_t c = i;
|
||||||
@ -269,8 +268,8 @@ static int decode_chunk(uint32_t const * crc_table, uint8_t const * mem, int & o
|
|||||||
offset += length;
|
offset += length;
|
||||||
uint32_t e_crc = decode_int32be(mem, offset);
|
uint32_t e_crc = decode_int32be(mem, offset);
|
||||||
if (e_crc != a_crc) {
|
if (e_crc != a_crc) {
|
||||||
state->error = "chunk crc mismatch";
|
state->error = "chunk crc mismatch2";
|
||||||
return -5;
|
return -offset;
|
||||||
}
|
}
|
||||||
offset += 4;
|
offset += 4;
|
||||||
|
|
||||||
@ -285,12 +284,7 @@ static int decode_chunk(uint32_t const * crc_table, uint8_t const * mem, int & o
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int decode(uint32_t const * crc_table, uint8_t const * mem, int length,
|
int png_decode(uint32_t const * crc_table, uint8_t const * mem, int length,
|
||||||
Header * header,
|
|
||||||
uint8_t * obuf, int osize,
|
|
||||||
char const ** error);
|
|
||||||
|
|
||||||
int decode(uint32_t const * crc_table, uint8_t const * mem, int length,
|
|
||||||
Header * header,
|
Header * header,
|
||||||
uint8_t * obuf, int osize,
|
uint8_t * obuf, int osize,
|
||||||
char const ** error)
|
char const ** error)
|
||||||
@ -376,18 +370,18 @@ int main(int argc, char const ** argv)
|
|||||||
void * ibuf = read_file(argv[1], &isize);
|
void * ibuf = read_file(argv[1], &isize);
|
||||||
|
|
||||||
uint32_t crc_table[256];
|
uint32_t crc_table[256];
|
||||||
build_crc_table(crc_table);
|
png_build_crc_table(crc_table);
|
||||||
|
|
||||||
uint8_t mem[] = {0x49, 0x45, 0x4E, 0x44};
|
uint8_t mem[] = {0x49, 0x45, 0x4E, 0x44};
|
||||||
uint32_t crc = calculate_crc(crc_table, mem, 0, 4);
|
uint32_t crc = calculate_crc(crc_table, mem, 0, 4);
|
||||||
assert(crc == 0xae426082);
|
assert(crc == 0xae426082);
|
||||||
|
|
||||||
int osize = 8 * 1024 * 1024;
|
int osize = 8 * 2048 * 2048;
|
||||||
void * obuf = malloc(osize);
|
void * obuf = malloc(osize);
|
||||||
|
|
||||||
Header header{};
|
Header header{};
|
||||||
char const * error;
|
char const * error;
|
||||||
int ret = decode(crc_table,
|
int ret = png_decode(crc_table,
|
||||||
reinterpret_cast<uint8_t *>(ibuf), isize,
|
reinterpret_cast<uint8_t *>(ibuf), isize,
|
||||||
&header,
|
&header,
|
||||||
reinterpret_cast<uint8_t *>(obuf), osize,
|
reinterpret_cast<uint8_t *>(obuf), osize,
|
||||||
|
|||||||