mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-08 02:45:38 +00:00
gpu/internal/opengl,internal: move sRGB emulation to OpenGL driver
There is only one driver but several backends (EGL, WebGL). Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -8,13 +8,11 @@ import (
|
|||||||
|
|
||||||
"gioui.org/gpu"
|
"gioui.org/gpu"
|
||||||
"gioui.org/internal/gl"
|
"gioui.org/internal/gl"
|
||||||
"gioui.org/internal/srgb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type context struct {
|
type context struct {
|
||||||
ctx js.Value
|
ctx js.Value
|
||||||
cnv js.Value
|
cnv js.Value
|
||||||
srgbFBO *srgb.FBO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newContext(w *window) (*context, error) {
|
func newContext(w *window) (*context, error) {
|
||||||
@@ -43,19 +41,9 @@ func (c *context) API() gpu.API {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) Release() {
|
func (c *context) Release() {
|
||||||
if c.srgbFBO != nil {
|
|
||||||
c.srgbFBO.Release()
|
|
||||||
c.srgbFBO = nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *context) Present() error {
|
func (c *context) Present() error {
|
||||||
if c.srgbFBO != nil {
|
|
||||||
c.srgbFBO.Blit()
|
|
||||||
}
|
|
||||||
if c.srgbFBO != nil {
|
|
||||||
c.srgbFBO.AfterPresent()
|
|
||||||
}
|
|
||||||
if c.ctx.Call("isContextLost").Bool() {
|
if c.ctx.Call("isContextLost").Bool() {
|
||||||
return errors.New("context lost")
|
return errors.New("context lost")
|
||||||
}
|
}
|
||||||
@@ -67,20 +55,6 @@ func (c *context) Lock() {}
|
|||||||
func (c *context) Unlock() {}
|
func (c *context) Unlock() {}
|
||||||
|
|
||||||
func (c *context) MakeCurrent() error {
|
func (c *context) MakeCurrent() error {
|
||||||
if c.srgbFBO == nil {
|
|
||||||
var err error
|
|
||||||
c.srgbFBO, err = srgb.New(gl.Context(c.ctx))
|
|
||||||
if err != nil {
|
|
||||||
c.Release()
|
|
||||||
c.srgbFBO = nil
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w, h := c.cnv.Get("width").Int(), c.cnv.Get("height").Int()
|
|
||||||
if err := c.srgbFBO.Refresh(w, h); err != nil {
|
|
||||||
c.Release()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -280,7 +280,7 @@ func (g *compute) Frame() error {
|
|||||||
Y: (viewport.Y + tileHeightPx - 1) / tileHeightPx,
|
Y: (viewport.Y + tileHeightPx - 1) / tileHeightPx,
|
||||||
}
|
}
|
||||||
|
|
||||||
defFBO := g.ctx.BeginFrame()
|
defFBO := g.ctx.BeginFrame(viewport)
|
||||||
defer g.ctx.EndFrame()
|
defer g.ctx.EndFrame()
|
||||||
|
|
||||||
if g.drawOps.profile && g.timers.t == nil && g.ctx.Caps().Features.Has(driver.FeatureTimers) {
|
if g.drawOps.profile && g.timers.t == nil && g.ctx.Caps().Features.Has(driver.FeatureTimers) {
|
||||||
|
|||||||
+2
-2
@@ -425,9 +425,9 @@ func (g *gpu) Collect(viewport image.Point, frameOps *op.Ops) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (g *gpu) Frame() error {
|
func (g *gpu) Frame() error {
|
||||||
defFBO := g.ctx.BeginFrame()
|
|
||||||
defer g.ctx.EndFrame()
|
|
||||||
viewport := g.renderer.blitter.viewport
|
viewport := g.renderer.blitter.viewport
|
||||||
|
defFBO := g.ctx.BeginFrame(viewport)
|
||||||
|
defer g.ctx.EndFrame()
|
||||||
for _, img := range g.drawOps.imageOps {
|
for _, img := range g.drawOps.imageOps {
|
||||||
expandPathOp(img.path, img.clip)
|
expandPathOp(img.path, img.clip)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ func newDriver(t *testing.T) driver.Device {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
b.BeginFrame()
|
b.BeginFrame(image.Pt(1, 1))
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
b.EndFrame()
|
b.EndFrame()
|
||||||
ctx.ReleaseCurrent()
|
ctx.ReleaseCurrent()
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ func newDirect3D11Device(api driver.Direct3D11) (driver.Device, error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) BeginFrame() driver.Framebuffer {
|
func (b *Backend) BeginFrame(viewport image.Point) driver.Framebuffer {
|
||||||
renderTarget, depthView := b.ctx.OMGetRenderTargets()
|
renderTarget, depthView := b.ctx.OMGetRenderTargets()
|
||||||
// Assume someone else is holding on to the render targets.
|
// Assume someone else is holding on to the render targets.
|
||||||
if renderTarget != nil {
|
if renderTarget != nil {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
// APIs such as OpenGL, Direct3D useful for rendering Gio
|
// APIs such as OpenGL, Direct3D useful for rendering Gio
|
||||||
// operations.
|
// operations.
|
||||||
type Device interface {
|
type Device interface {
|
||||||
BeginFrame() Framebuffer
|
BeginFrame(viewport image.Point) Framebuffer
|
||||||
EndFrame()
|
EndFrame()
|
||||||
Caps() Caps
|
Caps() Caps
|
||||||
NewTimer() Timer
|
NewTimer() Timer
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"gioui.org/gpu/internal/driver"
|
"gioui.org/gpu/internal/driver"
|
||||||
"gioui.org/internal/gl"
|
"gioui.org/internal/gl"
|
||||||
|
"gioui.org/internal/srgb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Backend implements driver.Device.
|
// Backend implements driver.Device.
|
||||||
@@ -30,6 +31,9 @@ type Backend struct {
|
|||||||
// Single channel alpha textures.
|
// Single channel alpha textures.
|
||||||
alphaTriple textureTriple
|
alphaTriple textureTriple
|
||||||
srgbaTriple textureTriple
|
srgbaTriple textureTriple
|
||||||
|
|
||||||
|
sRGBFBO *srgb.FBO
|
||||||
|
defFBO gl.Framebuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// State tracking.
|
// State tracking.
|
||||||
@@ -169,15 +173,43 @@ func newOpenGLDevice(api driver.OpenGL) (driver.Device, error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) BeginFrame() driver.Framebuffer {
|
func (b *Backend) BeginFrame(viewport image.Point) driver.Framebuffer {
|
||||||
// Assume GL state is reset between frames.
|
// Assume GL state is reset between frames.
|
||||||
b.state = glstate{}
|
b.state = glstate{}
|
||||||
fboID := gl.Framebuffer(b.funcs.GetBinding(gl.FRAMEBUFFER_BINDING))
|
b.defFBO = gl.Framebuffer(b.funcs.GetBinding(gl.FRAMEBUFFER_BINDING))
|
||||||
return &gpuFramebuffer{backend: b, obj: fboID, foreign: true}
|
// Determine color encoding of the output framebuffer.
|
||||||
|
var fbEncoding int
|
||||||
|
if !b.defFBO.Valid() {
|
||||||
|
fbEncoding = b.funcs.GetFramebufferAttachmentParameteri(gl.FRAMEBUFFER, gl.BACK, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)
|
||||||
|
} else {
|
||||||
|
fbEncoding = b.funcs.GetFramebufferAttachmentParameteri(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)
|
||||||
|
}
|
||||||
|
renderFBO := b.defFBO
|
||||||
|
if fbEncoding == gl.LINEAR {
|
||||||
|
if b.sRGBFBO == nil {
|
||||||
|
// Framebuffer is not in sRGB format. Emulate it.
|
||||||
|
sfbo, err := srgb.New(b.funcs)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
b.sRGBFBO = sfbo
|
||||||
|
}
|
||||||
|
if err := b.sRGBFBO.Refresh(viewport); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
renderFBO = b.sRGBFBO.Framebuffer()
|
||||||
|
}
|
||||||
|
b.funcs.BindFramebuffer(gl.FRAMEBUFFER, renderFBO)
|
||||||
|
return &gpuFramebuffer{backend: b, obj: renderFBO, foreign: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) EndFrame() {
|
func (b *Backend) EndFrame() {
|
||||||
b.funcs.ActiveTexture(gl.TEXTURE0)
|
b.funcs.ActiveTexture(gl.TEXTURE0)
|
||||||
|
if b.sRGBFBO != nil {
|
||||||
|
b.funcs.BindFramebuffer(gl.FRAMEBUFFER, b.defFBO)
|
||||||
|
b.sRGBFBO.Blit()
|
||||||
|
}
|
||||||
|
b.funcs.BindFramebuffer(gl.FRAMEBUFFER, b.defFBO)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) Caps() driver.Caps {
|
func (b *Backend) Caps() driver.Caps {
|
||||||
@@ -313,6 +345,10 @@ func glErr(f *gl.Functions) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) Release() {
|
func (b *Backend) Release() {
|
||||||
|
if b.sRGBFBO != nil {
|
||||||
|
b.sRGBFBO.Release()
|
||||||
|
}
|
||||||
|
*b = Backend{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Backend) MemoryBarrier() {
|
func (b *Backend) MemoryBarrier() {
|
||||||
|
|||||||
+1
-32
@@ -11,7 +11,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gioui.org/gpu"
|
"gioui.org/gpu"
|
||||||
"gioui.org/internal/srgb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Context struct {
|
type Context struct {
|
||||||
@@ -20,8 +19,6 @@ type Context struct {
|
|||||||
eglSurf _EGLSurface
|
eglSurf _EGLSurface
|
||||||
width, height int
|
width, height int
|
||||||
refreshFBO bool
|
refreshFBO bool
|
||||||
// For sRGB emulation.
|
|
||||||
srgbFBO *srgb.FBO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type eglContext struct {
|
type eglContext struct {
|
||||||
@@ -60,10 +57,6 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *Context) Release() {
|
func (c *Context) Release() {
|
||||||
if c.srgbFBO != nil {
|
|
||||||
c.srgbFBO.Release()
|
|
||||||
c.srgbFBO = nil
|
|
||||||
}
|
|
||||||
c.ReleaseSurface()
|
c.ReleaseSurface()
|
||||||
if c.eglCtx != nil {
|
if c.eglCtx != nil {
|
||||||
eglDestroyContext(c.disp, c.eglCtx.ctx)
|
eglDestroyContext(c.disp, c.eglCtx.ctx)
|
||||||
@@ -73,15 +66,9 @@ func (c *Context) Release() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Context) Present() error {
|
func (c *Context) Present() error {
|
||||||
if c.srgbFBO != nil {
|
|
||||||
c.srgbFBO.Blit()
|
|
||||||
}
|
|
||||||
if !eglSwapBuffers(c.disp, c.eglSurf) {
|
if !eglSwapBuffers(c.disp, c.eglSurf) {
|
||||||
return fmt.Errorf("eglSwapBuffers failed (%x)", eglGetError())
|
return fmt.Errorf("eglSwapBuffers failed (%x)", eglGetError())
|
||||||
}
|
}
|
||||||
if c.srgbFBO != nil {
|
|
||||||
c.srgbFBO.AfterPresent()
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,24 +138,6 @@ func (c *Context) MakeCurrent() error {
|
|||||||
if !eglMakeCurrent(c.disp, c.eglSurf, c.eglSurf, c.eglCtx.ctx) {
|
if !eglMakeCurrent(c.disp, c.eglSurf, c.eglSurf, c.eglCtx.ctx) {
|
||||||
return fmt.Errorf("eglMakeCurrent error 0x%x", eglGetError())
|
return fmt.Errorf("eglMakeCurrent error 0x%x", eglGetError())
|
||||||
}
|
}
|
||||||
if c.eglCtx.srgb || c.eglSurf == nilEGLSurface {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if c.srgbFBO == nil {
|
|
||||||
var err error
|
|
||||||
c.srgbFBO, err = srgb.New(nil)
|
|
||||||
if err != nil {
|
|
||||||
c.ReleaseCurrent()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if c.refreshFBO {
|
|
||||||
c.refreshFBO = false
|
|
||||||
if err := c.srgbFBO.Refresh(c.width, c.height); err != nil {
|
|
||||||
c.ReleaseCurrent()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,7 +237,7 @@ func createSurface(disp _EGLDisplay, eglCtx *eglContext, win NativeWindowType) (
|
|||||||
surfAttribs = append(surfAttribs, _EGL_NONE)
|
surfAttribs = append(surfAttribs, _EGL_NONE)
|
||||||
eglSurf := eglCreateWindowSurface(disp, eglCtx.config, win, surfAttribs)
|
eglSurf := eglCreateWindowSurface(disp, eglCtx.config, win, surfAttribs)
|
||||||
if eglSurf == nilEGLSurface && eglCtx.srgb {
|
if eglSurf == nilEGLSurface && eglCtx.srgb {
|
||||||
// Try again without sRGB
|
// Try again without sRGB.
|
||||||
eglCtx.srgb = false
|
eglCtx.srgb = false
|
||||||
surfAttribs = []_EGLint{_EGL_NONE}
|
surfAttribs = []_EGLint{_EGL_NONE}
|
||||||
eglSurf = eglCreateWindowSurface(disp, eglCtx.config, win, surfAttribs)
|
eglSurf = eglCreateWindowSurface(disp, eglCtx.config, win, surfAttribs)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ type (
|
|||||||
const (
|
const (
|
||||||
ALL_BARRIER_BITS = 0xffffffff
|
ALL_BARRIER_BITS = 0xffffffff
|
||||||
ARRAY_BUFFER = 0x8892
|
ARRAY_BUFFER = 0x8892
|
||||||
|
BACK = 0x0405
|
||||||
BLEND = 0xbe2
|
BLEND = 0xbe2
|
||||||
CLAMP_TO_EDGE = 0x812f
|
CLAMP_TO_EDGE = 0x812f
|
||||||
COLOR_ATTACHMENT0 = 0x8ce0
|
COLOR_ATTACHMENT0 = 0x8ce0
|
||||||
|
|||||||
@@ -436,6 +436,15 @@ func (f *Functions) GetFramebufferAttachmentParameteri(target, attachment, pname
|
|||||||
return int(f.ints[0])
|
return int(f.ints[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Functions) GetInteger4(pname Enum) [4]int {
|
||||||
|
C.glGetIntegerv(C.GLenum(pname), &f.ints[0])
|
||||||
|
var r [4]int
|
||||||
|
for i := range r {
|
||||||
|
r[i] = int(f.ints[i])
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
func (f *Functions) GetInteger(pname Enum) int {
|
func (f *Functions) GetInteger(pname Enum) int {
|
||||||
C.glGetIntegerv(C.GLenum(pname), &f.ints[0])
|
C.glGetIntegerv(C.GLenum(pname), &f.ints[0])
|
||||||
return int(f.ints[0])
|
return int(f.ints[0])
|
||||||
|
|||||||
@@ -292,6 +292,14 @@ func (c *Functions) GetFramebufferAttachmentParameteri(target, attachment, pname
|
|||||||
p, _, _ := syscall.Syscall(_glGetFramebufferAttachmentParameteri.Addr(), 3, uintptr(target), uintptr(attachment), uintptr(pname))
|
p, _, _ := syscall.Syscall(_glGetFramebufferAttachmentParameteri.Addr(), 3, uintptr(target), uintptr(attachment), uintptr(pname))
|
||||||
return int(p)
|
return int(p)
|
||||||
}
|
}
|
||||||
|
func (c *Functions) GetInteger4(pname Enum) [4]int {
|
||||||
|
syscall.Syscall(_glGetIntegerv.Addr(), 2, uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0])), 0)
|
||||||
|
var r [4]int
|
||||||
|
for i := range r {
|
||||||
|
r[i] = int(c.int32s[i])
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
func (c *Functions) GetInteger(pname Enum) int {
|
func (c *Functions) GetInteger(pname Enum) int {
|
||||||
syscall.Syscall(_glGetIntegerv.Addr(), 2, uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0])), 0)
|
syscall.Syscall(_glGetIntegerv.Addr(), 2, uintptr(pname), uintptr(unsafe.Pointer(&c.int32s[0])), 0)
|
||||||
return int(c.int32s[0])
|
return int(c.int32s[0])
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ type (
|
|||||||
Object struct{ V uint }
|
Object struct{ V uint }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (u Framebuffer) Valid() bool {
|
||||||
|
return u.V != 0
|
||||||
|
}
|
||||||
|
|
||||||
func (u Uniform) Valid() bool {
|
func (u Uniform) Valid() bool {
|
||||||
return u.V != -1
|
return u.V != -1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ type (
|
|||||||
Object js.Value
|
Object js.Value
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (f Framebuffer) Valid() bool {
|
||||||
|
return !js.Value(f).IsUndefined() && !js.Value(f).IsNull()
|
||||||
|
}
|
||||||
|
|
||||||
func (p Program) Valid() bool {
|
func (p Program) Valid() bool {
|
||||||
return !js.Value(p).IsUndefined() && !js.Value(p).IsNull()
|
return !js.Value(p).IsUndefined() && !js.Value(p).IsNull()
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-26
@@ -3,7 +3,9 @@
|
|||||||
package srgb
|
package srgb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -16,8 +18,8 @@ import (
|
|||||||
// sRGB enabled native framebuffers.
|
// sRGB enabled native framebuffers.
|
||||||
type FBO struct {
|
type FBO struct {
|
||||||
c *gl.Functions
|
c *gl.Functions
|
||||||
width, height int
|
viewport image.Point
|
||||||
frameBuffer gl.Framebuffer
|
srgbBuffer gl.Framebuffer
|
||||||
depthBuffer gl.Renderbuffer
|
depthBuffer gl.Renderbuffer
|
||||||
colorTex gl.Texture
|
colorTex gl.Texture
|
||||||
blitted bool
|
blitted bool
|
||||||
@@ -26,11 +28,7 @@ type FBO struct {
|
|||||||
gl3 bool
|
gl3 bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(ctx gl.Context) (*FBO, error) {
|
func New(f *gl.Functions) (*FBO, error) {
|
||||||
f, err := gl.NewFunctions(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var gl3 bool
|
var gl3 bool
|
||||||
glVer := f.GetString(gl.VERSION)
|
glVer := f.GetString(gl.VERSION)
|
||||||
ver, _, err := gl.ParseGLVersion(glVer)
|
ver, _, err := gl.ParseGLVersion(glVer)
|
||||||
@@ -48,7 +46,7 @@ func New(ctx gl.Context) (*FBO, error) {
|
|||||||
s := &FBO{
|
s := &FBO{
|
||||||
c: f,
|
c: f,
|
||||||
gl3: gl3,
|
gl3: gl3,
|
||||||
frameBuffer: f.CreateFramebuffer(),
|
srgbBuffer: f.CreateFramebuffer(),
|
||||||
colorTex: f.CreateTexture(),
|
colorTex: f.CreateTexture(),
|
||||||
depthBuffer: f.CreateRenderbuffer(),
|
depthBuffer: f.CreateRenderbuffer(),
|
||||||
}
|
}
|
||||||
@@ -81,7 +79,6 @@ func (s *FBO) Blit() {
|
|||||||
s.c.BufferSubData(gl.ARRAY_BUFFER, 0, coords)
|
s.c.BufferSubData(gl.ARRAY_BUFFER, 0, coords)
|
||||||
s.blitted = true
|
s.blitted = true
|
||||||
}
|
}
|
||||||
s.c.BindFramebuffer(gl.FRAMEBUFFER, gl.Framebuffer{})
|
|
||||||
s.c.UseProgram(s.prog)
|
s.c.UseProgram(s.prog)
|
||||||
s.c.BindTexture(gl.TEXTURE_2D, s.colorTex)
|
s.c.BindTexture(gl.TEXTURE_2D, s.colorTex)
|
||||||
s.c.BindBuffer(gl.ARRAY_BUFFER, s.quad)
|
s.c.BindBuffer(gl.ARRAY_BUFFER, s.quad)
|
||||||
@@ -93,38 +90,38 @@ func (s *FBO) Blit() {
|
|||||||
s.c.BindTexture(gl.TEXTURE_2D, gl.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(gl.FRAMEBUFFER, s.frameBuffer)
|
s.c.BindFramebuffer(gl.FRAMEBUFFER, s.srgbBuffer)
|
||||||
s.c.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0)
|
s.c.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0)
|
||||||
s.c.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT)
|
s.c.InvalidateFramebuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT)
|
||||||
// The Android emulator requires framebuffer 0 bound at eglSwapBuffer time.
|
|
||||||
// Bind the sRGB framebuffer again in afterPresent.
|
|
||||||
s.c.BindFramebuffer(gl.FRAMEBUFFER, gl.Framebuffer{})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FBO) AfterPresent() {
|
func (s *FBO) Framebuffer() gl.Framebuffer {
|
||||||
s.c.BindFramebuffer(gl.FRAMEBUFFER, s.frameBuffer)
|
return s.srgbBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FBO) Refresh(w, h int) error {
|
func (s *FBO) Refresh(viewport image.Point) error {
|
||||||
s.width, s.height = w, h
|
if viewport.X == 0 || viewport.Y == 0 {
|
||||||
if w == 0 || h == 0 {
|
return errors.New("srgb: zero-sized framebuffer")
|
||||||
|
}
|
||||||
|
if s.viewport == viewport {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
s.viewport = viewport
|
||||||
s.c.BindTexture(gl.TEXTURE_2D, s.colorTex)
|
s.c.BindTexture(gl.TEXTURE_2D, s.colorTex)
|
||||||
if s.gl3 {
|
if s.gl3 {
|
||||||
s.c.TexImage2D(gl.TEXTURE_2D, 0, gl.SRGB8_ALPHA8, w, h, gl.RGBA, gl.UNSIGNED_BYTE)
|
s.c.TexImage2D(gl.TEXTURE_2D, 0, gl.SRGB8_ALPHA8, viewport.X, viewport.Y, gl.RGBA, gl.UNSIGNED_BYTE)
|
||||||
} else /* EXT_sRGB */ {
|
} else /* EXT_sRGB */ {
|
||||||
s.c.TexImage2D(gl.TEXTURE_2D, 0, gl.SRGB_ALPHA_EXT, w, h, gl.SRGB_ALPHA_EXT, gl.UNSIGNED_BYTE)
|
s.c.TexImage2D(gl.TEXTURE_2D, 0, gl.SRGB_ALPHA_EXT, viewport.X, viewport.Y, gl.SRGB_ALPHA_EXT, gl.UNSIGNED_BYTE)
|
||||||
}
|
}
|
||||||
currentRB := gl.Renderbuffer(s.c.GetBinding(gl.RENDERBUFFER_BINDING))
|
currentRB := gl.Renderbuffer(s.c.GetBinding(gl.RENDERBUFFER_BINDING))
|
||||||
s.c.BindRenderbuffer(gl.RENDERBUFFER, s.depthBuffer)
|
s.c.BindRenderbuffer(gl.RENDERBUFFER, s.depthBuffer)
|
||||||
s.c.RenderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, w, h)
|
s.c.RenderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, viewport.X, viewport.Y)
|
||||||
s.c.BindRenderbuffer(gl.RENDERBUFFER, currentRB)
|
s.c.BindRenderbuffer(gl.RENDERBUFFER, currentRB)
|
||||||
s.c.BindFramebuffer(gl.FRAMEBUFFER, s.frameBuffer)
|
s.c.BindFramebuffer(gl.FRAMEBUFFER, s.srgbBuffer)
|
||||||
s.c.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, s.colorTex, 0)
|
s.c.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, s.colorTex, 0)
|
||||||
s.c.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, s.depthBuffer)
|
s.c.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, s.depthBuffer)
|
||||||
if st := s.c.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.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", viewport.X, viewport.Y, st, s.c.GetError())
|
||||||
}
|
}
|
||||||
|
|
||||||
if runtime.GOOS == "js" {
|
if runtime.GOOS == "js" {
|
||||||
@@ -136,9 +133,9 @@ func (s *FBO) Refresh(w, h int) error {
|
|||||||
var pixel [4]byte
|
var pixel [4]byte
|
||||||
s.c.ReadPixels(0, 0, 1, 1, gl.RGBA, gl.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(gl.TEXTURE_2D, 0, gl.RGBA, w, h, gl.RGBA, gl.UNSIGNED_BYTE)
|
s.c.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, viewport.X, viewport.Y, gl.RGBA, gl.UNSIGNED_BYTE)
|
||||||
if st := s.c.CheckFramebufferStatus(gl.FRAMEBUFFER); st != gl.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", viewport.X, viewport.Y, st, s.c.GetError())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,7 +144,7 @@ func (s *FBO) Refresh(w, h int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *FBO) Release() {
|
func (s *FBO) Release() {
|
||||||
s.c.DeleteFramebuffer(s.frameBuffer)
|
s.c.DeleteFramebuffer(s.srgbBuffer)
|
||||||
s.c.DeleteTexture(s.colorTex)
|
s.c.DeleteTexture(s.colorTex)
|
||||||
s.c.DeleteRenderbuffer(s.depthBuffer)
|
s.c.DeleteRenderbuffer(s.depthBuffer)
|
||||||
if s.blitted {
|
if s.blitted {
|
||||||
|
|||||||
Reference in New Issue
Block a user