internal/driver: Optimization: Replace interface{} with driver.Uniform

Converting a value from/to interface{} can create a value in heap
and this is not efficient.
This commit is contained in:
Hajime Hoshi 2021-10-30 02:51:02 +09:00
parent 1f82bb297c
commit 06f4142ca0
11 changed files with 128 additions and 114 deletions

View File

@ -407,13 +407,13 @@ func (i *Image) processSrc(src *Image) {
// 5: Color G // 5: Color G
// 6: Color B // 6: Color B
// 7: Color Y // 7: Color Y
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, evenOdd bool) { func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []driver.Uniform, evenOdd bool) {
backendsM.Lock() backendsM.Lock()
defer backendsM.Unlock() defer backendsM.Unlock()
i.drawTriangles(srcs, vertices, indices, colorm, mode, filter, address, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd, false) i.drawTriangles(srcs, vertices, indices, colorm, mode, filter, address, dstRegion, srcRegion, subimageOffsets, shader, uniforms, evenOdd, false)
} }
func (i *Image) drawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, evenOdd bool, keepOnAtlas bool) { func (i *Image) drawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []driver.Uniform, evenOdd bool, keepOnAtlas bool) {
if i.disposed { if i.disposed {
panic("atlas: the drawing target image must not be disposed (DrawTriangles)") panic("atlas: the drawing target image must not be disposed (DrawTriangles)")
} }

View File

@ -202,7 +202,7 @@ func (i *Image) replacePendingPixels(pix []byte, x, y, width, height int) {
// DrawTriangles draws the src image with the given vertices. // DrawTriangles draws the src image with the given vertices.
// //
// Copying vertices and indices is the caller's responsibility. // Copying vertices and indices is the caller's responsibility.
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, evenOdd bool) { func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []driver.Uniform, evenOdd bool) {
for _, src := range srcs { for _, src := range srcs {
if i == src { if i == src {
panic("buffered: Image.DrawTriangles: source images must be different from the receiver") panic("buffered: Image.DrawTriangles: source images must be different from the receiver")

View File

@ -39,6 +39,11 @@ type ColorM interface {
Elements(body *[16]float32, translate *[4]float32) Elements(body *[16]float32, translate *[4]float32)
} }
type Uniform struct {
Float32 float32
Float32s []float32
}
type Graphics interface { type Graphics interface {
Begin() Begin()
End() End()
@ -64,7 +69,7 @@ type Graphics interface {
// //
// * float32 // * float32
// * []float32 // * []float32
DrawTriangles(dst ImageID, srcs [graphics.ShaderImageNum]ImageID, offsets [graphics.ShaderImageNum - 1][2]float32, shader ShaderID, indexLen int, indexOffset int, mode CompositeMode, colorM ColorM, filter Filter, address Address, dstRegion, srcRegion Region, uniforms []interface{}, evenOdd bool) error DrawTriangles(dst ImageID, srcs [graphics.ShaderImageNum]ImageID, offsets [graphics.ShaderImageNum - 1][2]float32, shader ShaderID, indexLen int, indexOffset int, mode CompositeMode, colorM ColorM, filter Filter, address Address, dstRegion, srcRegion Region, uniforms []Uniform, evenOdd bool) error
} }
// GraphicsNotReady represents that the graphics driver is not ready for recovering from the context lost. // GraphicsNotReady represents that the graphics driver is not ready for recovering from the context lost.

View File

@ -145,7 +145,7 @@ func (q *commandQueue) appendIndices(indices []uint16, offset uint16) {
} }
// EnqueueDrawTrianglesCommand enqueues a drawing-image command. // EnqueueDrawTrianglesCommand enqueues a drawing-image command.
func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, color affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []interface{}, evenOdd bool) { func (q *commandQueue) EnqueueDrawTrianglesCommand(dst *Image, srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, color affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []driver.Uniform, evenOdd bool) {
if len(indices) > graphics.IndicesNum { if len(indices) > graphics.IndicesNum {
panic(fmt.Sprintf("graphicscommand: len(indices) must be <= graphics.IndicesNum but not at EnqueueDrawTrianglesCommand: len(indices): %d, graphics.IndicesNum: %d", len(indices), graphics.IndicesNum)) panic(fmt.Sprintf("graphicscommand: len(indices) must be <= graphics.IndicesNum but not at EnqueueDrawTrianglesCommand: len(indices): %d, graphics.IndicesNum: %d", len(indices), graphics.IndicesNum))
} }
@ -363,7 +363,7 @@ type drawTrianglesCommand struct {
dstRegion driver.Region dstRegion driver.Region
srcRegion driver.Region srcRegion driver.Region
shader *Shader shader *Shader
uniforms []interface{} uniforms []driver.Uniform
evenOdd bool evenOdd bool
} }

View File

@ -141,7 +141,7 @@ func (i *Image) InternalSize() (int, int) {
// //
// If the source image is not specified, i.e., src is nil and there is no image in the uniform variables, the // If the source image is not specified, i.e., src is nil and there is no image in the uniform variables, the
// elements for the source image are not used. // elements for the source image are not used.
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, clr affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []interface{}, evenOdd bool) { func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, clr affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []driver.Uniform, evenOdd bool) {
if shader == nil { if shader == nil {
// Fast path for rendering without a shader (#1355). // Fast path for rendering without a shader (#1355).
img := srcs[0] img := srcs[0]

View File

@ -775,7 +775,7 @@ func (g *Graphics) flushRenderCommandEncoderIfNeeded() {
g.lastDst = nil g.lastDst = nil
} }
func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion driver.Region, srcs [graphics.ShaderImageNum]*Image, indexLen int, indexOffset int, uniforms []interface{}, stencilMode stencilMode) error { func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion driver.Region, srcs [graphics.ShaderImageNum]*Image, indexLen int, indexOffset int, uniforms []driver.Uniform, stencilMode stencilMode) error {
// When prepareing a stencil buffer, flush the current render command encoder // When prepareing a stencil buffer, flush the current render command encoder
// to make sure the stencil buffer is cleared when loading. // to make sure the stencil buffer is cleared when loading.
// TODO: What about clearing the stencil buffer by vertices? // TODO: What about clearing the stencil buffer by vertices?
@ -840,15 +840,14 @@ func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion drive
g.rce.SetVertexBuffer(g.vb, 0, 0) g.rce.SetVertexBuffer(g.vb, 0, 0)
for i, u := range uniforms { for i, u := range uniforms {
switch u := u.(type) { if len(u.Float32s) == 0 {
case float32: v := u.Float32
g.rce.SetVertexBytes(unsafe.Pointer(&u), unsafe.Sizeof(u), i+1) g.rce.SetVertexBytes(unsafe.Pointer(&v), unsafe.Sizeof(v), i+1)
g.rce.SetFragmentBytes(unsafe.Pointer(&u), unsafe.Sizeof(u), i+1) g.rce.SetFragmentBytes(unsafe.Pointer(&v), unsafe.Sizeof(v), i+1)
case []float32: } else {
g.rce.SetVertexBytes(unsafe.Pointer(&u[0]), unsafe.Sizeof(u[0])*uintptr(len(u)), i+1) v := u.Float32s
g.rce.SetFragmentBytes(unsafe.Pointer(&u[0]), unsafe.Sizeof(u[0])*uintptr(len(u)), i+1) g.rce.SetVertexBytes(unsafe.Pointer(&v[0]), unsafe.Sizeof(v[0])*uintptr(len(v)), i+1)
default: g.rce.SetFragmentBytes(unsafe.Pointer(&v[0]), unsafe.Sizeof(v[0])*uintptr(len(v)), i+1)
return fmt.Errorf("metal: unexpected uniform value: %[1]v (type: %[1]T)", u)
} }
} }
@ -867,7 +866,7 @@ func (g *Graphics) draw(rps mtl.RenderPipelineState, dst *Image, dstRegion drive
return nil return nil
} }
func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderImageNum]driver.ImageID, offsets [graphics.ShaderImageNum - 1][2]float32, shaderID driver.ShaderID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM driver.ColorM, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, uniforms []interface{}, evenOdd bool) error { func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderImageNum]driver.ImageID, offsets [graphics.ShaderImageNum - 1][2]float32, shaderID driver.ShaderID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM driver.ColorM, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, uniforms []driver.Uniform, evenOdd bool) error {
dst := g.images[dstID] dst := g.images[dstID]
if dst.screen { if dst.screen {
@ -880,7 +879,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
} }
rpss := map[stencilMode]mtl.RenderPipelineState{} rpss := map[stencilMode]mtl.RenderPipelineState{}
var uniformVars []interface{} var uniformVars []driver.Uniform
if shaderID == driver.InvalidShaderID { if shaderID == driver.InvalidShaderID {
if dst.screen && filter == driver.FilterScreen { if dst.screen && filter == driver.FilterScreen {
rpss[noStencil] = g.screenRPS rpss[noStencil] = g.screenRPS
@ -915,18 +914,30 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
if filter == driver.FilterScreen { if filter == driver.FilterScreen {
scale = float32(dst.width) / float32(srcs[0].width) scale = float32(dst.width) / float32(srcs[0].width)
} }
uniformVars = []interface{}{ uniformVars = []driver.Uniform{
[]float32{float32(w), float32(h)}, {
sourceSize, Float32s: []float32{float32(w), float32(h)},
esBody[:], },
esTranslate[:], {
scale, Float32s: sourceSize,
[]float32{ },
{
Float32s: esBody[:],
},
{
Float32s: esTranslate[:],
},
{
Float32: scale,
},
{
Float32s: []float32{
srcRegion.X, srcRegion.X,
srcRegion.Y, srcRegion.Y,
srcRegion.X + srcRegion.Width, srcRegion.X + srcRegion.Width,
srcRegion.Y + srcRegion.Height, srcRegion.Y + srcRegion.Height,
}, },
},
} }
} else { } else {
for _, stencil := range []stencilMode{ for _, stencil := range []stencilMode{
@ -941,11 +952,13 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
} }
} }
uniformVars = make([]interface{}, graphics.PreservedUniformVariablesNum+len(uniforms)) uniformVars = make([]driver.Uniform, graphics.PreservedUniformVariablesNum+len(uniforms))
// Set the destination texture size. // Set the destination texture size.
dw, dh := dst.internalSize() dw, dh := dst.internalSize()
uniformVars[graphics.DestinationTextureSizeUniformVariableIndex] = []float32{float32(dw), float32(dh)} uniformVars[graphics.DestinationTextureSizeUniformVariableIndex] = driver.Uniform{
Float32s: []float32{float32(dw), float32(dh)},
}
// Set the source texture sizes. // Set the source texture sizes.
usizes := make([]float32, 2*len(srcs)) usizes := make([]float32, 2*len(srcs))
@ -956,15 +969,21 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
usizes[2*i+1] = float32(h) usizes[2*i+1] = float32(h)
} }
} }
uniformVars[graphics.TextureSizesUniformVariableIndex] = usizes uniformVars[graphics.TextureSizesUniformVariableIndex] = driver.Uniform{
Float32s: usizes,
}
// Set the destination region's origin. // Set the destination region's origin.
udorigin := []float32{float32(dstRegion.X) / float32(dw), float32(dstRegion.Y) / float32(dh)} udorigin := []float32{float32(dstRegion.X) / float32(dw), float32(dstRegion.Y) / float32(dh)}
uniformVars[graphics.TextureDestinationRegionOriginUniformVariableIndex] = udorigin uniformVars[graphics.TextureDestinationRegionOriginUniformVariableIndex] = driver.Uniform{
Float32s: udorigin,
}
// Set the destination region's size. // Set the destination region's size.
udsize := []float32{float32(dstRegion.Width) / float32(dw), float32(dstRegion.Height) / float32(dh)} udsize := []float32{float32(dstRegion.Width) / float32(dw), float32(dstRegion.Height) / float32(dh)}
uniformVars[graphics.TextureDestinationRegionSizeUniformVariableIndex] = udsize uniformVars[graphics.TextureDestinationRegionSizeUniformVariableIndex] = driver.Uniform{
Float32s: udsize,
}
// Set the source offsets. // Set the source offsets.
uoffsets := make([]float32, 2*len(offsets)) uoffsets := make([]float32, 2*len(offsets))
@ -972,15 +991,21 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
uoffsets[2*i] = offset[0] uoffsets[2*i] = offset[0]
uoffsets[2*i+1] = offset[1] uoffsets[2*i+1] = offset[1]
} }
uniformVars[graphics.TextureSourceOffsetsUniformVariableIndex] = uoffsets uniformVars[graphics.TextureSourceOffsetsUniformVariableIndex] = driver.Uniform{
Float32s: uoffsets,
}
// Set the source region's origin of texture0. // Set the source region's origin of texture0.
usorigin := []float32{float32(srcRegion.X), float32(srcRegion.Y)} usorigin := []float32{float32(srcRegion.X), float32(srcRegion.Y)}
uniformVars[graphics.TextureSourceRegionOriginUniformVariableIndex] = usorigin uniformVars[graphics.TextureSourceRegionOriginUniformVariableIndex] = driver.Uniform{
Float32s: usorigin,
}
// Set the source region's size of texture0. // Set the source region's size of texture0.
ussize := []float32{float32(srcRegion.Width), float32(srcRegion.Height)} ussize := []float32{float32(srcRegion.Width), float32(srcRegion.Height)}
uniformVars[graphics.TextureSourceRegionSizeUniformVariableIndex] = ussize uniformVars[graphics.TextureSourceRegionSizeUniformVariableIndex] = driver.Uniform{
Float32s: ussize,
}
// Set the additional uniform variables. // Set the additional uniform variables.
for i, v := range uniforms { for i, v := range uniforms {

View File

@ -170,7 +170,7 @@ func (g *Graphics) uniformVariableName(idx int) string {
return name return name
} }
func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderImageNum]driver.ImageID, offsets [graphics.ShaderImageNum - 1][2]float32, shaderID driver.ShaderID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM driver.ColorM, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, uniforms []interface{}, evenOdd bool) error { func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderImageNum]driver.ImageID, offsets [graphics.ShaderImageNum - 1][2]float32, shaderID driver.ShaderID, indexLen int, indexOffset int, mode driver.CompositeMode, colorM driver.ColorM, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, uniforms []driver.Uniform, evenOdd bool) error {
destination := g.images[dstID] destination := g.images[dstID]
g.drawCalled = true g.drawCalled = true
@ -197,14 +197,14 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
dw, dh := destination.framebufferSize() dw, dh := destination.framebufferSize()
g.uniformVars = append(g.uniformVars, uniformVariable{ g.uniformVars = append(g.uniformVars, uniformVariable{
name: "viewport_size", name: "viewport_size",
value: uniformVariableValue{ value: driver.Uniform{
f32s: []float32{float32(dw), float32(dh)}, Float32s: []float32{float32(dw), float32(dh)},
}, },
typ: shaderir.Type{Main: shaderir.Vec2}, typ: shaderir.Type{Main: shaderir.Vec2},
}, uniformVariable{ }, uniformVariable{
name: "source_region", name: "source_region",
value: uniformVariableValue{ value: driver.Uniform{
f32s: []float32{ Float32s: []float32{
srcRegion.X, srcRegion.X,
srcRegion.Y, srcRegion.Y,
srcRegion.X + srcRegion.Width, srcRegion.X + srcRegion.Width,
@ -221,14 +221,14 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
colorM.Elements(&esBody, &esTranslate) colorM.Elements(&esBody, &esTranslate)
g.uniformVars = append(g.uniformVars, uniformVariable{ g.uniformVars = append(g.uniformVars, uniformVariable{
name: "color_matrix_body", name: "color_matrix_body",
value: uniformVariableValue{ value: driver.Uniform{
f32s: esBody[:], Float32s: esBody[:],
}, },
typ: shaderir.Type{Main: shaderir.Mat4}, typ: shaderir.Type{Main: shaderir.Mat4},
}, uniformVariable{ }, uniformVariable{
name: "color_matrix_translation", name: "color_matrix_translation",
value: uniformVariableValue{ value: driver.Uniform{
f32s: esTranslate[:], Float32s: esTranslate[:],
}, },
typ: shaderir.Type{Main: shaderir.Vec4}, typ: shaderir.Type{Main: shaderir.Vec4},
}) })
@ -238,8 +238,8 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
sw, sh := g.images[srcIDs[0]].framebufferSize() sw, sh := g.images[srcIDs[0]].framebufferSize()
g.uniformVars = append(g.uniformVars, uniformVariable{ g.uniformVars = append(g.uniformVars, uniformVariable{
name: "source_size", name: "source_size",
value: uniformVariableValue{ value: driver.Uniform{
f32s: []float32{float32(sw), float32(sh)}, Float32s: []float32{float32(sw), float32(sh)},
}, },
typ: shaderir.Type{Main: shaderir.Vec2}, typ: shaderir.Type{Main: shaderir.Vec2},
}) })
@ -249,8 +249,8 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
scale := float32(destination.width) / float32(g.images[srcIDs[0]].width) scale := float32(destination.width) / float32(g.images[srcIDs[0]].width)
g.uniformVars = append(g.uniformVars, uniformVariable{ g.uniformVars = append(g.uniformVars, uniformVariable{
name: "scale", name: "scale",
value: uniformVariableValue{ value: driver.Uniform{
f32: scale, Float32: scale,
}, },
typ: shaderir.Type{Main: shaderir.Float}, typ: shaderir.Type{Main: shaderir.Float},
}) })
@ -270,7 +270,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
const idx = graphics.DestinationTextureSizeUniformVariableIndex const idx = graphics.DestinationTextureSizeUniformVariableIndex
w, h := destination.framebufferSize() w, h := destination.framebufferSize()
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].value.f32s = []float32{float32(w), float32(h)} g.uniformVars[idx].value.Float32s = []float32{float32(w), float32(h)}
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
{ {
@ -285,7 +285,7 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
} }
const idx = graphics.TextureSizesUniformVariableIndex const idx = graphics.TextureSizesUniformVariableIndex
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].value.f32s = sizes g.uniformVars[idx].value.Float32s = sizes
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
dw, dh := destination.framebufferSize() dw, dh := destination.framebufferSize()
@ -293,14 +293,14 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
origin := []float32{float32(dstRegion.X) / float32(dw), float32(dstRegion.Y) / float32(dh)} origin := []float32{float32(dstRegion.X) / float32(dw), float32(dstRegion.Y) / float32(dh)}
const idx = graphics.TextureDestinationRegionOriginUniformVariableIndex const idx = graphics.TextureDestinationRegionOriginUniformVariableIndex
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].value.f32s = origin g.uniformVars[idx].value.Float32s = origin
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
{ {
size := []float32{float32(dstRegion.Width) / float32(dw), float32(dstRegion.Height) / float32(dh)} size := []float32{float32(dstRegion.Width) / float32(dw), float32(dstRegion.Height) / float32(dh)}
const idx = graphics.TextureDestinationRegionSizeUniformVariableIndex const idx = graphics.TextureDestinationRegionSizeUniformVariableIndex
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].value.f32s = size g.uniformVars[idx].value.Float32s = size
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
{ {
@ -311,35 +311,28 @@ func (g *Graphics) DrawTriangles(dstID driver.ImageID, srcIDs [graphics.ShaderIm
} }
const idx = graphics.TextureSourceOffsetsUniformVariableIndex const idx = graphics.TextureSourceOffsetsUniformVariableIndex
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].value.f32s = voffsets g.uniformVars[idx].value.Float32s = voffsets
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
{ {
origin := []float32{float32(srcRegion.X), float32(srcRegion.Y)} origin := []float32{float32(srcRegion.X), float32(srcRegion.Y)}
const idx = graphics.TextureSourceRegionOriginUniformVariableIndex const idx = graphics.TextureSourceRegionOriginUniformVariableIndex
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].value.f32s = origin g.uniformVars[idx].value.Float32s = origin
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
{ {
size := []float32{float32(srcRegion.Width), float32(srcRegion.Height)} size := []float32{float32(srcRegion.Width), float32(srcRegion.Height)}
const idx = graphics.TextureSourceRegionSizeUniformVariableIndex const idx = graphics.TextureSourceRegionSizeUniformVariableIndex
g.uniformVars[idx].name = g.uniformVariableName(idx) g.uniformVars[idx].name = g.uniformVariableName(idx)
g.uniformVars[idx].value.f32s = size g.uniformVars[idx].value.Float32s = size
g.uniformVars[idx].typ = shader.ir.Uniforms[idx] g.uniformVars[idx].typ = shader.ir.Uniforms[idx]
} }
for i, v := range uniforms { for i, v := range uniforms {
const offset = graphics.PreservedUniformVariablesNum const offset = graphics.PreservedUniformVariablesNum
g.uniformVars[i+offset].name = fmt.Sprintf("U%d", i+offset) g.uniformVars[i+offset].name = fmt.Sprintf("U%d", i+offset)
switch v := v.(type) { g.uniformVars[i+offset].value = v
case float32:
g.uniformVars[i+offset].value.f32 = v
case []float32:
g.uniformVars[i+offset].value.f32s = v
default:
return fmt.Errorf("opengl: unexpected uniform value: %v (type: %T)", v, v)
}
g.uniformVars[i+offset].typ = shader.ir.Uniforms[i+offset] g.uniformVars[i+offset].typ = shader.ir.Uniforms[i+offset]
} }
} }

View File

@ -120,11 +120,6 @@ type programKey struct {
address driver.Address address driver.Address
} }
type uniformVariableValue struct {
f32 float32
f32s []float32
}
// openGLState is a state for // openGLState is a state for
type openGLState struct { type openGLState struct {
// arrayBuffer is OpenGL's array buffer (vertices data). // arrayBuffer is OpenGL's array buffer (vertices data).
@ -137,7 +132,7 @@ type openGLState struct {
programs map[programKey]program programs map[programKey]program
lastProgram program lastProgram program
lastUniforms map[string]uniformVariableValue lastUniforms map[string]driver.Uniform
lastActiveTexture int lastActiveTexture int
} }
@ -247,7 +242,7 @@ func areSameFloat32Array(a, b []float32) bool {
type uniformVariable struct { type uniformVariable struct {
name string name string
value uniformVariableValue value driver.Uniform
typ shaderir.Type typ shaderir.Type
} }
@ -275,7 +270,7 @@ func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textu
} }
for _, u := range uniforms { for _, u := range uniforms {
if len(u.value.f32s) == 0 { if len(u.value.Float32s) == 0 {
if u.typ.Main != shaderir.Float { if u.typ.Main != shaderir.Float {
expected := &shaderir.Type{Main: shaderir.Float} expected := &shaderir.Type{Main: shaderir.Float}
got := &u.typ got := &u.typ
@ -283,33 +278,29 @@ func (g *Graphics) useProgram(program program, uniforms []uniformVariable, textu
} }
cached, ok := g.state.lastUniforms[u.name] cached, ok := g.state.lastUniforms[u.name]
if ok && cached.f32 == u.value.f32 { if ok && cached.Float32 == u.value.Float32 {
continue continue
} }
// TODO: Remember whether the location is available or not. // TODO: Remember whether the location is available or not.
g.context.uniformFloat(program, u.name, u.value.f32) g.context.uniformFloat(program, u.name, u.value.Float32)
if g.state.lastUniforms == nil { if g.state.lastUniforms == nil {
g.state.lastUniforms = map[string]uniformVariableValue{} g.state.lastUniforms = map[string]driver.Uniform{}
}
g.state.lastUniforms[u.name] = uniformVariableValue{
f32: u.value.f32,
} }
g.state.lastUniforms[u.name] = u.value
} else { } else {
if got, expected := len(u.value.f32s), u.typ.FloatNum(); got != expected { if got, expected := len(u.value.Float32s), u.typ.FloatNum(); got != expected {
return fmt.Errorf("opengl: length of a uniform variables %s (%s) doesn't match: expected %d but %d", u.name, u.typ.String(), expected, got) return fmt.Errorf("opengl: length of a uniform variables %s (%s) doesn't match: expected %d but %d", u.name, u.typ.String(), expected, got)
} }
cached, ok := g.state.lastUniforms[u.name] cached, ok := g.state.lastUniforms[u.name]
if ok && areSameFloat32Array(cached.f32s, u.value.f32s) { if ok && areSameFloat32Array(cached.Float32s, u.value.Float32s) {
continue continue
} }
g.context.uniformFloats(program, u.name, u.value.f32s, u.typ) g.context.uniformFloats(program, u.name, u.value.Float32s, u.typ)
if g.state.lastUniforms == nil { if g.state.lastUniforms == nil {
g.state.lastUniforms = map[string]uniformVariableValue{} g.state.lastUniforms = map[string]driver.Uniform{}
}
g.state.lastUniforms[u.name] = uniformVariableValue{
f32s: u.value.f32s,
} }
g.state.lastUniforms[u.name] = u.value
} }
} }

View File

@ -83,7 +83,7 @@ func (m *Mipmap) Pixels(x, y, width, height int) ([]byte, error) {
return m.orig.Pixels(x, y, width, height) return m.orig.Pixels(x, y, width, height)
} }
func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageNum]*Mipmap, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []interface{}, evenOdd bool, canSkipMipmap bool) { func (m *Mipmap) DrawTriangles(srcs [graphics.ShaderImageNum]*Mipmap, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, subimageOffsets [graphics.ShaderImageNum - 1][2]float32, shader *Shader, uniforms []driver.Uniform, evenOdd bool, canSkipMipmap bool) {
if len(indices) == 0 { if len(indices) == 0 {
return return
} }

View File

@ -76,7 +76,7 @@ type drawTrianglesHistoryItem struct {
dstRegion driver.Region dstRegion driver.Region
srcRegion driver.Region srcRegion driver.Region
shader *Shader shader *Shader
uniforms []interface{} uniforms []driver.Uniform
evenOdd bool evenOdd bool
} }
@ -365,7 +365,7 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
// 5: Color G // 5: Color G
// 6: Color B // 6: Color B
// 7: Color Y // 7: Color Y
func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []interface{}, evenOdd bool) { func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []driver.Uniform, evenOdd bool) {
if i.priority { if i.priority {
panic("restorable: DrawTriangles cannot be called on a priority image") panic("restorable: DrawTriangles cannot be called on a priority image")
} }
@ -410,7 +410,7 @@ func (i *Image) DrawTriangles(srcs [graphics.ShaderImageNum]*Image, offsets [gra
} }
// appendDrawTrianglesHistory appends a draw-image history item to the image. // appendDrawTrianglesHistory appends a draw-image history item to the image.
func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []interface{}, evenOdd bool) { func (i *Image) appendDrawTrianglesHistory(srcs [graphics.ShaderImageNum]*Image, offsets [graphics.ShaderImageNum - 1][2]float32, vertices []float32, indices []uint16, colorm affine.ColorM, mode driver.CompositeMode, filter driver.Filter, address driver.Address, dstRegion, srcRegion driver.Region, shader *Shader, uniforms []driver.Uniform, evenOdd bool) {
if i.stale || i.volatile || i.screen { if i.stale || i.volatile || i.screen {
return return
} }

View File

@ -21,6 +21,7 @@ import (
"go/token" "go/token"
"strings" "strings"
"github.com/hajimehoshi/ebiten/v2/internal/driver"
"github.com/hajimehoshi/ebiten/v2/internal/graphics" "github.com/hajimehoshi/ebiten/v2/internal/graphics"
"github.com/hajimehoshi/ebiten/v2/internal/mipmap" "github.com/hajimehoshi/ebiten/v2/internal/mipmap"
"github.com/hajimehoshi/ebiten/v2/internal/shader" "github.com/hajimehoshi/ebiten/v2/internal/shader"
@ -172,7 +173,7 @@ func (s *Shader) Dispose() {
s.shader = nil s.shader = nil
} }
func (s *Shader) convertUniforms(uniforms map[string]interface{}) []interface{} { func (s *Shader) convertUniforms(uniforms map[string]interface{}) []driver.Uniform {
type index struct { type index struct {
resultIndex int resultIndex int
shaderUniformIndex int shaderUniformIndex int
@ -191,20 +192,26 @@ func (s *Shader) convertUniforms(uniforms map[string]interface{}) []interface{}
idx++ idx++
} }
us := make([]interface{}, len(names)) us := make([]driver.Uniform, len(names))
for name, idx := range names { for name, idx := range names {
if v, ok := uniforms[name]; ok { if v, ok := uniforms[name]; ok {
// TODO: Check the uniform variable types? switch v := v.(type) {
us[idx.resultIndex] = v case float32:
us[idx.resultIndex] = driver.Uniform{
Float32: v,
}
case []float32:
us[idx.resultIndex] = driver.Uniform{
Float32s: v,
}
default:
panic(fmt.Sprintf("ebiten: unexpected uniform value type: %s, %T", name, v))
}
continue continue
} }
t := s.uniformTypes[idx.shaderUniformIndex] t := s.uniformTypes[idx.shaderUniformIndex]
v := zeroUniformValue(t) us[idx.resultIndex] = zeroUniformValue(name, t)
if v == nil {
panic(fmt.Sprintf("ebiten: unexpected uniform variable type: %s", t.String()))
}
us[idx.resultIndex] = v
} }
// TODO: Panic if uniforms include an invalid name // TODO: Panic if uniforms include an invalid name
@ -212,24 +219,17 @@ func (s *Shader) convertUniforms(uniforms map[string]interface{}) []interface{}
return us return us
} }
func zeroUniformValue(t shaderir.Type) interface{} { func zeroUniformValue(name string, t shaderir.Type) driver.Uniform {
switch t.Main { switch t.Main {
case shaderir.Bool:
return false
case shaderir.Int:
return 0
case shaderir.Float: case shaderir.Float:
return float32(0) return driver.Uniform{
Float32: 0,
}
case shaderir.Array: case shaderir.Array:
switch t.Sub[0].Main { return driver.Uniform{
case shaderir.Bool: Float32s: make([]float32, t.FloatNum()),
return make([]bool, t.Length)
case shaderir.Int:
return make([]int, t.Length)
default:
return make([]float32, t.FloatNum())
} }
default: default:
return make([]float32, t.FloatNum()) panic(fmt.Sprintf("ebiten: unexpected uniform variable type: %s, %s", name, t.String()))
} }
} }