Compare commits

..

6 Commits

Author SHA1 Message Date
Hajime Hoshi
7142a3bcd9 internal/graphicsdriver/opengl: bug fix: total must be reset 2024-08-25 15:29:22 +09:00
Hajime Hoshi
d570406735 all: update ebitengine/gomobile 2024-08-25 13:39:36 +09:00
Hajime Hoshi
65aec12d88 all: update PureGo to v0.8.0-alpha.5 2024-08-25 13:03:30 +09:00
Hajime Hoshi
a42a8548b1 internal/shader: refactoring 2024-08-25 12:57:11 +09:00
Hajime Hoshi
6db3b11b36 internal/shader: refactoring 2024-08-25 12:29:24 +09:00
Hajime Hoshi
3547d999b1 internal/graphicsdriver/opengl/gl: bug fix: crash when log length is 0 2024-08-25 11:45:54 +09:00
6 changed files with 88 additions and 83 deletions

4
go.mod
View File

@ -3,10 +3,10 @@ module github.com/hajimehoshi/ebiten/v2
go 1.19 go 1.19
require ( require (
github.com/ebitengine/gomobile v0.0.0-20240802043200-192f051f4fcc github.com/ebitengine/gomobile v0.0.0-20240825043811-96c531f5bd83
github.com/ebitengine/hideconsole v1.0.0 github.com/ebitengine/hideconsole v1.0.0
github.com/ebitengine/oto/v3 v3.3.0-alpha.4 github.com/ebitengine/oto/v3 v3.3.0-alpha.4
github.com/ebitengine/purego v0.8.0-alpha.4 github.com/ebitengine/purego v0.8.0-alpha.5
github.com/gen2brain/mpeg v0.3.2-0.20240412154320-a2ac4fc8a46f github.com/gen2brain/mpeg v0.3.2-0.20240412154320-a2ac4fc8a46f
github.com/go-text/typesetting v0.1.1 github.com/go-text/typesetting v0.1.1
github.com/hajimehoshi/bitmapfont/v3 v3.2.0-alpha.4 github.com/hajimehoshi/bitmapfont/v3 v3.2.0-alpha.4

8
go.sum
View File

@ -1,11 +1,11 @@
github.com/ebitengine/gomobile v0.0.0-20240802043200-192f051f4fcc h1:76TYsaP1F48tiQRlrr71NsbfxBcFM9/8bEHS9/JbsQg= github.com/ebitengine/gomobile v0.0.0-20240825043811-96c531f5bd83 h1:yA0CtFKYZI/db1snCOInRS0Z18QGZU6aBYkqUT0H6RI=
github.com/ebitengine/gomobile v0.0.0-20240802043200-192f051f4fcc/go.mod h1:RM/c3pvru6dRqgGEW7RCTb6czFXYAa3MxbXu3u8/dcI= github.com/ebitengine/gomobile v0.0.0-20240825043811-96c531f5bd83/go.mod h1:n2NbB/F4d9wOXFzC7FT1ipERidmYWC5I4YNOYRs5N7I=
github.com/ebitengine/hideconsole v1.0.0 h1:5J4U0kXF+pv/DhiXt5/lTz0eO5ogJ1iXb8Yj1yReDqE= github.com/ebitengine/hideconsole v1.0.0 h1:5J4U0kXF+pv/DhiXt5/lTz0eO5ogJ1iXb8Yj1yReDqE=
github.com/ebitengine/hideconsole v1.0.0/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A= github.com/ebitengine/hideconsole v1.0.0/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A=
github.com/ebitengine/oto/v3 v3.3.0-alpha.4 h1:w9SD7kK4GgJULkh5pWVTToMA5Ia1bP7VxD4rIjQqb8M= github.com/ebitengine/oto/v3 v3.3.0-alpha.4 h1:w9SD7kK4GgJULkh5pWVTToMA5Ia1bP7VxD4rIjQqb8M=
github.com/ebitengine/oto/v3 v3.3.0-alpha.4/go.mod h1:B+Sz3hzZXcx251YqSPIj+cVMicvlx7Xiq29AEUIbc7E= github.com/ebitengine/oto/v3 v3.3.0-alpha.4/go.mod h1:B+Sz3hzZXcx251YqSPIj+cVMicvlx7Xiq29AEUIbc7E=
github.com/ebitengine/purego v0.8.0-alpha.4 h1:Dg9xRGC3giyQedfISyHH94eQM0md4a84+HHr7KBBH/Q= github.com/ebitengine/purego v0.8.0-alpha.5 h1:M0+PSgsdVNczTB8ijX89HmYqCfb2HUuBEx4A+wNuHto=
github.com/ebitengine/purego v0.8.0-alpha.4/go.mod h1:SQ56/omnSL8DdaBSKswoBvsMjgaWQyxyeMtb48sOskI= github.com/ebitengine/purego v0.8.0-alpha.5/go.mod h1:SQ56/omnSL8DdaBSKswoBvsMjgaWQyxyeMtb48sOskI=
github.com/gen2brain/mpeg v0.3.2-0.20240412154320-a2ac4fc8a46f h1:ysqRe+lvUiL0dH5XzkH0Bz68bFMPJ4f5Si4L/HD9SGk= github.com/gen2brain/mpeg v0.3.2-0.20240412154320-a2ac4fc8a46f h1:ysqRe+lvUiL0dH5XzkH0Bz68bFMPJ4f5Si4L/HD9SGk=
github.com/gen2brain/mpeg v0.3.2-0.20240412154320-a2ac4fc8a46f/go.mod h1:i/ebyRRv/IoHixuZ9bElZnXbmfoUVPGQpdsJ4sVuX38= github.com/gen2brain/mpeg v0.3.2-0.20240412154320-a2ac4fc8a46f/go.mod h1:i/ebyRRv/IoHixuZ9bElZnXbmfoUVPGQpdsJ4sVuX38=
github.com/go-text/typesetting v0.1.1 h1:bGAesCuo85nXnEN5LmFMVGAGpGkCPtHrZLi//qD7EJo= github.com/go-text/typesetting v0.1.1 h1:bGAesCuo85nXnEN5LmFMVGAGpGkCPtHrZLi//qD7EJo=

View File

@ -592,6 +592,9 @@ func (c *defaultContext) GetInteger(pname uint32) int {
func (c *defaultContext) GetProgramInfoLog(program uint32) string { func (c *defaultContext) GetProgramInfoLog(program uint32) string {
bufSize := c.GetProgrami(program, INFO_LOG_LENGTH) bufSize := c.GetProgrami(program, INFO_LOG_LENGTH)
if bufSize == 0 {
return ""
}
infoLog := make([]byte, bufSize) infoLog := make([]byte, bufSize)
C.glowGetProgramInfoLog(c.gpGetProgramInfoLog, C.GLuint(program), C.GLsizei(bufSize), nil, (*C.GLchar)(unsafe.Pointer(&infoLog[0]))) C.glowGetProgramInfoLog(c.gpGetProgramInfoLog, C.GLuint(program), C.GLsizei(bufSize), nil, (*C.GLchar)(unsafe.Pointer(&infoLog[0])))
return string(infoLog) return string(infoLog)
@ -605,6 +608,9 @@ func (c *defaultContext) GetProgrami(program uint32, pname uint32) int {
func (c *defaultContext) GetShaderInfoLog(shader uint32) string { func (c *defaultContext) GetShaderInfoLog(shader uint32) string {
bufSize := c.GetShaderi(shader, INFO_LOG_LENGTH) bufSize := c.GetShaderi(shader, INFO_LOG_LENGTH)
if bufSize == 0 {
return ""
}
infoLog := make([]byte, bufSize) infoLog := make([]byte, bufSize)
C.glowGetShaderInfoLog(c.gpGetShaderInfoLog, C.GLuint(shader), C.GLsizei(bufSize), nil, (*C.GLchar)(unsafe.Pointer(&infoLog[0]))) C.glowGetShaderInfoLog(c.gpGetShaderInfoLog, C.GLuint(shader), C.GLsizei(bufSize), nil, (*C.GLchar)(unsafe.Pointer(&infoLog[0])))
return string(infoLog) return string(infoLog)

View File

@ -300,6 +300,9 @@ func (c *defaultContext) GetInteger(pname uint32) int {
func (c *defaultContext) GetProgramInfoLog(program uint32) string { func (c *defaultContext) GetProgramInfoLog(program uint32) string {
bufSize := c.GetProgrami(program, INFO_LOG_LENGTH) bufSize := c.GetProgrami(program, INFO_LOG_LENGTH)
if bufSize == 0 {
return ""
}
infoLog := make([]byte, bufSize) infoLog := make([]byte, bufSize)
purego.SyscallN(c.gpGetProgramInfoLog, uintptr(program), uintptr(bufSize), 0, uintptr(unsafe.Pointer(&infoLog[0]))) purego.SyscallN(c.gpGetProgramInfoLog, uintptr(program), uintptr(bufSize), 0, uintptr(unsafe.Pointer(&infoLog[0])))
return string(infoLog) return string(infoLog)
@ -313,6 +316,9 @@ func (c *defaultContext) GetProgrami(program uint32, pname uint32) int {
func (c *defaultContext) GetShaderInfoLog(shader uint32) string { func (c *defaultContext) GetShaderInfoLog(shader uint32) string {
bufSize := c.GetShaderi(shader, INFO_LOG_LENGTH) bufSize := c.GetShaderi(shader, INFO_LOG_LENGTH)
if bufSize == 0 {
return ""
}
infoLog := make([]byte, bufSize) infoLog := make([]byte, bufSize)
purego.SyscallN(c.gpGetShaderInfoLog, uintptr(shader), uintptr(bufSize), 0, uintptr(unsafe.Pointer(&infoLog[0]))) purego.SyscallN(c.gpGetShaderInfoLog, uintptr(shader), uintptr(bufSize), 0, uintptr(unsafe.Pointer(&infoLog[0])))
return string(infoLog) return string(infoLog)

View File

@ -66,6 +66,11 @@ func (a *arrayBufferLayout) float32Count() int {
return a.total return a.total
} }
func (a *arrayBufferLayout) addPart(part arrayBufferLayoutPart) {
a.parts = append(a.parts, part)
a.total = 0
}
// enable starts using the array buffer. // enable starts using the array buffer.
func (a *arrayBufferLayout) enable(context *context) { func (a *arrayBufferLayout) enable(context *context) {
for i := range a.parts { for i := range a.parts {
@ -117,7 +122,7 @@ func init() {
if d > 4 { if d > 4 {
panic("opengl: the array buffer layout is too small") panic("opengl: the array buffer layout is too small")
} }
theArrayBufferLayout.parts = append(theArrayBufferLayout.parts, arrayBufferLayoutPart{ theArrayBufferLayout.addPart(arrayBufferLayoutPart{
name: "A3", name: "A3",
num: d, num: d,
}) })

View File

@ -55,9 +55,7 @@ type compileState struct {
ir shaderir.Program ir shaderir.Program
funcs []function funcs []function
vertexOutParams []shaderir.Type
fragmentInParams []shaderir.Type
global block global block
@ -292,18 +290,17 @@ func (cs *compileState) parse(f *ast.File) {
// Parse function names so that any other function call the others. // Parse function names so that any other function call the others.
// The function data is provisional and will be updated soon. // The function data is provisional and will be updated soon.
var vertexInParams []shaderir.Type
var vertexOutParams []shaderir.Type
var fragmentInParams []shaderir.Type
var fragmentOutParams []shaderir.Type
var fragmentReturnType shaderir.Type
for _, d := range f.Decls { for _, d := range f.Decls {
fd, ok := d.(*ast.FuncDecl) fd, ok := d.(*ast.FuncDecl)
if !ok { if !ok {
continue continue
} }
n := fd.Name.Name n := fd.Name.Name
if n == cs.vertexEntry {
continue
}
if n == cs.fragmentEntry {
continue
}
for _, f := range cs.funcs { for _, f := range cs.funcs {
if f.name == n { if f.name == n {
@ -321,6 +318,18 @@ func (cs *compileState) parse(f *ast.File) {
outT = append(outT, v.typ) outT = append(outT, v.typ)
} }
if n == cs.vertexEntry {
vertexInParams = inT
vertexOutParams = outT
continue
}
if n == cs.fragmentEntry {
fragmentInParams = inT
fragmentOutParams = outT
fragmentReturnType = ret
continue
}
cs.funcs = append(cs.funcs, function{ cs.funcs = append(cs.funcs, function{
name: n, name: n,
ir: shaderir.Func{ ir: shaderir.Func{
@ -333,6 +342,45 @@ func (cs *compileState) parse(f *ast.File) {
}) })
} }
// Check varying variables.
// In testings, there might not be vertex and fragment entry points.
if len(vertexOutParams) > 0 && len(fragmentInParams) > 0 {
if len(vertexOutParams) != len(fragmentInParams) {
cs.addError(0, "the number of vertex entry point's returning values and the number of fragment entry point's params must be the same")
}
for i, t := range vertexOutParams {
if !t.Equal(&fragmentInParams[i]) {
cs.addError(0, "vertex entry point's returning value types and fragment entry point's param types must match")
}
}
// The first out-param is treated as gl_Position in GLSL.
if vertexOutParams[0].Main != shaderir.Vec4 {
cs.addError(0, "vertex entry point must have at least one returning vec4 value for a position")
}
if len(fragmentInParams) == 0 {
cs.addError(0, "fragment entry point must have at least one vec4 parameter for a position")
}
if fragmentInParams[0].Main != shaderir.Vec4 {
cs.addError(0, "fragment entry point must have at least one vec4 parameter for a position")
}
if len(fragmentOutParams) != 0 || fragmentReturnType.Main != shaderir.Vec4 {
cs.addError(0, "fragment entry point must have one returning vec4 value for a color")
}
}
if len(cs.errs) > 0 {
return
}
// Set attribute varying veraibles.
cs.ir.Attributes = append(cs.ir.Attributes, vertexInParams...)
if len(vertexOutParams) > 0 {
// TODO: Check that these params are not arrays or structs
// The 0th argument is a special variable for position and is not included in varying variables.
cs.ir.Varyings = append(cs.ir.Varyings, vertexOutParams[1:]...)
}
// Parse functions. // Parse functions.
for _, d := range f.Decls { for _, d := range f.Decls {
if f, ok := d.(*ast.FuncDecl); ok { if f, ok := d.(*ast.FuncDecl); ok {
@ -348,29 +396,6 @@ func (cs *compileState) parse(f *ast.File) {
return return
} }
// Parse varying veraibles.
// In testings, there might not be vertex and fragment entry points.
if cs.ir.VertexFunc.Block != nil && cs.ir.FragmentFunc.Block != nil {
if len(cs.fragmentInParams) != len(cs.vertexOutParams) {
cs.addError(0, "the number of vertex entry point's returning values and the number of fragment entry point's params must be the same")
}
for i, t := range cs.vertexOutParams {
if !t.Equal(&cs.fragmentInParams[i]) {
cs.addError(0, "vertex entry point's returning value types and fragment entry point's param types must match")
}
}
}
if cs.ir.VertexFunc.Block != nil {
// TODO: Check that these params are not arrays or structs
// The 0th argument is a special variable for position and is not included in varying variables.
cs.ir.Varyings = append(cs.ir.Varyings, cs.vertexOutParams[1:]...)
}
if len(cs.errs) > 0 {
return
}
for _, f := range cs.funcs { for _, f := range cs.funcs {
cs.ir.Funcs = append(cs.ir.Funcs, f.ir) cs.ir.Funcs = append(cs.ir.Funcs, f.ir)
} }
@ -483,10 +508,8 @@ func (cs *compileState) parseDecl(b *block, fname string, d ast.Decl) ([]shaderi
switch d.Name.Name { switch d.Name.Name {
case cs.vertexEntry: case cs.vertexEntry:
cs.ir.VertexFunc.Block = f.ir.Block cs.ir.VertexFunc.Block = f.ir.Block
cs.vertexOutParams = f.ir.OutParams
case cs.fragmentEntry: case cs.fragmentEntry:
cs.ir.FragmentFunc.Block = f.ir.Block cs.ir.FragmentFunc.Block = f.ir.Block
cs.fragmentInParams = f.ir.InParams
default: default:
// The function is already registered for their names. // The function is already registered for their names.
for i := range cs.funcs { for i := range cs.funcs {
@ -768,7 +791,13 @@ func (cs *compileState) parseFuncParams(block *block, fname string, d *ast.FuncD
// If there is only one returning value, it is treated as a returning value. // If there is only one returning value, it is treated as a returning value.
// An array cannot be a returning value, especially for HLSL (#2923). // An array cannot be a returning value, especially for HLSL (#2923).
if len(out) == 1 && out[0].name == "" && out[0].typ.Main != shaderir.Array { //
// For the vertex entry, a parameter (variable) is used as a returning value.
// For example, GLSL doesn't treat gl_Position as a returning value.
// Thus, the returning value is not set for the vertex entry.
// TODO: This can be resolved by having an indirect function like what the fragment entry already does.
// See internal/shaderir/glsl.adjustProgram.
if len(out) == 1 && out[0].name == "" && out[0].typ.Main != shaderir.Array && fname != cs.vertexEntry {
ret = out[0].typ ret = out[0].typ
out = nil out = nil
} }
@ -791,47 +820,6 @@ func (cs *compileState) parseFunc(block *block, d *ast.FuncDecl) (function, bool
} }
inParams, outParams, returnType := cs.parseFuncParams(block, d.Name.Name, d) inParams, outParams, returnType := cs.parseFuncParams(block, d.Name.Name, d)
if block == &cs.global {
switch d.Name.Name {
case cs.vertexEntry:
for _, v := range inParams {
cs.ir.Attributes = append(cs.ir.Attributes, v.typ)
}
// For the vertex entry, a parameter (variable) is used as a returning value.
// For example, GLSL doesn't treat gl_Position as a returning value.
// TODO: This can be resolved by having an indirect function like what the fragment entry already does.
// See internal/shaderir/glsl.adjustProgram.
if len(outParams) == 0 {
outParams = append(outParams, variable{
typ: shaderir.Type{Main: shaderir.Vec4},
})
}
// The first out-param is treated as gl_Position in GLSL.
if outParams[0].typ.Main != shaderir.Vec4 {
cs.addError(d.Pos(), "vertex entry point must have at least one returning vec4 value for a position")
return function{}, false
}
case cs.fragmentEntry:
if len(inParams) == 0 {
cs.addError(d.Pos(), "fragment entry point must have at least one vec4 parameter for a position")
return function{}, false
}
if inParams[0].typ.Main != shaderir.Vec4 {
cs.addError(d.Pos(), "fragment entry point must have at least one vec4 parameter for a position")
return function{}, false
}
if len(outParams) != 0 || returnType.Main != shaderir.Vec4 {
cs.addError(d.Pos(), "fragment entry point must have one returning vec4 value for a color")
return function{}, false
}
}
}
b, ok := cs.parseBlock(block, d.Name.Name, d.Body.List, inParams, outParams, returnType, true) b, ok := cs.parseBlock(block, d.Name.Name, d.Body.List, inParams, outParams, returnType, true)
if !ok { if !ok {
return function{}, false return function{}, false