github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/internal/gl/gl_js.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package gl 4 5 import ( 6 "errors" 7 "strings" 8 "syscall/js" 9 ) 10 11 type Functions struct { 12 Ctx js.Value 13 EXT_disjoint_timer_query js.Value 14 EXT_disjoint_timer_query_webgl2 js.Value 15 16 // Cached reference to the Uint8Array JS type. 17 uint8Array js.Value 18 19 // Cached JS arrays. 20 arrayBuf js.Value 21 int32Buf js.Value 22 23 isWebGL2 bool 24 } 25 26 type Context js.Value 27 28 func NewFunctions(ctx Context, forceES bool) (*Functions, error) { 29 f := &Functions{ 30 Ctx: js.Value(ctx), 31 uint8Array: js.Global().Get("Uint8Array"), 32 } 33 if err := f.Init(); err != nil { 34 return nil, err 35 } 36 return f, nil 37 } 38 39 func (f *Functions) Init() error { 40 webgl2Class := js.Global().Get("WebGL2RenderingContext") 41 f.isWebGL2 = !webgl2Class.IsUndefined() && f.Ctx.InstanceOf(webgl2Class) 42 if !f.isWebGL2 { 43 f.EXT_disjoint_timer_query = f.getExtension("EXT_disjoint_timer_query") 44 if f.getExtension("OES_texture_half_float").IsNull() && f.getExtension("OES_texture_float").IsNull() { 45 return errors.New("gl: no support for neither OES_texture_half_float nor OES_texture_float") 46 } 47 if f.getExtension("EXT_sRGB").IsNull() { 48 return errors.New("gl: EXT_sRGB not supported") 49 } 50 } else { 51 // WebGL2 extensions. 52 f.EXT_disjoint_timer_query_webgl2 = f.getExtension("EXT_disjoint_timer_query_webgl2") 53 if f.getExtension("EXT_color_buffer_half_float").IsNull() && f.getExtension("EXT_color_buffer_float").IsNull() { 54 return errors.New("gl: no support for neither EXT_color_buffer_half_float nor EXT_color_buffer_float") 55 } 56 } 57 return nil 58 } 59 60 func (f *Functions) getExtension(name string) js.Value { 61 return f.Ctx.Call("getExtension", name) 62 } 63 64 func (f *Functions) ActiveTexture(t Enum) { 65 f.Ctx.Call("activeTexture", int(t)) 66 } 67 func (f *Functions) AttachShader(p Program, s Shader) { 68 f.Ctx.Call("attachShader", js.Value(p), js.Value(s)) 69 } 70 func (f *Functions) BeginQuery(target Enum, query Query) { 71 if !f.EXT_disjoint_timer_query_webgl2.IsNull() { 72 f.Ctx.Call("beginQuery", int(target), js.Value(query)) 73 } else { 74 f.EXT_disjoint_timer_query.Call("beginQueryEXT", int(target), js.Value(query)) 75 } 76 } 77 func (f *Functions) BindAttribLocation(p Program, a Attrib, name string) { 78 f.Ctx.Call("bindAttribLocation", js.Value(p), int(a), name) 79 } 80 func (f *Functions) BindBuffer(target Enum, b Buffer) { 81 f.Ctx.Call("bindBuffer", int(target), js.Value(b)) 82 } 83 func (f *Functions) BindBufferBase(target Enum, index int, b Buffer) { 84 f.Ctx.Call("bindBufferBase", int(target), index, js.Value(b)) 85 } 86 func (f *Functions) BindFramebuffer(target Enum, fb Framebuffer) { 87 f.Ctx.Call("bindFramebuffer", int(target), js.Value(fb)) 88 } 89 func (f *Functions) BindRenderbuffer(target Enum, rb Renderbuffer) { 90 f.Ctx.Call("bindRenderbuffer", int(target), js.Value(rb)) 91 } 92 func (f *Functions) BindTexture(target Enum, t Texture) { 93 f.Ctx.Call("bindTexture", int(target), js.Value(t)) 94 } 95 func (f *Functions) BindImageTexture(unit int, t Texture, level int, layered bool, layer int, access, format Enum) { 96 panic("not implemented") 97 } 98 func (f *Functions) BindVertexArray(a VertexArray) { 99 panic("not supported") 100 } 101 func (f *Functions) BlendEquation(mode Enum) { 102 f.Ctx.Call("blendEquation", int(mode)) 103 } 104 func (f *Functions) BlendFuncSeparate(srcRGB, dstRGB, srcA, dstA Enum) { 105 f.Ctx.Call("blendFunc", int(srcRGB), int(dstRGB), int(srcA), int(dstA)) 106 } 107 func (f *Functions) BlitFramebuffer(sx0, sy0, sx1, sy1, dx0, dy0, dx1, dy1 int, mask Enum, filter Enum) { 108 panic("not implemented") 109 } 110 func (f *Functions) BufferData(target Enum, size int, usage Enum) { 111 f.Ctx.Call("bufferData", int(target), size, int(usage)) 112 } 113 func (f *Functions) BufferSubData(target Enum, offset int, src []byte) { 114 f.Ctx.Call("bufferSubData", int(target), offset, f.byteArrayOf(src)) 115 } 116 func (f *Functions) CheckFramebufferStatus(target Enum) Enum { 117 return Enum(f.Ctx.Call("checkFramebufferStatus", int(target)).Int()) 118 } 119 func (f *Functions) Clear(mask Enum) { 120 f.Ctx.Call("clear", int(mask)) 121 } 122 func (f *Functions) ClearColor(red, green, blue, alpha float32) { 123 f.Ctx.Call("clearColor", red, green, blue, alpha) 124 } 125 func (f *Functions) ClearDepthf(d float32) { 126 f.Ctx.Call("clearDepth", d) 127 } 128 func (f *Functions) CompileShader(s Shader) { 129 f.Ctx.Call("compileShader", js.Value(s)) 130 } 131 func (f *Functions) CreateBuffer() Buffer { 132 return Buffer(f.Ctx.Call("createBuffer")) 133 } 134 func (f *Functions) CreateFramebuffer() Framebuffer { 135 return Framebuffer(f.Ctx.Call("createFramebuffer")) 136 } 137 func (f *Functions) CreateProgram() Program { 138 return Program(f.Ctx.Call("createProgram")) 139 } 140 func (f *Functions) CreateQuery() Query { 141 return Query(f.Ctx.Call("createQuery")) 142 } 143 func (f *Functions) CreateRenderbuffer() Renderbuffer { 144 return Renderbuffer(f.Ctx.Call("createRenderbuffer")) 145 } 146 func (f *Functions) CreateShader(ty Enum) Shader { 147 return Shader(f.Ctx.Call("createShader", int(ty))) 148 } 149 func (f *Functions) CreateTexture() Texture { 150 return Texture(f.Ctx.Call("createTexture")) 151 } 152 func (f *Functions) CreateVertexArray() VertexArray { 153 panic("not supported") 154 } 155 func (f *Functions) DeleteBuffer(v Buffer) { 156 f.Ctx.Call("deleteBuffer", js.Value(v)) 157 } 158 func (f *Functions) DeleteFramebuffer(v Framebuffer) { 159 f.Ctx.Call("deleteFramebuffer", js.Value(v)) 160 } 161 func (f *Functions) DeleteProgram(p Program) { 162 f.Ctx.Call("deleteProgram", js.Value(p)) 163 } 164 func (f *Functions) DeleteQuery(query Query) { 165 if !f.EXT_disjoint_timer_query_webgl2.IsNull() { 166 f.Ctx.Call("deleteQuery", js.Value(query)) 167 } else { 168 f.EXT_disjoint_timer_query.Call("deleteQueryEXT", js.Value(query)) 169 } 170 } 171 func (f *Functions) DeleteShader(s Shader) { 172 f.Ctx.Call("deleteShader", js.Value(s)) 173 } 174 func (f *Functions) DeleteRenderbuffer(v Renderbuffer) { 175 f.Ctx.Call("deleteRenderbuffer", js.Value(v)) 176 } 177 func (f *Functions) DeleteTexture(v Texture) { 178 f.Ctx.Call("deleteTexture", js.Value(v)) 179 } 180 func (f *Functions) DeleteVertexArray(a VertexArray) { 181 panic("not implemented") 182 } 183 func (f *Functions) DepthFunc(fn Enum) { 184 f.Ctx.Call("depthFunc", int(fn)) 185 } 186 func (f *Functions) DepthMask(mask bool) { 187 f.Ctx.Call("depthMask", mask) 188 } 189 func (f *Functions) DisableVertexAttribArray(a Attrib) { 190 f.Ctx.Call("disableVertexAttribArray", int(a)) 191 } 192 func (f *Functions) Disable(cap Enum) { 193 f.Ctx.Call("disable", int(cap)) 194 } 195 func (f *Functions) DrawArrays(mode Enum, first, count int) { 196 f.Ctx.Call("drawArrays", int(mode), first, count) 197 } 198 func (f *Functions) DrawElements(mode Enum, count int, ty Enum, offset int) { 199 f.Ctx.Call("drawElements", int(mode), count, int(ty), offset) 200 } 201 func (f *Functions) DispatchCompute(x, y, z int) { 202 panic("not implemented") 203 } 204 func (f *Functions) Enable(cap Enum) { 205 f.Ctx.Call("enable", int(cap)) 206 } 207 func (f *Functions) EnableVertexAttribArray(a Attrib) { 208 f.Ctx.Call("enableVertexAttribArray", int(a)) 209 } 210 func (f *Functions) EndQuery(target Enum) { 211 if !f.EXT_disjoint_timer_query_webgl2.IsNull() { 212 f.Ctx.Call("endQuery", int(target)) 213 } else { 214 f.EXT_disjoint_timer_query.Call("endQueryEXT", int(target)) 215 } 216 } 217 func (f *Functions) Finish() { 218 f.Ctx.Call("finish") 219 } 220 func (f *Functions) Flush() { 221 f.Ctx.Call("flush") 222 } 223 func (f *Functions) FramebufferRenderbuffer(target, attachment, renderbuffertarget Enum, renderbuffer Renderbuffer) { 224 f.Ctx.Call("framebufferRenderbuffer", int(target), int(attachment), int(renderbuffertarget), js.Value(renderbuffer)) 225 } 226 func (f *Functions) FramebufferTexture2D(target, attachment, texTarget Enum, t Texture, level int) { 227 f.Ctx.Call("framebufferTexture2D", int(target), int(attachment), int(texTarget), js.Value(t), level) 228 } 229 func (f *Functions) GetError() Enum { 230 // Avoid slow getError calls. See gio#179. 231 return 0 232 } 233 func (f *Functions) GetRenderbufferParameteri(target, pname Enum) int { 234 return paramVal(f.Ctx.Call("getRenderbufferParameteri", int(pname))) 235 } 236 func (f *Functions) GetFramebufferAttachmentParameteri(target, attachment, pname Enum) int { 237 if !f.isWebGL2 && pname == FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING { 238 // FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING is only available on WebGL 2 239 return LINEAR 240 } 241 return paramVal(f.Ctx.Call("getFramebufferAttachmentParameter", int(target), int(attachment), int(pname))) 242 } 243 func (f *Functions) GetBinding(pname Enum) Object { 244 obj := f.Ctx.Call("getParameter", int(pname)) 245 if !obj.Truthy() { 246 return Object{} 247 } 248 return Object(obj) 249 } 250 func (f *Functions) GetBindingi(pname Enum, idx int) Object { 251 obj := f.Ctx.Call("getIndexedParameter", int(pname), idx) 252 if !obj.Truthy() { 253 return Object{} 254 } 255 return Object(obj) 256 } 257 func (f *Functions) GetInteger(pname Enum) int { 258 return paramVal(f.Ctx.Call("getParameter", int(pname))) 259 } 260 func (f *Functions) GetFloat(pname Enum) float32 { 261 return float32(f.Ctx.Call("getParameter", int(pname)).Float()) 262 } 263 func (f *Functions) GetInteger4(pname Enum) [4]int { 264 arr := f.Ctx.Call("getParameter", int(pname)) 265 var res [4]int 266 for i := range res { 267 res[i] = arr.Index(i).Int() 268 } 269 return res 270 } 271 func (f *Functions) GetFloat4(pname Enum) [4]float32 { 272 arr := f.Ctx.Call("getParameter", int(pname)) 273 var res [4]float32 274 for i := range res { 275 res[i] = float32(arr.Index(i).Float()) 276 } 277 return res 278 } 279 func (f *Functions) GetProgrami(p Program, pname Enum) int { 280 return paramVal(f.Ctx.Call("getProgramParameter", js.Value(p), int(pname))) 281 } 282 func (f *Functions) GetProgramInfoLog(p Program) string { 283 return f.Ctx.Call("getProgramInfoLog", js.Value(p)).String() 284 } 285 func (f *Functions) GetQueryObjectuiv(query Query, pname Enum) uint { 286 if !f.EXT_disjoint_timer_query_webgl2.IsNull() { 287 return uint(paramVal(f.Ctx.Call("getQueryParameter", js.Value(query), int(pname)))) 288 } else { 289 return uint(paramVal(f.EXT_disjoint_timer_query.Call("getQueryObjectEXT", js.Value(query), int(pname)))) 290 } 291 } 292 func (f *Functions) GetShaderi(s Shader, pname Enum) int { 293 return paramVal(f.Ctx.Call("getShaderParameter", js.Value(s), int(pname))) 294 } 295 func (f *Functions) GetShaderInfoLog(s Shader) string { 296 return f.Ctx.Call("getShaderInfoLog", js.Value(s)).String() 297 } 298 func (f *Functions) GetString(pname Enum) string { 299 switch pname { 300 case EXTENSIONS: 301 extsjs := f.Ctx.Call("getSupportedExtensions") 302 var exts []string 303 for i := 0; i < extsjs.Length(); i++ { 304 exts = append(exts, "GL_"+extsjs.Index(i).String()) 305 } 306 return strings.Join(exts, " ") 307 default: 308 return f.Ctx.Call("getParameter", int(pname)).String() 309 } 310 } 311 func (f *Functions) GetUniformBlockIndex(p Program, name string) uint { 312 return uint(paramVal(f.Ctx.Call("getUniformBlockIndex", js.Value(p), name))) 313 } 314 func (f *Functions) GetUniformLocation(p Program, name string) Uniform { 315 return Uniform(f.Ctx.Call("getUniformLocation", js.Value(p), name)) 316 } 317 func (f *Functions) GetVertexAttrib(index int, pname Enum) int { 318 return paramVal(f.Ctx.Call("getVertexAttrib", index, int(pname))) 319 } 320 func (f *Functions) GetVertexAttribBinding(index int, pname Enum) Object { 321 obj := f.Ctx.Call("getVertexAttrib", index, int(pname)) 322 if !obj.Truthy() { 323 return Object{} 324 } 325 return Object(obj) 326 } 327 func (f *Functions) GetVertexAttribPointer(index int, pname Enum) uintptr { 328 return uintptr(f.Ctx.Call("getVertexAttribOffset", index, int(pname)).Int()) 329 } 330 func (f *Functions) InvalidateFramebuffer(target, attachment Enum) { 331 fn := f.Ctx.Get("invalidateFramebuffer") 332 if !fn.IsUndefined() { 333 if f.int32Buf.IsUndefined() { 334 f.int32Buf = js.Global().Get("Int32Array").New(1) 335 } 336 f.int32Buf.SetIndex(0, int32(attachment)) 337 f.Ctx.Call("invalidateFramebuffer", int(target), f.int32Buf) 338 } 339 } 340 func (f *Functions) IsEnabled(cap Enum) bool { 341 return f.Ctx.Call("isEnabled", int(cap)).Truthy() 342 } 343 func (f *Functions) LinkProgram(p Program) { 344 f.Ctx.Call("linkProgram", js.Value(p)) 345 } 346 func (f *Functions) PixelStorei(pname Enum, param int32) { 347 f.Ctx.Call("pixelStorei", int(pname), param) 348 } 349 func (f *Functions) MemoryBarrier(barriers Enum) { 350 panic("not implemented") 351 } 352 func (f *Functions) MapBufferRange(target Enum, offset, length int, access Enum) []byte { 353 panic("not implemented") 354 } 355 func (f *Functions) RenderbufferStorage(target, internalformat Enum, width, height int) { 356 f.Ctx.Call("renderbufferStorage", int(target), int(internalformat), width, height) 357 } 358 func (f *Functions) ReadPixels(x, y, width, height int, format, ty Enum, data []byte) { 359 ba := f.byteArrayOf(data) 360 f.Ctx.Call("readPixels", x, y, width, height, int(format), int(ty), ba) 361 js.CopyBytesToGo(data, ba) 362 } 363 func (f *Functions) Scissor(x, y, width, height int32) { 364 f.Ctx.Call("scissor", x, y, width, height) 365 } 366 func (f *Functions) ShaderSource(s Shader, src string) { 367 f.Ctx.Call("shaderSource", js.Value(s), src) 368 } 369 func (f *Functions) TexImage2D(target Enum, level int, internalFormat Enum, width, height int, format, ty Enum) { 370 f.Ctx.Call("texImage2D", int(target), int(level), int(internalFormat), int(width), int(height), 0, int(format), int(ty), nil) 371 } 372 func (f *Functions) TexStorage2D(target Enum, levels int, internalFormat Enum, width, height int) { 373 f.Ctx.Call("texStorage2D", int(target), levels, int(internalFormat), width, height) 374 } 375 func (f *Functions) TexSubImage2D(target Enum, level int, x, y, width, height int, format, ty Enum, data []byte) { 376 f.Ctx.Call("texSubImage2D", int(target), level, x, y, width, height, int(format), int(ty), f.byteArrayOf(data)) 377 } 378 func (f *Functions) TexParameteri(target, pname Enum, param int) { 379 f.Ctx.Call("texParameteri", int(target), int(pname), int(param)) 380 } 381 func (f *Functions) UniformBlockBinding(p Program, uniformBlockIndex uint, uniformBlockBinding uint) { 382 f.Ctx.Call("uniformBlockBinding", js.Value(p), int(uniformBlockIndex), int(uniformBlockBinding)) 383 } 384 func (f *Functions) Uniform1f(dst Uniform, v float32) { 385 f.Ctx.Call("uniform1f", js.Value(dst), v) 386 } 387 func (f *Functions) Uniform1i(dst Uniform, v int) { 388 f.Ctx.Call("uniform1i", js.Value(dst), v) 389 } 390 func (f *Functions) Uniform2f(dst Uniform, v0, v1 float32) { 391 f.Ctx.Call("uniform2f", js.Value(dst), v0, v1) 392 } 393 func (f *Functions) Uniform3f(dst Uniform, v0, v1, v2 float32) { 394 f.Ctx.Call("uniform3f", js.Value(dst), v0, v1, v2) 395 } 396 func (f *Functions) Uniform4f(dst Uniform, v0, v1, v2, v3 float32) { 397 f.Ctx.Call("uniform4f", js.Value(dst), v0, v1, v2, v3) 398 } 399 func (f *Functions) UseProgram(p Program) { 400 f.Ctx.Call("useProgram", js.Value(p)) 401 } 402 func (f *Functions) UnmapBuffer(target Enum) bool { 403 panic("not implemented") 404 } 405 func (f *Functions) VertexAttribPointer(dst Attrib, size int, ty Enum, normalized bool, stride, offset int) { 406 f.Ctx.Call("vertexAttribPointer", int(dst), size, int(ty), normalized, stride, offset) 407 } 408 func (f *Functions) Viewport(x, y, width, height int) { 409 f.Ctx.Call("viewport", x, y, width, height) 410 } 411 412 func (f *Functions) byteArrayOf(data []byte) js.Value { 413 if len(data) == 0 { 414 return js.Null() 415 } 416 f.resizeByteBuffer(len(data)) 417 ba := f.uint8Array.New(f.arrayBuf, int(0), int(len(data))) 418 js.CopyBytesToJS(ba, data) 419 return ba 420 } 421 422 func (f *Functions) resizeByteBuffer(n int) { 423 if n == 0 { 424 return 425 } 426 if !f.arrayBuf.IsUndefined() && f.arrayBuf.Length() >= n { 427 return 428 } 429 f.arrayBuf = js.Global().Get("ArrayBuffer").New(n) 430 } 431 432 func paramVal(v js.Value) int { 433 switch v.Type() { 434 case js.TypeBoolean: 435 if b := v.Bool(); b { 436 return 1 437 } else { 438 return 0 439 } 440 case js.TypeNumber: 441 return v.Int() 442 default: 443 panic("unknown parameter type") 444 } 445 }