From c6863581e0e2cc31a35bbcdce75b4f94a834d19b Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Wed, 8 May 2019 15:36:28 +0200 Subject: [PATCH] ui/app/internal/gl: add workaround for broken sRGB FBOs Safari on macOS don't treat sRGB correctly. Signed-off-by: Elias Naur --- ui/app/internal/gl/functions.go | 8 ++++++++ ui/app/internal/gl/gl_windows.go | 4 ++++ ui/app/internal/gl/srgb.go | 30 ++++++++++++++++++++++++++---- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/ui/app/internal/gl/functions.go b/ui/app/internal/gl/functions.go index 4145a742..2bc93b5a 100644 --- a/ui/app/internal/gl/functions.go +++ b/ui/app/internal/gl/functions.go @@ -409,6 +409,14 @@ func (f *Functions) Scissor(x, y, width, height int32) { C.glScissor(C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height)) } +func (f *Functions) ReadPixels(x, y, width, height int, format, ty Enum, data []byte) { + var p unsafe.Pointer + if len(data) > 0 { + p = unsafe.Pointer(&data[0]) + } + C.glReadPixels(C.GLint(x), C.GLint(y), C.GLsizei(width), C.GLsizei(height), C.GLenum(format), C.GLenum(ty), p) +} + func (f *Functions) RenderbufferStorage(target, internalformat Enum, width, height int) { C.glRenderbufferStorage(C.GLenum(target), C.GLenum(internalformat), C.GLsizei(width), C.GLsizei(height)) } diff --git a/ui/app/internal/gl/gl_windows.go b/ui/app/internal/gl/gl_windows.go index 49054abd..e4b5aa8c 100644 --- a/ui/app/internal/gl/gl_windows.go +++ b/ui/app/internal/gl/gl_windows.go @@ -69,6 +69,7 @@ var ( _glInvalidateFramebuffer = LibGLESv2.NewProc("glInvalidateFramebuffer") _glLinkProgram = LibGLESv2.NewProc("glLinkProgram") _glPixelStorei = LibGLESv2.NewProc("glPixelStorei") + _glReadPixels = LibGLESv2.NewProc("glReadPixels") _glRenderbufferStorage = LibGLESv2.NewProc("glRenderbufferStorage") _glScissor = LibGLESv2.NewProc("glScissor") _glShaderSource = LibGLESv2.NewProc("glShaderSource") @@ -319,6 +320,9 @@ func (c *Functions) LinkProgram(p Program) { func (c *Functions) PixelStorei(pname Enum, param int32) { syscall.Syscall(_glPixelStorei.Addr(), 2, uintptr(pname), uintptr(param), 0) } +func (f *Functions) ReadPixels(x, y, width, height int, format, ty Enum, data []byte) { + syscall.Syscall6(_glReadPixels.Addr(), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(format), uintptr(ty), uintptr(unsafe.Pointer(&data[0]))) +} func (c *Functions) RenderbufferStorage(target, internalformat Enum, width, height int) { syscall.Syscall6(_glRenderbufferStorage.Addr(), 4, uintptr(target), uintptr(internalformat), uintptr(width), uintptr(height), 0, 0) } diff --git a/ui/app/internal/gl/srgb.go b/ui/app/internal/gl/srgb.go index de86494c..753650da 100644 --- a/ui/app/internal/gl/srgb.go +++ b/ui/app/internal/gl/srgb.go @@ -4,6 +4,7 @@ package gl import ( "fmt" + "runtime" "strings" ) @@ -116,6 +117,23 @@ func (s *SRGBFBO) Refresh(w, h int) error { if st := s.c.CheckFramebufferStatus(FRAMEBUFFER); st != FRAMEBUFFER_COMPLETE { return fmt.Errorf("sRGB framebuffer incomplete (%dx%d), status: %#x error: %x", s.width, s.height, st, s.c.GetError()) } + + if runtime.GOOS == "js" { + // With macOS Safari, rendering to and then reading from a SRGB8_ALPHA8 + // texture result in twice gamma corrected colors. Using a plain RGBA + // texture seems to work. + s.c.ClearColor(.5, .5, .5, 1.0) + s.c.Clear(COLOR_BUFFER_BIT) + var pixel [4]byte + s.c.ReadPixels(0, 0, 1, 1, RGBA, UNSIGNED_BYTE, pixel[:]) + if pixel[0] == 128 { // Correct sRGB color value is ~188 + s.c.TexImage2D(TEXTURE_2D, 0, RGBA, w, h, RGBA, UNSIGNED_BYTE, nil) + if st := s.c.CheckFramebufferStatus(FRAMEBUFFER); st != FRAMEBUFFER_COMPLETE { + return fmt.Errorf("fallback RGBA framebuffer incomplete (%dx%d), status: %#x error: %x", s.width, s.height, st, s.c.GetError()) + } + } + } + return nil } @@ -149,13 +167,17 @@ precision mediump float; uniform sampler2D tex; varying vec2 vUV; -void main() { - vec4 col = texture2D(tex, vUV); - vec3 rgb = col.rgb; +vec3 gamma(vec3 rgb) { vec3 exp = vec3(1.055)*pow(rgb, vec3(0.41666)) - vec3(0.055); vec3 lin = rgb * vec3(12.92); bvec3 cut = lessThan(rgb, vec3(0.0031308)); - rgb = vec3(cut.r ? lin.r : exp.r, cut.g ? lin.g : exp.g, cut.b ? lin.b : exp.b); + return vec3(cut.r ? lin.r : exp.r, cut.g ? lin.g : exp.g, cut.b ? lin.b : exp.b); +} + +void main() { + vec4 col = texture2D(tex, vUV); + vec3 rgb = col.rgb; + rgb = gamma(rgb); gl_FragColor = vec4(rgb, col.a); } `