mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 01:45:36 +00:00
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:
@@ -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
@@ -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
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user