port rle encoding to wasm. deprecate js but preserve as legacy for debugging

This commit is contained in:
Stewart Allen 2020-05-02 23:12:31 -04:00
commit 18e0d11803
3 changed files with 173 additions and 73 deletions

View file

@ -32,7 +32,10 @@ let gs_kiri_sla = exports;
preview, preview,
previewSmall, previewSmall,
previewLarge, previewLarge,
fill_cache; fill_cache,
legacy = false;
if (legacy) console.log("SLA Driver in Legacy Mode");
/** /**
* DRIVER SLICE CONTRACT - runs in worker * DRIVER SLICE CONTRACT - runs in worker
@ -48,9 +51,9 @@ let gs_kiri_sla = exports;
work_total, work_total,
work_remain; work_remain;
// if (!self.OffscreenCanvas) { if (legacy && !self.OffscreenCanvas) {
// return ondone("browser lacks support for OffscreenCanvas",true); return ondone("browser lacks support for OffscreenCanvas",true);
// } }
// calculate % complete and call onupdate() // calculate % complete and call onupdate()
function doupdate(work, msg) { function doupdate(work, msg) {
@ -594,7 +597,6 @@ let gs_kiri_sla = exports;
device = settings.device, device = settings.device,
process = settings.process, process = settings.process,
output = print.output, output = print.output,
images = [],
layermax = 0, layermax = 0,
width = 2560, width = 2560,
height = 1440, height = 1440,
@ -602,26 +604,35 @@ let gs_kiri_sla = exports;
height2 = height/2, height2 = height/2,
scaleX = width / device.bedWidth, scaleX = width / device.bedWidth,
scaleY = height / device.bedDepth, scaleY = height / device.bedDepth,
mark = Date.now(); mark = Date.now(),
layers = process.slaAntiAlias || 1,
masks = [],
images = [],
slices = [];
let d = 8 / layers;
for (let i=0; i<layers; i++) {
masks.push((1 << (8 - i * d)) - 1);
}
// find max layer count // find max layer count
widgets.forEach(widget => { widgets.forEach(widget => {
layermax = Math.max(widget.slices.length); layermax = Math.max(widget.slices.length);
}); });
// let render = renderLayer; let render = legacy ? renderLayer : renderLayerWasm;
let render = renderLayerWasm;
// generate layer 8-bit bitaps using canvas // generate layer 8-bit bitaps using canvas
for (let index=0; index < layermax; index++) { for (let index=0; index < layermax; index++) {
let param = { index, width, height, widgets, scaleX, scaleY }; let param = { index, width, height, widgets, scaleX, scaleY, masks };
let {data, end} = render(param); let {image, layers, end} = render(param);
images.push(data); images.push(image);
slices.push(layers);
// transfer images to browser main // transfer images to browser main
online({ online({
progress: (index / layermax) * 0.25, progress: (index / layermax) * 0.85,
message: "image_gen", message: "image_gen",
data: data data: image
}); });
if (end) break; if (end) break;
} }
@ -640,11 +651,12 @@ let gs_kiri_sla = exports;
let file = exp_func(print, { let file = exp_func(print, {
width: width, width: width,
height: height, height: height,
lines: images,
small: previewSmall.data, small: previewSmall.data,
large: previewLarge.data large: previewLarge.data,
lines: images,
slices: slices
}, (progress, message) => { }, (progress, message) => {
online({progress: progress * 0.75 + 0.25, message}); online({progress: progress * 0.15 + 0.85, message});
}); });
ondone({ ondone({
@ -833,42 +845,57 @@ let gs_kiri_sla = exports;
layerBytes = width * height, layerBytes = width * height,
small = conf.small, small = conf.small,
large = conf.large, large = conf.large,
slices = conf.slices,
subcount = process.slaAntiAlias || 1, subcount = process.slaAntiAlias || 1,
masks = []; masks = [],
coded;
let d = 8 / subcount; if (legacy) {
for (let i=0; i<subcount; i++) { let d = 8 / subcount;
masks.push((1 << (8 - i * d)) - 1); for (let i=0; i<subcount; i++) {
} masks.push((1 << (8 - i * d)) - 1);
let ccl = 0;
let tcl = conf.lines.length * subcount;
let converted = conf.lines.map((line, index) => {
let count = line.length;
let lineDV = new DataView(line.buffer);
let bits = new Uint8Array(line.length);
let bitsDV = new DataView(bits.buffer);
let subs = [{ data: bits, view: bitsDV }];
for (let sl=1; sl<subcount; sl++) {
bits = bits.slice();
bitsDV = new DataView(bits.buffer);
subs.push({ data: bits, view: bitsDV });
} }
// use R from RGB since that was painted on the canvas let ccl = 0;
for (let s=0; s<subcount; s++) { let tcl = conf.lines.length * subcount;
let view = subs[s].view; let converted = conf.lines.map((line, index) => {
let mask = masks[s]; let count = line.length;
for (let i = 0; i < count; i++) { let lineDV = new DataView(line.buffer);
let dv = lineDV.getUint8(i); let bits = new Uint8Array(line.length);
view.setUint8(i, (dv / subcount) & mask ? 1 : 0); let bitsDV = new DataView(bits.buffer);
let subs = [{ data: bits, view: bitsDV }];
for (let sl=1; sl<subcount; sl++) {
bits = bits.slice();
bitsDV = new DataView(bits.buffer);
subs.push({ data: bits, view: bitsDV });
} }
progress((ccl++/tcl) * 0.4, `layer_convert`); // use R from RGB since that was painted on the canvas
} for (let s=0; s<subcount; s++) {
return { subs }; let view = subs[s].view;
}); let mask = masks[s];
for (let i = 0; i < count; i++) {
let dv = lineDV.getUint8(i);
view.setUint8(i, (dv / subcount) & mask ? 1 : 0);
}
progress((ccl++/tcl) * 0.4, `layer_convert`);
}
return { subs };
});
coded = encodeLayers(converted, "photon", (pro => {
progress(pro * 0.4 + 0.4, "layer_encode");
}));
} else {
let codedlen = slices.reduce((t,l) => {
return t + l.reduce((t,a) => {
return t + a.length
}, 0);
}, 0);
coded = {
layers: slices.map(slice => { return { sublayers: slice }}),
length: codedlen
};
}
let coded = encodeLayers(converted, "photon", (pro => {
progress(pro * 0.4 + 0.4, "layer_encode");
}));
let buflen = 3000 + coded.length + (layerCount * subcount * 28) + small.byteLength + large.byteLength; let buflen = 3000 + coded.length + (layerCount * subcount * 28) + small.byteLength + large.byteLength;
let filebuf = new ArrayBuffer(buflen); let filebuf = new ArrayBuffer(buflen);
let filedat = new DataWriter(new DataView(filebuf)); let filedat = new DataWriter(new DataView(filebuf));
@ -972,27 +999,41 @@ let gs_kiri_sla = exports;
device = printset.device, device = printset.device,
width = conf.width, width = conf.width,
height = conf.height, height = conf.height,
slices = conf.slices,
layerCount = conf.lines.length, layerCount = conf.lines.length,
layerBytes = width * height; layerBytes = width * height,
coded;
let converted = conf.lines.map((line, index) => { if (legacy) {
let count = line.length / 4; let converted = conf.lines.map((line, index) => {
let bits = new Uint8Array(line.length / 4); let count = line.length / 4;
let bitsDV = new DataView(bits.buffer); let bits = new Uint8Array(line.length / 4);
let lineDV = new DataView(line.buffer); let bitsDV = new DataView(bits.buffer);
// reduce RGB to R = 0||1 let lineDV = new DataView(line.buffer);
for (let i = 0; i < count; i++) { // reduce RGB to R = 0||1
// defeat anti-aliasing for the moment for (let i = 0; i < count; i++) {
bitsDV.setUint8(i, lineDV.getUint8(i * 4) > 0 ? 1 : 0); // defeat anti-aliasing for the moment
} bitsDV.setUint8(i, lineDV.getUint8(i * 4) > 0 ? 1 : 0);
progress(index / conf.lines.length); }
return { subs: [{ progress(index / conf.lines.length);
exposureTime: process.slaLayerOn, return { subs: [{
data: bits exposureTime: process.slaLayerOn,
}] }; data: bits
}); }] };
});
coded = encodeLayers(converted, "photons");
} else {
let codedlen = slices.reduce((t,l) => {
return t + l.reduce((t,a) => {
return t + a.length
}, 0);
}, 0);
coded = {
layers: slices.map(slice => { return { sublayers: slice }}),
length: codedlen
};
}
let coded = encodeLayers(converted, "photons");
let filebuf = new ArrayBuffer(75366 + coded.length + 28 * layerCount); let filebuf = new ArrayBuffer(75366 + coded.length + 28 * layerCount);
let filedat = new DataView(filebuf); let filedat = new DataView(filebuf);
let filePos = 0; let filePos = 0;
@ -1282,13 +1323,14 @@ let gs_kiri_sla = exports;
self.wasm = { self.wasm = {
heap, heap,
memory: exports.memory, memory: exports.memory,
render: exports.render render: exports.render,
rle_encode: exports.rle_encode
}; };
// console.log({heap}); // console.log({heap});
}); });
self.renderLayerWasm = function renderLayer(params) { self.renderLayerWasm = function renderLayer(params) {
let { width, height, index, widgets, scaleX, scaleY } = params; let { width, height, index, widgets, scaleX, scaleY, masks } = params;
let width2 = width / 2, height2 = height / 2; let width2 = width / 2, height2 = height / 2;
let array = []; let array = [];
let count = 0; let count = 0;
@ -1359,10 +1401,15 @@ let gs_kiri_sla = exports;
writePoly(writer, poly); writePoly(writer, poly);
} }
let out = wasm.render(0, imagelen, 0); wasm.render(0, imagelen, 0);
let data = wasm.heap.slice(0, imagelen); let image = wasm.heap.slice(0, imagelen), layers = [];
return { data: data, end: count === 0 }; for (let l=0; l<masks.length; l++) {
let rlelen = wasm.rle_encode(0, 0, imagelen, masks[l], imagelen, 0);
layers.push(wasm.heap.slice(imagelen, imagelen + rlelen));
}
return { image, layers, end: count === 0 };
} }
function polyout(poly, ctx, opt) { function polyout(poly, ctx, opt) {
@ -1414,7 +1461,7 @@ let gs_kiri_sla = exports;
for (let i=0; i<red.length; i++) { for (let i=0; i<red.length; i++) {
red[i] = data[i*4]; red[i] = data[i*4];
} }
return { data: red, end: count === 0 }; return { image: red, end: count === 0 };
} }
} }

View file

@ -146,6 +146,12 @@ void rasterize_poly(unsigned char *m, Uint32 o, Uint32 height) {
readoff = nextpoly; readoff = nextpoly;
} }
/**
* m = memory base pointer
* i = input memory location (polygon records)
* o = output memory location (for raster)
* returns last read position in memory
*/
EMSCRIPTEN_KEEPALIVE EMSCRIPTEN_KEEPALIVE
Uint32 render(unsigned char *m, Uint32 i, Uint32 o) { Uint32 render(unsigned char *m, Uint32 i, Uint32 o) {
struct info *info = (struct info *)(m + i); struct info *info = (struct info *)(m + i);
@ -160,5 +166,52 @@ Uint32 render(unsigned char *m, Uint32 i, Uint32 o) {
rasterize_poly(m, o, info->height); rasterize_poly(m, o, info->height);
} }
return 1; return readoff;
}
Uint8 rle_byte(Uint8 color, Uint8 count, Uint8 type) {
if (type == 0) {
return (count & 0x7f) | ((color << 7) & 0x80);
} else {
Uint8 run = count - 1;
return
(run & 1 ? 128 : 0) |
(run & 2 ? 64 : 0) |
(run & 4 ? 32 : 0) |
(run & 8 ? 16 : 0) |
(run & 16 ? 8 : 0) |
(run & 32 ? 4 : 0) |
(run & 64 ? 2 : 0) | color;
}
}
/**
* mem = memory base pointer
* in = input memory location (raster)
* ilen = input raster length in bytes
* out = output memory location (for rle-encoded image)
* type = 0=photon, 1=photons
* returns length of rle-encoded image
*/
EMSCRIPTEN_KEEPALIVE
Uint32 rle_encode(unsigned char *mem, Uint32 in, Uint32 ilen, Uint8 mask, Uint32 out, Uint8 type) {
Uint8 color = (mem[in++] & mask) ? 1 : 0; // current color
Uint8 count = 1; // number of color matches
Uint8 cmax = type == 0 ? 125 : 128; // count max
Uint8 next; // next color
Uint32 opos = out;
while (--ilen > 0) {
next = (mem[in++] & mask) ? 1 : 0;
if (color != next || count == cmax) {
mem[opos++] = rle_byte(color, count, type);
count = 0;
}
count++;
color = next;
}
if (count > 0) {
mem[opos++] = rle_byte(color, count, type);
}
return opos - out;
} }

Binary file not shown.