1
+ ( function ( ) {
2
+ // turbo.js
3
+ // (c) turbo - github.com/turbo
4
+ // MIT licensed
5
+ "use strict" ;
6
+
7
+ var gl = document . createElement ( 'canvas' ) . getContext ( 'experimental-webgl' , { alpha : false , antialias : false } ) ;
8
+
9
+ // turbo.js requires a 32bit float vec4 texture. Some systems only provide 8bit/float
10
+ // textures. A workaround is being created, but turbo.js shouldn't be used on those
11
+ // systems anyway.
12
+ if ( ! gl . getExtension ( 'OES_texture_float' ) )
13
+ throw new Error ( 'turbojs requires OES_texture_float extension.' ) ;
14
+
15
+ // GPU texture buffer from JS typed array
16
+ function newBuffer ( data , f , e ) {
17
+ var buf = gl . createBuffer ( ) ;
18
+
19
+ gl . bindBuffer ( ( e || gl . ARRAY_BUFFER ) , buf ) ;
20
+ gl . bufferData ( ( e || gl . ARRAY_BUFFER ) , new ( f || Float32Array ) ( data ) , gl . STATIC_DRAW ) ;
21
+
22
+ return buf ;
23
+ }
24
+
25
+ var positionBuffer = newBuffer ( [ - 1 , - 1 , 1 , - 1 , 1 , 1 , - 1 , 1 ] ) ;
26
+ var textureBuffer = newBuffer ( [ 0 , 0 , 1 , 0 , 1 , 1 , 0 , 1 ] ) ;
27
+ var indexBuffer = newBuffer ( [ 1 , 2 , 0 , 3 , 0 , 2 ] , Uint16Array , gl . ELEMENT_ARRAY_BUFFER ) ;
28
+
29
+ var vertexShaderCode =
30
+ "attribute vec2 position;\n" +
31
+ "varying vec2 pos;\n" +
32
+ "attribute vec2 texture;\n" +
33
+ "\n" +
34
+ "void main(void) {\n" +
35
+ " pos = texture;\n" +
36
+ " gl_Position = vec4(position.xy, 0.0, 1.0);\n" +
37
+ "}"
38
+
39
+ var stdlib =
40
+ "\n" +
41
+ "precision mediump float;\n" +
42
+ "uniform sampler2D u_texture;\n" +
43
+ "varying vec2 pos;\n" +
44
+ "\n" +
45
+ "vec4 read(void) {\n" +
46
+ " return texture2D(u_texture, pos);\n" +
47
+ "}\n" +
48
+ "\n" +
49
+ "void commit(vec4 val) {\n" +
50
+ " gl_FragColor = val;\n" +
51
+ "}\n" +
52
+ "\n" +
53
+ "// user code begins here\n" +
54
+ "\n"
55
+
56
+ var vertexShader = gl . createShader ( gl . VERTEX_SHADER ) ;
57
+
58
+ gl . shaderSource ( vertexShader , vertexShaderCode ) ;
59
+ gl . compileShader ( vertexShader ) ;
60
+
61
+ // This should not fail.
62
+ if ( ! gl . getShaderParameter ( vertexShader , gl . COMPILE_STATUS ) )
63
+ throw new Error (
64
+ "\nERROR: Could not build internal vertex shader (fatal).\n" + "\n" +
65
+ "INFO: >REPORT< THIS. That's our fault!\n" + "\n" +
66
+ "--- CODE DUMP ---\n" + vertexShaderCode + "\n\n" +
67
+ "--- ERROR LOG ---\n" + gl . getShaderInfoLog ( vertexShader )
68
+ ) ;
69
+
70
+ // Transfer data onto clamped texture and turn off any filtering
71
+ function createTexture ( data , size ) {
72
+ var texture = gl . createTexture ( ) ;
73
+
74
+ gl . bindTexture ( gl . TEXTURE_2D , texture ) ;
75
+ gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_S , gl . CLAMP_TO_EDGE ) ;
76
+ gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_T , gl . CLAMP_TO_EDGE ) ;
77
+ gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MIN_FILTER , gl . NEAREST ) ;
78
+ gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MAG_FILTER , gl . NEAREST ) ;
79
+ gl . texImage2D ( gl . TEXTURE_2D , 0 , gl . RGBA , size , size , 0 , gl . RGBA , gl . FLOAT , data ) ;
80
+ gl . bindTexture ( gl . TEXTURE_2D , null ) ;
81
+
82
+ return texture ;
83
+ }
84
+
85
+ window . turbojs = {
86
+ // run code against a pre-allocated array
87
+ run : function ( ipt , code ) {
88
+ var fragmentShader = gl . createShader ( gl . FRAGMENT_SHADER ) ;
89
+
90
+ gl . shaderSource (
91
+ fragmentShader ,
92
+ stdlib + code
93
+ ) ;
94
+
95
+ gl . compileShader ( fragmentShader ) ;
96
+
97
+ // Use this output to debug the shader
98
+ // Keep in mind that WebGL GLSL is **much** stricter than e.g. OpenGL GLSL
99
+ if ( ! gl . getShaderParameter ( fragmentShader , gl . COMPILE_STATUS ) ) {
100
+ var LOC = code . split ( '\n' ) ;
101
+ var dbgMsg = "ERROR: Could not build shader (fatal).\n\n------------------ KERNEL CODE DUMP ------------------\n"
102
+
103
+ for ( var nl = 0 ; nl < LOC . length ; nl ++ )
104
+ dbgMsg += ( stdlib . split ( '\n' ) . length + nl ) + "> " + LOC [ nl ] + "\n" ;
105
+
106
+ dbgMsg += "\n--------------------- ERROR LOG ---------------------\n" + gl . getShaderInfoLog ( fragmentShader )
107
+
108
+ throw new Error ( dbgMsg ) ;
109
+ }
110
+
111
+ var program = gl . createProgram ( ) ;
112
+
113
+ gl . attachShader ( program , vertexShader ) ;
114
+ gl . attachShader ( program , fragmentShader ) ;
115
+ gl . linkProgram ( program ) ;
116
+
117
+ if ( ! gl . getProgramParameter ( program , gl . LINK_STATUS ) )
118
+ throw new Error ( 'ERROR: Could not initialize shaders (fatal).\n' ) ;
119
+
120
+ var uTexture = gl . getUniformLocation ( program , 'u_texture' ) ;
121
+ var aPosition = gl . getAttribLocation ( program , 'position' ) ;
122
+ var aTexture = gl . getAttribLocation ( program , 'texture' ) ;
123
+
124
+ gl . useProgram ( program ) ;
125
+
126
+ var size = Math . sqrt ( ipt . data . length ) / 4 ;
127
+ var texture = createTexture ( ipt . data , size ) ;
128
+
129
+ gl . viewport ( 0 , 0 , size , size ) ;
130
+ gl . bindFramebuffer ( gl . FRAMEBUFFER , gl . createFramebuffer ( ) ) ;
131
+
132
+ // Types arrays speed this up tremendously.
133
+ var nTexture = createTexture ( new Float32Array ( ipt . data . length ) , size ) ;
134
+
135
+ gl . framebufferTexture2D ( gl . FRAMEBUFFER , gl . COLOR_ATTACHMENT0 , gl . TEXTURE_2D , nTexture , 0 ) ;
136
+
137
+ var frameBufferStatus = ( gl . checkFramebufferStatus ( gl . FRAMEBUFFER ) == gl . FRAMEBUFFER_COMPLETE ) ;
138
+
139
+ if ( ! frameBufferStatus )
140
+ throw new Error ( 'ERROR: (fatal): ' + frameBufferStatus . message ) ;
141
+
142
+ gl . bindTexture ( gl . TEXTURE_2D , texture ) ;
143
+ gl . activeTexture ( gl . TEXTURE0 ) ;
144
+ gl . uniform1i ( uTexture , 0 ) ;
145
+ gl . bindBuffer ( gl . ARRAY_BUFFER , textureBuffer ) ;
146
+ gl . enableVertexAttribArray ( aTexture ) ;
147
+ gl . vertexAttribPointer ( aTexture , 2 , gl . FLOAT , false , 0 , 0 ) ;
148
+ gl . bindBuffer ( gl . ARRAY_BUFFER , positionBuffer ) ;
149
+ gl . enableVertexAttribArray ( aPosition ) ;
150
+ gl . vertexAttribPointer ( aPosition , 2 , gl . FLOAT , false , 0 , 0 ) ;
151
+ gl . bindBuffer ( gl . ELEMENT_ARRAY_BUFFER , indexBuffer ) ;
152
+ gl . drawElements ( gl . TRIANGLES , 6 , gl . UNSIGNED_SHORT , 0 ) ;
153
+ gl . readPixels ( 0 , 0 , size , size , gl . RGBA , gl . FLOAT , ipt . data ) ;
154
+ // ^ 4 x 32 bit ^
155
+
156
+ return ipt . data . subarray ( 0 , ipt . length ) ;
157
+ } ,
158
+ alloc : function ( sz ) {
159
+ // A sane limit for most GPUs out there.
160
+ // JS falls apart before GLSL limits could ever be reached.
161
+ if ( sz > 16777216 )
162
+ throw new Error ( "Whoops, the maximum array size is exceeded!" ) ;
163
+
164
+ var ns = Math . pow ( Math . pow ( 2 , Math . ceil ( Math . log ( sz ) / 1.386 ) - 1 ) , 2 ) ;
165
+ return {
166
+ data : new Float32Array ( ns * 16 ) ,
167
+ length : sz
168
+ } ;
169
+ }
170
+ } ;
171
+ } ) ( ) ;
0 commit comments