context_desktop.go (15481B)
1 // Copyright 2014 Hajime Hoshi 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // +build darwin freebsd linux windows 16 // +build !android 17 // +build !ios 18 19 package opengl 20 21 import ( 22 "errors" 23 "fmt" 24 25 "github.com/hajimehoshi/ebiten/v2/internal/driver" 26 "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver/opengl/gl" 27 "github.com/hajimehoshi/ebiten/v2/internal/shaderir" 28 ) 29 30 type ( 31 textureNative uint32 32 framebufferNative uint32 33 shader uint32 34 program uint32 35 buffer uint32 36 ) 37 38 func (t textureNative) equal(rhs textureNative) bool { 39 return t == rhs 40 } 41 42 func (f framebufferNative) equal(rhs framebufferNative) bool { 43 return f == rhs 44 } 45 46 func (s shader) equal(rhs shader) bool { 47 return s == rhs 48 } 49 50 func (b buffer) equal(rhs buffer) bool { 51 return b == rhs 52 } 53 54 func (u uniformLocation) equal(rhs uniformLocation) bool { 55 return u == rhs 56 } 57 58 func (p program) equal(rhs program) bool { 59 return p == rhs 60 } 61 62 var InvalidTexture textureNative 63 64 type ( 65 uniformLocation int32 66 attribLocation int32 67 ) 68 69 type programID uint32 70 71 const ( 72 invalidTexture = 0 73 invalidFramebuffer = (1 << 32) - 1 74 invalidUniform = -1 75 ) 76 77 func getProgramID(p program) programID { 78 return programID(p) 79 } 80 81 const ( 82 vertexShader = shaderType(gl.VERTEX_SHADER) 83 fragmentShader = shaderType(gl.FRAGMENT_SHADER) 84 arrayBuffer = bufferType(gl.ARRAY_BUFFER) 85 elementArrayBuffer = bufferType(gl.ELEMENT_ARRAY_BUFFER) 86 dynamicDraw = bufferUsage(gl.DYNAMIC_DRAW) 87 short = dataType(gl.SHORT) 88 float = dataType(gl.FLOAT) 89 90 zero = operation(gl.ZERO) 91 one = operation(gl.ONE) 92 srcAlpha = operation(gl.SRC_ALPHA) 93 dstAlpha = operation(gl.DST_ALPHA) 94 oneMinusSrcAlpha = operation(gl.ONE_MINUS_SRC_ALPHA) 95 oneMinusDstAlpha = operation(gl.ONE_MINUS_DST_ALPHA) 96 dstColor = operation(gl.DST_COLOR) 97 ) 98 99 type contextImpl struct { 100 init bool 101 } 102 103 func (c *context) reset() error { 104 if err := c.t.Call(func() error { 105 if c.init { 106 return nil 107 } 108 // Note that this initialization must be done after Loop is called. 109 if err := gl.Init(); err != nil { 110 return fmt.Errorf("opengl: initializing error %v", err) 111 } 112 c.init = true 113 return nil 114 }); err != nil { 115 return err 116 } 117 c.locationCache = newLocationCache() 118 c.lastTexture = invalidTexture 119 c.lastFramebuffer = invalidFramebuffer 120 c.lastViewportWidth = 0 121 c.lastViewportHeight = 0 122 c.lastCompositeMode = driver.CompositeModeUnknown 123 _ = c.t.Call(func() error { 124 gl.Enable(gl.BLEND) 125 return nil 126 }) 127 c.blendFunc(driver.CompositeModeSourceOver) 128 _ = c.t.Call(func() error { 129 f := int32(0) 130 gl.GetIntegerv(gl.FRAMEBUFFER_BINDING, &f) 131 c.screenFramebuffer = framebufferNative(f) 132 return nil 133 }) 134 return nil 135 } 136 137 func (c *context) blendFunc(mode driver.CompositeMode) { 138 _ = c.t.Call(func() error { 139 if c.lastCompositeMode == mode { 140 return nil 141 } 142 c.lastCompositeMode = mode 143 s, d := mode.Operations() 144 s2, d2 := convertOperation(s), convertOperation(d) 145 gl.BlendFunc(uint32(s2), uint32(d2)) 146 return nil 147 }) 148 } 149 150 func (c *context) newTexture(width, height int) (textureNative, error) { 151 var texture textureNative 152 if err := c.t.Call(func() error { 153 var t uint32 154 gl.GenTextures(1, &t) 155 // TODO: Use gl.IsTexture 156 if t <= 0 { 157 return errors.New("opengl: creating texture failed") 158 } 159 gl.PixelStorei(gl.UNPACK_ALIGNMENT, 4) 160 texture = textureNative(t) 161 return nil 162 }); err != nil { 163 return 0, err 164 } 165 c.bindTexture(texture) 166 _ = c.t.Call(func() error { 167 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) 168 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) 169 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) 170 gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) 171 // If data is nil, this just allocates memory and the content is undefined. 172 // https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glTexImage2D.xhtml 173 gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(width), int32(height), 0, gl.RGBA, gl.UNSIGNED_BYTE, nil) 174 return nil 175 }) 176 return texture, nil 177 } 178 179 func (c *context) bindFramebufferImpl(f framebufferNative) { 180 _ = c.t.Call(func() error { 181 gl.BindFramebufferEXT(gl.FRAMEBUFFER, uint32(f)) 182 return nil 183 }) 184 } 185 186 func (c *context) framebufferPixels(f *framebuffer, width, height int) ([]byte, error) { 187 var pixels []byte 188 _ = c.t.Call(func() error { 189 gl.Flush() 190 return nil 191 }) 192 c.bindFramebuffer(f.native) 193 if err := c.t.Call(func() error { 194 pixels = make([]byte, 4*width*height) 195 gl.ReadPixels(0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(pixels)) 196 return nil 197 }); err != nil { 198 return nil, err 199 } 200 return pixels, nil 201 } 202 203 func (c *context) activeTexture(idx int) { 204 _ = c.t.Call(func() error { 205 gl.ActiveTexture(gl.TEXTURE0 + uint32(idx)) 206 return nil 207 }) 208 } 209 210 func (c *context) bindTextureImpl(t textureNative) { 211 _ = c.t.Call(func() error { 212 gl.BindTexture(gl.TEXTURE_2D, uint32(t)) 213 return nil 214 }) 215 } 216 217 func (c *context) deleteTexture(t textureNative) { 218 _ = c.t.Call(func() error { 219 tt := uint32(t) 220 if !gl.IsTexture(tt) { 221 return nil 222 } 223 if c.lastTexture == t { 224 c.lastTexture = invalidTexture 225 } 226 gl.DeleteTextures(1, &tt) 227 return nil 228 }) 229 } 230 231 func (c *context) isTexture(t textureNative) bool { 232 panic("opengl: isTexture is not implemented") 233 } 234 235 func (c *context) newFramebuffer(texture textureNative) (framebufferNative, error) { 236 var framebuffer framebufferNative 237 var f uint32 238 if err := c.t.Call(func() error { 239 gl.GenFramebuffersEXT(1, &f) 240 // TODO: Use gl.IsFramebuffer 241 if f <= 0 { 242 return errors.New("opengl: creating framebuffer failed: gl.IsFramebuffer returns false") 243 } 244 return nil 245 }); err != nil { 246 return 0, err 247 } 248 c.bindFramebuffer(framebufferNative(f)) 249 if err := c.t.Call(func() error { 250 gl.FramebufferTexture2DEXT(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, uint32(texture), 0) 251 s := gl.CheckFramebufferStatusEXT(gl.FRAMEBUFFER) 252 if s != gl.FRAMEBUFFER_COMPLETE { 253 if s != 0 { 254 return fmt.Errorf("opengl: creating framebuffer failed: %v", s) 255 } 256 if e := gl.GetError(); e != gl.NO_ERROR { 257 return fmt.Errorf("opengl: creating framebuffer failed: (glGetError) %d", e) 258 } 259 return fmt.Errorf("opengl: creating framebuffer failed: unknown error") 260 } 261 framebuffer = framebufferNative(f) 262 return nil 263 }); err != nil { 264 return 0, err 265 } 266 return framebuffer, nil 267 } 268 269 func (c *context) setViewportImpl(width, height int) { 270 _ = c.t.Call(func() error { 271 gl.Viewport(0, 0, int32(width), int32(height)) 272 return nil 273 }) 274 } 275 276 func (c *context) deleteFramebuffer(f framebufferNative) { 277 _ = c.t.Call(func() error { 278 ff := uint32(f) 279 if !gl.IsFramebufferEXT(ff) { 280 return nil 281 } 282 if c.lastFramebuffer == f { 283 c.lastFramebuffer = invalidFramebuffer 284 c.lastViewportWidth = 0 285 c.lastViewportHeight = 0 286 } 287 gl.DeleteFramebuffersEXT(1, &ff) 288 return nil 289 }) 290 } 291 292 func (c *context) newShader(shaderType shaderType, source string) (shader, error) { 293 var sh shader 294 if err := c.t.Call(func() error { 295 s := gl.CreateShader(uint32(shaderType)) 296 if s == 0 { 297 return fmt.Errorf("opengl: glCreateShader failed: shader type: %d", shaderType) 298 } 299 cSources, free := gl.Strs(source + "\x00") 300 gl.ShaderSource(uint32(s), 1, cSources, nil) 301 free() 302 gl.CompileShader(s) 303 304 var v int32 305 gl.GetShaderiv(s, gl.COMPILE_STATUS, &v) 306 if v == gl.FALSE { 307 var l int32 308 var log []byte 309 gl.GetShaderiv(uint32(s), gl.INFO_LOG_LENGTH, &l) 310 if l != 0 { 311 log = make([]byte, l) 312 gl.GetShaderInfoLog(s, l, nil, (*uint8)(gl.Ptr(log))) 313 } 314 return fmt.Errorf("opengl: shader compile failed: %s", log) 315 } 316 sh = shader(s) 317 return nil 318 }); err != nil { 319 return 0, err 320 } 321 return sh, nil 322 } 323 324 func (c *context) deleteShader(s shader) { 325 _ = c.t.Call(func() error { 326 gl.DeleteShader(uint32(s)) 327 return nil 328 }) 329 } 330 331 func (c *context) newProgram(shaders []shader, attributes []string) (program, error) { 332 var pr program 333 if err := c.t.Call(func() error { 334 p := gl.CreateProgram() 335 if p == 0 { 336 return errors.New("opengl: glCreateProgram failed") 337 } 338 339 for _, shader := range shaders { 340 gl.AttachShader(p, uint32(shader)) 341 } 342 343 for i, name := range attributes { 344 l, free := gl.Strs(name + "\x00") 345 gl.BindAttribLocation(p, uint32(i), *l) 346 free() 347 } 348 349 gl.LinkProgram(p) 350 var v int32 351 gl.GetProgramiv(p, gl.LINK_STATUS, &v) 352 if v == gl.FALSE { 353 var l int32 354 var log []byte 355 gl.GetProgramiv(p, gl.INFO_LOG_LENGTH, &l) 356 if l != 0 { 357 log = make([]byte, l) 358 gl.GetProgramInfoLog(p, l, nil, (*uint8)(gl.Ptr(log))) 359 } 360 return fmt.Errorf("opengl: program error: %s", log) 361 } 362 pr = program(p) 363 return nil 364 }); err != nil { 365 return 0, err 366 } 367 return pr, nil 368 } 369 370 func (c *context) useProgram(p program) { 371 _ = c.t.Call(func() error { 372 gl.UseProgram(uint32(p)) 373 return nil 374 }) 375 } 376 377 func (c *context) deleteProgram(p program) { 378 _ = c.t.Call(func() error { 379 if !gl.IsProgram(uint32(p)) { 380 return nil 381 } 382 gl.DeleteProgram(uint32(p)) 383 return nil 384 }) 385 } 386 387 func (c *context) getUniformLocationImpl(p program, location string) uniformLocation { 388 l, free := gl.Strs(location + "\x00") 389 uniform := uniformLocation(gl.GetUniformLocation(uint32(p), *l)) 390 free() 391 return uniform 392 } 393 394 func (c *context) uniformInt(p program, location string, v int) bool { 395 var r bool 396 _ = c.t.Call(func() error { 397 l := int32(c.locationCache.GetUniformLocation(c, p, location)) 398 if l == invalidUniform { 399 return nil 400 } 401 r = true 402 gl.Uniform1i(l, int32(v)) 403 return nil 404 }) 405 return r 406 } 407 408 func (c *context) uniformFloat(p program, location string, v float32) bool { 409 var r bool 410 _ = c.t.Call(func() error { 411 l := int32(c.locationCache.GetUniformLocation(c, p, location)) 412 if l == invalidUniform { 413 return nil 414 } 415 r = true 416 gl.Uniform1f(l, v) 417 return nil 418 }) 419 return r 420 } 421 422 func (c *context) uniformFloats(p program, location string, v []float32, typ shaderir.Type) bool { 423 var r bool 424 _ = c.t.Call(func() error { 425 l := int32(c.locationCache.GetUniformLocation(c, p, location)) 426 if l == invalidUniform { 427 return nil 428 } 429 r = true 430 431 base := typ.Main 432 len := int32(1) 433 if base == shaderir.Array { 434 base = typ.Sub[0].Main 435 len = int32(typ.Length) 436 } 437 438 switch base { 439 case shaderir.Float: 440 gl.Uniform1fv(l, len, (*float32)(gl.Ptr(v))) 441 case shaderir.Vec2: 442 gl.Uniform2fv(l, len, (*float32)(gl.Ptr(v))) 443 case shaderir.Vec3: 444 gl.Uniform3fv(l, len, (*float32)(gl.Ptr(v))) 445 case shaderir.Vec4: 446 gl.Uniform4fv(l, len, (*float32)(gl.Ptr(v))) 447 case shaderir.Mat2: 448 gl.UniformMatrix2fv(l, len, false, (*float32)(gl.Ptr(v))) 449 case shaderir.Mat3: 450 gl.UniformMatrix3fv(l, len, false, (*float32)(gl.Ptr(v))) 451 case shaderir.Mat4: 452 gl.UniformMatrix4fv(l, len, false, (*float32)(gl.Ptr(v))) 453 default: 454 panic(fmt.Sprintf("opengl: unexpected type: %s", typ.String())) 455 } 456 return nil 457 }) 458 return r 459 } 460 461 func (c *context) vertexAttribPointer(p program, index int, size int, dataType dataType, stride int, offset int) { 462 _ = c.t.Call(func() error { 463 gl.VertexAttribPointer(uint32(index), int32(size), uint32(dataType), false, int32(stride), uintptr(offset)) 464 return nil 465 }) 466 } 467 468 func (c *context) enableVertexAttribArray(p program, index int) { 469 _ = c.t.Call(func() error { 470 gl.EnableVertexAttribArray(uint32(index)) 471 return nil 472 }) 473 } 474 475 func (c *context) disableVertexAttribArray(p program, index int) { 476 _ = c.t.Call(func() error { 477 gl.DisableVertexAttribArray(uint32(index)) 478 return nil 479 }) 480 } 481 482 func (c *context) newArrayBuffer(size int) buffer { 483 var bf buffer 484 _ = c.t.Call(func() error { 485 var b uint32 486 gl.GenBuffers(1, &b) 487 gl.BindBuffer(uint32(arrayBuffer), b) 488 gl.BufferData(uint32(arrayBuffer), size, nil, uint32(dynamicDraw)) 489 bf = buffer(b) 490 return nil 491 }) 492 return bf 493 } 494 495 func (c *context) newElementArrayBuffer(size int) buffer { 496 var bf buffer 497 _ = c.t.Call(func() error { 498 var b uint32 499 gl.GenBuffers(1, &b) 500 gl.BindBuffer(uint32(elementArrayBuffer), b) 501 gl.BufferData(uint32(elementArrayBuffer), size, nil, uint32(dynamicDraw)) 502 bf = buffer(b) 503 return nil 504 }) 505 return bf 506 } 507 508 func (c *context) bindBuffer(bufferType bufferType, b buffer) { 509 _ = c.t.Call(func() error { 510 gl.BindBuffer(uint32(bufferType), uint32(b)) 511 return nil 512 }) 513 } 514 515 func (c *context) arrayBufferSubData(data []float32) { 516 _ = c.t.Call(func() error { 517 gl.BufferSubData(uint32(arrayBuffer), 0, len(data)*4, gl.Ptr(data)) 518 return nil 519 }) 520 } 521 522 func (c *context) elementArrayBufferSubData(data []uint16) { 523 _ = c.t.Call(func() error { 524 gl.BufferSubData(uint32(elementArrayBuffer), 0, len(data)*2, gl.Ptr(data)) 525 return nil 526 }) 527 } 528 529 func (c *context) deleteBuffer(b buffer) { 530 _ = c.t.Call(func() error { 531 bb := uint32(b) 532 gl.DeleteBuffers(1, &bb) 533 return nil 534 }) 535 } 536 537 func (c *context) drawElements(len int, offsetInBytes int) { 538 _ = c.t.Call(func() error { 539 gl.DrawElements(gl.TRIANGLES, int32(len), gl.UNSIGNED_SHORT, uintptr(offsetInBytes)) 540 return nil 541 }) 542 } 543 544 func (c *context) maxTextureSizeImpl() int { 545 size := 0 546 _ = c.t.Call(func() error { 547 s := int32(0) 548 gl.GetIntegerv(gl.MAX_TEXTURE_SIZE, &s) 549 size = int(s) 550 return nil 551 }) 552 return size 553 } 554 555 func (c *context) getShaderPrecisionFormatPrecision() int { 556 // glGetShaderPrecisionFormat is not defined at OpenGL 2.0. Assume that desktop environments always have 557 // enough highp precision. 558 return highpPrecision 559 } 560 561 func (c *context) flush() { 562 _ = c.t.Call(func() error { 563 gl.Flush() 564 return nil 565 }) 566 } 567 568 func (c *context) needsRestoring() bool { 569 return false 570 } 571 572 func (c *context) canUsePBO() bool { 573 var available bool 574 _ = c.t.Call(func() error { 575 available = isPBOAvailable() 576 return nil 577 }) 578 579 return available 580 } 581 582 func (c *context) texSubImage2D(t textureNative, width, height int, args []*driver.ReplacePixelsArgs) { 583 c.bindTexture(t) 584 _ = c.t.Call(func() error { 585 for _, a := range args { 586 gl.TexSubImage2D(gl.TEXTURE_2D, 0, int32(a.X), int32(a.Y), int32(a.Width), int32(a.Height), gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(a.Pixels)) 587 } 588 return nil 589 }) 590 } 591 592 func (c *context) newPixelBufferObject(width, height int) buffer { 593 var bf buffer 594 _ = c.t.Call(func() error { 595 var b uint32 596 gl.GenBuffers(1, &b) 597 gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, b) 598 gl.BufferData(gl.PIXEL_UNPACK_BUFFER, 4*width*height, nil, gl.STREAM_DRAW) 599 gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, 0) 600 bf = buffer(b) 601 return nil 602 }) 603 return bf 604 } 605 606 func (c *context) replacePixelsWithPBO(buffer buffer, t textureNative, width, height int, args []*driver.ReplacePixelsArgs) { 607 c.bindTexture(t) 608 _ = c.t.Call(func() error { 609 gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, uint32(buffer)) 610 611 stride := 4 * width 612 for _, a := range args { 613 offset := 4 * (a.Y*width + a.X) 614 for j := 0; j < a.Height; j++ { 615 gl.BufferSubData(gl.PIXEL_UNPACK_BUFFER, offset+stride*j, 4*a.Width, gl.Ptr(a.Pixels[4*a.Width*j:4*a.Width*(j+1)])) 616 } 617 } 618 619 gl.TexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, int32(width), int32(height), gl.RGBA, gl.UNSIGNED_BYTE, nil) 620 gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, 0) 621 return nil 622 }) 623 }