ui/app/internal/gpu: introduce caps and context

Enables graceful fallback to OpenGL ES 2 and WebGL.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2019-05-04 11:45:28 +02:00
parent 8df5feeeea
commit d118bd5a88
4 changed files with 130 additions and 102 deletions
+52
View File
@@ -0,0 +1,52 @@
package gpu
import (
"strings"
"gioui.org/ui/app/internal/gl"
)
type context struct {
caps caps
*gl.Functions
}
type caps struct {
EXT_disjoint_timer_query bool
srgbMode srgbMode
}
type srgbMode uint8
const (
srgbES3 srgbMode = iota
srgbEXT
)
func newContext(glctx gl.Context) (*context, error) {
ctx := &context{
Functions: glctx.Functions(),
}
exts := ctx.GetString(gl.EXTENSIONS)
glVer := ctx.GetString(gl.VERSION)
ver, err := gl.ParseGLVersion(glVer)
if err != nil {
return nil, err
}
ctx.caps = caps{
EXT_disjoint_timer_query: strings.Contains(exts, "GL_EXT_disjoint_timer_query"),
srgbMode: srgbModeFor(ver, exts),
}
return ctx, nil
}
func srgbModeFor(ver [2]int, exts string) srgbMode {
switch {
case ver[0] >= 3:
return srgbES3
case strings.Contains(exts, "EXT_sRGB"):
return srgbEXT
default:
panic("neither OpenGL ES 3 nor EXT_sRGB is supported")
}
}
+44 -68
View File
@@ -47,8 +47,7 @@ type frameResult struct {
} }
type renderer struct { type renderer struct {
ctx *gl.Functions ctx *context
srgbMode srgbMode
blitter *blitter blitter *blitter
pather *pather pather *pather
packer packer packer packer
@@ -115,7 +114,7 @@ type resourceCache struct {
} }
type resource interface { type resource interface {
release(ctx *gl.Functions) release(ctx *context)
} }
type texture struct { type texture struct {
@@ -125,7 +124,7 @@ type texture struct {
} }
type blitter struct { type blitter struct {
ctx *gl.Functions ctx *context
viewport image.Point viewport image.Point
prog [2]gl.Program prog [2]gl.Program
vars [2]struct { vars [2]struct {
@@ -138,12 +137,6 @@ type blitter struct {
} }
type materialType uint8 type materialType uint8
type srgbMode uint8
const (
srgbES3 srgbMode = iota
srgbEXT
)
const ( const (
clipTypeNone clipType = iota clipTypeNone clipType = iota
@@ -172,14 +165,13 @@ func NewGPU(ctx gl.Context) (*GPU, error) {
stopped: make(chan struct{}), stopped: make(chan struct{}),
cache: newResourceCache(), cache: newResourceCache(),
} }
// Pretend the last error was nil.
if err := g.renderLoop(ctx); err != nil { if err := g.renderLoop(ctx); err != nil {
return nil, err return nil, err
} }
return g, nil return g, nil
} }
func (g *GPU) renderLoop(ctx gl.Context) error { func (g *GPU) renderLoop(glctx gl.Context) error {
// GL Operations must happen on a single OS thread, so // GL Operations must happen on a single OS thread, so
// pass initialization result through a channel. // pass initialization result through a channel.
initErr := make(chan error) initErr := make(chan error)
@@ -187,35 +179,31 @@ func (g *GPU) renderLoop(ctx gl.Context) error {
runtime.LockOSThread() runtime.LockOSThread()
// Don't UnlockOSThread to avoid reuse by the Go runtime. // Don't UnlockOSThread to avoid reuse by the Go runtime.
defer close(g.stopped) defer close(g.stopped)
defer ctx.Release() defer glctx.Release()
if err := ctx.MakeCurrent(); err != nil { if err := glctx.MakeCurrent(); err != nil {
initErr <- err initErr <- err
return return
} }
funcs := ctx.Functions() ctx, err := newContext(glctx)
defer g.cache.release(funcs)
exts := funcs.GetString(gl.EXTENSIONS)
glVer := funcs.GetString(gl.VERSION)
ver, err := gl.ParseGLVersion(glVer)
if err != nil { if err != nil {
initErr <- err initErr <- err
return return
} }
r := newRenderer(funcs, srgbModeFor(ver, exts)) defer g.cache.release(ctx)
r := newRenderer(ctx)
defer r.release() defer r.release()
var timers *timers var timers *timers
var zopsTimer, stencilTimer, coverTimer, cleanupTimer *timer var zopsTimer, stencilTimer, coverTimer, cleanupTimer *timer
hasTimers := strings.Contains(exts, "GL_EXT_disjoint_timer_query")
initErr <- nil initErr <- nil
loop: loop:
for { for {
select { select {
case <-g.refresh: case <-g.refresh:
g.refreshErr <- ctx.MakeCurrent() g.refreshErr <- glctx.MakeCurrent()
case frame := <-g.frames: case frame := <-g.frames:
if frame.collectStats && timers == nil && hasTimers { if frame.collectStats && timers == nil && ctx.caps.EXT_disjoint_timer_query {
timers = newTimers(funcs, exts) timers = newTimers(ctx)
zopsTimer = timers.newTimer() zopsTimer = timers.newTimer()
stencilTimer = timers.newTimer() stencilTimer = timers.newTimer()
coverTimer = timers.newTimer() coverTimer = timers.newTimer()
@@ -231,29 +219,29 @@ func (g *GPU) renderLoop(ctx gl.Context) error {
if frame.collectStats { if frame.collectStats {
zopsTimer.begin() zopsTimer.begin()
} }
funcs.DepthFunc(gl.GREATER) ctx.DepthFunc(gl.GREATER)
funcs.ClearColor(ops.clearColor[0], ops.clearColor[1], ops.clearColor[2], 1.0) ctx.ClearColor(ops.clearColor[0], ops.clearColor[1], ops.clearColor[2], 1.0)
funcs.ClearDepthf(0.0) ctx.ClearDepthf(0.0)
funcs.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) ctx.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
funcs.Viewport(0, 0, frame.viewport.X, frame.viewport.Y) ctx.Viewport(0, 0, frame.viewport.X, frame.viewport.Y)
r.drawZOps(ops.zimageOps) r.drawZOps(ops.zimageOps)
zopsTimer.end() zopsTimer.end()
stencilTimer.begin() stencilTimer.begin()
funcs.Enable(gl.BLEND) ctx.Enable(gl.BLEND)
r.packStencils(&ops.pathOps) r.packStencils(&ops.pathOps)
r.stencilClips(g.cache, ops.pathOps) r.stencilClips(g.cache, ops.pathOps)
r.packIntersections(ops.imageOps) r.packIntersections(ops.imageOps)
r.intersect(ops.imageOps) r.intersect(ops.imageOps)
stencilTimer.end() stencilTimer.end()
coverTimer.begin() coverTimer.begin()
funcs.Viewport(0, 0, frame.viewport.X, frame.viewport.Y) ctx.Viewport(0, 0, frame.viewport.X, frame.viewport.Y)
r.drawOps(ops.imageOps) r.drawOps(ops.imageOps)
funcs.Disable(gl.BLEND) ctx.Disable(gl.BLEND)
r.pather.stenciler.invalidateFBO() r.pather.stenciler.invalidateFBO()
coverTimer.end() coverTimer.end()
err := ctx.Present() err := glctx.Present()
cleanupTimer.begin() cleanupTimer.begin()
g.cache.frame(funcs) g.cache.frame(ctx)
cleanupTimer.end() cleanupTimer.end()
var res frameResult var res frameResult
if frame.collectStats && timers.ready() { if frame.collectStats && timers.ready() {
@@ -335,18 +323,17 @@ func (r *renderer) texHandle(t *texture) gl.Texture {
return t.id return t.id
} }
func (t *texture) release(ctx *gl.Functions) { func (t *texture) release(ctx *context) {
if t.id != (gl.Texture{}) { if t.id != (gl.Texture{}) {
ctx.DeleteTexture(t.id) ctx.DeleteTexture(t.id)
} }
} }
func newRenderer(ctx *gl.Functions, mode srgbMode) *renderer { func newRenderer(ctx *context) *renderer {
r := &renderer{ r := &renderer{
ctx: ctx, ctx: ctx,
srgbMode: mode, blitter: newBlitter(ctx),
blitter: newBlitter(ctx), pather: newPather(ctx),
pather: newPather(ctx),
} }
r.packer.maxDim = ctx.GetInteger(gl.MAX_TEXTURE_SIZE) r.packer.maxDim = ctx.GetInteger(gl.MAX_TEXTURE_SIZE)
r.intersections.maxDim = r.packer.maxDim r.intersections.maxDim = r.packer.maxDim
@@ -381,7 +368,7 @@ func (r *resourceCache) put(key interface{}, val resource) {
r.newRes[key] = val r.newRes[key] = val
} }
func (r *resourceCache) frame(ctx *gl.Functions) { func (r *resourceCache) frame(ctx *context) {
for k, v := range r.res { for k, v := range r.res {
if _, exists := r.newRes[k]; !exists { if _, exists := r.newRes[k]; !exists {
delete(r.res, k) delete(r.res, k)
@@ -394,7 +381,7 @@ func (r *resourceCache) frame(ctx *gl.Functions) {
} }
} }
func (r *resourceCache) release(ctx *gl.Functions) { func (r *resourceCache) release(ctx *context) {
for _, v := range r.newRes { for _, v := range r.newRes {
v.release(ctx) v.release(ctx)
} }
@@ -402,7 +389,7 @@ func (r *resourceCache) release(ctx *gl.Functions) {
r.res = nil r.res = nil
} }
func newBlitter(ctx *gl.Functions) *blitter { func newBlitter(ctx *context) *blitter {
prog, err := createColorPrograms(ctx, blitVSrc, blitFSrc) prog, err := createColorPrograms(ctx, blitVSrc, blitFSrc)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -426,16 +413,16 @@ func newBlitter(ctx *gl.Functions) *blitter {
ctx.UseProgram(prog) ctx.UseProgram(prog)
switch materialType(i) { switch materialType(i) {
case materialTexture: case materialTexture:
uTex := gl.GetUniformLocation(ctx, prog, "tex") uTex := gl.GetUniformLocation(ctx.Functions, prog, "tex")
ctx.Uniform1i(uTex, 0) ctx.Uniform1i(uTex, 0)
b.vars[i].uUVScale = gl.GetUniformLocation(ctx, prog, "uvScale") b.vars[i].uUVScale = gl.GetUniformLocation(ctx.Functions, prog, "uvScale")
b.vars[i].uUVOffset = gl.GetUniformLocation(ctx, prog, "uvOffset") b.vars[i].uUVOffset = gl.GetUniformLocation(ctx.Functions, prog, "uvOffset")
case materialColor: case materialColor:
b.vars[i].uColor = gl.GetUniformLocation(ctx, prog, "color") b.vars[i].uColor = gl.GetUniformLocation(ctx.Functions, prog, "color")
} }
b.vars[i].z = gl.GetUniformLocation(ctx, prog, "z") b.vars[i].z = gl.GetUniformLocation(ctx.Functions, prog, "z")
b.vars[i].uScale = gl.GetUniformLocation(ctx, prog, "scale") b.vars[i].uScale = gl.GetUniformLocation(ctx.Functions, prog, "scale")
b.vars[i].uOffset = gl.GetUniformLocation(ctx, prog, "offset") b.vars[i].uOffset = gl.GetUniformLocation(ctx.Functions, prog, "offset")
} }
return b return b
} }
@@ -447,7 +434,7 @@ func (b *blitter) release() {
} }
} }
func createColorPrograms(ctx *gl.Functions, vsSrc, fsSrc string) ([2]gl.Program, error) { func createColorPrograms(ctx *context, vsSrc, fsSrc string) ([2]gl.Program, error) {
var prog [2]gl.Program var prog [2]gl.Program
frep := strings.NewReplacer( frep := strings.NewReplacer(
"HEADER", ` "HEADER", `
@@ -457,7 +444,7 @@ uniform sampler2D tex;
) )
fsSrcTex := frep.Replace(fsSrc) fsSrcTex := frep.Replace(fsSrc)
var err error var err error
prog[materialTexture], err = gl.CreateProgram(ctx, vsSrc, fsSrcTex, blitAttribs) prog[materialTexture], err = gl.CreateProgram(ctx.Functions, vsSrc, fsSrcTex, blitAttribs)
if err != nil { if err != nil {
return prog, err return prog, err
} }
@@ -468,7 +455,7 @@ uniform vec4 color;
"GET_COLOR", `color`, "GET_COLOR", `color`,
) )
fsSrcCol := frep.Replace(fsSrc) fsSrcCol := frep.Replace(fsSrc)
prog[materialColor], err = gl.CreateProgram(ctx, vsSrc, fsSrcCol, blitAttribs) prog[materialColor], err = gl.CreateProgram(ctx.Functions, vsSrc, fsSrcCol, blitAttribs)
if err != nil { if err != nil {
ctx.DeleteProgram(prog[materialTexture]) ctx.DeleteProgram(prog[materialTexture])
return prog, err return prog, err
@@ -886,7 +873,7 @@ func (r *renderer) uploadTexture(img image.Image, opaque bool) {
r.ctx.PixelStorei(gl.UNPACK_ALIGNMENT, 1) r.ctx.PixelStorei(gl.UNPACK_ALIGNMENT, 1)
var internal int var internal int
var format gl.Enum var format gl.Enum
switch r.srgbMode { switch r.ctx.caps.srgbMode {
case srgbES3: case srgbES3:
internal, format = gl.SRGB8, gl.RGB internal, format = gl.SRGB8, gl.RGB
case srgbEXT: case srgbEXT:
@@ -897,7 +884,7 @@ func (r *renderer) uploadTexture(img image.Image, opaque bool) {
} else { } else {
var internal int var internal int
var format gl.Enum var format gl.Enum
switch r.srgbMode { switch r.ctx.caps.srgbMode {
case srgbES3: case srgbES3:
internal, format = gl.SRGB8_ALPHA8, gl.RGBA internal, format = gl.SRGB8_ALPHA8, gl.RGBA
case srgbEXT: case srgbEXT:
@@ -970,14 +957,14 @@ func clipSpaceTransform(r image.Rectangle, viewport image.Point) (f32.Point, f32
return scale, offset return scale, offset
} }
func bindFramebuffer(ctx *gl.Functions, fbo gl.Framebuffer) { func bindFramebuffer(ctx *context, fbo gl.Framebuffer) {
ctx.BindFramebuffer(gl.FRAMEBUFFER, fbo) ctx.BindFramebuffer(gl.FRAMEBUFFER, fbo)
if st := ctx.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE { if st := ctx.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
panic(fmt.Errorf("AA FBO not complete; status = 0x%x, err = %d", st, ctx.GetError())) panic(fmt.Errorf("AA FBO not complete; status = 0x%x, err = %d", st, ctx.GetError()))
} }
} }
func createTexture(ctx *gl.Functions) gl.Texture { func createTexture(ctx *context) gl.Texture {
tex := ctx.CreateTexture() tex := ctx.CreateTexture()
ctx.BindTexture(gl.TEXTURE_2D, tex) ctx.BindTexture(gl.TEXTURE_2D, tex)
ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
@@ -993,17 +980,6 @@ func copyImage(img image.Image, r image.Rectangle) *image.RGBA {
return tmp return tmp
} }
func srgbModeFor(ver [2]int, exts string) srgbMode {
switch {
case ver[0] >= 3:
return srgbES3
case strings.Contains(exts, "EXT_sRGB"):
return srgbEXT
default:
panic("neither OpenGL ES 3 nor EXT_sRGB is supported")
}
}
const blitVSrc = ` const blitVSrc = `
#version 100 #version 100
+31 -31
View File
@@ -15,7 +15,7 @@ import (
) )
type pather struct { type pather struct {
ctx *gl.Functions ctx *context
viewport image.Point viewport image.Point
@@ -24,7 +24,7 @@ type pather struct {
} }
type coverer struct { type coverer struct {
ctx *gl.Functions ctx *context
prog [2]gl.Program prog [2]gl.Program
vars [2]struct { vars [2]struct {
z gl.Uniform z gl.Uniform
@@ -36,7 +36,7 @@ type coverer struct {
} }
type stenciler struct { type stenciler struct {
ctx *gl.Functions ctx *context
defFBO gl.Framebuffer defFBO gl.Framebuffer
indexBufQuads int indexBufQuads int
prog gl.Program prog gl.Program
@@ -77,7 +77,7 @@ var (
intersectAttribs = []string{"pos", "uv"} intersectAttribs = []string{"pos", "uv"}
) )
func newPather(ctx *gl.Functions) *pather { func newPather(ctx *context) *pather {
return &pather{ return &pather{
ctx: ctx, ctx: ctx,
stenciler: newStenciler(ctx), stenciler: newStenciler(ctx),
@@ -85,7 +85,7 @@ func newPather(ctx *gl.Functions) *pather {
} }
} }
func newCoverer(ctx *gl.Functions) *coverer { func newCoverer(ctx *context) *coverer {
prog, err := createColorPrograms(ctx, coverVSrc, coverFSrc) prog, err := createColorPrograms(ctx, coverVSrc, coverFSrc)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -98,42 +98,42 @@ func newCoverer(ctx *gl.Functions) *coverer {
ctx.UseProgram(prog) ctx.UseProgram(prog)
switch materialType(i) { switch materialType(i) {
case materialTexture: case materialTexture:
uTex := gl.GetUniformLocation(ctx, prog, "tex") uTex := gl.GetUniformLocation(ctx.Functions, prog, "tex")
ctx.Uniform1i(uTex, 0) ctx.Uniform1i(uTex, 0)
c.vars[i].uUVScale = gl.GetUniformLocation(ctx, prog, "uvScale") c.vars[i].uUVScale = gl.GetUniformLocation(ctx.Functions, prog, "uvScale")
c.vars[i].uUVOffset = gl.GetUniformLocation(ctx, prog, "uvOffset") c.vars[i].uUVOffset = gl.GetUniformLocation(ctx.Functions, prog, "uvOffset")
case materialColor: case materialColor:
c.vars[i].uColor = gl.GetUniformLocation(ctx, prog, "color") c.vars[i].uColor = gl.GetUniformLocation(ctx.Functions, prog, "color")
} }
uCover := gl.GetUniformLocation(ctx, prog, "cover") uCover := gl.GetUniformLocation(ctx.Functions, prog, "cover")
ctx.Uniform1i(uCover, 1) ctx.Uniform1i(uCover, 1)
c.vars[i].z = gl.GetUniformLocation(ctx, prog, "z") c.vars[i].z = gl.GetUniformLocation(ctx.Functions, prog, "z")
c.vars[i].uScale = gl.GetUniformLocation(ctx, prog, "scale") c.vars[i].uScale = gl.GetUniformLocation(ctx.Functions, prog, "scale")
c.vars[i].uOffset = gl.GetUniformLocation(ctx, prog, "offset") c.vars[i].uOffset = gl.GetUniformLocation(ctx.Functions, prog, "offset")
c.vars[i].uCoverUVScale = gl.GetUniformLocation(ctx, prog, "uvCoverScale") c.vars[i].uCoverUVScale = gl.GetUniformLocation(ctx.Functions, prog, "uvCoverScale")
c.vars[i].uCoverUVOffset = gl.GetUniformLocation(ctx, prog, "uvCoverOffset") c.vars[i].uCoverUVOffset = gl.GetUniformLocation(ctx.Functions, prog, "uvCoverOffset")
} }
return c return c
} }
func newStenciler(ctx *gl.Functions) *stenciler { func newStenciler(ctx *context) *stenciler {
defFBO := gl.Framebuffer(ctx.GetBinding(gl.FRAMEBUFFER_BINDING)) defFBO := gl.Framebuffer(ctx.GetBinding(gl.FRAMEBUFFER_BINDING))
prog, err := gl.CreateProgram(ctx, stencilVSrc, stencilFSrc, pathAttribs) prog, err := gl.CreateProgram(ctx.Functions, stencilVSrc, stencilFSrc, pathAttribs)
if err != nil { if err != nil {
panic(err) panic(err)
} }
uAreaLUT := gl.GetUniformLocation(ctx, prog, "areaLUT") uAreaLUT := gl.GetUniformLocation(ctx.Functions, prog, "areaLUT")
ctx.UseProgram(prog) ctx.UseProgram(prog)
ctx.Uniform1i(uAreaLUT, 0) ctx.Uniform1i(uAreaLUT, 0)
areaLUT, err := loadLUT(ctx, genAreaLUT(256, 256)) areaLUT, err := loadLUT(ctx, genAreaLUT(256, 256))
if err != nil { if err != nil {
panic(err) panic(err)
} }
iprog, err := gl.CreateProgram(ctx, intersectVSrc, intersectFSrc, intersectAttribs) iprog, err := gl.CreateProgram(ctx.Functions, intersectVSrc, intersectFSrc, intersectAttribs)
if err != nil { if err != nil {
panic(err) panic(err)
} }
coverLoc := gl.GetUniformLocation(ctx, iprog, "cover") coverLoc := gl.GetUniformLocation(ctx.Functions, iprog, "cover")
ctx.UseProgram(iprog) ctx.UseProgram(iprog)
ctx.Uniform1i(coverLoc, 0) ctx.Uniform1i(coverLoc, 0)
return &stenciler{ return &stenciler{
@@ -142,16 +142,16 @@ func newStenciler(ctx *gl.Functions) *stenciler {
prog: prog, prog: prog,
iprog: iprog, iprog: iprog,
areaLUT: areaLUT, areaLUT: areaLUT,
uScale: gl.GetUniformLocation(ctx, prog, "scale"), uScale: gl.GetUniformLocation(ctx.Functions, prog, "scale"),
uOffset: gl.GetUniformLocation(ctx, prog, "offset"), uOffset: gl.GetUniformLocation(ctx.Functions, prog, "offset"),
uPathOffset: gl.GetUniformLocation(ctx, prog, "pathOffset"), uPathOffset: gl.GetUniformLocation(ctx.Functions, prog, "pathOffset"),
uIntersectUVScale: gl.GetUniformLocation(ctx, iprog, "uvScale"), uIntersectUVScale: gl.GetUniformLocation(ctx.Functions, iprog, "uvScale"),
uIntersectUVOffset: gl.GetUniformLocation(ctx, iprog, "uvOffset"), uIntersectUVOffset: gl.GetUniformLocation(ctx.Functions, iprog, "uvOffset"),
indexBuf: ctx.CreateBuffer(), indexBuf: ctx.CreateBuffer(),
} }
} }
func (s *fboSet) resize(ctx *gl.Functions, sizes []image.Point, internalFormat int, format, ty gl.Enum) { func (s *fboSet) resize(ctx *context, sizes []image.Point, internalFormat int, format, ty gl.Enum) {
// Add fbos. // Add fbos.
for i := len(s.fbos); i < len(sizes); i++ { for i := len(s.fbos); i < len(sizes); i++ {
tex := ctx.CreateTexture() tex := ctx.CreateTexture()
@@ -186,14 +186,14 @@ func (s *fboSet) resize(ctx *gl.Functions, sizes []image.Point, internalFormat i
s.delete(ctx, len(sizes)) s.delete(ctx, len(sizes))
} }
func (s *fboSet) invalidate(ctx *gl.Functions) { func (s *fboSet) invalidate(ctx *context) {
for _, f := range s.fbos { for _, f := range s.fbos {
ctx.BindFramebuffer(gl.FRAMEBUFFER, f.fbo) ctx.BindFramebuffer(gl.FRAMEBUFFER, f.fbo)
ctx.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0) ctx.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0)
} }
} }
func (s *fboSet) delete(ctx *gl.Functions, idx int) { func (s *fboSet) delete(ctx *context, idx int) {
for i := idx; i < len(s.fbos); i++ { for i := idx; i < len(s.fbos); i++ {
f := s.fbos[i] f := s.fbos[i]
ctx.DeleteFramebuffer(f.fbo) ctx.DeleteFramebuffer(f.fbo)
@@ -220,7 +220,7 @@ func (c *coverer) release() {
} }
} }
func buildPath(ctx *gl.Functions, p *path.Path) *pathData { func buildPath(ctx *context, p *path.Path) *pathData {
buf := ctx.CreateBuffer() buf := ctx.CreateBuffer()
ctx.BindBuffer(gl.ARRAY_BUFFER, buf) ctx.BindBuffer(gl.ARRAY_BUFFER, buf)
ctx.BufferData(gl.ARRAY_BUFFER, gl.BytesView(p.Vertices), gl.STATIC_DRAW) ctx.BufferData(gl.ARRAY_BUFFER, gl.BytesView(p.Vertices), gl.STATIC_DRAW)
@@ -230,7 +230,7 @@ func buildPath(ctx *gl.Functions, p *path.Path) *pathData {
} }
} }
func (p *pathData) release(ctx *gl.Functions) { func (p *pathData) release(ctx *context) {
ctx.DeleteBuffer(p.data) ctx.DeleteBuffer(p.data)
} }
@@ -364,7 +364,7 @@ func (c *coverer) cover(z float32, mat materialType, col [4]float32, scale, off,
c.ctx.DrawArrays(gl.TRIANGLE_STRIP, 0, 4) c.ctx.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
} }
func loadLUT(ctx *gl.Functions, lut *image.Gray) (gl.Texture, error) { func loadLUT(ctx *context, lut *image.Gray) (gl.Texture, error) {
tex := ctx.CreateTexture() tex := ctx.CreateTexture()
ctx.BindTexture(gl.TEXTURE_2D, tex) ctx.BindTexture(gl.TEXTURE_2D, tex)
ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) ctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
+3 -3
View File
@@ -9,13 +9,13 @@ import (
) )
type timers struct { type timers struct {
ctx *gl.Functions ctx *context
timers []*timer timers []*timer
} }
type timer struct { type timer struct {
Elapsed time.Duration Elapsed time.Duration
ctx *gl.Functions ctx *context
obj gl.Query obj gl.Query
state timerState state timerState
} }
@@ -28,7 +28,7 @@ const (
timerWaiting timerWaiting
) )
func newTimers(ctx *gl.Functions, exts string) *timers { func newTimers(ctx *context) *timers {
return &timers{ return &timers{
ctx: ctx, ctx: ctx,
} }