From 08ddb4233ba89f0461758ee4039013312628dcba Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Wed, 12 Jan 2022 01:41:06 +0900 Subject: [PATCH] internal/shaderir/glsl: bug fix: % was not available on old GLSLs Use a new utility function modInt instead. Closes #1951 --- internal/shader/shader_test.go | 14 +++++++++++--- internal/shaderir/glsl/glsl.go | 22 ++++++++++++++++++++-- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/internal/shader/shader_test.go b/internal/shader/shader_test.go index 07c0d8f87..5527fd8f9 100644 --- a/internal/shader/shader_test.go +++ b/internal/shader/shader_test.go @@ -29,7 +29,15 @@ import ( "github.com/hajimehoshi/ebiten/v2/internal/shaderir/metal" ) -func glslNormalize(str string) string { +func glslVertexNormalize(str string) string { + p := glsl.VertexPrelude(glsl.GLSLVersionDefault) + if strings.HasPrefix(str, p) { + str = str[len(p):] + } + return strings.TrimSpace(str) +} + +func glslFragmentNormalize(str string) string { p := glsl.FragmentPrelude(glsl.GLSLVersionDefault) if strings.HasPrefix(str, p) { str = str[len(p):] @@ -158,11 +166,11 @@ func TestCompile(t *testing.T) { // GLSL vs, fs := glsl.Compile(s, glsl.GLSLVersionDefault) - if got, want := glslNormalize(vs), glslNormalize(string(tc.VS)); got != want { + if got, want := glslVertexNormalize(vs), glslVertexNormalize(string(tc.VS)); got != want { compare(t, "GLSL Vertex", got, want) } if tc.FS != nil { - if got, want := glslNormalize(fs), glslNormalize(string(tc.FS)); got != want { + if got, want := glslFragmentNormalize(fs), glslFragmentNormalize(string(tc.FS)); got != want { compare(t, "GLSL Fragment", got, want) } } diff --git a/internal/shaderir/glsl/glsl.go b/internal/shaderir/glsl/glsl.go index 11b32d186..43da99803 100644 --- a/internal/shaderir/glsl/glsl.go +++ b/internal/shaderir/glsl/glsl.go @@ -33,8 +33,18 @@ const ( GLSLVersionES300 ) +// utilFunctions is GLSL utility functions for old GLSL versions. +const utilFunctions = `int modInt(int x, int y) { + return x - y*(x/y); +}` + func VertexPrelude(version GLSLVersion) string { - if version == GLSLVersionES300 { + switch version { + case GLSLVersionDefault: + return utilFunctions + case GLSLVersionES100: + return utilFunctions + case GLSLVersionES300: return `#version 300 es` } return "" @@ -48,13 +58,17 @@ func FragmentPrelude(version GLSLVersion) string { case GLSLVersionES300: prefix = `#version 300 es` + "\n\n" } - return prefix + `#if defined(GL_ES) + prelude := prefix + `#if defined(GL_ES) precision highp float; #else #define lowp #define mediump #define highp #endif` + if version == GLSLVersionDefault || version == GLSLVersionES100 { + prelude += "\n\n" + utilFunctions + } + return prelude } type compileContext struct { @@ -496,6 +510,10 @@ func (c *compileContext) glslBlock(p *shaderir.Program, topBlock, block *shaderi } return fmt.Sprintf("%s(%s)", op, glslExpr(&e.Exprs[0])) case shaderir.Binary: + if e.Op == shaderir.ModOp && (c.version == GLSLVersionDefault || c.version == GLSLVersionES100) { + // '%' is not defined. + return fmt.Sprintf("modInt((%s), (%s))", glslExpr(&e.Exprs[0]), glslExpr(&e.Exprs[1])) + } return fmt.Sprintf("(%s) %s (%s)", glslExpr(&e.Exprs[0]), e.Op, glslExpr(&e.Exprs[1])) case shaderir.Selection: return fmt.Sprintf("(%s) ? (%s) : (%s)", glslExpr(&e.Exprs[0]), glslExpr(&e.Exprs[1]), glslExpr(&e.Exprs[2]))