A screen.Window is currently:

type Window interface {
   // This discussion proposes no changes to these methods.
   Events() etc

   // EndPaint flushes any pending Upload and Draw calls to the window.
   // If EndPaint is called with an old generation number, it is ignored.
   EndPaint(p paint.Event)

The exact semantics aren't fully nailed down yet. For example:

It's not clear exactly when the Drawer/Uploader methods are safe to
call. Can they be called at any time, or only in response to a
paint.Event? If an app wants to update its window contents due to a
mouse click, can it Draw immediately or does it first have to somehow
schedule or wait for a paint.Event?

It's not clear whether Drawer/Uploader method have immediate effects.
Their doc comments say things like "When drawing on a Window, there
might not be any visible effect until EndPaint is called". This is
"might"; the model allows for both single-buffered and double-buffered
windows. If an app wants to never show a half-painted window, it's not
possible to tell whether it has to do its own buffering. It can always
buffer, but that might be wasteful.

It's not clear, when an app gets a paint.Event, what it can assume
about the state of the window (its front buffer) and its back buffer
(if it exists). There is no distinction between paint.Events generated
by the app somehow (e.g. a key press leads to a glyph being rendered)
and paint.Events generated by the operating system (e.g. a window was

Here's a proposal.

Apps should assume that a Window implementation is double buffered.
(As an optimization, implemented later, the app might be able to ask
for a single buffered window during a NewWindow call, but that request
can be denied). IIUC the gldriver already behaves like this. This will
mean more code for the windriver and the x11driver, but that code
might be sharable if the library-provided back buffer is based on a

Apps can call Draw/Upload methods at any time. This modifies the back
buffer, and has no visible effect on the screen.

The EndPaint method is removed. Instead, we have
Publish(sender Sender)
which copies the back buffer to the front buffer. In OpenGL terms,
it's not just glFlush or glFinish, it's eglSwapBuffers. Afterwards,
the contents of the back buffer are undefined. (Again, as an
optimization, there might be a way to distinguish a copy versus flip
of the back buffer to the front, and the copy would preserve the back
buffer, but for now, it is undefined). If the sender is non-nil, then
a publish.Event will be sent when that Publish finishes.

package publish
type Event struct {}

Consider two different apps: one animating (e.g. a game) and one
static (e.g. a spreadsheet). The animating app would pass a non-nil
sender to subscribe to publish.Events, so it can paint frames as fast
as possible. The static app would pass a nil sender. It has no more UI
work to do until some external stimulus (e.g. a mouse click, or I/O),
and until then, it can happily sit there consuming 0% CPU.

Separate to a publish.Event, a paint.Event signifies that the window's
front and/or back buffers' contents have become undefined, from
something other than a Publish call. If the front buffer needs
painting (e.g. the window was uncovered), the app should respond by
calling Publish. If the back buffer also needs painting (e.g. the
window was un-minimized and the library and/or OS previously subbed in
a /dev/null back buffer), then the app will need to paint from
scratch. Otherwise, there is no change to the back buffer. If the app
was already half-way into painting the back buffer, it can just keep
on going.

package paint
type Event struct {
   PaintFrontBuffer, PaintBackBuffer bool
   Generation uint32

(It may then be less confusing to rename what's currently
screen.Buffer to screen.Image.)

A generation number lets a window indicate stale paint or size events:
if a window is resized interactively, only the last one really
matters. A Window would gain this method:

Stale(event interface{}) bool

and app code would look like:

switch e := e.(type) {
case paint.Event:
   if w.Stale(e) {
case size.Event:
   if w.Stale(e) {

Stale events would be relatively rare, though. If an app wanted to
animate at 60Hz, they'd get a steady stream of publish.Events, not
paint.Events, and the rate that publish.Events arrive is the rate that
Window.Publish is called, which is controlled by the app, not the

(TODO: does paint.Event stale-ness need to distinguish between the
front and back buffers? If both need painting, should they be two
events? Of the same type? Of a different type?

This proposal is far from fully baked. It seems that a bit more
thinking could unify the paint.Event and publish.Event concepts of
"your back buffer's contents were lost", some names could probably be
improved (there are only two hard problems in Computer Science), and
integrating OpenGL app code is still an open question, but
https://go-review.googlesource.com/#/c/13550/ is blocked on me, so I
thought I'd get this out there sooner rather than later. WDYT?

You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

Discussion Posts

Follow ups

Related Discussions

Discussion Navigation
viewthread | post
posts ‹ prev | 1 of 7 | next ›
Discussion Overview
groupgolang-dev @
postedAug 31, '15 at 12:24p
activeSep 2, '15 at 12:42a



site design / logo © 2021 Grokbase