mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 18:58:54 +01:00
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:
parent
161771cc99
commit
65fdf48cbf
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
})
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user