Created
May 13, 2019 18:24
-
-
Save robertleeplummerjr/52b31665faf62662dd38d0e51e6cc7a1 to your computer and use it in GitHub Desktop.
100-over.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function kernel(context = null) { | |
const gl = context; | |
const glVariables0 = gl.getExtension('OES_texture_float'); | |
const glVariables1 = gl.getExtension('OES_texture_float_linear'); | |
const glVariables2 = gl.getExtension('OES_element_index_uint'); | |
const glVariables3 = gl.getExtension('WEBGL_draw_buffers'); | |
const glVariables4 = gl.getExtension('WEBGL_color_buffer_float'); | |
const glVariable5 = gl.createTexture(); | |
const glVariable6 = gl.createTexture(); | |
gl.enable(gl.SCISSOR_TEST); | |
gl.viewport(0, 0, 1, 1); | |
const glVariable7 = gl.createShader(gl.VERTEX_SHADER); | |
gl.shaderSource(glVariable7, `precision highp float; | |
precision highp int; | |
precision highp sampler2D; | |
attribute vec2 aPos; | |
attribute vec2 aTexCoord; | |
varying vec2 vTexCoord; | |
uniform vec2 ratio; | |
void main(void) { | |
gl_Position = vec4((aPos + vec2(1)) * ratio + vec2(-1), 0, 1); | |
vTexCoord = aTexCoord; | |
}`); | |
gl.compileShader(glVariable7); | |
const glVariable8 = gl.createShader(gl.FRAGMENT_SHADER); | |
gl.shaderSource(glVariable8, `#extension GL_EXT_draw_buffers : require | |
precision highp float; | |
precision highp int; | |
precision highp sampler2D; | |
const int LOOP_MAX = 1000; | |
uniform ivec3 uOutputDim; | |
uniform ivec2 uTexSize; | |
varying vec2 vTexCoord; | |
vec4 round(vec4 x) { | |
return floor(x + 0.5); | |
} | |
float round(float x) { | |
return floor(x + 0.5); | |
} | |
vec2 integerMod(vec2 x, float y) { | |
vec2 res = floor(mod(x, y)); | |
return res * step(1.0 - floor(y), -res); | |
} | |
vec3 integerMod(vec3 x, float y) { | |
vec3 res = floor(mod(x, y)); | |
return res * step(1.0 - floor(y), -res); | |
} | |
vec4 integerMod(vec4 x, vec4 y) { | |
vec4 res = floor(mod(x, y)); | |
return res * step(1.0 - floor(y), -res); | |
} | |
float integerMod(float x, float y) { | |
float res = floor(mod(x, y)); | |
return res * (res > floor(y) - 1.0 ? 0.0 : 1.0); | |
} | |
int integerMod(int x, int y) { | |
return x - (y * int(x / y)); | |
} | |
float div_with_int_check(float x, float y) { | |
if (floor(x) == x && floor(y) == y && integerMod(x, y) == 0.0) { | |
return float(int(x)/int(y)); | |
} | |
return x / y; | |
} | |
// Here be dragons! | |
// DO NOT OPTIMIZE THIS CODE | |
// YOU WILL BREAK SOMETHING ON SOMEBODY'S MACHINE | |
// LEAVE IT AS IT IS, LEST YOU WASTE YOUR OWN TIME | |
const vec2 MAGIC_VEC = vec2(1.0, -256.0); | |
const vec4 SCALE_FACTOR = vec4(1.0, 256.0, 65536.0, 0.0); | |
const vec4 SCALE_FACTOR_INV = vec4(1.0, 0.00390625, 0.0000152587890625, 0.0); // 1, 1/256, 1/65536 | |
float decode32(vec4 texel) { | |
texel *= 255.0; | |
vec2 gte128; | |
gte128.x = texel.b >= 128.0 ? 1.0 : 0.0; | |
gte128.y = texel.a >= 128.0 ? 1.0 : 0.0; | |
float exponent = 2.0 * texel.a - 127.0 + dot(gte128, MAGIC_VEC); | |
float res = exp2(round(exponent)); | |
texel.b = texel.b - 128.0 * gte128.x; | |
res = dot(texel, SCALE_FACTOR) * exp2(round(exponent-23.0)) + res; | |
res *= gte128.y * -2.0 + 1.0; | |
return res; | |
} | |
float decode16(vec4 texel, int index) { | |
int channel = integerMod(index, 2); | |
if (channel == 0) return texel.r * 255.0 + texel.g * 65280.0; | |
if (channel == 1) return texel.b * 255.0 + texel.a * 65280.0; | |
return 0.0; | |
} | |
float decode8(vec4 texel, int index) { | |
int channel = integerMod(index, 4); | |
if (channel == 0) return texel.r * 255.0; | |
if (channel == 1) return texel.g * 255.0; | |
if (channel == 2) return texel.b * 255.0; | |
if (channel == 3) return texel.a * 255.0; | |
return 0.0; | |
} | |
vec4 encode32(float f) { | |
float F = abs(f); | |
float sign = f < 0.0 ? 1.0 : 0.0; | |
float exponent = floor(log2(F)); | |
float mantissa = (exp2(-exponent) * F); | |
// exponent += floor(log2(mantissa)); | |
vec4 texel = vec4(F * exp2(23.0-exponent)) * SCALE_FACTOR_INV; | |
texel.rg = integerMod(texel.rg, 256.0); | |
texel.b = integerMod(texel.b, 128.0); | |
texel.a = exponent*0.5 + 63.5; | |
texel.ba += vec2(integerMod(exponent+127.0, 2.0), sign) * 128.0; | |
texel = floor(texel); | |
texel *= 0.003921569; // 1/255 | |
return texel; | |
} | |
// Dragons end here | |
int index; | |
ivec3 threadId; | |
ivec3 indexTo3D(int idx, ivec3 texDim) { | |
int z = int(idx / (texDim.x * texDim.y)); | |
idx -= z * int(texDim.x * texDim.y); | |
int y = int(idx / texDim.x); | |
int x = int(integerMod(idx, texDim.x)); | |
return ivec3(x, y, z); | |
} | |
float get32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
ivec3 xyz = ivec3(x, y, z); | |
int index = xyz.x + texDim.x * (xyz.y + texDim.y * xyz.z); | |
int w = texSize.x; | |
vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5; | |
vec4 texel = texture2D(tex, st / vec2(texSize)); | |
return decode32(texel); | |
} | |
float get16(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
ivec3 xyz = ivec3(x, y, z); | |
int index = xyz.x + texDim.x * (xyz.y + texDim.y * xyz.z); | |
int w = texSize.x * 2; | |
vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5; | |
vec4 texel = texture2D(tex, st / vec2(texSize.x * 2, texSize.y)); | |
return decode16(texel, index); | |
} | |
float get8(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
ivec3 xyz = ivec3(x, y, z); | |
int index = xyz.x + texDim.x * (xyz.y + texDim.y * xyz.z); | |
int w = texSize.x * 4; | |
vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5; | |
vec4 texel = texture2D(tex, st / vec2(texSize.x * 4, texSize.y)); | |
return decode8(texel, index); | |
} | |
float getMemoryOptimized32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
ivec3 xyz = ivec3(x, y, z); | |
int index = xyz.x + texDim.x * (xyz.y + texDim.y * xyz.z); | |
int channel = integerMod(index, 4); | |
index = index / 4; | |
int w = texSize.x; | |
vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5; | |
vec4 texel = texture2D(tex, st / vec2(texSize)); | |
if (channel == 0) return texel.r; | |
if (channel == 1) return texel.g; | |
if (channel == 2) return texel.b; | |
if (channel == 3) return texel.a; | |
return 0.0; | |
} | |
vec4 getImage2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
ivec3 xyz = ivec3(x, y, z); | |
int index = xyz.x + texDim.x * (xyz.y + texDim.y * xyz.z); | |
int w = texSize.x; | |
vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5; | |
return texture2D(tex, st / vec2(texSize)); | |
} | |
float getFloatFromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
vec4 result = getImage2D(tex, texSize, texDim, z, y, x); | |
return result[0]; | |
} | |
vec2 getVec2FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
vec4 result = getImage2D(tex, texSize, texDim, z, y, x); | |
return vec2(result[0], result[1]); | |
} | |
vec3 getVec3FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
vec4 result = getImage2D(tex, texSize, texDim, z, y, x); | |
return vec3(result[0], result[1], result[2]); | |
} | |
vec4 getVec4FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
return getImage2D(tex, texSize, texDim, z, y, x); | |
} | |
vec4 actualColor; | |
void color(float r, float g, float b, float a) { | |
actualColor = vec4(r,g,b,a); | |
} | |
void color(float r, float g, float b) { | |
color(r,g,b,1.0); | |
} | |
void color(sampler2D image) { | |
actualColor = texture2D(image, vTexCoord); | |
} | |
uniform sampler2D user_a; | |
ivec2 user_aSize = ivec2(1, 1); | |
ivec3 user_aDim = ivec3(1, 1, 1); | |
uniform sampler2D user_b; | |
ivec2 user_bSize = ivec2(1, 1); | |
ivec3 user_bDim = ivec3(1, 1, 1); | |
float kernelResult; | |
float subKernelResult_value1 = 0.0; | |
float subKernelResult_value2 = 0.0; | |
float value2(float user_value) { | |
subKernelResult_value2 = (user_value+50.0);return subKernelResult_value2; | |
} | |
float value1(float user_value) { | |
subKernelResult_value1 = (user_value+10.0);return subKernelResult_value1; | |
} | |
void kernel() { | |
value1(get32(user_a, user_aSize, user_aDim, 0, 0, threadId.x)); | |
kernelResult = (value2(get32(user_b, user_bSize, user_bDim, 0, 0, threadId.x))+100.0);return; | |
} | |
void main(void) { | |
index = int(vTexCoord.s * float(uTexSize.x)) + int(vTexCoord.t * float(uTexSize.y)) * uTexSize.x; | |
threadId = indexTo3D(index, uOutputDim); | |
kernel(); | |
gl_FragData[0] = encode32(kernelResult); | |
gl_FragData[1] = encode32(subKernelResult_value1); | |
gl_FragData[2] = encode32(subKernelResult_value2); | |
}`); | |
gl.compileShader(glVariable8); | |
const glVariable9 = gl.getShaderParameter(glVariable7, gl.COMPILE_STATUS); | |
const glVariable10 = gl.getShaderParameter(glVariable8, gl.COMPILE_STATUS); | |
const glVariable11 = gl.createProgram(); | |
gl.attachShader(glVariable11, glVariable7); | |
gl.attachShader(glVariable11, glVariable8); | |
gl.linkProgram(glVariable11); | |
const glVariable12 = gl.createFramebuffer(); | |
const glVariable13 = gl.createBuffer(); | |
gl.bindBuffer(gl.ARRAY_BUFFER, glVariable13); | |
gl.bufferData(gl.ARRAY_BUFFER, 64, gl.STATIC_DRAW); | |
const glVariable14 = new Float32Array([-1,-1,1,-1,-1,1,1,1]); | |
gl.bufferSubData(gl.ARRAY_BUFFER, 0, glVariable14); | |
const glVariable15 = new Float32Array([0,0,1,0,0,1,1,1]); | |
gl.bufferSubData(gl.ARRAY_BUFFER, 32, glVariable15); | |
const glVariable16 = gl.getAttribLocation(glVariable11, 'aPos'); | |
gl.enableVertexAttribArray(glVariable16); | |
gl.vertexAttribPointer(glVariable16, 2, gl.FLOAT, false, 0, 0); | |
const glVariable17 = gl.getAttribLocation(glVariable11, 'aTexCoord'); | |
gl.enableVertexAttribArray(glVariable17); | |
gl.vertexAttribPointer(glVariable17, 2, gl.FLOAT, false, 0, 32); | |
gl.bindFramebuffer(gl.FRAMEBUFFER, glVariable12); | |
gl.useProgram(glVariable11); | |
/** start of injected functions **/ | |
function flattenTo(array, target) { | |
if (/*utils.*/isArray(array[0])) { | |
if (/*utils.*/isArray(array[0][0])) { | |
/*utils.*/flatten3dArrayTo(array, target); | |
} else { | |
/*utils.*/flatten2dArrayTo(array, target); | |
} | |
} else { | |
target.set(array); | |
} | |
} | |
function flatten2dArrayTo(array, target) { | |
let offset = 0; | |
for (let y = 0; y < array.length; y++) { | |
target.set(array[y], offset); | |
offset += array[y].length; | |
} | |
} | |
function flatten3dArrayTo(array, target) { | |
let offset = 0; | |
for (let z = 0; z < array.length; z++) { | |
for (let y = 0; y < array[z].length; y++) { | |
target.set(array[z][y], offset); | |
offset += array[z][y].length; | |
} | |
} | |
} | |
function isArray(array) { | |
return !isNaN(array.length); | |
} | |
class Texture { | |
constructor(settings) { | |
const { | |
texture, | |
size, | |
dimensions, | |
output, | |
context, | |
gpu, | |
type = 'NumberTexture', | |
} = settings; | |
if (!output) throw new Error('settings property "output" required.'); | |
if (!context) throw new Error('settings property "context" required.'); | |
this.texture = texture; | |
this.size = size; | |
this.dimensions = dimensions; | |
this.output = output; | |
this.context = context; | |
this.gpu = gpu; | |
this.kernel = null; | |
this.type = type; | |
} | |
toArray(gpu) { | |
let { | |
kernel | |
} = this; | |
if (kernel) return kernel(this); | |
gpu = gpu || this.gpu; | |
if (!gpu) throw new Error('settings property "gpu" or argument required.'); | |
kernel = gpu.createKernel(function(x) { | |
return x[this.thread.z][this.thread.y][this.thread.x]; | |
}, { | |
output: this.output, | |
precision: this.getPrecision(), | |
optimizeFloatMemory: this.type === 'MemoryOptimizedNumberTexture', | |
}); | |
this.kernel = kernel; | |
return kernel(this); | |
} | |
getPrecision() { | |
switch (this.type) { | |
case 'NumberTexture': | |
return 'unsigned'; | |
case 'MemoryOptimizedNumberTexture': | |
case 'ArrayTexture(1)': | |
case 'ArrayTexture(2)': | |
case 'ArrayTexture(3)': | |
case 'ArrayTexture(4)': | |
return 'single'; | |
default: | |
throw new Error('Unknown texture type'); | |
} | |
} | |
delete() { | |
return this.context.deleteTexture(this.texture); | |
} | |
} | |
const renderOutput = function renderTexture() { | |
return new Texture({ | |
texture: null, | |
size: new Int32Array([1,1]), | |
dimensions: new Int32Array([1,1,1]), | |
output: new Int32Array(undefined), | |
context: gl, | |
gpu: null, | |
type: 'NumberTexture', | |
}); | |
}; | |
/** end of injected functions **/ | |
return function (a, b) { | |
/** start setup uploads for kernel values **/ | |
const uploadValue_a = a; | |
const uploadValue_b = b; | |
/** end setup uploads for kernel values **/ | |
gl.useProgram(glVariable11); | |
gl.scissor(0, 0, 1, 1); | |
const glVariable18 = gl.getUniformLocation(glVariable11, 'uOutputDim'); | |
const glVariable19 = new Array(1,1,1); | |
gl.uniform3iv(glVariable18, glVariable19); | |
const glVariable20 = gl.getUniformLocation(glVariable11, 'uTexSize'); | |
const glVariable21 = new Int32Array([1,1]); | |
gl.uniform2iv(glVariable20, glVariable21); | |
const glVariable22 = gl.getUniformLocation(glVariable11, 'ratio'); | |
gl.uniform2f(glVariable22, 1, 1); | |
gl.bindFramebuffer(gl.FRAMEBUFFER, glVariable12); | |
const glVariable23 = gl.createTexture(); | |
gl.activeTexture(33986); | |
gl.bindTexture(gl.TEXTURE_2D, glVariable23); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); | |
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, glVariable23, 0); | |
const glVariable24 = gl.createTexture(); | |
gl.activeTexture(33986); | |
gl.bindTexture(gl.TEXTURE_2D, glVariable24); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); | |
gl.framebufferTexture2D(gl.FRAMEBUFFER, 36065, gl.TEXTURE_2D, glVariable24, 0); | |
const glVariable25 = gl.createTexture(); | |
gl.activeTexture(33987); | |
gl.bindTexture(gl.TEXTURE_2D, glVariable25); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); | |
gl.framebufferTexture2D(gl.FRAMEBUFFER, 36066, gl.TEXTURE_2D, glVariable25, 0); | |
glVariables3.drawBuffersWEBGL([gl.COLOR_ATTACHMENT0, 36065, 36066]); | |
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); | |
return renderOutput(undefined); | |
}; } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function kernel(context = null) { | |
const gl = context; | |
const glVariables0 = gl.getExtension('OES_texture_float'); | |
const glVariables1 = gl.getExtension('OES_texture_float_linear'); | |
const glVariables2 = gl.getExtension('OES_element_index_uint'); | |
const glVariables3 = gl.getExtension('WEBGL_draw_buffers'); | |
const glVariables4 = gl.getExtension('WEBGL_color_buffer_float'); | |
const glVariable5 = gl.createTexture(); | |
const glVariable6 = gl.createTexture(); | |
gl.enable(gl.SCISSOR_TEST); | |
gl.viewport(0, 0, 1, 1); | |
const glVariable7 = gl.createShader(gl.VERTEX_SHADER); | |
gl.shaderSource(glVariable7, `precision highp float; | |
precision highp int; | |
precision highp sampler2D; | |
attribute vec2 aPos; | |
attribute vec2 aTexCoord; | |
varying vec2 vTexCoord; | |
uniform vec2 ratio; | |
void main(void) { | |
gl_Position = vec4((aPos + vec2(1)) * ratio + vec2(-1), 0, 1); | |
vTexCoord = aTexCoord; | |
}`); | |
gl.compileShader(glVariable7); | |
const glVariable8 = gl.createShader(gl.FRAGMENT_SHADER); | |
gl.shaderSource(glVariable8, `#extension GL_EXT_draw_buffers : require | |
precision highp float; | |
precision highp int; | |
precision highp sampler2D; | |
const int LOOP_MAX = 1000; | |
uniform ivec3 uOutputDim; | |
uniform ivec2 uTexSize; | |
varying vec2 vTexCoord; | |
vec4 round(vec4 x) { | |
return floor(x + 0.5); | |
} | |
float round(float x) { | |
return floor(x + 0.5); | |
} | |
vec2 integerMod(vec2 x, float y) { | |
vec2 res = floor(mod(x, y)); | |
return res * step(1.0 - floor(y), -res); | |
} | |
vec3 integerMod(vec3 x, float y) { | |
vec3 res = floor(mod(x, y)); | |
return res * step(1.0 - floor(y), -res); | |
} | |
vec4 integerMod(vec4 x, vec4 y) { | |
vec4 res = floor(mod(x, y)); | |
return res * step(1.0 - floor(y), -res); | |
} | |
float integerMod(float x, float y) { | |
float res = floor(mod(x, y)); | |
return res * (res > floor(y) - 1.0 ? 0.0 : 1.0); | |
} | |
int integerMod(int x, int y) { | |
return x - (y * int(x / y)); | |
} | |
float div_with_int_check(float x, float y) { | |
if (floor(x) == x && floor(y) == y && integerMod(x, y) == 0.0) { | |
return float(int(x)/int(y)); | |
} | |
return x / y; | |
} | |
// Here be dragons! | |
// DO NOT OPTIMIZE THIS CODE | |
// YOU WILL BREAK SOMETHING ON SOMEBODY'S MACHINE | |
// LEAVE IT AS IT IS, LEST YOU WASTE YOUR OWN TIME | |
const vec2 MAGIC_VEC = vec2(1.0, -256.0); | |
const vec4 SCALE_FACTOR = vec4(1.0, 256.0, 65536.0, 0.0); | |
const vec4 SCALE_FACTOR_INV = vec4(1.0, 0.00390625, 0.0000152587890625, 0.0); // 1, 1/256, 1/65536 | |
float decode32(vec4 texel) { | |
texel *= 255.0; | |
vec2 gte128; | |
gte128.x = texel.b >= 128.0 ? 1.0 : 0.0; | |
gte128.y = texel.a >= 128.0 ? 1.0 : 0.0; | |
float exponent = 2.0 * texel.a - 127.0 + dot(gte128, MAGIC_VEC); | |
float res = exp2(round(exponent)); | |
texel.b = texel.b - 128.0 * gte128.x; | |
res = dot(texel, SCALE_FACTOR) * exp2(round(exponent-23.0)) + res; | |
res *= gte128.y * -2.0 + 1.0; | |
return res; | |
} | |
float decode16(vec4 texel, int index) { | |
int channel = integerMod(index, 2); | |
if (channel == 0) return texel.r * 255.0 + texel.g * 65280.0; | |
if (channel == 1) return texel.b * 255.0 + texel.a * 65280.0; | |
return 0.0; | |
} | |
float decode8(vec4 texel, int index) { | |
int channel = integerMod(index, 4); | |
if (channel == 0) return texel.r * 255.0; | |
if (channel == 1) return texel.g * 255.0; | |
if (channel == 2) return texel.b * 255.0; | |
if (channel == 3) return texel.a * 255.0; | |
return 0.0; | |
} | |
vec4 encode32(float f) { | |
float F = abs(f); | |
float sign = f < 0.0 ? 1.0 : 0.0; | |
float exponent = floor(log2(F)); | |
float mantissa = (exp2(-exponent) * F); | |
// exponent += floor(log2(mantissa)); | |
vec4 texel = vec4(F * exp2(23.0-exponent)) * SCALE_FACTOR_INV; | |
texel.rg = integerMod(texel.rg, 256.0); | |
texel.b = integerMod(texel.b, 128.0); | |
texel.a = exponent*0.5 + 63.5; | |
texel.ba += vec2(integerMod(exponent+127.0, 2.0), sign) * 128.0; | |
texel = floor(texel); | |
texel *= 0.003921569; // 1/255 | |
return texel; | |
} | |
// Dragons end here | |
int index; | |
ivec3 threadId; | |
ivec3 indexTo3D(int idx, ivec3 texDim) { | |
int z = int(idx / (texDim.x * texDim.y)); | |
idx -= z * int(texDim.x * texDim.y); | |
int y = int(idx / texDim.x); | |
int x = int(integerMod(idx, texDim.x)); | |
return ivec3(x, y, z); | |
} | |
float get32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
ivec3 xyz = ivec3(x, y, z); | |
int index = xyz.x + texDim.x * (xyz.y + texDim.y * xyz.z); | |
int w = texSize.x; | |
vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5; | |
vec4 texel = texture2D(tex, st / vec2(texSize)); | |
return decode32(texel); | |
} | |
float get16(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
ivec3 xyz = ivec3(x, y, z); | |
int index = xyz.x + texDim.x * (xyz.y + texDim.y * xyz.z); | |
int w = texSize.x * 2; | |
vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5; | |
vec4 texel = texture2D(tex, st / vec2(texSize.x * 2, texSize.y)); | |
return decode16(texel, index); | |
} | |
float get8(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
ivec3 xyz = ivec3(x, y, z); | |
int index = xyz.x + texDim.x * (xyz.y + texDim.y * xyz.z); | |
int w = texSize.x * 4; | |
vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5; | |
vec4 texel = texture2D(tex, st / vec2(texSize.x * 4, texSize.y)); | |
return decode8(texel, index); | |
} | |
float getMemoryOptimized32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
ivec3 xyz = ivec3(x, y, z); | |
int index = xyz.x + texDim.x * (xyz.y + texDim.y * xyz.z); | |
int channel = integerMod(index, 4); | |
index = index / 4; | |
int w = texSize.x; | |
vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5; | |
vec4 texel = texture2D(tex, st / vec2(texSize)); | |
if (channel == 0) return texel.r; | |
if (channel == 1) return texel.g; | |
if (channel == 2) return texel.b; | |
if (channel == 3) return texel.a; | |
return 0.0; | |
} | |
vec4 getImage2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
ivec3 xyz = ivec3(x, y, z); | |
int index = xyz.x + texDim.x * (xyz.y + texDim.y * xyz.z); | |
int w = texSize.x; | |
vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5; | |
return texture2D(tex, st / vec2(texSize)); | |
} | |
float getFloatFromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
vec4 result = getImage2D(tex, texSize, texDim, z, y, x); | |
return result[0]; | |
} | |
vec2 getVec2FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
vec4 result = getImage2D(tex, texSize, texDim, z, y, x); | |
return vec2(result[0], result[1]); | |
} | |
vec3 getVec3FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
vec4 result = getImage2D(tex, texSize, texDim, z, y, x); | |
return vec3(result[0], result[1], result[2]); | |
} | |
vec4 getVec4FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) { | |
return getImage2D(tex, texSize, texDim, z, y, x); | |
} | |
vec4 actualColor; | |
void color(float r, float g, float b, float a) { | |
actualColor = vec4(r,g,b,a); | |
} | |
void color(float r, float g, float b) { | |
color(r,g,b,1.0); | |
} | |
void color(sampler2D image) { | |
actualColor = texture2D(image, vTexCoord); | |
} | |
uniform sampler2D user_a; | |
ivec2 user_aSize = ivec2(2, 2); | |
ivec3 user_aDim = ivec3(1, 1, 1); | |
uniform sampler2D user_b; | |
ivec2 user_bSize = ivec2(2, 2); | |
ivec3 user_bDim = ivec3(1, 1, 1); | |
float kernelResult; | |
float subKernelResult_value1 = 0.0; | |
float subKernelResult_value2 = 0.0; | |
float value2(float user_value) { | |
subKernelResult_value2 = (user_value+50.0);return subKernelResult_value2; | |
} | |
float value1(float user_value) { | |
subKernelResult_value1 = (user_value+10.0);return subKernelResult_value1; | |
} | |
void kernel() { | |
value1(get32(user_a, user_aSize, user_aDim, 0, 0, threadId.x)); | |
kernelResult = (value2(get32(user_b, user_bSize, user_bDim, 0, 0, threadId.x))+100.0);return; | |
} | |
void main(void) { | |
index = int(vTexCoord.s * float(uTexSize.x)) + int(vTexCoord.t * float(uTexSize.y)) * uTexSize.x; | |
threadId = indexTo3D(index, uOutputDim); | |
kernel(); | |
gl_FragData[0] = encode32(kernelResult); | |
gl_FragData[1] = encode32(subKernelResult_value1); | |
gl_FragData[2] = encode32(subKernelResult_value2); | |
}`); | |
gl.compileShader(glVariable8); | |
const glVariable9 = gl.getShaderParameter(glVariable7, gl.COMPILE_STATUS); | |
const glVariable10 = gl.getShaderParameter(glVariable8, gl.COMPILE_STATUS); | |
const glVariable11 = gl.createProgram(); | |
gl.attachShader(glVariable11, glVariable7); | |
gl.attachShader(glVariable11, glVariable8); | |
gl.linkProgram(glVariable11); | |
const glVariable12 = gl.createFramebuffer(); | |
const glVariable13 = gl.createBuffer(); | |
gl.bindBuffer(gl.ARRAY_BUFFER, glVariable13); | |
gl.bufferData(gl.ARRAY_BUFFER, 64, gl.STATIC_DRAW); | |
const glVariable14 = new Float32Array([-1,-1,1,-1,-1,1,1,1]); | |
gl.bufferSubData(gl.ARRAY_BUFFER, 0, glVariable14); | |
const glVariable15 = new Float32Array([0,0,1,0,0,1,1,1]); | |
gl.bufferSubData(gl.ARRAY_BUFFER, 32, glVariable15); | |
const glVariable16 = gl.getAttribLocation(glVariable11, 'aPos'); | |
gl.enableVertexAttribArray(glVariable16); | |
gl.vertexAttribPointer(glVariable16, 2, gl.FLOAT, false, 0, 0); | |
const glVariable17 = gl.getAttribLocation(glVariable11, 'aTexCoord'); | |
gl.enableVertexAttribArray(glVariable17); | |
gl.vertexAttribPointer(glVariable17, 2, gl.FLOAT, false, 0, 32); | |
gl.bindFramebuffer(gl.FRAMEBUFFER, glVariable12); | |
gl.useProgram(glVariable11); | |
/** start of injected functions **/ | |
function flattenTo(array, target) { | |
if (/*utils.*/isArray(array[0])) { | |
if (/*utils.*/isArray(array[0][0])) { | |
/*utils.*/flatten3dArrayTo(array, target); | |
} else { | |
/*utils.*/flatten2dArrayTo(array, target); | |
} | |
} else { | |
target.set(array); | |
} | |
} | |
function flatten2dArrayTo(array, target) { | |
let offset = 0; | |
for (let y = 0; y < array.length; y++) { | |
target.set(array[y], offset); | |
offset += array[y].length; | |
} | |
} | |
function flatten3dArrayTo(array, target) { | |
let offset = 0; | |
for (let z = 0; z < array.length; z++) { | |
for (let y = 0; y < array[z].length; y++) { | |
target.set(array[z][y], offset); | |
offset += array[z][y].length; | |
} | |
} | |
} | |
function isArray(array) { | |
return !isNaN(array.length); | |
} | |
class Texture { | |
constructor(settings) { | |
const { | |
texture, | |
size, | |
dimensions, | |
output, | |
context, | |
gpu, | |
type = 'NumberTexture', | |
} = settings; | |
if (!output) throw new Error('settings property "output" required.'); | |
if (!context) throw new Error('settings property "context" required.'); | |
this.texture = texture; | |
this.size = size; | |
this.dimensions = dimensions; | |
this.output = output; | |
this.context = context; | |
this.gpu = gpu; | |
this.kernel = null; | |
this.type = type; | |
} | |
toArray(gpu) { | |
let { | |
kernel | |
} = this; | |
if (kernel) return kernel(this); | |
gpu = gpu || this.gpu; | |
if (!gpu) throw new Error('settings property "gpu" or argument required.'); | |
kernel = gpu.createKernel(function(x) { | |
return x[this.thread.z][this.thread.y][this.thread.x]; | |
}, { | |
output: this.output, | |
precision: this.getPrecision(), | |
optimizeFloatMemory: this.type === 'MemoryOptimizedNumberTexture', | |
}); | |
this.kernel = kernel; | |
return kernel(this); | |
} | |
getPrecision() { | |
switch (this.type) { | |
case 'NumberTexture': | |
return 'unsigned'; | |
case 'MemoryOptimizedNumberTexture': | |
case 'ArrayTexture(1)': | |
case 'ArrayTexture(2)': | |
case 'ArrayTexture(3)': | |
case 'ArrayTexture(4)': | |
return 'single'; | |
default: | |
throw new Error('Unknown texture type'); | |
} | |
} | |
delete() { | |
return this.context.deleteTexture(this.texture); | |
} | |
} | |
const renderOutput = function renderTexture() { | |
return new Texture({ | |
texture: null, | |
size: new Int32Array([1,1]), | |
dimensions: new Int32Array([1,1,1]), | |
output: new Int32Array(undefined), | |
context: gl, | |
gpu: null, | |
type: 'NumberTexture', | |
}); | |
}; | |
/** end of injected functions **/ | |
return function (a, b) { | |
/** start setup uploads for kernel values **/ | |
const preUploadValue_a = new Float32Array(4); | |
const uploadValue_a = new Uint8Array(preUploadValue_a.buffer); | |
flattenTo(a, preUploadValue_a); | |
const preUploadValue_b = new Float32Array(4); | |
const uploadValue_b = new Uint8Array(preUploadValue_b.buffer); | |
flattenTo(b, preUploadValue_b); | |
/** end setup uploads for kernel values **/ | |
gl.useProgram(glVariable11); | |
gl.scissor(0, 0, 1, 1); | |
const glVariable18 = gl.getUniformLocation(glVariable11, 'uOutputDim'); | |
const glVariable19 = new Array(1,1,1); | |
gl.uniform3iv(glVariable18, glVariable19); | |
const glVariable20 = gl.getUniformLocation(glVariable11, 'uTexSize'); | |
const glVariable21 = new Int32Array([1,1]); | |
gl.uniform2iv(glVariable20, glVariable21); | |
const glVariable22 = gl.getUniformLocation(glVariable11, 'ratio'); | |
gl.uniform2f(glVariable22, 1, 1); | |
const glVariable23 = gl.getUniformLocation(glVariable11, 'user_a'); | |
gl.uniform1i(glVariable23, 0); | |
const glVariable24 = gl.getUniformLocation(glVariable11, 'user_b'); | |
gl.uniform1i(glVariable24, 1); | |
gl.bindFramebuffer(gl.FRAMEBUFFER, glVariable12); | |
const glVariable25 = gl.createTexture(); | |
gl.activeTexture(33986); | |
gl.bindTexture(gl.TEXTURE_2D, glVariable25); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); | |
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, glVariable25, 0); | |
const glVariable26 = gl.createTexture(); | |
gl.activeTexture(33986); | |
gl.bindTexture(gl.TEXTURE_2D, glVariable26); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); | |
gl.framebufferTexture2D(gl.FRAMEBUFFER, 36065, gl.TEXTURE_2D, glVariable26, 0); | |
const glVariable27 = gl.createTexture(); | |
gl.activeTexture(33987); | |
gl.bindTexture(gl.TEXTURE_2D, glVariable27); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); | |
gl.framebufferTexture2D(gl.FRAMEBUFFER, 36066, gl.TEXTURE_2D, glVariable27, 0); | |
glVariables3.drawBuffersWEBGL([gl.COLOR_ATTACHMENT0, 36065, 36066]); | |
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); | |
return renderOutput(undefined); | |
}; } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function value1(value) { | |
return value + 10; | |
} | |
function value2(value) { | |
return value + 50; | |
} | |
const gpu = new GPU({ mode }); | |
const kernel = gpu.createKernelMap( | |
{ | |
valueOutput1: value1, | |
valueOutput2: value2 | |
}, | |
function (a, b) { | |
value1(a[this.thread.x]); | |
return value2(b[this.thread.x]) + 100; | |
}, | |
{ | |
output: [1], | |
immutable: true, | |
pipeline: true, | |
precision: 'unsigned', | |
} | |
); | |
// start with a value on CPU | |
const output1 = kernel([10], [20]); | |
// reuse that output, simulating that this value will be monitored, and updated via the same kernel | |
// this is often used in neural networks | |
const output2 = kernel(output1.result, output1.valueOutput2); | |
const output3 = kernel(output2.result, output2.valueOutput2); | |
function toArray(value) { | |
return value.toArray ? value.toArray() : value; | |
} | |
assert.equal(toArray(output1.valueOutput1)[0], 20); // 10 + 10 | |
assert.equal(toArray(output1.valueOutput2)[0], 70); // 20 + 50 | |
assert.equal(toArray(output1.result)[0], 170); // (20 + 50) + 100 | |
assert.equal(toArray(output2.valueOutput1)[0], 180); // 170 + 10 | |
assert.equal(toArray(output2.valueOutput2)[0], 120); // 70 + 50 | |
assert.equal(toArray(output2.result)[0], 220); // (70 + 50) + 100 | |
assert.equal(toArray(output3.valueOutput1)[0], 230); // 220 + 10 | |
assert.equal(toArray(output3.valueOutput2)[0], 170); // 120 + 50 | |
assert.equal(toArray(output3.result)[0], 270); // (120 + 50) + 100 | |
gpu.destroy(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment