gl.mx raw

   1  // SPDX-License-Identifier: Unlicense OR MIT
   2  
   3  // GL types, constants, and Functions wrapper over jsbridge/webgl.
   4  // WASM/WebGL2 only. GL handle types are prefixed with GL to avoid
   5  // conflicts with the driver.Buffer/Texture interfaces.
   6  
   7  package gio
   8  
   9  import (
  10  	"bytes"
  11  	"errors"
  12  	"fmt"
  13  	"unsafe"
  14  
  15  	"jsbridge/webgl"
  16  )
  17  
  18  type (
  19  	Enum     uint32
  20  	GLAttrib uint32
  21  )
  22  
  23  const (
  24  	ACTIVE_TEXTURE                        = 0x84E0
  25  	ALL_BARRIER_BITS                      = 0xffffffff
  26  	ARRAY_BUFFER                          = 0x8892
  27  	ARRAY_BUFFER_BINDING                  = 0x8894
  28  	BACK                                  = 0x0405
  29  	BLEND                                 = 0xbe2
  30  	BLEND_DST_RGB                         = 0x80C8
  31  	BLEND_SRC_RGB                         = 0x80C9
  32  	BLEND_DST_ALPHA                       = 0x80CA
  33  	BLEND_SRC_ALPHA                       = 0x80CB
  34  	CLAMP_TO_EDGE                         = 0x812f
  35  	COLOR_ATTACHMENT0                     = 0x8ce0
  36  	COLOR_BUFFER_BIT                      = 0x4000
  37  	COLOR_CLEAR_VALUE                     = 0x0C22
  38  	COMPILE_STATUS                        = 0x8b81
  39  	CURRENT_PROGRAM                       = 0x8B8D
  40  	DEPTH_ATTACHMENT                      = 0x8d00
  41  	DEPTH_BUFFER_BIT                      = 0x100
  42  	DEPTH_CLEAR_VALUE                     = 0x0B73
  43  	DEPTH_COMPONENT16                     = 0x81a5
  44  	DEPTH_COMPONENT24                     = 0x81A6
  45  	DEPTH_COMPONENT32F                    = 0x8CAC
  46  	DEPTH_FUNC                            = 0x0B74
  47  	DEPTH_TEST                            = 0xb71
  48  	DEPTH_WRITEMASK                       = 0x0B72
  49  	DRAW_FRAMEBUFFER                      = 0x8CA9
  50  	DST_COLOR                             = 0x306
  51  	DYNAMIC_DRAW                          = 0x88E8
  52  	ELEMENT_ARRAY_BUFFER                  = 0x8893
  53  	ELEMENT_ARRAY_BUFFER_BINDING          = 0x8895
  54  	EXTENSIONS                            = 0x1f03
  55  	FALSE                                 = 0
  56  	FLOAT                                 = 0x1406
  57  	FRAGMENT_SHADER                       = 0x8b30
  58  	FRAMEBUFFER                           = 0x8d40
  59  	FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING = 0x8210
  60  	FRAMEBUFFER_BINDING                   = 0x8ca6
  61  	FRAMEBUFFER_COMPLETE                  = 0x8cd5
  62  	FRAMEBUFFER_SRGB                      = 0x8db9
  63  	HALF_FLOAT                            = 0x140b
  64  	HALF_FLOAT_OES                        = 0x8d61
  65  	INFO_LOG_LENGTH                       = 0x8B84
  66  	INVALID_INDEX                         = ^uint32(0)
  67  	GREATER                               = 0x204
  68  	GEQUAL                                = 0x206
  69  	LINEAR                                = 0x2601
  70  	LINEAR_MIPMAP_LINEAR                  = 0x2703
  71  	LINK_STATUS                           = 0x8b82
  72  	LUMINANCE                             = 0x1909
  73  	MAX_TEXTURE_SIZE                      = 0xd33
  74  	NEAREST                               = 0x2600
  75  	NO_ERROR                              = 0x0
  76  	ONE                                   = 0x1
  77  	ONE_MINUS_SRC_ALPHA                   = 0x303
  78  	PACK_ROW_LENGTH                       = 0x0D02
  79  	R16F                                  = 0x822d
  80  	RGBA16F                               = 0x881A
  81  	RGBA32F                               = 0x8814
  82  	R8                                    = 0x8229
  83  	READ_FRAMEBUFFER                      = 0x8ca8
  84  	READ_FRAMEBUFFER_BINDING              = 0x8CAA
  85  	RED                                   = 0x1903
  86  	RENDERER                              = 0x1F01
  87  	RENDERBUFFER                          = 0x8d41
  88  	RENDERBUFFER_BINDING                  = 0x8ca7
  89  	RGB                                   = 0x1907
  90  	GL_RGBA                               = 0x1908
  91  	RGBA8                                 = 0x8058
  92  	SHORT                                 = 0x1402
  93  	SRGB                                  = 0x8c40
  94  	SRGB_ALPHA_EXT                        = 0x8c42
  95  	SRGB8                                 = 0x8c41
  96  	SRGB8_ALPHA8                          = 0x8c43
  97  	STATIC_DRAW                           = 0x88e4
  98  	STENCIL_BUFFER_BIT                    = 0x00000400
  99  	TEXTURE_2D                            = 0xde1
 100  	TEXTURE_BINDING_2D                    = 0x8069
 101  	TEXTURE_MAG_FILTER                    = 0x2800
 102  	TEXTURE_MIN_FILTER                    = 0x2801
 103  	TEXTURE_WRAP_S                        = 0x2802
 104  	TEXTURE_WRAP_T                        = 0x2803
 105  	TEXTURE0                              = 0x84c0
 106  	TEXTURE1                              = 0x84c1
 107  	TRIANGLE_STRIP                        = 0x5
 108  	TRIANGLES                             = 0x4
 109  	TRUE                                  = 1
 110  	UNIFORM_BUFFER                        = 0x8A11
 111  	UNIFORM_BUFFER_BINDING                = 0x8A28
 112  	UNPACK_ALIGNMENT                      = 0xcf5
 113  	UNPACK_ROW_LENGTH                     = 0x0CF2
 114  	UNSIGNED_BYTE                         = 0x1401
 115  	UNSIGNED_SHORT                        = 0x1403
 116  	VIEWPORT                              = 0x0BA2
 117  	VERSION                               = 0x1f02
 118  	VERTEX_ARRAY_BINDING                  = 0x85B5
 119  	VERTEX_SHADER                         = 0x8b31
 120  	WRITE_ONLY                            = 0x88B9
 121  	ZERO                                  = 0x0
 122  )
 123  
 124  // GL object handle types. Zero value means unbound/invalid.
 125  // Prefixed GL to avoid conflicts with driver.Buffer/Texture interfaces.
 126  type (
 127  	GLObject       struct{ V int32 }
 128  	GLBuffer       GLObject
 129  	GLFramebuffer  GLObject
 130  	GLProgram      GLObject
 131  	GLRenderbuffer GLObject
 132  	GLShader       GLObject
 133  	GLTexture      GLObject
 134  	GLUniform      struct{ V int32 }
 135  )
 136  
 137  func (o GLObject) valid() bool        { return o.V != 0 }
 138  func (b GLBuffer) Valid() bool        { return GLObject(b).valid() }
 139  func (f GLFramebuffer) Valid() bool   { return GLObject(f).valid() }
 140  func (p GLProgram) Valid() bool       { return GLObject(p).valid() }
 141  func (s GLShader) Valid() bool        { return GLObject(s).valid() }
 142  func (u GLUniform) Valid() bool       { return u.V != -1 }
 143  
 144  func (f GLFramebuffer) Equal(f2 GLFramebuffer) bool   { return f == f2 }
 145  func (p GLProgram) Equal(p2 GLProgram) bool           { return p == p2 }
 146  func (s GLShader) Equal(s2 GLShader) bool             { return s == s2 }
 147  func (u GLUniform) Equal(u2 GLUniform) bool           { return u == u2 }
 148  func (b GLBuffer) Equal(b2 GLBuffer) bool             { return b == b2 }
 149  func (t GLTexture) Equal(t2 GLTexture) bool           { return t == t2 }
 150  func (r GLRenderbuffer) Equal(r2 GLRenderbuffer) bool { return r == r2 }
 151  
 152  // GLContext is a WebGL2 rendering context handle.
 153  type GLContext = webgl.Context
 154  
 155  // Functions wraps all WebGL2 operations via jsbridge/webgl.
 156  type Functions struct {
 157  	ctx webgl.Context
 158  }
 159  
 160  func NewFunctions(ctx GLContext) (*Functions, error) {
 161  	if ctx == 0 {
 162  		return nil, errors.New("gl: null context")
 163  	}
 164  	return &Functions{ctx: ctx}, nil
 165  }
 166  
 167  func (f *Functions) ActiveTexture(t Enum) {
 168  	webgl.ActiveTexture(f.ctx, int32(t))
 169  }
 170  
 171  func (f *Functions) AttachShader(p GLProgram, s GLShader) {
 172  	webgl.AttachShader(f.ctx, webgl.Program(p.V), webgl.Shader(s.V))
 173  }
 174  
 175  func (f *Functions) BindAttribLocation(p GLProgram, a GLAttrib, name string) {
 176  	webgl.BindAttribLocation(f.ctx, webgl.Program(p.V), int32(a), unsafe.StringData(name), int32(len(name)))
 177  }
 178  
 179  func (f *Functions) BindBuffer(target Enum, b GLBuffer) {
 180  	webgl.BindBuffer(f.ctx, int32(target), webgl.Buffer(b.V))
 181  }
 182  
 183  func (f *Functions) BindFramebuffer(target Enum, fb GLFramebuffer) {
 184  	webgl.BindFramebuffer(f.ctx, int32(target), webgl.Framebuffer(fb.V))
 185  }
 186  
 187  func (f *Functions) BindRenderbuffer(target Enum, rb GLRenderbuffer) {
 188  	webgl.BindRenderbuffer(f.ctx, int32(target), webgl.Renderbuffer(rb.V))
 189  }
 190  
 191  func (f *Functions) BindTexture(target Enum, t GLTexture) {
 192  	webgl.BindTexture(f.ctx, int32(target), webgl.Texture(t.V))
 193  }
 194  
 195  func (f *Functions) BlendFuncSeparate(srcRGB, dstRGB, srcA, dstA Enum) {
 196  	webgl.BlendFuncSeparate(f.ctx, int32(srcRGB), int32(dstRGB), int32(srcA), int32(dstA))
 197  }
 198  
 199  func (f *Functions) BufferData(target Enum, size int, usage Enum, data []byte) {
 200  	if data == nil {
 201  		webgl.BufferData(f.ctx, int32(target), nil, int32(size), int32(usage))
 202  	} else {
 203  		webgl.BufferData(f.ctx, int32(target), &data[0], int32(len(data)), int32(usage))
 204  	}
 205  }
 206  
 207  func (f *Functions) BufferSubData(target Enum, offset int, src []byte) {
 208  	if len(src) > 0 {
 209  		webgl.BufferSubData(f.ctx, int32(target), int32(offset), &src[0], int32(len(src)))
 210  	}
 211  }
 212  
 213  func (f *Functions) CheckFramebufferStatus(target Enum) Enum {
 214  	return Enum(webgl.CheckFramebufferStatus(f.ctx, int32(target)))
 215  }
 216  
 217  func (f *Functions) Clear(mask Enum) {
 218  	webgl.Clear(f.ctx, int32(mask))
 219  }
 220  
 221  func (f *Functions) ClearColor(red, green, blue, alpha float32) {
 222  	webgl.ClearColor(f.ctx, red, green, blue, alpha)
 223  }
 224  
 225  func (f *Functions) ClearDepthf(d float32) {
 226  	webgl.ClearDepth(f.ctx, d)
 227  }
 228  
 229  func (f *Functions) CompileShader(s GLShader) {
 230  	webgl.CompileShader(f.ctx, webgl.Shader(s.V))
 231  }
 232  
 233  func (f *Functions) CopyTexSubImage2D(target Enum, level, xoffset, yoffset, x, y, width, height int) {
 234  	webgl.CopyTexSubImage2D(f.ctx, int32(target), int32(level), int32(xoffset), int32(yoffset), int32(x), int32(y), int32(width), int32(height))
 235  }
 236  
 237  func (f *Functions) CreateBuffer() GLBuffer {
 238  	return GLBuffer{V: int32(webgl.CreateBuffer(f.ctx))}
 239  }
 240  
 241  func (f *Functions) CreateFramebuffer() GLFramebuffer {
 242  	return GLFramebuffer{V: int32(webgl.CreateFramebuffer(f.ctx))}
 243  }
 244  
 245  func (f *Functions) CreateProgram() GLProgram {
 246  	return GLProgram{V: int32(webgl.CreateProgram(f.ctx))}
 247  }
 248  
 249  func (f *Functions) CreateRenderbuffer() GLRenderbuffer {
 250  	return GLRenderbuffer{V: int32(webgl.CreateRenderbuffer(f.ctx))}
 251  }
 252  
 253  func (f *Functions) CreateShader(ty Enum) GLShader {
 254  	return GLShader{V: int32(webgl.CreateShader(f.ctx, int32(ty)))}
 255  }
 256  
 257  func (f *Functions) CreateTexture() GLTexture {
 258  	return GLTexture{V: int32(webgl.CreateTexture(f.ctx))}
 259  }
 260  
 261  func (f *Functions) DeleteBuffer(v GLBuffer) {
 262  	webgl.DeleteBuffer(f.ctx, webgl.Buffer(v.V))
 263  }
 264  
 265  func (f *Functions) DeleteFramebuffer(v GLFramebuffer) {
 266  	webgl.DeleteFramebuffer(f.ctx, webgl.Framebuffer(v.V))
 267  }
 268  
 269  func (f *Functions) DeleteProgram(p GLProgram) {
 270  	webgl.DeleteProgram(f.ctx, webgl.Program(p.V))
 271  }
 272  
 273  func (f *Functions) DeleteShader(s GLShader) {
 274  	webgl.DeleteShader(f.ctx, webgl.Shader(s.V))
 275  }
 276  
 277  func (f *Functions) DeleteRenderbuffer(v GLRenderbuffer) {
 278  	webgl.DeleteRenderbuffer(f.ctx, webgl.Renderbuffer(v.V))
 279  }
 280  
 281  func (f *Functions) DeleteTexture(v GLTexture) {
 282  	webgl.DeleteTexture(f.ctx, webgl.Texture(v.V))
 283  }
 284  
 285  func (f *Functions) DepthFunc(fn Enum) {
 286  	webgl.DepthFunc(f.ctx, int32(fn))
 287  }
 288  
 289  func (f *Functions) DepthMask(mask bool) {
 290  	m := int32(0)
 291  	if mask {
 292  		m = 1
 293  	}
 294  	webgl.DepthMask(f.ctx, m)
 295  }
 296  
 297  func (f *Functions) DisableVertexAttribArray(a GLAttrib) {
 298  	webgl.DisableVertexAttribArray(f.ctx, int32(a))
 299  }
 300  
 301  func (f *Functions) Disable(cap Enum) {
 302  	webgl.Disable(f.ctx, int32(cap))
 303  }
 304  
 305  func (f *Functions) DrawArrays(mode Enum, first, count int) {
 306  	webgl.DrawArrays(f.ctx, int32(mode), int32(first), int32(count))
 307  }
 308  
 309  func (f *Functions) DrawElements(mode Enum, count int, ty Enum, offset int) {
 310  	webgl.DrawElements(f.ctx, int32(mode), int32(count), int32(ty), int32(offset))
 311  }
 312  
 313  func (f *Functions) Enable(cap Enum) {
 314  	webgl.Enable(f.ctx, int32(cap))
 315  }
 316  
 317  func (f *Functions) EnableVertexAttribArray(a GLAttrib) {
 318  	webgl.EnableVertexAttribArray(f.ctx, int32(a))
 319  }
 320  
 321  func (f *Functions) Finish() {
 322  	webgl.Finish(f.ctx)
 323  }
 324  
 325  func (f *Functions) Flush() {
 326  	webgl.Flush(f.ctx)
 327  }
 328  
 329  func (f *Functions) FramebufferRenderbuffer(target, attachment, renderbuffertarget Enum, renderbuffer GLRenderbuffer) {
 330  	webgl.FramebufferRenderbuffer(f.ctx, int32(target), int32(attachment), int32(renderbuffertarget), webgl.Renderbuffer(renderbuffer.V))
 331  }
 332  
 333  func (f *Functions) FramebufferTexture2D(target, attachment, texTarget Enum, t GLTexture, level int) {
 334  	webgl.FramebufferTexture2D(f.ctx, int32(target), int32(attachment), int32(texTarget), webgl.Texture(t.V), int32(level))
 335  }
 336  
 337  func (f *Functions) GenerateMipmap(target Enum) {
 338  	webgl.GenerateMipmap(f.ctx, int32(target))
 339  }
 340  
 341  func (f *Functions) GetError() Enum {
 342  	return 0 // avoid slow getError; WebGL2 errors are reported as exceptions
 343  }
 344  
 345  func (f *Functions) GetInteger(pname Enum) int {
 346  	return int(webgl.GetInteger(f.ctx, int32(pname)))
 347  }
 348  
 349  func (f *Functions) GetProgrami(p GLProgram, pname Enum) int {
 350  	return int(webgl.GetProgramParameter(f.ctx, webgl.Program(p.V), int32(pname)))
 351  }
 352  
 353  func (f *Functions) GetProgramInfoLog(p GLProgram) string {
 354  	buf := []byte{:512} // heap-allocated, not stack
 355  	n := webgl.GetProgramInfoLog(f.ctx, webgl.Program(p.V), &buf[0], 512)
 356  	if n > 512 {
 357  		n = 512
 358  	}
 359  	return string(buf[:n])
 360  }
 361  
 362  func (f *Functions) GetShaderi(s GLShader, pname Enum) int {
 363  	return int(webgl.GetShaderParameter(f.ctx, webgl.Shader(s.V), int32(pname)))
 364  }
 365  
 366  func (f *Functions) GetShaderInfoLog(s GLShader) string {
 367  	buf := []byte{:512} // heap-allocated, not stack
 368  	n := webgl.GetShaderInfoLog(f.ctx, webgl.Shader(s.V), &buf[0], 512)
 369  	if n > 512 {
 370  		n = 512
 371  	}
 372  	return string(buf[:n])
 373  }
 374  
 375  func (f *Functions) GetUniformLocation(p GLProgram, name string) GLUniform {
 376  	loc := webgl.GetUniformLocation(f.ctx, webgl.Program(p.V), unsafe.StringData(name), int32(len(name)))
 377  	if loc == 0 {
 378  		return GLUniform{V: -1}
 379  	}
 380  	return GLUniform{V: int32(loc)}
 381  }
 382  
 383  func (f *Functions) InvalidateFramebuffer(target, attachment Enum) {
 384  	webgl.InvalidateFramebuffer(f.ctx, int32(target), int32(attachment))
 385  }
 386  
 387  func (f *Functions) IsEnabled(cap Enum) bool {
 388  	return webgl.IsEnabled(f.ctx, int32(cap)) != 0
 389  }
 390  
 391  func (f *Functions) LinkProgram(p GLProgram) {
 392  	webgl.LinkProgram(f.ctx, webgl.Program(p.V))
 393  }
 394  
 395  func (f *Functions) PixelStorei(pname Enum, param int) {
 396  	webgl.PixelStorei(f.ctx, int32(pname), int32(param))
 397  }
 398  
 399  func (f *Functions) RenderbufferStorage(target, internalformat Enum, width, height int) {
 400  	webgl.RenderbufferStorage(f.ctx, int32(target), int32(internalformat), int32(width), int32(height))
 401  }
 402  
 403  func (f *Functions) ReadPixels(x, y, width, height int, format, ty Enum, data []byte) {
 404  	if len(data) > 0 {
 405  		webgl.ReadPixels(f.ctx, int32(x), int32(y), int32(width), int32(height), int32(format), int32(ty), &data[0], int32(len(data)))
 406  	}
 407  }
 408  
 409  func (f *Functions) Scissor(x, y, width, height int32) {
 410  	webgl.Scissor(f.ctx, x, y, width, height)
 411  }
 412  
 413  func (f *Functions) ShaderSource(s GLShader, src string) {
 414  	webgl.ShaderSource(f.ctx, webgl.Shader(s.V), unsafe.StringData(src), int32(len(src)))
 415  }
 416  
 417  func (f *Functions) TexImage2D(target Enum, level int, internalFormat Enum, width, height int, format, ty Enum) {
 418  	webgl.TexImage2D(f.ctx, int32(target), int32(level), int32(internalFormat), int32(width), int32(height), 0, int32(format), int32(ty), nil, 0)
 419  }
 420  
 421  func (f *Functions) TexStorage2D(target Enum, levels int, internalFormat Enum, width, height int) {
 422  	webgl.TexStorage2D(f.ctx, int32(target), int32(levels), int32(internalFormat), int32(width), int32(height))
 423  }
 424  
 425  func (f *Functions) TexSubImage2D(target Enum, level int, x, y, width, height int, format, ty Enum, data []byte) {
 426  	if len(data) > 0 {
 427  		webgl.TexSubImage2D(f.ctx, int32(target), int32(level), int32(x), int32(y), int32(width), int32(height), int32(format), int32(ty), &data[0], int32(len(data)))
 428  	}
 429  }
 430  
 431  func (f *Functions) TexParameteri(target, pname Enum, param int) {
 432  	webgl.TexParameteri(f.ctx, int32(target), int32(pname), int32(param))
 433  }
 434  
 435  func (f *Functions) Uniform1f(dst GLUniform, v float32) {
 436  	webgl.Uniform1f(f.ctx, webgl.UniformLocation(dst.V), v)
 437  }
 438  
 439  func (f *Functions) Uniform1i(dst GLUniform, v int) {
 440  	webgl.Uniform1i(f.ctx, webgl.UniformLocation(dst.V), int32(v))
 441  }
 442  
 443  func (f *Functions) Uniform2f(dst GLUniform, v0, v1 float32) {
 444  	webgl.Uniform2f(f.ctx, webgl.UniformLocation(dst.V), v0, v1)
 445  }
 446  
 447  func (f *Functions) Uniform3f(dst GLUniform, v0, v1, v2 float32) {
 448  	webgl.Uniform3f(f.ctx, webgl.UniformLocation(dst.V), v0, v1, v2)
 449  }
 450  
 451  func (f *Functions) Uniform4f(dst GLUniform, v0, v1, v2, v3 float32) {
 452  	webgl.Uniform4f(f.ctx, webgl.UniformLocation(dst.V), v0, v1, v2, v3)
 453  }
 454  
 455  func (f *Functions) UseProgram(p GLProgram) {
 456  	webgl.UseProgram(f.ctx, webgl.Program(p.V))
 457  }
 458  
 459  func (f *Functions) VertexAttribPointer(dst GLAttrib, size int, ty Enum, normalized bool, stride, offset int) {
 460  	norm := int32(0)
 461  	if normalized {
 462  		norm = 1
 463  	}
 464  	webgl.VertexAttribPointer(f.ctx, int32(dst), int32(size), int32(ty), norm, int32(stride), int32(offset))
 465  }
 466  
 467  func (f *Functions) Viewport(x, y, width, height int) {
 468  	webgl.Viewport(f.ctx, int32(x), int32(y), int32(width), int32(height))
 469  }
 470  
 471  // GLCreateProgram links a vertex and fragment shader into a program.
 472  func GLCreateProgram(ctx *Functions, vsSrc, fsSrc string, attribs []string) (GLProgram, error) {
 473  	vs, err := GLCreateShader(ctx, VERTEX_SHADER, vsSrc)
 474  	if err != nil {
 475  		return GLProgram{}, err
 476  	}
 477  	defer ctx.DeleteShader(vs)
 478  	fs, err := GLCreateShader(ctx, FRAGMENT_SHADER, fsSrc)
 479  	if err != nil {
 480  		return GLProgram{}, err
 481  	}
 482  	defer ctx.DeleteShader(fs)
 483  	prog := ctx.CreateProgram()
 484  	if !prog.Valid() {
 485  		return GLProgram{}, errors.New("glCreateProgram failed")
 486  	}
 487  	ctx.AttachShader(prog, vs)
 488  	ctx.AttachShader(prog, fs)
 489  	for i, a := range attribs {
 490  		ctx.BindAttribLocation(prog, GLAttrib(i), a)
 491  	}
 492  	ctx.LinkProgram(prog)
 493  	if ctx.GetProgrami(prog, LINK_STATUS) == 0 {
 494  		log := ctx.GetProgramInfoLog(prog)
 495  		ctx.DeleteProgram(prog)
 496  		return GLProgram{}, fmt.Errorf("program link failed: %s", bytes.TrimSpace(log))
 497  	}
 498  	return prog, nil
 499  }
 500  
 501  // GLCreateShader compiles a shader from source.
 502  func GLCreateShader(ctx *Functions, typ Enum, src string) (GLShader, error) {
 503  	sh := ctx.CreateShader(typ)
 504  	if !sh.Valid() {
 505  		return GLShader{}, errors.New("glCreateShader failed")
 506  	}
 507  	ctx.ShaderSource(sh, src)
 508  	ctx.CompileShader(sh)
 509  	if ctx.GetShaderi(sh, COMPILE_STATUS) == 0 {
 510  		log := ctx.GetShaderInfoLog(sh)
 511  		ctx.DeleteShader(sh)
 512  		return GLShader{}, fmt.Errorf("shader compilation failed: %s", bytes.TrimSpace(log))
 513  	}
 514  	return sh, nil
 515  }
 516