gpu,gpu/backend: implement GLSL 300 es shader variants

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2020-02-25 18:52:28 +01:00
parent 3a5a2cff6b
commit 0d266c413d
7 changed files with 190 additions and 109 deletions
+60 -21
View File
@@ -19,7 +19,8 @@ type Backend struct {
state glstate
feats backend.Caps
gles300 bool
feats backend.Caps
// floatTriple holds the settings for floating point
// textures.
floatTriple textureTriple
@@ -67,6 +68,7 @@ type gpuFramebuffer struct {
type gpuBuffer struct {
backend *Backend
hasBuffer bool
obj Buffer
typ backend.BufferBinding
size int
@@ -115,7 +117,7 @@ type textureTriple struct {
func NewBackend(f Functions) (*Backend, error) {
exts := strings.Split(f.GetString(EXTENSIONS), " ")
glVer := f.GetString(VERSION)
ver, err := ParseGLVersion(glVer)
ver, gles, err := ParseGLVersion(glVer)
if err != nil {
return nil, err
}
@@ -127,7 +129,9 @@ func NewBackend(f Functions) (*Backend, error) {
if err != nil {
return nil, err
}
gles300 := gles && ver[0] >= 3
b := &Backend{
gles300: gles300,
funcs: f,
floatTriple: floatTriple,
alphaTriple: alphaTripleFor(ver),
@@ -236,10 +240,13 @@ func (b *Backend) NewBuffer(typ backend.BufferBinding, size int) (backend.Buffer
if typ != backend.BufferBindingUniforms {
return nil, errors.New("uniforms buffers cannot be bound as anything else")
}
// GLES 2 doesn't support uniform buffers.
buf.data = make([]byte, size)
if !b.gles300 {
// GLES 2 doesn't support uniform buffers.
buf.data = make([]byte, size)
}
}
if typ&^backend.BufferBindingUniforms != 0 {
if typ&^backend.BufferBindingUniforms != 0 || b.gles300 {
buf.hasBuffer = true
buf.obj = b.funcs.CreateBuffer()
if err := glErr(b.funcs); err != nil {
buf.Release()
@@ -252,7 +259,7 @@ func (b *Backend) NewBuffer(typ backend.BufferBinding, size int) (backend.Buffer
func (b *Backend) NewImmutableBuffer(typ backend.BufferBinding, data []byte) (backend.Buffer, error) {
glErr(b.funcs)
obj := b.funcs.CreateBuffer()
buf := &gpuBuffer{backend: b, obj: obj, typ: typ, size: len(data)}
buf := &gpuBuffer{backend: b, obj: obj, typ: typ, size: len(data), hasBuffer: true}
buf.Upload(data)
buf.immutable = true
if err := glErr(b.funcs); err != nil {
@@ -419,12 +426,16 @@ func (b *Backend) NewInputLayout(vs backend.ShaderSources, layout []backend.Inpu
}, nil
}
func (b *Backend) NewProgram(vssrc, fssrc backend.ShaderSources) (backend.Program, error) {
attr := make([]string, len(vssrc.Inputs))
for _, inp := range vssrc.Inputs {
func (b *Backend) NewProgram(vertShader, fragShader backend.ShaderSources) (backend.Program, error) {
attr := make([]string, len(vertShader.Inputs))
for _, inp := range vertShader.Inputs {
attr[inp.Location] = inp.Name
}
p, err := CreateProgram(b.funcs, vssrc.GLES2, fssrc.GLES2, attr)
vsrc, fsrc := vertShader.GLSL100ES, fragShader.GLSL100ES
if b.gles300 {
vsrc, fsrc = vertShader.GLSL300ES, fragShader.GLSL300ES
}
p, err := CreateProgram(b.funcs, vsrc, fsrc, attr)
if err != nil {
return nil, err
}
@@ -435,20 +446,39 @@ func (b *Backend) NewProgram(vssrc, fssrc backend.ShaderSources) (backend.Progra
}
b.BindProgram(gpuProg)
// Bind texture uniforms.
for _, tex := range vssrc.Textures {
for _, tex := range vertShader.Textures {
u := b.funcs.GetUniformLocation(p, tex.Name)
if u.valid() {
b.funcs.Uniform1i(u, tex.Binding)
}
}
for _, tex := range fssrc.Textures {
for _, tex := range fragShader.Textures {
u := b.funcs.GetUniformLocation(p, tex.Name)
if u.valid() {
b.funcs.Uniform1i(u, tex.Binding)
}
}
gpuProg.vertUniforms.setup(b.funcs, p, vssrc.UniformSize, vssrc.Uniforms)
gpuProg.fragUniforms.setup(b.funcs, p, fssrc.UniformSize, fssrc.Uniforms)
if b.gles300 {
for _, block := range vertShader.Uniforms.Blocks {
blockIdx := b.funcs.GetUniformBlockIndex(p, block.Name)
if blockIdx != INVALID_INDEX {
b.funcs.UniformBlockBinding(p, blockIdx, uint(block.Binding))
}
}
// To match Direct3D 11 with separate vertex and fragment
// shader uniform buffers, offset all fragment blocks to be
// located after the vertex blocks.
off := len(vertShader.Uniforms.Blocks)
for _, block := range fragShader.Uniforms.Blocks {
blockIdx := b.funcs.GetUniformBlockIndex(p, block.Name)
if blockIdx != INVALID_INDEX {
b.funcs.UniformBlockBinding(p, blockIdx, uint(block.Binding+off))
}
}
} else {
gpuProg.vertUniforms.setup(b.funcs, p, vertShader.Uniforms.Size, vertShader.Uniforms.Locations)
gpuProg.fragUniforms.setup(b.funcs, p, fragShader.Uniforms.Size, fragShader.Uniforms.Locations)
}
return gpuProg, nil
}
@@ -466,8 +496,18 @@ func (p *gpuProgram) SetFragmentUniforms(buffer backend.Buffer) {
}
func (p *gpuProgram) updateUniforms() {
p.vertUniforms.update(p.backend.funcs)
p.fragUniforms.update(p.backend.funcs)
f := p.backend.funcs
if p.backend.gles300 {
if b := p.vertUniforms.buf; b != nil {
f.BindBufferBase(UNIFORM_BUFFER, 0, b.obj)
}
if b := p.fragUniforms.buf; b != nil {
f.BindBufferBase(UNIFORM_BUFFER, 1, b.obj)
}
} else {
p.vertUniforms.update(f)
p.fragUniforms.update(f)
}
}
func (b *Backend) BindProgram(prog backend.Program) {
@@ -540,10 +580,8 @@ func (b *gpuBuffer) Upload(data []byte) {
panic("buffer size overflow")
}
b.version++
if b.typ&backend.BufferBindingUniforms != 0 {
copy(b.data, data)
}
if b.typ&^backend.BufferBindingUniforms != 0 {
copy(b.data, data)
if b.hasBuffer {
firstBinding := firstBufferType(b.typ)
b.backend.funcs.BindBuffer(firstBinding, b.obj)
b.backend.funcs.BufferData(firstBinding, data, STATIC_DRAW)
@@ -551,8 +589,9 @@ func (b *gpuBuffer) Upload(data []byte) {
}
func (b *gpuBuffer) Release() {
if b.typ&^backend.BufferBindingUniforms != 0 {
if b.hasBuffer {
b.backend.funcs.DeleteBuffer(b.obj)
b.hasBuffer = false
}
}
+4
View File
@@ -33,6 +33,7 @@ const (
HALF_FLOAT = 0x140b
HALF_FLOAT_OES = 0x8d61
INFO_LOG_LENGTH = 0x8B84
INVALID_INDEX = ^uint(0)
GREATER = 0x204
LINEAR = 0x2601
LINK_STATUS = 0x8b82
@@ -92,6 +93,7 @@ type Functions interface {
BeginQuery(target Enum, query Query)
BindAttribLocation(p Program, a Attrib, name string)
BindBuffer(target Enum, b Buffer)
BindBufferBase(target Enum, index int, buffer Buffer)
BindFramebuffer(target Enum, fb Framebuffer)
BindRenderbuffer(target Enum, fb Renderbuffer)
BindTexture(target Enum, t Texture)
@@ -136,6 +138,7 @@ type Functions interface {
GetShaderi(s Shader, pname Enum) int
GetShaderInfoLog(s Shader) string
GetString(pname Enum) string
GetUniformBlockIndex(p Program, name string) uint
GetUniformLocation(p Program, name string) Uniform
InvalidateFramebuffer(target, attachment Enum)
LinkProgram(p Program)
@@ -144,6 +147,7 @@ type Functions interface {
ShaderSource(s Shader, src string)
TexImage2D(target Enum, level int, internalFormat int, width, height int, format, ty Enum, data []byte)
TexParameteri(target, pname Enum, param int)
UniformBlockBinding(p Program, uniformBlockIndex uint, uniformBlockBinding uint)
Uniform1f(dst Uniform, v float32)
Uniform1i(dst Uniform, v int)
Uniform2f(dst Uniform, v0, v1 float32)
+5 -5
View File
@@ -60,16 +60,16 @@ func createShader(ctx Functions, typ Enum, src string) (Shader, error) {
return sh, nil
}
func ParseGLVersion(glVer string) ([2]int, error) {
func ParseGLVersion(glVer string) (version [2]int, gles bool, err error) {
var ver [2]int
if _, err := fmt.Sscanf(glVer, "OpenGL ES %d.%d", &ver[0], &ver[1]); err == nil {
return ver, nil
return ver, true, nil
} else if _, err := fmt.Sscanf(glVer, "WebGL %d.%d", &ver[0], &ver[1]); err == nil {
// WebGL major version v corresponds to OpenGL ES version v + 1
ver[0]++
return ver, nil
return ver, true, nil
} else if _, err := fmt.Sscanf(glVer, "%d.%d", &ver[0], &ver[1]); err == nil {
return ver, nil
return ver, false, nil
}
return ver, fmt.Errorf("failed to parse OpenGL ES version (%s)", glVer)
return ver, false, fmt.Errorf("failed to parse OpenGL ES version (%s)", glVer)
}