graphicsdriver: Refactoring: ReplacePixels takes multiple arguments

This reduces the number of graphics commands, and this works more
efficiently if the driver has an efficient way.
This commit is contained in:
Hajime Hoshi 2019-11-21 23:42:46 +09:00
parent 161771cc99
commit 65fdf48cbf
5 changed files with 56 additions and 61 deletions

View File

@ -44,7 +44,15 @@ type Image interface {
Pixels() ([]byte, error)
SetAsDestination()
SetAsSource()
ReplacePixels(pixels []byte, x, y, width, height int)
ReplacePixels(args []*ReplacePixelsArgs)
}
type ReplacePixelsArgs struct {
Pixels []byte
X int
Y int
Width int
Height int
}
type VDirection int

View File

@ -434,21 +434,17 @@ func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image,
// replacePixelsCommand represents a command to replace pixels of an image.
type replacePixelsCommand struct {
dst *Image
pixels []byte
x int
y int
width int
height int
dst *Image
args []*driver.ReplacePixelsArgs
}
func (c *replacePixelsCommand) String() string {
return fmt.Sprintf("replace-pixels: dst: %d, x: %d, y: %d, width: %d, height: %d", c.dst.id, c.x, c.y, c.width, c.height)
return fmt.Sprintf("replace-pixels: dst: %d, len(args): %d", c.dst.id, len(c.args))
}
// Exec executes the replacePixelsCommand.
func (c *replacePixelsCommand) Exec(indexOffset int) error {
c.dst.image.ReplacePixels(c.pixels, c.x, c.y, c.width, c.height)
c.dst.image.ReplacePixels(c.args)
return nil
}

View File

@ -45,6 +45,8 @@ type Image struct {
screen bool
id int
bufferedRP []*driver.ReplacePixelsArgs
lastCommand lastCommand
}
@ -90,6 +92,18 @@ func NewScreenFramebufferImage(width, height int) *Image {
return i
}
func (i *Image) resolveBufferedReplacePixels() {
if len(i.bufferedRP) == 0 {
return
}
c := &replacePixelsCommand{
dst: i,
args: i.bufferedRP,
}
theCommandQueue.Enqueue(c)
i.bufferedRP = nil
}
func (i *Image) Dispose() {
c := &disposeCommand{
target: i,
@ -134,6 +148,9 @@ func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16,
}
}
src.resolveBufferedReplacePixels()
i.resolveBufferedReplacePixels()
theCommandQueue.EnqueueDrawTrianglesCommand(i, src, vertices, indices, clr, mode, filter, address)
if i.lastCommand == lastCommandNone && !i.screen {
@ -146,6 +163,7 @@ func (i *Image) DrawTriangles(src *Image, vertices []float32, indices []uint16,
// Pixels returns the image's pixels.
// Pixels might return nil when OpenGL error happens.
func (i *Image) Pixels() []byte {
i.resolveBufferedReplacePixels()
c := &pixelsCommand{
result: nil,
img: i,
@ -162,15 +180,13 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
panic("graphicscommand: ReplacePixels for a part after DrawTriangles is forbidden")
}
}
c := &replacePixelsCommand{
dst: i,
pixels: pixels,
x: x,
y: y,
width: width,
height: height,
}
theCommandQueue.Enqueue(c)
i.bufferedRP = append(i.bufferedRP, &driver.ReplacePixelsArgs{
Pixels: pixels,
X: x,
Y: y,
Width: width,
Height: height,
})
i.lastCommand = lastCommandReplacePixels
}

View File

@ -809,7 +809,7 @@ func (i *Image) SetAsSource() {
})
}
func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
func (i *Image) ReplacePixels(args []*driver.ReplacePixelsArgs) {
d := i.driver
if d.drawCalled {
d.flush(true, false)
@ -817,10 +817,12 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
}
d.t.Call(func() error {
i.texture.ReplaceRegion(mtl.Region{
Origin: mtl.Origin{X: x, Y: y, Z: 0},
Size: mtl.Size{Width: width, Height: height, Depth: 1},
}, 0, unsafe.Pointer(&pixels[0]), 4*width)
for _, a := range args {
i.texture.ReplaceRegion(mtl.Region{
Origin: mtl.Origin{X: a.X, Y: a.Y, Z: 0},
Size: mtl.Size{Width: a.Width, Height: a.Height, Depth: 1},
}, 0, unsafe.Pointer(&a.Pixels[0]), 4*a.Width)
}
return nil
})
}

View File

@ -15,17 +15,10 @@
package opengl
import (
"github.com/hajimehoshi/ebiten/internal/driver"
"github.com/hajimehoshi/ebiten/internal/graphics"
)
type bufferedRP struct {
pixels []byte
x int
y int
width int
height int
}
type Image struct {
driver *Driver
textureNative textureNative
@ -34,8 +27,6 @@ type Image struct {
width int
height int
screen bool
bufferedRPs []bufferedRP
}
func (i *Image) IsInvalidated() bool {
@ -55,7 +46,6 @@ func (i *Image) Dispose() {
}
func (i *Image) SetAsDestination() {
i.resolveReplacePixels()
i.driver.state.destination = i
}
@ -68,7 +58,6 @@ func (i *Image) setViewport() error {
}
func (i *Image) Pixels() ([]byte, error) {
i.resolveReplacePixels()
if err := i.ensureFramebuffer(); err != nil {
return nil, err
}
@ -101,34 +90,14 @@ func (i *Image) ensureFramebuffer() error {
return nil
}
func (i *Image) ReplacePixels(p []byte, x, y, width, height int) {
func (i *Image) ReplacePixels(args []*driver.ReplacePixelsArgs) {
if i.screen {
panic("opengl: ReplacePixels cannot be called on the screen, that doesn't have a texture")
}
i.bufferedRPs = append(i.bufferedRPs, bufferedRP{
pixels: p,
x: x,
y: y,
width: width,
height: height,
})
}
func (i *Image) SetAsSource() {
i.resolveReplacePixels()
i.driver.state.source = i
}
func (i *Image) resolveReplacePixels() {
if len(i.bufferedRPs) == 0 {
if len(args) == 0 {
return
}
defer func() {
i.bufferedRPs = nil
}()
// glFlush is necessary on Android.
// glTexSubImage2D didn't work without this hack at least on Nexus 5x and NuAns NEO [Reloaded] (#211).
if i.driver.drawCalled {
@ -137,15 +106,19 @@ func (i *Image) resolveReplacePixels() {
i.driver.drawCalled = false
if !canUsePBO {
for _, rp := range i.bufferedRPs {
i.driver.context.texSubImage2D(i.textureNative, rp.pixels, rp.x, rp.y, rp.width, rp.height)
for _, a := range args {
i.driver.context.texSubImage2D(i.textureNative, a.Pixels, a.X, a.Y, a.Width, a.Height)
}
return
}
thePBOState.mapPBO(i)
for _, rp := range i.bufferedRPs {
thePBOState.draw(rp.pixels, rp.x, rp.y, rp.width, rp.height)
for _, a := range args {
thePBOState.draw(a.Pixels, a.X, a.Y, a.Width, a.Height)
}
thePBOState.unmapPBO()
}
func (i *Image) SetAsSource() {
i.driver.state.source = i
}