mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08: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)
|
Pixels() ([]byte, error)
|
||||||
SetAsDestination()
|
SetAsDestination()
|
||||||
SetAsSource()
|
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
|
type VDirection int
|
||||||
|
@ -435,20 +435,16 @@ func (c *drawTrianglesCommand) CanMergeWithDrawTrianglesCommand(dst, src *Image,
|
|||||||
// replacePixelsCommand represents a command to replace pixels of an image.
|
// replacePixelsCommand represents a command to replace pixels of an image.
|
||||||
type replacePixelsCommand struct {
|
type replacePixelsCommand struct {
|
||||||
dst *Image
|
dst *Image
|
||||||
pixels []byte
|
args []*driver.ReplacePixelsArgs
|
||||||
x int
|
|
||||||
y int
|
|
||||||
width int
|
|
||||||
height int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *replacePixelsCommand) String() string {
|
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.
|
// Exec executes the replacePixelsCommand.
|
||||||
func (c *replacePixelsCommand) Exec(indexOffset int) error {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,8 @@ type Image struct {
|
|||||||
screen bool
|
screen bool
|
||||||
id int
|
id int
|
||||||
|
|
||||||
|
bufferedRP []*driver.ReplacePixelsArgs
|
||||||
|
|
||||||
lastCommand lastCommand
|
lastCommand lastCommand
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,6 +92,18 @@ func NewScreenFramebufferImage(width, height int) *Image {
|
|||||||
return i
|
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() {
|
func (i *Image) Dispose() {
|
||||||
c := &disposeCommand{
|
c := &disposeCommand{
|
||||||
target: i,
|
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)
|
theCommandQueue.EnqueueDrawTrianglesCommand(i, src, vertices, indices, clr, mode, filter, address)
|
||||||
|
|
||||||
if i.lastCommand == lastCommandNone && !i.screen {
|
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 returns the image's pixels.
|
||||||
// Pixels might return nil when OpenGL error happens.
|
// Pixels might return nil when OpenGL error happens.
|
||||||
func (i *Image) Pixels() []byte {
|
func (i *Image) Pixels() []byte {
|
||||||
|
i.resolveBufferedReplacePixels()
|
||||||
c := &pixelsCommand{
|
c := &pixelsCommand{
|
||||||
result: nil,
|
result: nil,
|
||||||
img: i,
|
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")
|
panic("graphicscommand: ReplacePixels for a part after DrawTriangles is forbidden")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c := &replacePixelsCommand{
|
i.bufferedRP = append(i.bufferedRP, &driver.ReplacePixelsArgs{
|
||||||
dst: i,
|
Pixels: pixels,
|
||||||
pixels: pixels,
|
X: x,
|
||||||
x: x,
|
Y: y,
|
||||||
y: y,
|
Width: width,
|
||||||
width: width,
|
Height: height,
|
||||||
height: height,
|
})
|
||||||
}
|
|
||||||
theCommandQueue.Enqueue(c)
|
|
||||||
i.lastCommand = lastCommandReplacePixels
|
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
|
d := i.driver
|
||||||
if d.drawCalled {
|
if d.drawCalled {
|
||||||
d.flush(true, false)
|
d.flush(true, false)
|
||||||
@ -817,10 +817,12 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
d.t.Call(func() error {
|
d.t.Call(func() error {
|
||||||
|
for _, a := range args {
|
||||||
i.texture.ReplaceRegion(mtl.Region{
|
i.texture.ReplaceRegion(mtl.Region{
|
||||||
Origin: mtl.Origin{X: x, Y: y, Z: 0},
|
Origin: mtl.Origin{X: a.X, Y: a.Y, Z: 0},
|
||||||
Size: mtl.Size{Width: width, Height: height, Depth: 1},
|
Size: mtl.Size{Width: a.Width, Height: a.Height, Depth: 1},
|
||||||
}, 0, unsafe.Pointer(&pixels[0]), 4*width)
|
}, 0, unsafe.Pointer(&a.Pixels[0]), 4*a.Width)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -15,17 +15,10 @@
|
|||||||
package opengl
|
package opengl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/driver"
|
||||||
"github.com/hajimehoshi/ebiten/internal/graphics"
|
"github.com/hajimehoshi/ebiten/internal/graphics"
|
||||||
)
|
)
|
||||||
|
|
||||||
type bufferedRP struct {
|
|
||||||
pixels []byte
|
|
||||||
x int
|
|
||||||
y int
|
|
||||||
width int
|
|
||||||
height int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Image struct {
|
type Image struct {
|
||||||
driver *Driver
|
driver *Driver
|
||||||
textureNative textureNative
|
textureNative textureNative
|
||||||
@ -34,8 +27,6 @@ type Image struct {
|
|||||||
width int
|
width int
|
||||||
height int
|
height int
|
||||||
screen bool
|
screen bool
|
||||||
|
|
||||||
bufferedRPs []bufferedRP
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) IsInvalidated() bool {
|
func (i *Image) IsInvalidated() bool {
|
||||||
@ -55,7 +46,6 @@ func (i *Image) Dispose() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) SetAsDestination() {
|
func (i *Image) SetAsDestination() {
|
||||||
i.resolveReplacePixels()
|
|
||||||
i.driver.state.destination = i
|
i.driver.state.destination = i
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +58,6 @@ func (i *Image) setViewport() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) Pixels() ([]byte, error) {
|
func (i *Image) Pixels() ([]byte, error) {
|
||||||
i.resolveReplacePixels()
|
|
||||||
if err := i.ensureFramebuffer(); err != nil {
|
if err := i.ensureFramebuffer(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -101,34 +90,14 @@ func (i *Image) ensureFramebuffer() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Image) ReplacePixels(p []byte, x, y, width, height int) {
|
func (i *Image) ReplacePixels(args []*driver.ReplacePixelsArgs) {
|
||||||
if i.screen {
|
if i.screen {
|
||||||
panic("opengl: ReplacePixels cannot be called on the screen, that doesn't have a texture")
|
panic("opengl: ReplacePixels cannot be called on the screen, that doesn't have a texture")
|
||||||
}
|
}
|
||||||
|
if len(args) == 0 {
|
||||||
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 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
|
||||||
i.bufferedRPs = nil
|
|
||||||
}()
|
|
||||||
|
|
||||||
// glFlush is necessary on Android.
|
// glFlush is necessary on Android.
|
||||||
// glTexSubImage2D didn't work without this hack at least on Nexus 5x and NuAns NEO [Reloaded] (#211).
|
// glTexSubImage2D didn't work without this hack at least on Nexus 5x and NuAns NEO [Reloaded] (#211).
|
||||||
if i.driver.drawCalled {
|
if i.driver.drawCalled {
|
||||||
@ -137,15 +106,19 @@ func (i *Image) resolveReplacePixels() {
|
|||||||
i.driver.drawCalled = false
|
i.driver.drawCalled = false
|
||||||
|
|
||||||
if !canUsePBO {
|
if !canUsePBO {
|
||||||
for _, rp := range i.bufferedRPs {
|
for _, a := range args {
|
||||||
i.driver.context.texSubImage2D(i.textureNative, rp.pixels, rp.x, rp.y, rp.width, rp.height)
|
i.driver.context.texSubImage2D(i.textureNative, a.Pixels, a.X, a.Y, a.Width, a.Height)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
thePBOState.mapPBO(i)
|
thePBOState.mapPBO(i)
|
||||||
for _, rp := range i.bufferedRPs {
|
for _, a := range args {
|
||||||
thePBOState.draw(rp.pixels, rp.x, rp.y, rp.width, rp.height)
|
thePBOState.draw(a.Pixels, a.X, a.Y, a.Width, a.Height)
|
||||||
}
|
}
|
||||||
thePBOState.unmapPBO()
|
thePBOState.unmapPBO()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Image) SetAsSource() {
|
||||||
|
i.driver.state.source = i
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user