app/internal/srgb: move sRGB emulation to new internal package

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2020-02-10 16:53:51 +01:00
parent 3ae5a37c24
commit adb950cbf3
11 changed files with 81 additions and 80 deletions
+5 -3
View File
@@ -9,6 +9,8 @@ import (
"image" "image"
"runtime" "runtime"
"gioui.org/app/internal/glimpl"
"gioui.org/app/internal/srgb"
"gioui.org/gpu" "gioui.org/gpu"
"gioui.org/gpu/gl" "gioui.org/gpu/gl"
"gioui.org/op" "gioui.org/op"
@@ -18,12 +20,12 @@ import (
type Window struct { type Window struct {
size image.Point size image.Point
ctx context ctx context
fbo *gl.SRGBFBO fbo *srgb.SRGBFBO
gpu *gpu.GPU gpu *gpu.GPU
} }
type context interface { type context interface {
Functions() gl.Functions Functions() *glimpl.Functions
MakeCurrent() error MakeCurrent() error
ReleaseCurrent() ReleaseCurrent()
Release() Release()
@@ -41,7 +43,7 @@ func NewWindow(width, height int) (*Window, error) {
} }
err = contextDo(ctx, func() error { err = contextDo(ctx, func() error {
f := ctx.Functions() f := ctx.Functions()
fbo, err := gl.NewSRGBFBO(f) fbo, err := srgb.NewSRGBFBO(f)
if err != nil { if err != nil {
ctx.Release() ctx.Release()
return err return err
+2 -3
View File
@@ -4,7 +4,6 @@ package headless
import ( import (
"gioui.org/app/internal/glimpl" "gioui.org/app/internal/glimpl"
"gioui.org/gpu/gl"
) )
/* /*
@@ -16,7 +15,7 @@ import (
import "C" import "C"
type nsContext struct { type nsContext struct {
c gl.Functions c *glimpl.Functions
ctx C.CFTypeRef ctx C.CFTypeRef
prepared bool prepared bool
} }
@@ -39,7 +38,7 @@ func (c *nsContext) ReleaseCurrent() {
C.gio_headless_clearCurrentContext(c.ctx) C.gio_headless_clearCurrentContext(c.ctx)
} }
func (c *nsContext) Functions() gl.Functions { func (c *nsContext) Functions() *glimpl.Functions {
return c.c return c.c
} }
+2 -3
View File
@@ -7,12 +7,11 @@ import (
"syscall/js" "syscall/js"
"gioui.org/app/internal/glimpl" "gioui.org/app/internal/glimpl"
"gioui.org/gpu/gl"
) )
type jsContext struct { type jsContext struct {
ctx js.Value ctx js.Value
f gl.Functions f *glimpl.Functions
} }
func newContext() (*jsContext, error) { func newContext() (*jsContext, error) {
@@ -38,7 +37,7 @@ func newContext() (*jsContext, error) {
return c, nil return c, nil
} }
func (c *jsContext) Functions() gl.Functions { func (c *jsContext) Functions() *glimpl.Functions {
return c.f return c.f
} }
+5 -5
View File
@@ -11,18 +11,18 @@ import (
"strings" "strings"
"gioui.org/app/internal/glimpl" "gioui.org/app/internal/glimpl"
"gioui.org/gpu/gl" "gioui.org/app/internal/srgb"
) )
type Context struct { type Context struct {
c gl.Functions c *glimpl.Functions
disp _EGLDisplay disp _EGLDisplay
eglCtx *eglContext eglCtx *eglContext
eglSurf _EGLSurface eglSurf _EGLSurface
width, height int width, height int
refreshFBO bool refreshFBO bool
// For sRGB emulation. // For sRGB emulation.
srgbFBO *gl.SRGBFBO srgbFBO *srgb.SRGBFBO
} }
type eglContext struct { type eglContext struct {
@@ -115,7 +115,7 @@ func NewContext(disp NativeDisplayType) (*Context, error) {
return c, nil return c, nil
} }
func (c *Context) Functions() gl.Functions { func (c *Context) Functions() *glimpl.Functions {
return c.c return c.c
} }
@@ -161,7 +161,7 @@ func (c *Context) MakeCurrent() error {
} }
if c.srgbFBO == nil { if c.srgbFBO == nil {
var err error var err error
c.srgbFBO, err = gl.NewSRGBFBO(c.c) c.srgbFBO, err = srgb.NewSRGBFBO(c.c)
if err != nil { if err != nil {
return err return err
} }
+50 -48
View File
@@ -1,12 +1,14 @@
// SPDX-License-Identifier: Unlicense OR MIT // SPDX-License-Identifier: Unlicense OR MIT
package gl package srgb
import ( import (
"fmt" "fmt"
"runtime" "runtime"
"strings" "strings"
"gioui.org/app/internal/glimpl"
"gioui.org/gpu/gl"
"gioui.org/internal/unsafe" "gioui.org/internal/unsafe"
) )
@@ -14,28 +16,28 @@ import (
// for gamma-correct rendering on platforms without // for gamma-correct rendering on platforms without
// sRGB enabled native framebuffers. // sRGB enabled native framebuffers.
type SRGBFBO struct { type SRGBFBO struct {
c Functions c *glimpl.Functions
width, height int width, height int
frameBuffer Framebuffer frameBuffer gl.Framebuffer
depthBuffer Renderbuffer depthBuffer gl.Renderbuffer
colorTex Texture colorTex gl.Texture
blitted bool blitted bool
quad Buffer quad gl.Buffer
prog Program prog gl.Program
es3 bool es3 bool
} }
func NewSRGBFBO(f Functions) (*SRGBFBO, error) { func NewSRGBFBO(f *glimpl.Functions) (*SRGBFBO, error) {
var es3 bool var es3 bool
glVer := f.GetString(VERSION) glVer := f.GetString(gl.VERSION)
ver, err := parseGLVersion(glVer) ver, err := gl.ParseGLVersion(glVer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if ver[0] >= 3 { if ver[0] >= 3 {
es3 = true es3 = true
} else { } else {
exts := f.GetString(EXTENSIONS) exts := f.GetString(gl.EXTENSIONS)
if !strings.Contains(exts, "EXT_sRGB") { if !strings.Contains(exts, "EXT_sRGB") {
return nil, fmt.Errorf("no support for OpenGL ES 3 nor EXT_sRGB") return nil, fmt.Errorf("no support for OpenGL ES 3 nor EXT_sRGB")
} }
@@ -47,57 +49,57 @@ func NewSRGBFBO(f Functions) (*SRGBFBO, error) {
colorTex: f.CreateTexture(), colorTex: f.CreateTexture(),
depthBuffer: f.CreateRenderbuffer(), depthBuffer: f.CreateRenderbuffer(),
} }
f.BindTexture(TEXTURE_2D, s.colorTex) f.BindTexture(gl.TEXTURE_2D, s.colorTex)
f.TexParameteri(TEXTURE_2D, TEXTURE_WRAP_S, CLAMP_TO_EDGE) f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
f.TexParameteri(TEXTURE_2D, TEXTURE_WRAP_T, CLAMP_TO_EDGE) f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
f.TexParameteri(TEXTURE_2D, TEXTURE_MAG_FILTER, NEAREST) f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
f.TexParameteri(TEXTURE_2D, TEXTURE_MIN_FILTER, NEAREST) f.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
return s, nil return s, nil
} }
func (s *SRGBFBO) Blit() { func (s *SRGBFBO) Blit() {
if !s.blitted { if !s.blitted {
prog, err := createProgram(s.c, blitVSrc, blitFSrc, []string{"pos", "uv"}) prog, err := gl.CreateProgram(s.c, blitVSrc, blitFSrc, []string{"pos", "uv"})
if err != nil { if err != nil {
panic(err) panic(err)
} }
s.prog = prog s.prog = prog
s.c.UseProgram(prog) s.c.UseProgram(prog)
s.c.Uniform1i(getUniformLocation(s.c, prog, "tex"), 0) s.c.Uniform1i(gl.GetUniformLocation(s.c, prog, "tex"), 0)
s.quad = s.c.CreateBuffer() s.quad = s.c.CreateBuffer()
s.c.BindBuffer(ARRAY_BUFFER, s.quad) s.c.BindBuffer(gl.ARRAY_BUFFER, s.quad)
s.c.BufferData(ARRAY_BUFFER, s.c.BufferData(gl.ARRAY_BUFFER,
unsafe.BytesView([]float32{ unsafe.BytesView([]float32{
-1, +1, 0, 1, -1, +1, 0, 1,
+1, +1, 1, 1, +1, +1, 1, 1,
-1, -1, 0, 0, -1, -1, 0, 0,
+1, -1, 1, 0, +1, -1, 1, 0,
}), }),
STATIC_DRAW) gl.STATIC_DRAW)
s.blitted = true s.blitted = true
} }
s.c.BindFramebuffer(FRAMEBUFFER, Framebuffer{}) s.c.BindFramebuffer(gl.FRAMEBUFFER, gl.Framebuffer{})
s.c.UseProgram(s.prog) s.c.UseProgram(s.prog)
s.c.BindTexture(TEXTURE_2D, s.colorTex) s.c.BindTexture(gl.TEXTURE_2D, s.colorTex)
s.c.BindBuffer(ARRAY_BUFFER, s.quad) s.c.BindBuffer(gl.ARRAY_BUFFER, s.quad)
s.c.VertexAttribPointer(0 /* pos */, 2, FLOAT, false, 4*4, 0) s.c.VertexAttribPointer(0 /* pos */, 2, gl.FLOAT, false, 4*4, 0)
s.c.VertexAttribPointer(1 /* uv */, 2, FLOAT, false, 4*4, 4*2) s.c.VertexAttribPointer(1 /* uv */, 2, gl.FLOAT, false, 4*4, 4*2)
s.c.EnableVertexAttribArray(0) s.c.EnableVertexAttribArray(0)
s.c.EnableVertexAttribArray(1) s.c.EnableVertexAttribArray(1)
s.c.DrawArrays(TRIANGLE_STRIP, 0, 4) s.c.DrawArrays(gl.TRIANGLE_STRIP, 0, 4)
s.c.BindTexture(TEXTURE_2D, Texture{}) s.c.BindTexture(gl.TEXTURE_2D, gl.Texture{})
s.c.DisableVertexAttribArray(0) s.c.DisableVertexAttribArray(0)
s.c.DisableVertexAttribArray(1) s.c.DisableVertexAttribArray(1)
s.c.BindFramebuffer(FRAMEBUFFER, s.frameBuffer) s.c.BindFramebuffer(gl.FRAMEBUFFER, s.frameBuffer)
s.c.InvalidateFramebuffer(FRAMEBUFFER, COLOR_ATTACHMENT0) s.c.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0)
s.c.InvalidateFramebuffer(FRAMEBUFFER, DEPTH_ATTACHMENT) s.c.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT)
// The Android emulator requires framebuffer 0 bound at eglSwapBuffer time. // The Android emulator requires framebuffer 0 bound at eglSwapBuffer time.
// Bind the sRGB framebuffer again in afterPresent. // Bind the sRGB framebuffer again in afterPresent.
s.c.BindFramebuffer(FRAMEBUFFER, Framebuffer{}) s.c.BindFramebuffer(gl.FRAMEBUFFER, gl.Framebuffer{})
} }
func (s *SRGBFBO) AfterPresent() { func (s *SRGBFBO) AfterPresent() {
s.c.BindFramebuffer(FRAMEBUFFER, s.frameBuffer) s.c.BindFramebuffer(gl.FRAMEBUFFER, s.frameBuffer)
} }
func (s *SRGBFBO) Refresh(w, h int) error { func (s *SRGBFBO) Refresh(w, h int) error {
@@ -105,20 +107,20 @@ func (s *SRGBFBO) Refresh(w, h int) error {
if w == 0 || h == 0 { if w == 0 || h == 0 {
return nil return nil
} }
s.c.BindTexture(TEXTURE_2D, s.colorTex) s.c.BindTexture(gl.TEXTURE_2D, s.colorTex)
if s.es3 { if s.es3 {
s.c.TexImage2D(TEXTURE_2D, 0, SRGB8_ALPHA8, w, h, RGBA, UNSIGNED_BYTE, nil) s.c.TexImage2D(gl.TEXTURE_2D, 0, gl.SRGB8_ALPHA8, w, h, gl.RGBA, gl.UNSIGNED_BYTE, nil)
} else /* EXT_sRGB */ { } else /* EXT_sRGB */ {
s.c.TexImage2D(TEXTURE_2D, 0, SRGB_ALPHA_EXT, w, h, SRGB_ALPHA_EXT, UNSIGNED_BYTE, nil) s.c.TexImage2D(gl.TEXTURE_2D, 0, gl.SRGB_ALPHA_EXT, w, h, gl.SRGB_ALPHA_EXT, gl.UNSIGNED_BYTE, nil)
} }
currentRB := Renderbuffer(s.c.GetBinding(RENDERBUFFER_BINDING)) currentRB := gl.Renderbuffer(s.c.GetBinding(gl.RENDERBUFFER_BINDING))
s.c.BindRenderbuffer(RENDERBUFFER, s.depthBuffer) s.c.BindRenderbuffer(gl.RENDERBUFFER, s.depthBuffer)
s.c.RenderbufferStorage(RENDERBUFFER, DEPTH_COMPONENT16, w, h) s.c.RenderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h)
s.c.BindRenderbuffer(RENDERBUFFER, currentRB) s.c.BindRenderbuffer(gl.RENDERBUFFER, currentRB)
s.c.BindFramebuffer(FRAMEBUFFER, s.frameBuffer) s.c.BindFramebuffer(gl.FRAMEBUFFER, s.frameBuffer)
s.c.FramebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_2D, s.colorTex, 0) s.c.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, s.colorTex, 0)
s.c.FramebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT, RENDERBUFFER, s.depthBuffer) s.c.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, s.depthBuffer)
if st := s.c.CheckFramebufferStatus(FRAMEBUFFER); st != FRAMEBUFFER_COMPLETE { if st := s.c.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
return fmt.Errorf("sRGB framebuffer incomplete (%dx%d), status: %#x error: %x", s.width, s.height, st, s.c.GetError()) return fmt.Errorf("sRGB framebuffer incomplete (%dx%d), status: %#x error: %x", s.width, s.height, st, s.c.GetError())
} }
@@ -127,12 +129,12 @@ func (s *SRGBFBO) Refresh(w, h int) error {
// texture result in twice gamma corrected colors. Using a plain RGBA // texture result in twice gamma corrected colors. Using a plain RGBA
// texture seems to work. // texture seems to work.
s.c.ClearColor(.5, .5, .5, 1.0) s.c.ClearColor(.5, .5, .5, 1.0)
s.c.Clear(COLOR_BUFFER_BIT) s.c.Clear(gl.COLOR_BUFFER_BIT)
var pixel [4]byte var pixel [4]byte
s.c.ReadPixels(0, 0, 1, 1, RGBA, UNSIGNED_BYTE, pixel[:]) s.c.ReadPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel[:])
if pixel[0] == 128 { // Correct sRGB color value is ~188 if pixel[0] == 128 { // Correct sRGB color value is ~188
s.c.TexImage2D(TEXTURE_2D, 0, RGBA, w, h, RGBA, UNSIGNED_BYTE, nil) s.c.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, gl.RGBA, gl.UNSIGNED_BYTE, nil)
if st := s.c.CheckFramebufferStatus(FRAMEBUFFER); st != FRAMEBUFFER_COMPLETE { if st := s.c.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.FRAMEBUFFER_COMPLETE {
return fmt.Errorf("fallback RGBA framebuffer incomplete (%dx%d), status: %#x error: %x", s.width, s.height, st, s.c.GetError()) return fmt.Errorf("fallback RGBA framebuffer incomplete (%dx%d), status: %#x error: %x", s.width, s.height, st, s.c.GetError())
} }
} }
+2 -2
View File
@@ -22,7 +22,7 @@ import (
type context struct { type context struct {
owner *window owner *window
c gl.Functions c *glimpl.Functions
ctx C.CFTypeRef ctx C.CFTypeRef
layer C.CFTypeRef layer C.CFTypeRef
init bool init bool
@@ -50,7 +50,7 @@ func newContext(w *window) (*context, error) {
return c, nil return c, nil
} }
func (c *context) Functions() gl.Functions { func (c *context) Functions() *glimpl.Functions {
return c.c return c.c
} }
+5 -5
View File
@@ -7,14 +7,14 @@ import (
"syscall/js" "syscall/js"
"gioui.org/app/internal/glimpl" "gioui.org/app/internal/glimpl"
"gioui.org/gpu/gl" "gioui.org/app/internal/srgb"
) )
type context struct { type context struct {
ctx js.Value ctx js.Value
cnv js.Value cnv js.Value
f gl.Functions f *glimpl.Functions
srgbFBO *gl.SRGBFBO srgbFBO *srgb.SRGBFBO
} }
func newContext(w *window) (*context, error) { func newContext(w *window) (*context, error) {
@@ -45,7 +45,7 @@ func newContext(w *window) (*context, error) {
return c, nil return c, nil
} }
func (c *context) Functions() gl.Functions { func (c *context) Functions() *glimpl.Functions {
return c.f return c.f
} }
@@ -76,7 +76,7 @@ func (c *context) Unlock() {}
func (c *context) MakeCurrent() error { func (c *context) MakeCurrent() error {
if c.srgbFBO == nil { if c.srgbFBO == nil {
var err error var err error
c.srgbFBO, err = gl.NewSRGBFBO(c.f) c.srgbFBO, err = srgb.NewSRGBFBO(c.f)
if err != nil { if err != nil {
c.Release() c.Release()
c.srgbFBO = nil c.srgbFBO = nil
+2 -3
View File
@@ -6,7 +6,6 @@ package window
import ( import (
"gioui.org/app/internal/glimpl" "gioui.org/app/internal/glimpl"
"gioui.org/gpu/gl"
) )
/* /*
@@ -19,7 +18,7 @@ import (
import "C" import "C"
type context struct { type context struct {
c gl.Functions c *glimpl.Functions
ctx C.CFTypeRef ctx C.CFTypeRef
view C.CFTypeRef view C.CFTypeRef
} }
@@ -41,7 +40,7 @@ func newContext(w *window) (*context, error) {
return c, nil return c, nil
} }
func (c *context) Functions() gl.Functions { func (c *context) Functions() *glimpl.Functions {
return c.c return c.c
} }
+2 -2
View File
@@ -9,7 +9,7 @@ import (
"math" "math"
"time" "time"
"gioui.org/gpu/gl" "gioui.org/app/internal/glimpl"
"gioui.org/io/event" "gioui.org/io/event"
"gioui.org/io/system" "gioui.org/io/system"
"gioui.org/unit" "gioui.org/unit"
@@ -32,7 +32,7 @@ type Callbacks interface {
} }
type Context interface { type Context interface {
Functions() gl.Functions Functions() *glimpl.Functions
Present() error Present() error
MakeCurrent() error MakeCurrent() error
Release() Release()
+3 -3
View File
@@ -74,7 +74,7 @@ type textureTriple struct {
func NewBackend(f Functions) (*Backend, error) { func NewBackend(f Functions) (*Backend, error) {
exts := strings.Split(f.GetString(EXTENSIONS), " ") exts := strings.Split(f.GetString(EXTENSIONS), " ")
glVer := f.GetString(VERSION) glVer := f.GetString(VERSION)
ver, err := parseGLVersion(glVer) ver, err := ParseGLVersion(glVer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -282,7 +282,7 @@ func (b *Backend) DepthFunc(f gpu.DepthFunc) {
} }
func (b *Backend) NewProgram(vssrc, fssrc string, attr []string) (gpu.Program, error) { func (b *Backend) NewProgram(vssrc, fssrc string, attr []string) (gpu.Program, error) {
p, err := createProgram(b.funcs, vssrc, fssrc, attr) p, err := CreateProgram(b.funcs, vssrc, fssrc, attr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -316,7 +316,7 @@ func (p *gpuProgram) Bind() {
func (p *gpuProgram) UniformFor(uniform string) gpu.Uniform { func (p *gpuProgram) UniformFor(uniform string) gpu.Uniform {
f := p.backend.funcs f := p.backend.funcs
return getUniformLocation(f, p.obj, uniform) return GetUniformLocation(f, p.obj, uniform)
} }
func (b *Backend) SetupVertexArray(slot int, size int, dataType gpu.DataType, stride, offset int) { func (b *Backend) SetupVertexArray(slot int, size int, dataType gpu.DataType, stride, offset int) {
+3 -3
View File
@@ -8,7 +8,7 @@ import (
"strings" "strings"
) )
func createProgram(ctx Functions, vsSrc, fsSrc string, attribs []string) (Program, error) { func CreateProgram(ctx Functions, vsSrc, fsSrc string, attribs []string) (Program, error) {
vs, err := createShader(ctx, VERTEX_SHADER, vsSrc) vs, err := createShader(ctx, VERTEX_SHADER, vsSrc)
if err != nil { if err != nil {
return Program{}, err return Program{}, err
@@ -37,7 +37,7 @@ func createProgram(ctx Functions, vsSrc, fsSrc string, attribs []string) (Progra
return prog, nil return prog, nil
} }
func getUniformLocation(ctx Functions, prog Program, name string) Uniform { func GetUniformLocation(ctx Functions, prog Program, name string) Uniform {
loc := ctx.GetUniformLocation(prog, name) loc := ctx.GetUniformLocation(prog, name)
if !loc.Valid() { if !loc.Valid() {
panic(fmt.Errorf("uniform %s not found", name)) panic(fmt.Errorf("uniform %s not found", name))
@@ -60,7 +60,7 @@ func createShader(ctx Functions, typ Enum, src string) (Shader, error) {
return sh, nil return sh, nil
} }
func parseGLVersion(glVer string) ([2]int, error) { func ParseGLVersion(glVer string) ([2]int, error) {
var ver [2]int var ver [2]int
if _, err := fmt.Sscanf(glVer, "OpenGL ES %d.%d", &ver[0], &ver[1]); err == nil { if _, err := fmt.Sscanf(glVer, "OpenGL ES %d.%d", &ver[0], &ver[1]); err == nil {
return ver, nil return ver, nil