X backend better handles expose events

Previously, when an expose event was recieved, the backend would
call Window.paste, converting RGBA image data to BGRA image data.
Now we only call Window.pushRegion with the bounds given to us by
the expose event(s). This speeds up window resizing significantly.
This commit is contained in:
Sasha Koshka 2023-03-07 12:48:29 -05:00
parent 803812f9c9
commit 423e6869c0
4 changed files with 29 additions and 11 deletions

View File

@ -24,22 +24,27 @@ func (pattern Texture) Draw (destination canvas.Canvas, clip image.Rectangle) {
srcPoint := bounds.Min.Sub(realBounds.Min).Add(srcBounds.Min) srcPoint := bounds.Min.Sub(realBounds.Min).Add(srcBounds.Min)
srcPoint.X = wrap(srcPoint.X, srcBounds.Min.X, srcBounds.Max.X) srcPoint.X = wrap(srcPoint.X, srcBounds.Min.X, srcBounds.Max.X)
srcPoint.Y = wrap(srcPoint.Y, srcBounds.Min.Y, srcBounds.Max.Y) srcPoint.Y = wrap(srcPoint.Y, srcBounds.Min.Y, srcBounds.Max.Y)
srcPointXStart := srcPoint.X
for dstPoint.Y = bounds.Min.Y; dstPoint.Y < bounds.Max.Y; dstPoint.Y ++ { for dstPoint.Y = bounds.Min.Y; dstPoint.Y < bounds.Max.Y; dstPoint.Y ++ {
srcPoint.X = srcPointXStart srcPoint.X = srcBounds.Min.X
dstPoint.X = bounds.Min.X
dstYComponent := dstPoint.Y * dstStride
srcYComponent := srcPoint.Y * srcStride
for dstPoint.X = bounds.Min.X; dstPoint.X < bounds.Max.X; dstPoint.X ++ { for {
dstIndex := dstPoint.X + dstPoint.Y * dstStride dstIndex := dstYComponent + dstPoint.X
srcIndex := srcIndex := srcYComponent + srcPoint.X
srcPoint.X +
srcPoint.Y * srcStride
dstData[dstIndex] = srcData[srcIndex] dstData[dstIndex] = srcData[srcIndex]
srcPoint.X ++ srcPoint.X ++
if srcPoint.X >= srcBounds.Max.X { if srcPoint.X >= srcBounds.Max.X {
srcPoint.X = srcBounds.Min.X srcPoint.X = srcBounds.Min.X
} }
dstPoint.X ++
if dstPoint.X >= bounds.Max.X {
break
}
} }
srcPoint.Y ++ srcPoint.Y ++

View File

@ -1,5 +1,6 @@
package x package x
import "image"
import "git.tebibyte.media/sashakoshka/tomo/input" import "git.tebibyte.media/sashakoshka/tomo/input"
import "git.tebibyte.media/sashakoshka/tomo/elements" import "git.tebibyte.media/sashakoshka/tomo/elements"
@ -47,8 +48,8 @@ func (window *Window) handleExpose (
connection *xgbutil.XUtil, connection *xgbutil.XUtil,
event xevent.ExposeEvent, event xevent.ExposeEvent,
) { ) {
_ = window.compressExpose(*event.ExposeEvent) _, region := window.compressExpose(*event.ExposeEvent)
window.redrawChildEntirely() window.pushRegion(region)
} }
func (window *Window) handleConfigureNotify ( func (window *Window) handleConfigureNotify (
@ -234,7 +235,13 @@ func (window *Window) compressExpose (
firstEvent xproto.ExposeEvent, firstEvent xproto.ExposeEvent,
) ( ) (
lastEvent xproto.ExposeEvent, lastEvent xproto.ExposeEvent,
region image.Rectangle,
) { ) {
region = image.Rect (
int(firstEvent.X), int(firstEvent.Y),
int(firstEvent.X + firstEvent.Width),
int(firstEvent.Y + firstEvent.Height))
window.backend.connection.Sync() window.backend.connection.Sync()
xevent.Read(window.backend.connection, false) xevent.Read(window.backend.connection, false)
lastEvent = firstEvent lastEvent = firstEvent
@ -245,8 +252,12 @@ func (window *Window) compressExpose (
typedEvent, ok := untypedEvent.Event.(xproto.ExposeEvent) typedEvent, ok := untypedEvent.Event.(xproto.ExposeEvent)
if !ok { continue } if !ok { continue }
// FIXME: union all areas into the last event
if firstEvent.Window == typedEvent.Window { if firstEvent.Window == typedEvent.Window {
region = region.Union (image.Rect (
int(typedEvent.X), int(typedEvent.Y),
int(typedEvent.X + typedEvent.Width),
int(typedEvent.Y + typedEvent.Height)))
lastEvent = typedEvent lastEvent = typedEvent
defer func (index int) { defer func (index int) {
xevent.DequeueAt(window.backend.connection, index) xevent.DequeueAt(window.backend.connection, index)

View File

@ -12,6 +12,7 @@ import "git.tebibyte.media/sashakoshka/tomo/theme"
import "git.tebibyte.media/sashakoshka/tomo/config" import "git.tebibyte.media/sashakoshka/tomo/config"
import "git.tebibyte.media/sashakoshka/tomo/canvas" import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/elements" import "git.tebibyte.media/sashakoshka/tomo/elements"
// import "runtime/debug"
type Window struct { type Window struct {
backend *Backend backend *Backend
@ -290,6 +291,7 @@ func (window *Window) childDrawCallback (region canvas.Canvas) {
func (window *Window) paste (canvas canvas.Canvas) (updatedRegion image.Rectangle) { func (window *Window) paste (canvas canvas.Canvas) (updatedRegion image.Rectangle) {
data, stride := canvas.Buffer() data, stride := canvas.Buffer()
bounds := canvas.Bounds().Intersect(window.xCanvas.Bounds()) bounds := canvas.Bounds().Intersect(window.xCanvas.Bounds())
// debug.PrintStack()
for x := bounds.Min.X; x < bounds.Max.X; x ++ { for x := bounds.Min.X; x < bounds.Max.X; x ++ {
for y := bounds.Min.Y; y < bounds.Max.Y; y ++ { for y := bounds.Min.Y; y < bounds.Max.Y; y ++ {
rgba := data[x + y * stride] rgba := data[x + y * stride]

View File

@ -150,7 +150,7 @@ func run () {
window.OnClose(tomo.Stop) window.OnClose(tomo.Stop)
window.Show() window.Show()
go func () { go func () {
http.ListenAndServe("localhost:6060", nil) http.ListenAndServe("localhost:9090", nil)
} () } ()
} }