From e52ee3ba9a59ebff7477099bbe791e39406fa8d9 Mon Sep 17 00:00:00 2001 From: faiface Date: Wed, 23 Nov 2016 18:50:49 +0100 Subject: [PATCH] encapsulate error handling add functions DoGLErr, DoErrGLErr and DoValGLErr to handle OpenGL errors --- pixelgl/error.go | 41 -------------------------- pixelgl/texture.go | 4 +-- pixelgl/thread.go | 73 ++++++++++++++++++++++++++++++++++++++++++++-- pixelgl/vertex.go | 7 ++--- 4 files changed, 74 insertions(+), 51 deletions(-) delete mode 100644 pixelgl/error.go diff --git a/pixelgl/error.go b/pixelgl/error.go deleted file mode 100644 index 48e5e90..0000000 --- a/pixelgl/error.go +++ /dev/null @@ -1,41 +0,0 @@ -package pixelgl - -import ( - "github.com/go-gl/gl/v3.3-core/gl" - "github.com/pkg/errors" -) - -// getLastError returns (and consumes) the last error generated by OpenGL inside the current Do, DoErr or DoVal. -// If no error has been generated, this function returns nil. -// -// Call this function only inside the OpenGL thread (Do, DoErr or DoVal function). It's not guaranteed -// to work correctly outside of it, because the thread swallows extra unchecked errors. -func getLastError() error { - err := uint32(gl.NO_ERROR) - for e := gl.GetError(); e != gl.NO_ERROR; e = gl.GetError() { - err = e - } - if err == gl.NO_ERROR { - return nil - } - switch err { - case gl.INVALID_ENUM: - return errors.New("invalid enum") - case gl.INVALID_VALUE: - return errors.New("invalid value") - case gl.INVALID_OPERATION: - return errors.New("invalid operation") - case gl.STACK_OVERFLOW: - return errors.New("stack overflow") - case gl.STACK_UNDERFLOW: - return errors.New("stack underflow") - case gl.OUT_OF_MEMORY: - return errors.New("out of memory") - case gl.INVALID_FRAMEBUFFER_OPERATION: - return errors.New("invalid framebuffer operation") - case gl.CONTEXT_LOST: - return errors.New("context lost") - default: - return errors.New("unknown error") - } -} diff --git a/pixelgl/texture.go b/pixelgl/texture.go index 7d02e5e..d9cad7b 100644 --- a/pixelgl/texture.go +++ b/pixelgl/texture.go @@ -15,7 +15,7 @@ type Texture struct { // The pixels must be a sequence of RGBA values. func NewTexture(parent BeginEnder, width, height int, pixels []uint8) (*Texture, error) { texture := &Texture{parent: parent} - err := DoErr(func() error { + err := DoGLErr(func() { gl.GenTextures(1, &texture.tex) gl.BindTexture(gl.TEXTURE_2D, texture.tex) @@ -33,8 +33,6 @@ func NewTexture(parent BeginEnder, width, height int, pixels []uint8) (*Texture, gl.GenerateMipmap(gl.TEXTURE_2D) gl.BindTexture(gl.TEXTURE_2D, 0) - - return getLastError() }) if err != nil { return nil, errors.Wrap(err, "failed to create a texture") diff --git a/pixelgl/thread.go b/pixelgl/thread.go index 03597da..b4b5800 100644 --- a/pixelgl/thread.go +++ b/pixelgl/thread.go @@ -1,6 +1,11 @@ package pixelgl -import "runtime" +import ( + "errors" + "runtime" + + "github.com/go-gl/gl/v2.1/gl" +) // Due to the existance and usage of thread-local variables by OpenGL, it's recommended to // execute all OpenGL calls from a single dedicated thread. This file defines functions to make @@ -16,7 +21,7 @@ func init() { go func() { runtime.LockOSThread() for f := range callQueue { - getLastError() // swallow unchecked errors + getLastGLErr() // swallow unchecked errors f() } }() @@ -58,3 +63,67 @@ func DoVal(f func() interface{}) interface{} { } return <-val } + +// DoGLErr is same as Do, but also return an error generated by OpenGL. +func DoGLErr(f func()) (gl error) { + glerr := make(chan error) + callQueue <- func() { + f() + glerr <- getLastGLErr() + } + return <-glerr +} + +// DoErrGLErr is same as DoErr, but also returns an error generated by OpenGL. +func DoErrGLErr(f func() error) (_, gl error) { + err := make(chan error) + glerr := make(chan error) + callQueue <- func() { + err <- f() + glerr <- getLastGLErr() + } + return <-err, <-glerr +} + +// DoValGLErr is same as DoVal, but also returns an error generated by OpenGL. +func DoValGLErr(f func() interface{}) (_ interface{}, gl error) { + val := make(chan interface{}) + glerr := make(chan error) + callQueue <- func() { + val <- f() + glerr <- getLastGLErr() + } + return <-val, <-glerr +} + +// getLastGLErr returns (and consumes) the last error generated by OpenGL. +// Don't use outside DoGLErr, DoErrGLErr and DoValGLErr. +func getLastGLErr() error { + err := uint32(gl.NO_ERROR) + for e := gl.GetError(); e != gl.NO_ERROR; e = gl.GetError() { + err = e + } + if err == gl.NO_ERROR { + return nil + } + switch err { + case gl.INVALID_ENUM: + return errors.New("invalid enum") + case gl.INVALID_VALUE: + return errors.New("invalid value") + case gl.INVALID_OPERATION: + return errors.New("invalid operation") + case gl.STACK_OVERFLOW: + return errors.New("stack overflow") + case gl.STACK_UNDERFLOW: + return errors.New("stack underflow") + case gl.OUT_OF_MEMORY: + return errors.New("out of memory") + case gl.INVALID_FRAMEBUFFER_OPERATION: + return errors.New("invalid framebuffer operation") + case gl.CONTEXT_LOST: + return errors.New("context lost") + default: + return errors.New("unknown error") + } +} diff --git a/pixelgl/vertex.go b/pixelgl/vertex.go index 8c0c09d..63cc498 100644 --- a/pixelgl/vertex.go +++ b/pixelgl/vertex.go @@ -105,7 +105,7 @@ func NewVertexArray(parent BeginEnder, format VertexFormat, mode VertexDrawMode, format: format, mode: mode, } - err := DoErr(func() error { + err := DoGLErr(func() { gl.GenVertexArrays(1, &va.vao) gl.BindVertexArray(va.vao) @@ -132,8 +132,6 @@ func NewVertexArray(parent BeginEnder, format VertexFormat, mode VertexDrawMode, gl.BindBuffer(gl.ARRAY_BUFFER, 0) gl.BindVertexArray(0) - - return getLastError() }) if err != nil { return nil, errors.Wrap(err, "failed to create a vertex array") @@ -173,11 +171,10 @@ func (va *VertexArray) Draw() { // // Offset is not a number of bytes, instead, it's an index in the array. func (va *VertexArray) UpdateData(offset int, data []float64) error { - err := DoErr(func() error { + err := DoGLErr(func() { gl.BindBuffer(gl.ARRAY_BUFFER, va.vbo) gl.BufferSubData(gl.ARRAY_BUFFER, 8*offset, 8*len(data), gl.Ptr(data)) gl.BindBuffer(gl.ARRAY_BUFFER, 0) - return getLastError() }) if err != nil { return errors.Wrap(err, "failed to update vertex array")