mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-09-26 20:11:28 +08:00
@@ -102,7 +102,7 @@ func compileShader(program *shaderir.Program) (vsh, psh *_ID3DBlob, ferr error)
|
||||
return vsh, psh, nil
|
||||
}
|
||||
|
||||
vs, ps, _ := hlsl.Compile(program)
|
||||
vs, ps, _, _ := hlsl.Compile(program)
|
||||
var flag uint32 = uint32(_D3DCOMPILE_OPTIMIZATION_LEVEL3)
|
||||
|
||||
var wg errgroup.Group
|
||||
|
@@ -421,6 +421,16 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
|
||||
return nil, nil, nil, false
|
||||
}
|
||||
finalType = shaderir.Type{Main: shaderir.Vec4}
|
||||
case shaderir.FrontFacing:
|
||||
if len(args) != 0 {
|
||||
cs.addError(e.Pos(), fmt.Sprintf("number of %s's arguments must be 0 but %d", callee.BuiltinFunc, len(args)))
|
||||
return nil, nil, nil, false
|
||||
}
|
||||
if fname != cs.fragmentEntry {
|
||||
cs.addError(e.Pos(), fmt.Sprintf("frontfacing is available only in %s", cs.fragmentEntry))
|
||||
return nil, nil, nil, false
|
||||
}
|
||||
finalType = shaderir.Type{Main: shaderir.Bool}
|
||||
case shaderir.DiscardF:
|
||||
if len(args) != 0 {
|
||||
cs.addError(e.Pos(), fmt.Sprintf("number of %s's arguments must be 0 but %d", callee.BuiltinFunc, len(args)))
|
||||
@@ -434,7 +444,6 @@ func (cs *compileState) parseExpr(block *block, fname string, expr ast.Expr, mar
|
||||
Type: shaderir.Discard,
|
||||
})
|
||||
return nil, nil, stmts, true
|
||||
|
||||
case shaderir.Clamp, shaderir.Mix, shaderir.Smoothstep, shaderir.Faceforward, shaderir.Refract:
|
||||
// 3 arguments
|
||||
if len(args) != 3 {
|
||||
|
@@ -180,8 +180,8 @@ func TestCompile(t *testing.T) {
|
||||
}
|
||||
|
||||
if tc.HLSL != nil {
|
||||
vs, _, prelude := hlsl.Compile(s)
|
||||
if got, want := hlslNormalize(vs, prelude), hlslNormalize(string(tc.HLSL), prelude); got != want {
|
||||
vs, _, vertexPrelude, _ := hlsl.Compile(s)
|
||||
if got, want := hlslNormalize(vs, vertexPrelude), hlslNormalize(string(tc.HLSL), vertexPrelude); got != want {
|
||||
compare(t, "HLSL", got, want)
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
void F0(thread array<float2, 3>& l0);
|
||||
void F0(bool front_facing, thread array<float2, 3>& l0);
|
||||
|
||||
void F0(thread array<float2, 3>& l0) {
|
||||
void F0(bool front_facing, thread array<float2, 3>& l0) {
|
||||
array<float2, 2> l1 = {};
|
||||
array<float2, 3> l2 = {};
|
||||
{
|
||||
|
4
internal/shader/testdata/atan.expected.metal
vendored
4
internal/shader/testdata/atan.expected.metal
vendored
@@ -1,6 +1,6 @@
|
||||
bool F0(float l0, float l1);
|
||||
bool F0(bool front_facing, float l0, float l1);
|
||||
|
||||
bool F0(float l0, float l1) {
|
||||
bool F0(bool front_facing, float l0, float l1) {
|
||||
float l2 = float(0);
|
||||
float l3 = float(0);
|
||||
l2 = atan((l1) / (l0));
|
||||
|
4
internal/shader/testdata/out.expected.metal
vendored
4
internal/shader/testdata/out.expected.metal
vendored
@@ -1,6 +1,6 @@
|
||||
void F0(thread float& l0, thread array<float, 4>& l1, thread float4& l2);
|
||||
void F0(bool front_facing, thread float& l0, thread array<float, 4>& l1, thread float4& l2);
|
||||
|
||||
void F0(thread float& l0, thread array<float, 4>& l1, thread float4& l2) {
|
||||
void F0(bool front_facing, thread float& l0, thread array<float, 4>& l1, thread float4& l2) {
|
||||
l0 = float(0);
|
||||
l1 = {};
|
||||
l2 = float4(0);
|
||||
|
@@ -29,6 +29,7 @@ vertex Varyings Vertex(
|
||||
|
||||
fragment float4 Fragment(
|
||||
Varyings varyings [[stage_in]],
|
||||
constant Uniforms& uniforms [[buffer(0)]]) {
|
||||
constant Uniforms& uniforms [[buffer(0)]],
|
||||
bool front_facing [[front_facing]]) {
|
||||
return float4((varyings.Position).x, (varyings.M0).y, (varyings.M1).z, 1.0);
|
||||
}
|
||||
|
@@ -520,6 +520,9 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
|
||||
}
|
||||
return result
|
||||
}
|
||||
if callee.BuiltinFunc == shaderir.FrontFacing {
|
||||
return "gl_FrontFacing"
|
||||
}
|
||||
}
|
||||
// Using parentheses at the callee is illegal.
|
||||
return fmt.Sprintf("%s(%s)", expr(&callee), strings.Join(args, ", "))
|
||||
|
@@ -80,14 +80,14 @@ float4x4 float4x4FromScalar(float x) {
|
||||
return float4x4(x, 0, 0, 0, 0, x, 0, 0, 0, 0, x, 0, 0, 0, 0, x);
|
||||
}`
|
||||
|
||||
func Compile(p *shaderir.Program) (vertexShader, pixelShader, prelude string) {
|
||||
func Compile(p *shaderir.Program) (vertexShader, pixelShader, vertexPrelude, pixelPrelude string) {
|
||||
offsets := UniformVariableOffsetsInDwords(p)
|
||||
|
||||
c := &compileContext{
|
||||
unit: p.Unit,
|
||||
}
|
||||
|
||||
var lines []string
|
||||
appendPrelude := func(lines []string, vertex bool) []string {
|
||||
lines = append(lines, strings.Split(utilFuncs, "\n")...)
|
||||
|
||||
lines = append(lines, "", "struct Varyings {")
|
||||
@@ -109,9 +109,21 @@ func Compile(p *shaderir.Program) (vertexShader, pixelShader, prelude string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if !vertex {
|
||||
lines = append(lines, "\tbool FrontFacing : SV_IsFrontFace;")
|
||||
}
|
||||
lines = append(lines, "};")
|
||||
prelude = strings.Join(lines, "\n")
|
||||
return lines
|
||||
}
|
||||
|
||||
var vslines, pslines []string
|
||||
vslines = appendPrelude(vslines, true)
|
||||
pslines = appendPrelude(pslines, false)
|
||||
|
||||
vertexPrelude = strings.Join(vslines, "\n")
|
||||
pixelPrelude = strings.Join(pslines, "\n")
|
||||
|
||||
appendGlobalVariables := func(lines []string) []string {
|
||||
lines = append(lines, "", "{{.Structs}}")
|
||||
|
||||
if len(p.Uniforms) > 0 {
|
||||
@@ -142,11 +154,10 @@ func Compile(p *shaderir.Program) (vertexShader, pixelShader, prelude string) {
|
||||
lines = append(lines, "SamplerState samp : register(s0);")
|
||||
}
|
||||
}
|
||||
|
||||
vslines := make([]string, len(lines))
|
||||
copy(vslines, lines)
|
||||
pslines := make([]string, len(lines))
|
||||
copy(pslines, lines)
|
||||
return lines
|
||||
}
|
||||
vslines = appendGlobalVariables(vslines)
|
||||
pslines = appendGlobalVariables(pslines)
|
||||
|
||||
var vsfuncs []*shaderir.Func
|
||||
if p.VertexFunc.Block != nil {
|
||||
@@ -522,6 +533,9 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
|
||||
}
|
||||
return result
|
||||
}
|
||||
if callee.Type == shaderir.BuiltinFuncExpr && callee.BuiltinFunc == shaderir.FrontFacing {
|
||||
return fmt.Sprintf("%s.FrontFacing", vsOut)
|
||||
}
|
||||
return fmt.Sprintf("%s(%s)", expr(&e.Exprs[0]), strings.Join(args, ", "))
|
||||
case shaderir.FieldSelector:
|
||||
return fmt.Sprintf("(%s).%s", expr(&e.Exprs[0]), expr(&e.Exprs[1]))
|
||||
|
@@ -819,9 +819,9 @@ void F0(in float l0, in float l1, out float l2) {
|
||||
}`,
|
||||
Metal: msl.Prelude(shaderir.Pixels) + `
|
||||
|
||||
void F0(float l0, float l1, thread float& l2);
|
||||
void F0(bool front_facing, float l0, float l1, thread float& l2);
|
||||
|
||||
void F0(float l0, float l1, thread float& l2) {
|
||||
void F0(bool front_facing, float l0, float l1, thread float& l2) {
|
||||
for (int l3 = 0; l3 < 100; l3++) {
|
||||
int l4 = 0;
|
||||
l2 = l4;
|
||||
@@ -916,9 +916,9 @@ void F0(in float l0, in float l1, out float l2) {
|
||||
}`,
|
||||
Metal: msl.Prelude(shaderir.Pixels) + `
|
||||
|
||||
void F0(float l0, float l1, thread float& l2);
|
||||
void F0(bool front_facing, float l0, float l1, thread float& l2);
|
||||
|
||||
void F0(float l0, float l1, thread float& l2) {
|
||||
void F0(bool front_facing, float l0, float l1, thread float& l2) {
|
||||
for (int l3 = 0; l3 < 100; l3++) {
|
||||
int l4 = 0;
|
||||
l2 = l4;
|
||||
|
@@ -156,6 +156,8 @@ func Compile(p *shaderir.Program) (shader string) {
|
||||
lines[len(lines)-1] += ","
|
||||
lines = append(lines, fmt.Sprintf("\ttexture2d<float> T%[1]d [[texture(%[1]d)]]", i))
|
||||
}
|
||||
lines[len(lines)-1] += ","
|
||||
lines = append(lines, "\tbool front_facing [[front_facing]]")
|
||||
lines[len(lines)-1] += ") {"
|
||||
lines = append(lines, c.block(p, p.FragmentFunc.Block, p.FragmentFunc.Block, 0)...)
|
||||
lines = append(lines, "}")
|
||||
@@ -244,6 +246,7 @@ func (c *compileContext) function(p *shaderir.Program, f *shaderir.Func, prototy
|
||||
for i := 0; i < p.TextureCount; i++ {
|
||||
args = append(args, fmt.Sprintf("texture2d<float> T%d", i))
|
||||
}
|
||||
args = append(args, "bool front_facing")
|
||||
|
||||
var idx int
|
||||
for _, t := range f.InParams {
|
||||
@@ -404,6 +407,7 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
|
||||
for i := 0; i < p.TextureCount; i++ {
|
||||
args = append(args, fmt.Sprintf("T%d", i))
|
||||
}
|
||||
args = append(args, "front_facing")
|
||||
}
|
||||
for _, exp := range e.Exprs[1:] {
|
||||
args = append(args, expr(&exp))
|
||||
@@ -425,6 +429,9 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
|
||||
}
|
||||
return result
|
||||
}
|
||||
if callee.Type == shaderir.BuiltinFuncExpr && callee.BuiltinFunc == shaderir.FrontFacing {
|
||||
return "(front_facing)"
|
||||
}
|
||||
return fmt.Sprintf("%s(%s)", expr(&callee), strings.Join(args, ", "))
|
||||
case shaderir.FieldSelector:
|
||||
return fmt.Sprintf("(%s).%s", expr(&e.Exprs[0]), expr(&e.Exprs[1]))
|
||||
|
@@ -294,6 +294,7 @@ const (
|
||||
Fwidth BuiltinFunc = "fwidth"
|
||||
DiscardF BuiltinFunc = "discard"
|
||||
TexelAt BuiltinFunc = "__texelAt"
|
||||
FrontFacing BuiltinFunc = "frontfacing"
|
||||
)
|
||||
|
||||
func ParseBuiltinFunc(str string) (BuiltinFunc, bool) {
|
||||
@@ -351,7 +352,8 @@ func ParseBuiltinFunc(str string) (BuiltinFunc, bool) {
|
||||
Dfdy,
|
||||
Fwidth,
|
||||
DiscardF,
|
||||
TexelAt:
|
||||
TexelAt,
|
||||
FrontFacing:
|
||||
return BuiltinFunc(str), true
|
||||
}
|
||||
return "", false
|
||||
|
@@ -497,7 +497,7 @@ func compile(shader *Shader, targets []string) error {
|
||||
Fragment: fs,
|
||||
}
|
||||
case "hlsl":
|
||||
vs, ps, _ := hlsl.Compile(ir)
|
||||
vs, ps, _, _ := hlsl.Compile(ir)
|
||||
shader.HLSL = &HLSL{
|
||||
Vertex: vs,
|
||||
Pixel: ps,
|
||||
|
@@ -3010,3 +3010,56 @@ func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestShaderFrontFacing(t *testing.T) {
|
||||
const w, h = 16, 16
|
||||
|
||||
dst := ebiten.NewImage(w, h)
|
||||
s, err := ebiten.NewShader([]byte(`//kage:unit pixels
|
||||
|
||||
package main
|
||||
|
||||
func Fragment(dstPos vec4, srcPos vec2, color vec4) vec4 {
|
||||
if frontfacing() {
|
||||
return vec4(0.5, 0, 0, 1)
|
||||
}
|
||||
return vec4(0, 0.5, 0, 1)
|
||||
}
|
||||
`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vs := []ebiten.Vertex{
|
||||
{
|
||||
DstX: 0,
|
||||
DstY: 0,
|
||||
},
|
||||
{
|
||||
DstX: w,
|
||||
DstY: 0,
|
||||
},
|
||||
{
|
||||
DstX: 0,
|
||||
DstY: h,
|
||||
},
|
||||
{
|
||||
DstX: w,
|
||||
DstY: h,
|
||||
},
|
||||
}
|
||||
op := &ebiten.DrawTrianglesShaderOptions{}
|
||||
op.Blend = ebiten.BlendLighter
|
||||
dst.DrawTrianglesShader32(vs, []uint32{0, 1, 2, 1, 2, 3}, s, op)
|
||||
dst.DrawTrianglesShader32(vs, []uint32{2, 1, 0, 3, 2, 1}, s, op)
|
||||
|
||||
for j := 0; j < h; j++ {
|
||||
for i := 0; i < w; i++ {
|
||||
got := dst.At(i, j).(color.RGBA)
|
||||
want := color.RGBA{R: 0x80, G: 0x80, B: 0x00, A: 0xff}
|
||||
if !sameColors(got, want, 2) {
|
||||
t.Errorf("dst.At(%d, %d): got: %v, want: %v", i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user