141 lines
3.8 KiB
Go
141 lines
3.8 KiB
Go
//go:build js
|
|
|
|
package webgl2
|
|
|
|
import (
|
|
"aego/core/log"
|
|
"aego/gpu"
|
|
"aego/gpu/internal/glstate"
|
|
)
|
|
|
|
const outputVert = `#version 300 es
|
|
void main() {
|
|
vec2 p = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
|
|
gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);
|
|
}
|
|
`
|
|
|
|
const outputFrag = `#version 300 es
|
|
precision highp float;
|
|
precision highp sampler2D;
|
|
uniform sampler2D tex0;
|
|
out vec4 o_color;
|
|
vec3 encode(vec3 c) {
|
|
c = clamp(c, 0.0, 1.0);
|
|
return mix(c * 12.92, 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, step(vec3(0.0031308), c));
|
|
}
|
|
void main() {
|
|
vec4 c = texelFetch(tex0, ivec2(gl_FragCoord.xy), 0);
|
|
o_color = vec4(encode(c.rgb), 1.0);
|
|
}
|
|
`
|
|
|
|
const outputLabel = "webgl2.output"
|
|
|
|
type backbuffer struct {
|
|
color uint32
|
|
depth uint32
|
|
fbo uint32
|
|
w, h int
|
|
}
|
|
|
|
type output struct {
|
|
prog uint32
|
|
vao uint32
|
|
smp uint32
|
|
}
|
|
|
|
func (d *Device) initOutput() error {
|
|
prog, err := d.link(gpu.ShaderDesc{Label: outputLabel, Sources: []gpu.ShaderSource{
|
|
{Stage: gpu.StageVertex, Source: outputVert},
|
|
{Stage: gpu.StageFragment, Source: outputFrag},
|
|
}})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d.out.prog = d.obj.reuse(d.out.prog, prog)
|
|
d.bindProgramSlots(prog, d.out.prog, outputLabel)
|
|
d.out.vao = d.obj.reuse(d.out.vao, d.call(d.f.CreateVertexArray))
|
|
d.out.smp = d.obj.reuse(d.out.smp, d.call(d.f.CreateSampler))
|
|
d.applySampler(d.out.smp, gpu.SamplerDesc{})
|
|
return nil
|
|
}
|
|
|
|
func (d *Device) freeOutput() {
|
|
d.cache.ForgetProgram(d.out.prog)
|
|
d.cache.ForgetVertexArray(d.out.vao)
|
|
d.cache.ForgetSampler(d.out.smp)
|
|
d.call(d.f.DeleteProgram, d.obj.drop(d.out.prog))
|
|
d.call(d.f.DeleteVertexArray, d.obj.drop(d.out.vao))
|
|
d.call(d.f.DeleteSampler, d.obj.drop(d.out.smp))
|
|
d.out = output{}
|
|
}
|
|
|
|
func (d *Device) ensureBackbuffer(w, h int) uint32 {
|
|
b := &d.bb
|
|
if b.fbo != 0 && b.w == w && b.h == h {
|
|
return b.fbo
|
|
}
|
|
d.freeBackbuffer()
|
|
if w <= 0 || h <= 0 {
|
|
return 0
|
|
}
|
|
tex := d.call(d.f.CreateTexture)
|
|
b.color = d.obj.put(tex)
|
|
d.bindScratch(b.color)
|
|
d.call(d.f.TexImage2D, glTexture2D, 0, glSRGB8Alpha8, w, h, 0, glRGBA, glUnsignedByte, nil)
|
|
d.call(d.f.TexParameteri, glTexture2D, glTextureMinFilter, glNearest)
|
|
d.call(d.f.TexParameteri, glTexture2D, glTextureMagFilter, glNearest)
|
|
d.call(d.f.TexParameteri, glTexture2D, glTextureWrapS, glClampToEdge)
|
|
d.call(d.f.TexParameteri, glTexture2D, glTextureWrapT, glClampToEdge)
|
|
rb := d.call(d.f.CreateRenderbuffer)
|
|
b.depth = d.obj.put(rb)
|
|
d.call(d.f.BindRenderbuffer, glRenderbuffer, rb)
|
|
d.call(d.f.RenderbufferStorage, glRenderbuffer, glDepth24Stencil8, w, h)
|
|
b.fbo = d.obj.put(d.call(d.f.CreateFramebuffer))
|
|
d.cache.BindFramebuffer(b.fbo)
|
|
d.call(d.f.FramebufferTexture2D, glFramebuffer, glColorAttachment0, glTexture2D, tex, 0)
|
|
d.call(d.f.FramebufferRenderbuffer, glFramebuffer, glDepthStencilAttachment, glRenderbuffer, rb)
|
|
if s := uint32(num(d.call(d.f.CheckFramebufferStatus, glFramebuffer))); s != glFramebufferComplete && !d.lost {
|
|
d.log.Error("the window backbuffer is incomplete", log.F("status", fbStatusName(s)), log.F("w", w), log.F("h", h))
|
|
}
|
|
b.w, b.h = w, h
|
|
return b.fbo
|
|
}
|
|
|
|
func (d *Device) freeBackbuffer() {
|
|
b := &d.bb
|
|
if b.fbo != 0 {
|
|
d.cache.ForgetFramebuffer(b.fbo)
|
|
d.call(d.f.DeleteFramebuffer, d.obj.drop(b.fbo))
|
|
}
|
|
if b.color != 0 {
|
|
d.cache.ForgetTexture(b.color)
|
|
d.call(d.f.DeleteTexture, d.obj.drop(b.color))
|
|
}
|
|
if b.depth != 0 {
|
|
d.call(d.f.DeleteRenderbuffer, d.obj.drop(b.depth))
|
|
}
|
|
*b = backbuffer{}
|
|
}
|
|
|
|
func (d *Device) present() {
|
|
b := &d.bb
|
|
if b.fbo == 0 || d.out.prog == 0 {
|
|
return
|
|
}
|
|
c := d.cache
|
|
c.BindFramebuffer(0)
|
|
c.SetViewport(glstate.Rect{W: int32(b.w), H: int32(b.h)})
|
|
c.SetScissor(false, glstate.Rect{})
|
|
c.SetBlend(glstate.Blend{})
|
|
c.SetDepth(glstate.Depth{})
|
|
c.SetCull(glstate.Cull{})
|
|
c.UseProgram(d.out.prog)
|
|
c.BindVertexArray(d.out.vao)
|
|
c.BindTexture(0, b.color)
|
|
c.BindSampler(0, d.out.smp)
|
|
d.call(d.f.DrawArrays, glTriangles, 0, 3)
|
|
c.BindTexture(0, 0)
|
|
}
|