gpu,gpu/shaders: [compute] decode sRGB texels in shader when EXT_sRGB is missing

This change avoids the hard dependency on GPU support for sRGB encoded
textures in the compute renderer.

With this change and the previously added CPU fallback, Gio no longer
rely on any GPU functionality outside the OpenGL ES 2.0 level.

Fixes gio#49
Fixes gio#154
Fixes gio#97
Fixes gio#36
Fixes gio#172

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-07-29 08:15:50 +02:00
parent d8f8740574
commit 8cec7e04eb
4 changed files with 107 additions and 32 deletions
+41 -11
View File
@@ -42,6 +42,7 @@ type compute struct {
texOps []textureOp texOps []textureOp
viewport image.Point viewport image.Point
maxTextureDim int maxTextureDim int
srgb bool
programs struct { programs struct {
elements computeProgram elements computeProgram
@@ -98,8 +99,14 @@ type compute struct {
buffer sizedBuffer buffer sizedBuffer
uniforms *materialUniforms vert struct {
uniBuf driver.Buffer uniforms *materialVertUniforms
buf driver.Buffer
}
frag struct {
buf driver.Buffer
}
// CPU fields // CPU fields
cpuTex cpu.ImageDescriptor cpuTex cpu.ImageDescriptor
@@ -154,11 +161,16 @@ type copyUniforms struct {
_ [8]byte // Pad to 16 bytes. _ [8]byte // Pad to 16 bytes.
} }
type materialUniforms struct { type materialVertUniforms struct {
scale [2]float32 scale [2]float32
pos [2]float32 pos [2]float32
} }
type materialFragUniforms struct {
emulateSRGB float32
_ [12]byte // Pad to 16 bytes
}
type collector struct { type collector struct {
hasher maphash.Hash hasher maphash.Hash
profile bool profile bool
@@ -372,6 +384,7 @@ func newCompute(ctx driver.Device) (*compute, error) {
g := &compute{ g := &compute{
ctx: ctx, ctx: ctx,
maxTextureDim: maxDim, maxTextureDim: maxDim,
srgb: caps.Features.Has(driver.FeatureSRGB),
conf: new(config), conf: new(config),
memHeader: new(memoryHeader), memHeader: new(memoryHeader),
} }
@@ -447,15 +460,27 @@ func newCompute(ctx driver.Device) (*compute, error) {
return nil, err return nil, err
} }
g.materials.layout = progLayout g.materials.layout = progLayout
g.materials.uniforms = new(materialUniforms) g.materials.vert.uniforms = new(materialVertUniforms)
buf, err = ctx.NewBuffer(driver.BufferBindingUniforms, int(unsafe.Sizeof(*g.materials.uniforms))) buf, err = ctx.NewBuffer(driver.BufferBindingUniforms, int(unsafe.Sizeof(*g.materials.vert.uniforms)))
if err != nil { if err != nil {
g.Release() g.Release()
return nil, err return nil, err
} }
g.materials.uniBuf = buf g.materials.vert.buf = buf
g.materials.prog.SetVertexUniforms(buf) g.materials.prog.SetVertexUniforms(buf)
var emulateSRGB materialFragUniforms
if !g.srgb {
emulateSRGB.emulateSRGB = 1.0
}
buf, err = ctx.NewBuffer(driver.BufferBindingUniforms, int(unsafe.Sizeof(emulateSRGB)))
if err != nil {
g.Release()
return nil, err
}
buf.Upload(byteslice.Struct(&emulateSRGB))
g.materials.frag.buf = buf
g.materials.prog.SetFragmentUniforms(buf)
for _, shader := range shaders { for _, shader := range shaders {
if !g.useCPU { if !g.useCPU {
@@ -875,9 +900,9 @@ restart:
} }
} }
// Transform to clip space: [-1, -1] - [1, 1]. // Transform to clip space: [-1, -1] - [1, 1].
g.materials.uniforms.scale = [2]float32{2 / float32(texSize), 2 / float32(texSize)} g.materials.vert.uniforms.scale = [2]float32{2 / float32(texSize), 2 / float32(texSize)}
g.materials.uniforms.pos = [2]float32{-1, -1} g.materials.vert.uniforms.pos = [2]float32{-1, -1}
g.materials.uniBuf.Upload(byteslice.Struct(g.materials.uniforms)) g.materials.vert.buf.Upload(byteslice.Struct(g.materials.vert.uniforms))
vertexData := byteslice.Slice(m.quads) vertexData := byteslice.Slice(m.quads)
n := pow2Ceil(len(vertexData)) n := pow2Ceil(len(vertexData))
m.buffer.ensureCapacity(false, g.ctx, driver.BufferBindingVertices, n) m.buffer.ensureCapacity(false, g.ctx, driver.BufferBindingVertices, n)
@@ -952,7 +977,11 @@ restart:
a.tex = nil a.tex = nil
} }
sz := a.packer.maxDim sz := a.packer.maxDim
handle, err := g.ctx.NewTexture(driver.TextureFormatSRGBA, sz, sz, driver.FilterLinear, driver.FilterLinear, driver.BufferBindingTexture) format := driver.TextureFormatSRGBA
if !g.srgb {
format = driver.TextureFormatRGBA8
}
handle, err := g.ctx.NewTexture(format, sz, sz, driver.FilterLinear, driver.FilterLinear, driver.BufferBindingTexture)
if err != nil { if err != nil {
return fmt.Errorf("compute: failed to create image atlas: %v", err) return fmt.Errorf("compute: failed to create image atlas: %v", err)
} }
@@ -1316,7 +1345,8 @@ func (g *compute) Release() {
g.materials.fbo, g.materials.fbo,
g.materials.tex, g.materials.tex,
&g.materials.buffer, &g.materials.buffer,
g.materials.uniBuf, g.materials.vert.buf,
g.materials.frag.buf,
g.timers.t, g.timers.t,
} }
g.materials.cpuTex.Free() g.materials.cpuTex.Free()
+1 -5
View File
@@ -9,7 +9,6 @@ package gpu
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"image" "image"
"image/color" "image/color"
@@ -361,11 +360,8 @@ func New(api API) (GPU, error) {
defer d.EndFrame() defer d.EndFrame()
forceCompute := os.Getenv("GIORENDERER") == "forcecompute" forceCompute := os.Getenv("GIORENDERER") == "forcecompute"
feats := d.Caps().Features feats := d.Caps().Features
if !feats.Has(driver.FeatureSRGB) {
return nil, errors.New("gpu: no sRGB texture formats found")
}
switch { switch {
case !forceCompute && feats.Has(driver.FeatureFloatRenderTargets): case !forceCompute && feats.Has(driver.FeatureFloatRenderTargets) && feats.Has(driver.FeatureSRGB):
return newGPU(d) return newGPU(d)
} }
return newCompute(d) return newCompute(d)
+56 -15
View File
File diff suppressed because one or more lines are too long
+9 -1
View File
@@ -10,6 +10,12 @@ layout(location = 0) in vec2 vUV;
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
layout(binding=0) uniform Color {
// If emulateSRGB is set (!= 0), the input texels are sRGB encoded. We save the
// conversion step below, at the cost of texture filtering in sRGB space.
float emulateSRGB;
};
vec3 RGBtosRGB(vec3 rgb) { vec3 RGBtosRGB(vec3 rgb) {
bvec3 cutoff = greaterThanEqual(rgb, vec3(0.0031308)); bvec3 cutoff = greaterThanEqual(rgb, vec3(0.0031308));
vec3 below = vec3(12.92)*rgb; vec3 below = vec3(12.92)*rgb;
@@ -19,6 +25,8 @@ vec3 RGBtosRGB(vec3 rgb) {
void main() { void main() {
vec4 texel = texture(tex, vUV); vec4 texel = texture(tex, vUV);
texel.rgb = RGBtosRGB(texel.rgb); if (emulateSRGB == 0.0) {
texel.rgb = RGBtosRGB(texel.rgb);
}
fragColor = texel; fragColor = texel;
} }