
The Present Extension
I ve finally gotten an initial implementation of the Present extension
written and running and thought I should write up the current design
and status.
Present Design
The current Present extension consists of two requests:
- PresentRegion. Puts new bits from a pixmap in a window.
- PresentSelectInput. Asks for Present events to be delivered.
PresentRegion
This request takes a pile of arguments:
PresentRegion
window: WINDOW
pixmap: PIXMAP
valid-area: REGION or None
update-area: REGION or None
x-off, y-off: INT16
target-msc: CARD64
divisor: CARD64
remainder: CARD64
idle-fence: FENCE
Errors: Drawable, Pixmap, Match
Provides new content for the specified window, to be made
visible at the specified time (defined by target-msc , divisor
and remainder ).
update-area defines the subset of the window to be updated, or None
if the whole window is to be updated.
valid-area defines the portion of pixmap which contains valid
window contents, or None if the pixmap contains valid contents for the
whole window.
PresentRegion may use any region of pixmap which contains
update-area and which is contained by valid-area . In other words,
areas inside update-area will be presented from pixmap , areas
outside valid-area will not be presented from pixmap and areas
inside valid-area but outside update-area may or may not be
presented at the discretion of the X server.
x-off and y-off define the location in the window where
the 0,0 location of the pixmap will be presented. valid-area
and update-area are relative to the pixmap.
If target-msc is greater than the current msc for window ,
the presentation will occur at (or after) the target-msc
field. Otherwise, the presentation will occur after the next
field where msc % divisor == remainder . If divisor is
zero, then the presentation will occur after the current field.
idle-fence is triggered when pixmap is no longer in
use. This may be at any time following the PresentRegion
request, the contents may be immediately copied to another
buffer, copied just in time for the vblank interrupt or the
pixmap may be used directly for display, in which case it will
be busy until some future PresentRegion operation.
If window is destroyed before the presentation occurs, then
the presentation action will not be completed.
PresentRegion holds a reference to pixmap until the
presentation occurs, so pixmap may be immediately freed
after the request executes, even if that is before the
presentation occurs.
If idle-fence is destroyed before the presentation occurs,
then idle-fence will not be signaled but the presentation will
occur normally.
PresentSelectInput
PresentSelectInput
event-id: PRESENTEVENTID
window: WINDOW
eventMask: SETofPRESENTEVENT
Errors: Window, Value, Match, IDchoice, Access
Selects the set of Present events to be delivered for the
specified window and event context. PresentSelectInput can
create, modify or delete event contexts. An event context is
associated with a specific window; using an existing event
context with a different window generates a Match error.
If eventContext specifies an existing event context, then if
eventMask is empty, PresentSelectInput deletes the specified
context, otherwise the specified event context is changed to
select a different set of events.
If eventContext is an unused XID, then if eventMask is empty
no operation is performed. Otherwise, a new event context is
created selecting the specified events.
Present Extension Events
There are three different events for the Present extension:
- PresentConfigureNotify
- PresentCompleteNotify
- PresentRedirectNotify
PresentConfigureNotify
This event is moving from the DRI3 extension where it doesn t belong.
PresentConfigureNotify
type: CARD8 XGE event type (35)
extension: CARD8 Present extension request number
length: CARD16 2
evtype: CARD16 Present_ConfigureNotify
eventID: PRESENTEVENTID
window: WINDOW
x: INT16
y: INT16
width: CARD16
height: CARD16
off_x: INT16
off_y: INT16
pixmap_width: CARD16
pixmap_height: CARD16
pixmap_flags: CARD32
PresentConfigureNotify events are sent when the window
configuration changes if PresentSelectInput has requested
it. PresentConfigureNotify events are XGE events and so do not
have a unique event type.
x and y are the parent-relative location of window .
PresentCompleteNotify
PresentCompleteNotify
type: CARD8 XGE event type (35)
extension: CARD8 Present extension request number
length: CARD16 2
evtype: CARD16 Present_CompleteNotify
eventID: PRESENTEVENTID
window: WINDOW
ust: CARD64
msc: CARD64
sbc: CARD64
Notify events are delivered when a PresentRegion operation has
completed and the specified contents are being displayed. sbc,
msc and ust indicate the swap count, frame count and system
time of the related PresentRegion request.
PresentRedirectNotify
This one is not specified yet, but the intent is for it to contain
sufficient information for the compositing manager to be able to
construct a suitable screen update that includes an application window
update.
Finishing GLX
OMLsync_control
At this point, Mesa only exposes the old swap
interval configuration
value, it doesn t provide any of the GLXOML
synccontrol
APIs. However, the Present protocol does have the bits necessary to
support glXSwapBuffersMscOML in the PresentRegion request. Let s see
how the remaining APIs in this GL extension will be supported.
glXGetSyncValuesOML
This one is easy; it only needs to return the UST/MSC/SBC values from
the most recent SwapBuffers request. Those are returned in the
PresentCompleteNotify event, so Mesa just needs to capture that event
and save the values away for return to the application. We don t need
any new Present protocol for this.
glXGetMscRateOML
This returns the refresh rate of the monitor associated with the
specified drawable. RandR exposes all of the necessary data for each
monitor, but the monitor each window is going to be synchronized
against isn t exposed anywhere, and is effectively
implementation-dependent. So, I think the easy thing to do here is to
have a Present request which reports which RandR output a window will
be synchronized with.
glXSwapBuffersMscOML
This is the one API which is already directly supported by the Present
extension.
glXWaitForMscOML
This is effectively the same as glXSwapBuffersMscOML, except that it
doesn t actually perform a swap. For this, I think we want a new
request that generates an X event when the target values are reached,
and then have the client block until that event is received. This will
avoid blocking other threads using the same X connection.
glXWaitForSbcOML
Like glXWaitForMscOML, this just needs to trigger an event to be
delivered at the right time.
Presentation Redirection
I m focusing on finishing the above stuff before I start writing the
redirection spec and code, but I ve been thinking a bit about it.
What we want is for applications that are presenting a new frame
within a redirected window to have that presentation delivered
directly to the compositing manager instead of having the bits copied
to the redirected buffer and have the compositing manager only learn
about this when the damage event is received from copying the bits.
Once the compositing manager receives notification that there are new
bits available for a portion of a window, it can then get those bits
onto the screen in one of two ways:
- Copy them to the back buffer for the whole screen and then present
that back buffer to the screen.
- Present them directly to the screen, bypassing the compositing
manager s back buffer entirely.
The first option is what you d do if there were more updates than just
a single window; it would update the whole screen at the same
time. The second option is what you d do if there was only the one
window update to act on, and this would automatically take advantage
of page flipping to avoid copying data at all. No need to un-redirect
windows for the page flip to work.
In both cases, we need to inform the original application both when
its pixmap is idle and when the swap actually hits the screen. And we
need to make sure the final swap happens when the application
requested.
For the pixmap idle notification, the current PresentRegion idle
fence
argument should suffice; we just need to pass the idlefence XID along
in the redirection event. Simple.
For completion notification, we need to make sure the SBC value for
the original window gets incremented and that a PresentCompleteNotify
event is delivered. I think that means we want to append a chunk of
data to the PresentRegion request so that suitable events can be
delivered when the compositing manager PresentRegion occur. I think
that just needs to be the window of that original window.
To make sure the swap happens at the right time, we just need to have
the target
msc value provided to the compositing manager. I m hoping
that having this all event driven is that when a later PresentRegion
is redirected that has an *earlier* targetmsc, we can simply queue
that as well and things should just work .
Current Status
I ve got the protocol definitions (both X server and XCB) done, and
libxcb supporting the extension.
I ve got the X server bits working, but the actual updates are not
synchronized to the monitor; they re using OS timers and CopyArea for
now, mostly so I can test things without also hacking drivers.
Mesa is using the extension, but it only provides the swap
interval
value and is not yet supporting the full GLXOML
synccontrol
extension.
I ve also got a simple 2D core X application using the extension which
is in the shmfd repository in my home directory on freedesktop.org.
Availability
As always, these bits are already published in my home directory on
freedesktop.org in various git repositories.