~eliasnaur/gio

e686a03ef1e2adc232eefb5c23536ea17c1aa15f — Elias Naur 12 days ago 37c9fee
wip output packing

Signed-off-by: Elias Naur <mail@eliasnaur.com>
4 files changed, 312 insertions(+), 26 deletions(-)

M gpu/compute.go
M gpu/shaders.go
A gpu/shaders/copy2.frag
A gpu/shaders/copy2.vert
M gpu/compute.go => gpu/compute.go +107 -26
@@ 31,6 31,7 @@ type compute struct {
	collector     collector
	enc           encoder
	texOps        []textureOp
	layerVertices []layerVertex
	viewport      image.Point
	maxTextureDim int



@@ 50,12 51,16 @@ type compute struct {
		memory sizedBuffer
	}
	output struct {
		size image.Point
		packer packer
		size   image.Point
		// image is the output texture. Note that it is in RGBA format,
		// but contains data in sRGB. See blitOutput for more detail.
		image    driver.Texture
		fbo      driver.Framebuffer
		blitProg driver.Program
		layout   driver.InputLayout

		buffer sizedBuffer
	}
	// images contains ImageOp images packed into a texture atlas.
	images struct {


@@ 155,6 160,11 @@ type clipState struct {
	stroke    clip.StrokeStyle
}

type layerVertex struct {
	posX, posY float32
	u, v       float32
}

// materialVertex describes a vertex of a quad used to render a transformed
// material.
type materialVertex struct {


@@ 276,12 286,23 @@ func newCompute(ctx driver.Device) (*compute, error) {
		memHeader:     new(memoryHeader),
	}

	blitProg, err := ctx.NewProgram(shader_copy_vert, shader_copy_frag)
	// Large enough for reasonable fill sizes, yet still spannable by the compute programs.
	g.output.packer.maxDim = 4096
	blitProg, err := ctx.NewProgram(shader_copy2_vert, shader_copy2_frag)
	if err != nil {
		g.Release()
		return nil, err
	}
	g.output.blitProg = blitProg
	progLayout, err := ctx.NewInputLayout(shader_copy2_vert, []driver.InputDesc{
		{Type: driver.DataTypeFloat, Size: 2, Offset: 0},
		{Type: driver.DataTypeFloat, Size: 2, Offset: 4 * 2},
	})
	if err != nil {
		g.Release()
		return nil, err
	}
	g.output.layout = progLayout

	materialProg, err := ctx.NewProgram(shader_material_vert, shader_material_frag)
	if err != nil {


@@ 289,7 310,7 @@ func newCompute(ctx driver.Device) (*compute, error) {
		return nil, err
	}
	g.materials.prog = materialProg
	progLayout, err := ctx.NewInputLayout(shader_material_vert, []driver.InputDesc{
	progLayout, err = ctx.NewInputLayout(shader_material_vert, []driver.InputDesc{
		{Type: driver.DataTypeFloat, Size: 2, Offset: 0},
		{Type: driver.DataTypeFloat, Size: 2, Offset: 4 * 2},
	})


@@ 332,13 353,26 @@ func newCompute(ctx driver.Device) (*compute, error) {
func (g *compute) Collect(viewport image.Point, ops *op.Ops) {
	g.viewport = viewport
	g.collector.reset()
	g.enc.reset()
	g.texOps = g.texOps[:0]

	// Flip Y-axis.
	flipY := f32.Affine2D{}.Scale(f32.Pt(0, 0), f32.Pt(1, -1)).Offset(f32.Pt(0, float32(viewport.Y)))
	flipY := f32.Affine2D{} //.Scale(f32.Pt(0, 0), f32.Pt(1, -1)).Offset(f32.Pt(0, float32(viewport.Y)))

	g.collector.collect(ops, flipY, viewport)
	g.collector.encode(viewport, &g.enc, &g.texOps)
	reclaimed := false
	for {
		g.enc.reset()
		g.texOps = g.texOps[:0]
		g.layerVertices = g.layerVertices[:0]
		if g.collector.encode(viewport, &g.enc, &g.texOps, &g.layerVertices, &g.output.packer) {
			break
		}
		if reclaimed {
			panic(fmt.Errorf("compute: k4 output atlas exhausted"))
		}
		g.output.packer.clear()
		g.output.packer.newPage()
		reclaimed = true
	}
}

func (g *compute) Clear(col color.NRGBA) {


@@ 347,10 381,14 @@ func (g *compute) Clear(col color.NRGBA) {
}

func (g *compute) Frame() error {
	if len(g.output.packer.sizes) == 0 {
		return nil
	}
	outputSize := g.output.packer.sizes[0]
	viewport := g.viewport
	tileDims := image.Point{
		X: (viewport.X + tileWidthPx - 1) / tileWidthPx,
		Y: (viewport.Y + tileHeightPx - 1) / tileHeightPx,
		X: (outputSize.X + tileWidthPx - 1) / tileWidthPx,
		Y: (outputSize.Y + tileHeightPx - 1) / tileHeightPx,
	}

	defFBO := g.ctx.BeginFrame()


@@ 377,7 415,8 @@ func (g *compute) Frame() error {
		g.ctx.Clear(g.collector.clearColor.Float32())
	}
	w, h := tileDims.X*tileWidthPx, tileDims.Y*tileHeightPx
	if g.output.size.X != w || g.output.size.Y != h {
	if g.output.size.X < w || g.output.size.Y < h {
		w, h = pow2Ceil(w), pow2Ceil(h)
		if err := g.resizeOutput(image.Pt(w, h)); err != nil {
			return err
		}


@@ 418,21 457,39 @@ func (g *compute) Profile() string {
	return g.timers.profile
}

// blitOutput copies the compute render output to the output FBO. We need to
// copy because compute shaders can only write to textures, not FBOs. Compute
// shader can only write to RGBA textures, but since we actually render in sRGB
// format we can't use glBlitFramebuffer, because it does sRGB conversion.
func (g *compute) blitOutput(viewport image.Point) {
	t := g.timers.blit
	t.begin()
	defer t.end()
	verts := g.layerVertices
	if len(verts) == 0 {
		return
	}
	// TODO: move to shaders.
	// Transform positions to clip space: [-1, -1] - [1, 1], and texture
	// coordinates to texture space: [0, 0] - [1, 1].
	clip := f32.Affine2D{}.Scale(f32.Pt(0, 0), f32.Pt(2/float32(viewport.X), 2/float32(viewport.Y))).Offset(f32.Pt(-1, -1))
	tex := f32.Affine2D{}.Scale(f32.Pt(0, 0), f32.Pt(1/float32(g.output.size.X), 1/float32(g.output.size.Y)))
	for i, v := range verts {
		p := clip.Transform(f32.Pt(v.posX, v.posY))
		verts[i].posX = p.X
		verts[i].posY = p.Y
		uv := tex.Transform(f32.Pt(v.u, v.v))
		verts[i].u = uv.X
		verts[i].v = uv.Y
	}
	vertexData := byteslice.Slice(verts)
	g.output.buffer.ensureCapacity(g.ctx, driver.BufferBindingVertices, len(vertexData))
	g.output.buffer.buffer.Upload(vertexData)
	g.ctx.BlendFunc(driver.BlendFactorOne, driver.BlendFactorOneMinusSrcAlpha)
	g.ctx.SetBlend(true)
	defer g.ctx.SetBlend(false)
	g.ctx.Viewport(0, 0, viewport.X, viewport.Y)
	g.ctx.BindTexture(0, g.output.image)
	g.ctx.BindProgram(g.output.blitProg)
	g.ctx.DrawArrays(driver.DrawModeTriangleStrip, 0, 4)
	t.end()
	g.ctx.BindVertexBuffer(g.output.buffer.buffer, int(unsafe.Sizeof(verts[0])), 0)
	g.ctx.BindInputLayout(g.output.layout)
	g.ctx.DrawArrays(driver.DrawModeTriangles, 0, len(verts))
}

func (g *compute) renderMaterials() error {


@@ 732,7 789,7 @@ func (g *compute) render(tileDims image.Point) error {
	if s := len(scene); s > g.buffers.scene.size {
		realloced = true
		paddedCap := s * 11 / 10
		if err := g.buffers.scene.ensureCapacity(g.ctx, paddedCap); err != nil {
		if err := g.buffers.scene.ensureCapacity(g.ctx, driver.BufferBindingShaderStorage, paddedCap); err != nil {
			return err
		}
	}


@@ 775,7 832,7 @@ func (g *compute) render(tileDims image.Point) error {
	if clearSize > g.buffers.state.size {
		realloced = true
		paddedCap := clearSize * 11 / 10
		if err := g.buffers.state.ensureCapacity(g.ctx, paddedCap); err != nil {
		if err := g.buffers.state.ensureCapacity(g.ctx, driver.BufferBindingShaderStorage, paddedCap); err != nil {
			return err
		}
	}


@@ 789,7 846,7 @@ func (g *compute) render(tileDims image.Point) error {
		// Add space for dynamic GPU allocations.
		const sizeBump = 4 * 1024 * 1024
		minSize += sizeBump
		if err := g.buffers.memory.ensureCapacity(g.ctx, minSize); err != nil {
		if err := g.buffers.memory.ensureCapacity(g.ctx, driver.BufferBindingShaderStorage, minSize); err != nil {
			return err
		}
	}


@@ 854,7 911,7 @@ func (g *compute) render(tileDims image.Point) error {
			// Resize memory and try again.
			realloced = true
			sz := g.buffers.memory.size * 15 / 10
			if err := g.buffers.memory.ensureCapacity(g.ctx, sz); err != nil {
			if err := g.buffers.memory.ensureCapacity(g.ctx, driver.BufferBindingShaderStorage, sz); err != nil {
				return err
			}
			continue


@@ 912,6 969,7 @@ func (g *compute) Release() {
		g.programs.coarse,
		g.programs.kernel4,
		g.output.blitProg,
		&g.output.buffer,
		&g.buffers.scene,
		&g.buffers.state,
		&g.buffers.memory,


@@ 953,14 1011,14 @@ func (b *sizedBuffer) Release() {
	*b = sizedBuffer{}
}

func (b *sizedBuffer) ensureCapacity(ctx driver.Device, size int) error {
func (b *sizedBuffer) ensureCapacity(ctx driver.Device, binding driver.BufferBinding, size int) error {
	if b.size >= size {
		return nil
	}
	if b.buffer != nil {
		b.Release()
	}
	buf, err := ctx.NewBuffer(driver.BufferBindingShaderStorage, size)
	buf, err := ctx.NewBuffer(binding, size)
	if err != nil {
		return err
	}


@@ 1219,19 1277,41 @@ func (c *collector) collect(root *op.Ops, trans f32.Affine2D, viewport image.Poi
	}
}

func (c *collector) encode(viewport image.Point, enc *encoder, texOps *[]textureOp) {
func (c *collector) encode(viewport image.Point, enc *encoder, texOps *[]textureOp, layerVerts *[]layerVertex, pck *packer) bool {
	fview := f32.Rectangle{Max: layout.FPt(viewport)}
	fillMode := scene.FillModeNonzero
	for _, op := range c.paintOps {
		// Position onto output atlas.
		atlasBounds := boundRectF(op.state.intersect)
		size := atlasBounds.Size()
		// Add padding to avoid overlap.
		place, fits := pck.tryAdd(size.Add(image.Pt(1, 1)))
		if !fits {
			return false
		}
		off := place.Pos.Sub(atlasBounds.Min)

		offf := layout.FPt(off)
		placef := layout.FPt(place.Pos)
		sizef := layout.FPt(size)
		quad := [4]layerVertex{
			{posX: float32(atlasBounds.Min.X), posY: float32(atlasBounds.Min.Y), u: placef.X, v: placef.Y},
			{posX: float32(atlasBounds.Min.X + size.X), posY: float32(atlasBounds.Min.Y), u: placef.X + sizef.X, v: placef.Y},
			{posX: float32(atlasBounds.Min.X + size.X), posY: float32(atlasBounds.Min.Y + size.Y), u: placef.X + sizef.X, v: placef.Y + sizef.Y},
			{posX: float32(atlasBounds.Min.X), posY: float32(atlasBounds.Min.Y + size.Y), u: placef.X, v: placef.Y + sizef.Y},
		}
		*layerVerts = append(*layerVerts, quad[0], quad[1], quad[3], quad[3], quad[2], quad[1])

		// Fill in clip bounds, which the shaders expect to be the union
		// of all affected bounds.
		var union f32.Rectangle
		for i, cl := range op.clipStack {
			union = union.Union(cl.state.absBounds)
			union = union.Union(cl.state.absBounds.Add(offf))
			op.clipStack[i].union = union
		}

		var inv f32.Affine2D
		inv := f32.Affine2D{}.Offset(offf)
		enc.transform(inv)
		for i := len(op.clipStack) - 1; i >= 0; i-- {
			cl := op.clipStack[i]
			if str := cl.state.stroke; str.Width > 0 {


@@ 1271,7 1351,7 @@ func (c *collector) encode(viewport image.Point, enc *encoder, texOps *[]texture
			*texOps = append(*texOps, textureOp{
				sceneIdx: idx,
				img:      op.state.image,
				off:      image.Pt(int(intx), int(inty)),
				off:      image.Pt(int(intx), int(inty)).Add(off),
				key: textureKey{
					transform: t,
					handle:    op.state.image.handle,


@@ 1292,6 1372,7 @@ func (c *collector) encode(viewport image.Point, enc *encoder, texOps *[]texture
			enc.endClip(cl.union)
		}
	}
	return true
}

func (c *collector) save(id int, state encoderState) {

M gpu/shaders.go => gpu/shaders.go +166 -0
@@ 2438,6 2438,172 @@ void main()
`,
		HLSL: "DXBC\x99\xb4[\xef]IX\xa2Qh\x9f\xb6!\x1cR\xe7\x01\x00\x00\x00\xc0\x02\x00\x00\x05\x00\x00\x004\x00\x00\x00\x80\x00\x00\x00\xb4\x00\x00\x00\xe8\x00\x00\x00D\x02\x00\x00RDEFD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x04\xfe\xff\x00\x01\x00\x00\x1c\x00\x00\x00Microsoft (R) HLSL Shader Compiler 10.1\x00ISGN,\x00\x00\x00\x01\x00\x00\x00\b\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00SV_VertexID\x00OSGN,\x00\x00\x00\x01\x00\x00\x00\b\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00SV_Position\x00SHDRT\x01\x00\x00@\x00\x01\x00U\x00\x00\x00`\x00\x00\x04\x12\x10\x10\x00\x00\x00\x00\x00\x06\x00\x00\x00g\x00\x00\x04\xf2 \x10\x00\x00\x00\x00\x00\x01\x00\x00\x00h\x00\x00\x02\x01\x00\x00\x00L\x00\x00\x03\n\x10\x10\x00\x00\x00\x00\x00\x06\x00\x00\x03\x01@\x00\x00\x00\x00\x00\x006\x00\x00\br\x00\x10\x00\x00\x00\x00\x00\x02@\x00\x00\x00\x00\x80\xbf\x00\x00\x80?\x00\x00\x80?\x00\x00\x00\x00\x02\x00\x00\x01\x06\x00\x00\x03\x01@\x00\x00\x01\x00\x00\x006\x00\x00\br\x00\x10\x00\x00\x00\x00\x00\x02@\x00\x00\x00\x00\x80?\x00\x00\x80?\x00\x00\x80?\x00\x00\x00\x00\x02\x00\x00\x01\x06\x00\x00\x03\x01@\x00\x00\x02\x00\x00\x006\x00\x00\br\x00\x10\x00\x00\x00\x00\x00\x02@\x00\x00\x00\x00\x80\xbf\x00\x00\x80\xbf\x00\x00\x80?\x00\x00\x00\x00\x02\x00\x00\x01\x06\x00\x00\x03\x01@\x00\x00\x03\x00\x00\x006\x00\x00\br\x00\x10\x00\x00\x00\x00\x00\x02@\x00\x00\x00\x00\x80?\x00\x00\x80\xbf\x00\x00\x80?\x00\x00\x00\x00\x02\x00\x00\x01\n\x00\x00\x016\x00\x00\br\x00\x10\x00\x00\x00\x00\x00\x02@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x01\x17\x00\x00\x016\x00\x00\x05\xb2 \x10\x00\x00\x00\x00\x00F\b\x10\x00\x00\x00\x00\x006\x00\x00\x05B \x10\x00\x00\x00\x00\x00\x01@\x00\x00\x00\x00\x00\x00>\x00\x00\x01STATt\x00\x00\x00\x14\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
	}
	shader_copy2_frag = driver.ShaderSources{
		Name:     "copy2.frag",
		Inputs:   []driver.InputLocation{{Name: "vUV", Location: 0, Semantic: "TEXCOORD", SemanticIndex: 0, Type: 0x0, Size: 2}},
		Textures: []driver.TextureBinding{{Name: "tex", Binding: 0}},
		GLSL100ES: `#version 100
precision mediump float;
precision highp int;

uniform mediump sampler2D tex;

varying vec2 vUV;

vec3 sRGBtoRGB(vec3 rgb)
{
    bvec3 cutoff = greaterThanEqual(rgb, vec3(0.040449999272823333740234375));
    vec3 below = rgb / vec3(12.9200000762939453125);
    vec3 above = pow((rgb + vec3(0.054999999701976776123046875)) / vec3(1.05499994754791259765625), vec3(2.400000095367431640625));
    return vec3(cutoff.x ? above.x : below.x, cutoff.y ? above.y : below.y, cutoff.z ? above.z : below.z);
}

void main()
{
    vec4 texel = texture2D(tex, vUV);
    vec3 param = texel.xyz;
    vec3 _59 = sRGBtoRGB(param);
    texel = vec4(_59.x, _59.y, _59.z, texel.w);
    gl_FragData[0] = texel;
}

`,
		GLSL300ES: `#version 300 es
precision mediump float;
precision highp int;

uniform mediump sampler2D tex;

in vec2 vUV;
layout(location = 0) out vec4 fragColor;

vec3 sRGBtoRGB(vec3 rgb)
{
    bvec3 cutoff = greaterThanEqual(rgb, vec3(0.040449999272823333740234375));
    vec3 below = rgb / vec3(12.9200000762939453125);
    vec3 above = pow((rgb + vec3(0.054999999701976776123046875)) / vec3(1.05499994754791259765625), vec3(2.400000095367431640625));
    return vec3(cutoff.x ? above.x : below.x, cutoff.y ? above.y : below.y, cutoff.z ? above.z : below.z);
}

void main()
{
    vec4 texel = texture(tex, vUV);
    vec3 param = texel.xyz;
    vec3 _59 = sRGBtoRGB(param);
    texel = vec4(_59.x, _59.y, _59.z, texel.w);
    fragColor = texel;
}

`,
		GLSL130: `#version 130

uniform sampler2D tex;

in vec2 vUV;
out vec4 fragColor;

vec3 sRGBtoRGB(vec3 rgb)
{
    bvec3 cutoff = greaterThanEqual(rgb, vec3(0.040449999272823333740234375));
    vec3 below = rgb / vec3(12.9200000762939453125);
    vec3 above = pow((rgb + vec3(0.054999999701976776123046875)) / vec3(1.05499994754791259765625), vec3(2.400000095367431640625));
    return vec3(cutoff.x ? above.x : below.x, cutoff.y ? above.y : below.y, cutoff.z ? above.z : below.z);
}

void main()
{
    vec4 texel = texture(tex, vUV);
    vec3 param = texel.xyz;
    vec3 _59 = sRGBtoRGB(param);
    texel = vec4(_59.x, _59.y, _59.z, texel.w);
    fragColor = texel;
}

`,
		GLSL150: `#version 150

uniform sampler2D tex;

in vec2 vUV;
out vec4 fragColor;

vec3 sRGBtoRGB(vec3 rgb)
{
    bvec3 cutoff = greaterThanEqual(rgb, vec3(0.040449999272823333740234375));
    vec3 below = rgb / vec3(12.9200000762939453125);
    vec3 above = pow((rgb + vec3(0.054999999701976776123046875)) / vec3(1.05499994754791259765625), vec3(2.400000095367431640625));
    return vec3(cutoff.x ? above.x : below.x, cutoff.y ? above.y : below.y, cutoff.z ? above.z : below.z);
}

void main()
{
    vec4 texel = texture(tex, vUV);
    vec3 param = texel.xyz;
    vec3 _59 = sRGBtoRGB(param);
    texel = vec4(_59.x, _59.y, _59.z, texel.w);
    fragColor = texel;
}

`,
		HLSL: "DXBCNNg\x84\xf9.<\u05c9a\xcf,\xf7\xcb\xeb\xb9\x01\x00\x00\x00\xe8\x04\x00\x00\x06\x00\x00\x008\x00\x00\x00\xc8\x01\x00\x00d\x03\x00\x00\xe0\x03\x00\x00\x80\x04\x00\x00\xb4\x04\x00\x00Aon9\x88\x01\x00\x00\x88\x01\x00\x00\x00\x02\xff\xff`\x01\x00\x00(\x00\x00\x00\x00\x00(\x00\x00\x00(\x00\x00\x00(\x00\x01\x00$\x00\x00\x00(\x00\x00\x00\x00\x00\x00\x02\xff\xffQ\x00\x00\x05\x00\x00\x0f\xa0\xe6\xae%\xbd\x91\x83\x9e=\xaeGa=o\xa7r?Q\x00\x00\x05\x01\x00\x0f\xa0\x9a\x99\x19@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x02\x00\x00\x00\x80\x00\x00\x03\xb0\x1f\x00\x00\x02\x00\x00\x00\x90\x00\b\x0f\xa0B\x00\x00\x03\x00\x00\x0f\x80\x00\x00\xe4\xb0\x00\b\xe4\xa0\x02\x00\x00\x03\x01\x00\a\x80\x00\x00\xe4\x80\x00\x00\xaa\xa0\x05\x00\x00\x03\x01\x00\a\x80\x01\x00\xe4\x80\x00\x00\xff\xa0\x0f\x00\x00\x02\x02\x00\x01\x80\x01\x00\x00\x80\x0f\x00\x00\x02\x02\x00\x02\x80\x01\x00U\x80\x0f\x00\x00\x02\x02\x00\x04\x80\x01\x00\xaa\x80\x05\x00\x00\x03\x01\x00\a\x80\x02\x00\xe4\x80\x01\x00\x00\xa0\x0e\x00\x00\x02\x01\x00\x01\x80\x01\x00\x00\x80\x02\x00\x00\x03\x01\x00\b\x80\x00\x00\x00\x80\x00\x00\x00\xa0\x05\x00\x00\x03\x02\x00\a\x80\x00\x00\xe4\x80\x00\x00U\xa0X\x00\x00\x04\x00\x00\x01\x80\x01\x00\xff\x80\x01\x00\x00\x80\x02\x00\x00\x80\x0e\x00\x00\x02\x01\x00\x01\x80\x01\x00U\x80\x0e\x00\x00\x02\x01\x00\x02\x80\x01\x00\xaa\x80\x02\x00\x00\x03\x01\x00\x04\x80\x00\x00U\x80\x00\x00\x00\xa0X\x00\x00\x04\x00\x00\x02\x80\x01\x00\xaa\x80\x01\x00\x00\x80\x02\x00U\x80\x02\x00\x00\x03\x01\x00\x01\x80\x00\x00\xaa\x80\x00\x00\x00\xa0X\x00\x00\x04\x00\x00\x04\x80\x01\x00\x00\x80\x01\x00U\x80\x02\x00\xaa\x80\x01\x00\x00\x02\x00\b\x0f\x80\x00\x00\xe4\x80\xff\xff\x00\x00SHDR\x94\x01\x00\x00@\x00\x00\x00e\x00\x00\x00Z\x00\x00\x03\x00`\x10\x00\x00\x00\x00\x00X\x18\x00\x04\x00p\x10\x00\x00\x00\x00\x00UU\x00\x00b\x10\x00\x032\x10\x10\x00\x00\x00\x00\x00e\x00\x00\x03\xf2 \x10\x00\x00\x00\x00\x00h\x00\x00\x02\x03\x00\x00\x00E\x00\x00\t\xf2\x00\x10\x00\x00\x00\x00\x00F\x10\x10\x00\x00\x00\x00\x00F~\x10\x00\x00\x00\x00\x00\x00`\x10\x00\x00\x00\x00\x00\x00\x00\x00\nr\x00\x10\x00\x01\x00\x00\x00F\x02\x10\x00\x00\x00\x00\x00\x02@\x00\x00\xaeGa=\xaeGa=\xaeGa=\x00\x00\x00\x008\x00\x00\nr\x00\x10\x00\x01\x00\x00\x00F\x02\x10\x00\x01\x00\x00\x00\x02@\x00\x00o\xa7r?o\xa7r?o\xa7r?\x00\x00\x00\x00/\x00\x00\x05r\x00\x10\x00\x01\x00\x00\x00F\x02\x10\x00\x01\x00\x00\x008\x00\x00\nr\x00\x10\x00\x01\x00\x00\x00F\x02\x10\x00\x01\x00\x00\x00\x02@\x00\x00\x9a\x99\x19@\x9a\x99\x19@\x9a\x99\x19@\x00\x00\x00\x00\x19\x00\x00\x05r\x00\x10\x00\x01\x00\x00\x00F\x02\x10\x00\x01\x00\x00\x00\x1d\x00\x00\nr\x00\x10\x00\x02\x00\x00\x00F\x02\x10\x00\x00\x00\x00\x00\x02@\x00\x00\xe6\xae%=\xe6\xae%=\xe6\xae%=\x00\x00\x00\x008\x00\x00\nr\x00\x10\x00\x00\x00\x00\x00F\x02\x10\x00\x00\x00\x00\x00\x02@\x00\x00\x91\x83\x9e=\x91\x83\x9e=\x91\x83\x9e=\x00\x00\x00\x006\x00\x00\x05\x82 \x10\x00\x00\x00\x00\x00:\x00\x10\x00\x00\x00\x00\x007\x00\x00\tr \x10\x00\x00\x00\x00\x00F\x02\x10\x00\x02\x00\x00\x00F\x02\x10\x00\x01\x00\x00\x00F\x02\x10\x00\x00\x00\x00\x00>\x00\x00\x01STATt\x00\x00\x00\v\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00RDEF\x98\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x1c\x00\x00\x00\x00\x04\xff\xff\x00\x01\x00\x00m\x00\x00\x00\\\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00i\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x01\x00\x00\x00\r\x00\x00\x00_tex_sampler\x00tex\x00Microsoft (R) HLSL Shader Compiler 10.1\x00\xab\xab\xabISGN,\x00\x00\x00\x01\x00\x00\x00\b\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x03\x00\x00TEXCOORD\x00\xab\xab\xabOSGN,\x00\x00\x00\x01\x00\x00\x00\b\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00SV_Target\x00\xab\xab",
	}
	shader_copy2_vert = driver.ShaderSources{
		Name:   "copy2.vert",
		Inputs: []driver.InputLocation{{Name: "pos", Location: 0, Semantic: "TEXCOORD", SemanticIndex: 0, Type: 0x0, Size: 2}, {Name: "uv", Location: 1, Semantic: "TEXCOORD", SemanticIndex: 1, Type: 0x0, Size: 2}},
		GLSL100ES: `#version 100

varying vec2 vUV;
attribute vec2 uv;
attribute vec2 pos;

void main()
{
    vUV = uv;
    gl_Position = vec4(pos, 0.0, 1.0);
}

`,
		GLSL300ES: `#version 300 es

out vec2 vUV;
layout(location = 1) in vec2 uv;
layout(location = 0) in vec2 pos;

void main()
{
    vUV = uv;
    gl_Position = vec4(pos, 0.0, 1.0);
}

`,
		GLSL130: `#version 130

out vec2 vUV;
in vec2 uv;
in vec2 pos;

void main()
{
    vUV = uv;
    gl_Position = vec4(pos, 0.0, 1.0);
}

`,
		GLSL150: `#version 150

out vec2 vUV;
in vec2 uv;
in vec2 pos;

void main()
{
    vUV = uv;
    gl_Position = vec4(pos, 0.0, 1.0);
}

`,
		HLSL: "DXBCg\xc0\xae\x16\xd8\xe1\xbdl~ń\xf1\xc4\xf6dV\x01\x00\x00\x00\xc4\x02\x00\x00\x06\x00\x00\x008\x00\x00\x00\xc8\x00\x00\x00X\x01\x00\x00\xd4\x01\x00\x00 \x02\x00\x00l\x02\x00\x00Aon9\x88\x00\x00\x00\x88\x00\x00\x00\x00\x02\xfe\xff`\x00\x00\x00(\x00\x00\x00\x00\x00$\x00\x00\x00$\x00\x00\x00$\x00\x00\x00$\x00\x01\x00$\x00\x00\x00\x00\x00\x00\x02\xfe\xffQ\x00\x00\x05\x01\x00\x0f\xa0\x00\x00\x00\x00\x00\x00\x80?\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x02\x05\x00\x00\x80\x00\x00\x0f\x90\x1f\x00\x00\x02\x05\x00\x01\x80\x01\x00\x0f\x90\x02\x00\x00\x03\x00\x00\x03\xc0\x00\x00\xe4\x90\x00\x00\xe4\xa0\x01\x00\x00\x02\x00\x00\x03\xe0\x01\x00\xe4\x90\x01\x00\x00\x02\x00\x00\f\xc0\x01\x00D\xa0\xff\xff\x00\x00SHDR\x88\x00\x00\x00@\x00\x01\x00\"\x00\x00\x00_\x00\x00\x032\x10\x10\x00\x00\x00\x00\x00_\x00\x00\x032\x10\x10\x00\x01\x00\x00\x00e\x00\x00\x032 \x10\x00\x00\x00\x00\x00g\x00\x00\x04\xf2 \x10\x00\x01\x00\x00\x00\x01\x00\x00\x006\x00\x00\x052 \x10\x00\x00\x00\x00\x00F\x10\x10\x00\x01\x00\x00\x006\x00\x00\x052 \x10\x00\x01\x00\x00\x00F\x10\x10\x00\x00\x00\x00\x006\x00\x00\b\xc2 \x10\x00\x01\x00\x00\x00\x02@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80?>\x00\x00\x01STATt\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00RDEFD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x04\xfe\xff\x00\x01\x00\x00\x1c\x00\x00\x00Microsoft (R) HLSL Shader Compiler 10.1\x00ISGND\x00\x00\x00\x02\x00\x00\x00\b\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\x03\x00\x008\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x01\x00\x00\x00\x03\x03\x00\x00TEXCOORD\x00\xab\xab\xabOSGNP\x00\x00\x00\x02\x00\x00\x00\b\x00\x00\x008\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x03\f\x00\x00A\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x03\x00\x00\x00\x01\x00\x00\x00\x0f\x00\x00\x00TEXCOORD\x00SV_Position\x00\xab\xab\xab",
	}
	shader_cover_frag = [...]driver.ShaderSources{
		{
			Name:   "cover.frag",

A gpu/shaders/copy2.frag => gpu/shaders/copy2.frag +24 -0
@@ 0,0 1,24 @@
#version 310 es

// SPDX-License-Identifier: Unlicense OR MIT

precision mediump float;

layout(binding = 0) uniform sampler2D tex;

layout(location = 0) in vec2 vUV;

layout(location = 0) out vec4 fragColor;

vec3 sRGBtoRGB(vec3 rgb) {
	bvec3 cutoff = greaterThanEqual(rgb, vec3(0.04045));
	vec3 below = rgb/vec3(12.92);
	vec3 above = pow((rgb + vec3(0.055))/vec3(1.055), vec3(2.4));
	return mix(below, above, cutoff);
}

void main() {
	vec4 texel = texture(tex, vUV);
	texel.rgb = sRGBtoRGB(texel.rgb);
	fragColor = texel;
}

A gpu/shaders/copy2.vert => gpu/shaders/copy2.vert +15 -0
@@ 0,0 1,15 @@
#version 310 es

// SPDX-License-Identifier: Unlicense OR MIT

precision highp float;

layout(location = 0) in vec2 pos;
layout(location = 1) in vec2 uv;

layout(location = 0) out vec2 vUV;

void main() {
	vUV = uv;
	gl_Position = vec4(pos, 0, 1);
}