Compare commits

...

5 Commits

Author SHA1 Message Date
Zyko
c3a358b44b Fixed missing arg on gl with CGo 2024-04-09 02:40:21 +02:00
Zyko
d1fd70495b Revert to gl_FragData (future webgl) 2024-04-09 02:26:29 +02:00
Zyko
c7eeae7189 Cleanup 2024-04-09 01:00:26 +02:00
Zyko
4536fadebe Update hlsl 2024-04-08 23:48:16 +02:00
Zyko
280cc1a732 Update glsl 2024-04-08 23:43:19 +02:00
8 changed files with 124 additions and 31 deletions

View File

@ -15,11 +15,13 @@
package main
import (
"fmt"
"image"
_ "image/jpeg"
"log"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
)
const (
@ -71,11 +73,9 @@ func init() {
}
type Game struct {
count int
}
func (g *Game) Update() error {
g.count++
return nil
}
@ -114,6 +114,8 @@ func (g *Game) Draw(screen *ebiten.Image) {
opts.GeoM.Reset()
opts.GeoM.Translate(dstSize, dstSize)
screen.DrawImage(dsts[3], opts)
ebitenutil.DebugPrint(screen, fmt.Sprintf("FPS: %.2f", ebiten.ActualFPS()))
}
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
@ -122,9 +124,10 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
func main() {
ebiten.SetWindowSize(screenWidth, screenHeight)
ebiten.SetVsyncEnabled(false)
ebiten.SetWindowTitle("MRT (Ebitengine Demo)")
if err := ebiten.RunGameWithOptions(&Game{}, &ebiten.RunGameOptions{
GraphicsLibrary: ebiten.GraphicsLibraryDirectX,
GraphicsLibrary: ebiten.GraphicsLibraryOpenGL,
}); err != nil {
log.Fatal(err)
}

View File

@ -128,6 +128,10 @@ package gl
// typedef void (*fn)(GLuint index);
// ((fn)(fnptr))(index);
// }
// static void glowDrawBuffers(uintptr_t fnptr, GLsizei n, const GLenum* bufs) {
// typedef void (*fn)(GLsizei n, const GLenum* bufs);
// ((fn)(fnptr))(n, bufs);
// }
// static void glowDrawElements(uintptr_t fnptr, GLenum mode, GLsizei count, GLenum type, const uintptr_t indices) {
// typedef void (*fn)(GLenum mode, GLsizei count, GLenum type, const uintptr_t indices);
// ((fn)(fnptr))(mode, count, type, indices);
@ -351,6 +355,7 @@ type defaultContext struct {
gpDeleteVertexArrays C.uintptr_t
gpDisable C.uintptr_t
gpDisableVertexAttribArray C.uintptr_t
gpDrawBuffers C.uintptr_t
gpDrawElements C.uintptr_t
gpEnable C.uintptr_t
gpEnableVertexAttribArray C.uintptr_t
@ -565,6 +570,10 @@ func (c *defaultContext) DisableVertexAttribArray(index uint32) {
C.glowDisableVertexAttribArray(c.gpDisableVertexAttribArray, C.GLuint(index))
}
func (c *defaultContext) DrawBuffers(bufs []uint32) {
C.glowDrawBuffers(c.gpDrawBuffers, C.GLsizei(len(bufs)), (*C.GLenum)(unsafe.Pointer(&bufs[0])))
}
func (c *defaultContext) DrawElements(mode uint32, count int32, xtype uint32, offset int) {
C.glowDrawElements(c.gpDrawElements, C.GLenum(mode), C.GLsizei(count), C.GLenum(xtype), C.uintptr_t(offset))
}
@ -801,6 +810,7 @@ func (c *defaultContext) LoadFunctions() error {
c.gpDeleteVertexArrays = C.uintptr_t(g.get("glDeleteVertexArrays"))
c.gpDisable = C.uintptr_t(g.get("glDisable"))
c.gpDisableVertexAttribArray = C.uintptr_t(g.get("glDisableVertexAttribArray"))
c.gpDrawBuffers = C.uintptr_t(g.get("glDrawBuffers"))
c.gpDrawElements = C.uintptr_t(g.get("glDrawElements"))
c.gpEnable = C.uintptr_t(g.get("glEnable"))
c.gpEnableVertexAttribArray = C.uintptr_t(g.get("glEnableVertexAttribArray"))

View File

@ -47,7 +47,6 @@ type Graphics struct {
uniformVariableNameCache map[int]string
textureVariableNameCache map[int]string
colorBufferVariableNameCache map[int]string
uniformVars []uniformVariable

View File

@ -258,18 +258,6 @@ func (g *Graphics) textureVariableName(idx int) string {
return name
}
func (g *Graphics) colorBufferVariableName(idx int) string {
if v, ok := g.colorBufferVariableNameCache[idx]; ok {
return v
}
if g.colorBufferVariableNameCache == nil {
g.colorBufferVariableNameCache = map[int]string{}
}
name := fmt.Sprintf("gl_FragData[%d]", idx)
g.colorBufferVariableNameCache[idx] = name
return name
}
// useProgram uses the program (programTexture).
func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textures [graphics.ShaderSrcImageCount]textureVariable) error {
if g.state.lastProgram != program {

View File

@ -822,10 +822,12 @@ func (cs *compileState) parseFunc(block *block, d *ast.FuncDecl) (function, bool
return function{}, false
}
// The first out-param is treated as gl_FragColor in GLSL.
if outParams[0].typ.Main != shaderir.Vec4 {
cs.addError(d.Pos(), "fragment entry point must have at least one returning vec4 value for a color")
return function{}, false
// The first out-param is treated as fragColor0 in GLSL.
for i := range outParams {
if outParams[i].typ.Main != shaderir.Vec4 {
cs.addError(d.Pos(), "fragment entry point must only have vec4 return values for colors")
return function{}, false
}
}
// Adjust the number of textures to write to
cs.ir.ColorsOutCount = len(outParams)

View File

@ -334,7 +334,8 @@ func (cs *compileState) parseStmt(block *block, fname string, stmt ast.Stmt, inP
case *ast.ReturnStmt:
if len(stmt.Results) != len(outParams) && len(stmt.Results) != 1 {
if !(len(stmt.Results) == 0 && len(outParams) > 0 && outParams[0].name != "") {
// Fragment function does not have to return a value due to discard
if fname != cs.fragmentEntry && !(len(stmt.Results) == 0 && len(outParams) > 0 && outParams[0].name != "") {
// TODO: Check variable shadowings.
// https://go.dev/ref/spec#Return_statements
cs.addError(stmt.Pos(), fmt.Sprintf("the number of returning variables must be %d but %d", len(outParams), len(stmt.Results)))

View File

@ -86,8 +86,7 @@ precision highp int;
#define lowp
#define mediump
#define highp
#endif
`
#endif`
if version == GLSLVersionDefault {
prelude += "\n\n" + utilFunctions
}
@ -291,6 +290,8 @@ func Compile(p *shaderir.Program, version GLSLVersion) (vertexShader, fragmentSh
vs = strings.TrimSpace(vs) + "\n"
fs = strings.TrimSpace(fs) + "\n"
fmt.Println("FS:", fs)
return vs, fs
}
@ -603,7 +604,7 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
}
case shaderir.Discard:
// 'discard' is invoked only in the fragment shader entry point.
lines = append(lines, idt+"discard;", idt+"return vec4(0.0);")
lines = append(lines, idt+"discard;") //, idt+"return vec4(0.0);")
default:
lines = append(lines, fmt.Sprintf("%s?(unexpected stmt: %d)", idt, s.Type))
}
@ -651,7 +652,7 @@ func adjustProgram(p *shaderir.Program) *shaderir.Program {
Main: shaderir.Vec4,
}
}
newP.FragmentFunc.Block.LocalVarIndexOffset += (p.ColorsOutCount-1)
newP.FragmentFunc.Block.LocalVarIndexOffset += (p.ColorsOutCount - 1)
newP.Funcs = append(newP.Funcs, shaderir.Func{
Index: funcIdx,

View File

@ -22,7 +22,6 @@ import (
"regexp"
"strings"
"github.com/hajimehoshi/ebiten/v2/internal/graphics"
"github.com/hajimehoshi/ebiten/v2/internal/shaderir"
)
@ -89,6 +88,7 @@ float4x4 float4x4FromScalar(float x) {
func Compile(p *shaderir.Program) (vertexShader, pixelShader string, offsets []int) {
offsets = calculateMemoryOffsets(p.Uniforms)
p = adjustProgram(p)
c := &compileContext{
unit: p.Unit,
@ -193,7 +193,7 @@ func Compile(p *shaderir.Program) (vertexShader, pixelShader string, offsets []i
pslines = append(pslines, "")
pslines = append(pslines, "struct PS_OUTPUT")
pslines = append(pslines, "{")
for i := 0; i < graphics.ShaderDstImageCount; i++ {
for i := 0; i < p.ColorsOutCount; i++ {
pslines = append(pslines, fmt.Sprintf("\tfloat4 Color%d: SV_Target%d;", i, i))
}
pslines = append(pslines, "};")
@ -404,6 +404,9 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
}
var lines []string
for i := range block.LocalVars {
lines = append(lines, c.initVariable(p, topBlock, block, block.LocalVarIndexOffset+i, true, level)...)
}
var expr func(e *shaderir.Expr) string
expr = func(e *shaderir.Expr) string {
@ -510,8 +513,7 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
case shaderir.Assign:
lhs := s.Exprs[0]
rhs := s.Exprs[1]
isOutput := strings.HasPrefix(expr(&lhs), "output.Color")
if !isOutput && lhs.Type == shaderir.LocalVariable {
if lhs.Type == shaderir.LocalVariable {
if t := p.LocalVariableType(topBlock, block, lhs.Index); t.Main == shaderir.Array {
for i := 0; i < t.Length; i++ {
lines = append(lines, fmt.Sprintf("%[1]s%[2]s[%[3]d] = %[4]s[%[3]d];", idt, expr(&lhs), i, expr(&rhs)))
@ -572,14 +574,18 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
switch {
case topBlock == p.VertexFunc.Block:
lines = append(lines, fmt.Sprintf("%sreturn %s;", idt, vsOut))
case len(s.Exprs) == 0:
case topBlock == p.FragmentFunc.Block:
// Call to the pseudo fragment func based on out parameters
lines = append(lines, idt+expr(&s.Exprs[0])+";")
lines = append(lines, idt+"return output;")
case len(s.Exprs) == 0:
lines = append(lines, idt+"return;")
default:
lines = append(lines, fmt.Sprintf("%sreturn %s;", idt, expr(&s.Exprs[0])))
}
case shaderir.Discard:
// 'discard' is invoked only in the fragment shader entry point.
lines = append(lines, idt+"discard;", idt+"return float4(0.0, 0.0, 0.0, 0.0);")
lines = append(lines, idt+"discard;")
default:
lines = append(lines, fmt.Sprintf("%s?(unexpected stmt: %d)", idt, s.Type))
}
@ -587,3 +593,86 @@ func (c *compileContext) block(p *shaderir.Program, topBlock, block *shaderir.Bl
return lines
}
func adjustProgram(p *shaderir.Program) *shaderir.Program {
if p.FragmentFunc.Block == nil {
return p
}
// Shallow-clone the program in order not to modify p itself.
newP := *p
// Create a new slice not to affect the original p.
newP.Funcs = make([]shaderir.Func, len(p.Funcs))
copy(newP.Funcs, p.Funcs)
// Create a new function whose body is the same is the fragment shader's entry point.
// Determine a unique index of the new function.
var funcIdx int
for _, f := range newP.Funcs {
if funcIdx <= f.Index {
funcIdx = f.Index + 1
}
}
// For parameters of a fragment func, see the comment in internal/shaderir/program.go.
inParams := make([]shaderir.Type, 1+len(newP.Varyings))
inParams[0] = shaderir.Type{
Main: shaderir.Vec4, // gl_FragCoord
}
copy(inParams[1:], newP.Varyings)
// Out parameters of a fragment func are colors
outParams := make([]shaderir.Type, p.ColorsOutCount)
for i := range outParams {
outParams[i] = shaderir.Type{
Main: shaderir.Vec4,
}
}
newP.FragmentFunc.Block.LocalVarIndexOffset += (p.ColorsOutCount - 1)
newP.Funcs = append(newP.Funcs, shaderir.Func{
Index: funcIdx,
InParams: inParams,
OutParams: outParams,
Block: newP.FragmentFunc.Block,
})
// Create an AST to call the new function.
call := []shaderir.Expr{
{
Type: shaderir.FunctionExpr,
Index: funcIdx,
},
}
for i := 0; i < 1+len(newP.Varyings)+p.ColorsOutCount; i++ {
call = append(call, shaderir.Expr{
Type: shaderir.LocalVariable,
Index: i,
})
}
// Replace the entry point with just calling the new function.
stmts := []shaderir.Stmt{
{
// Return: This will be replaced with a call to the new function.
// Then the output structure containing colors will be returned.
Type: shaderir.Return,
Exprs: []shaderir.Expr{
// The function call
{
Type: shaderir.Call,
Exprs: call,
},
},
},
}
newP.FragmentFunc = shaderir.FragmentFunc{
Block: &shaderir.Block{
LocalVars: nil,
LocalVarIndexOffset: 1 + len(newP.Varyings) + 1,
Stmts: stmts,
},
}
return &newP
}