1d514b0f3Smrg/*
2d514b0f3Smrg * Copyright (C) 2012 CodeWeavers, Inc.
3d514b0f3Smrg *
4d514b0f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5d514b0f3Smrg * copy of this software and associated documentation files (the "Software"),
6d514b0f3Smrg * to deal in the Software without restriction, including without limitation
7d514b0f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8d514b0f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
9d514b0f3Smrg * Software is furnished to do so, subject to the following conditions:
10d514b0f3Smrg *
11d514b0f3Smrg * The above copyright notice and this permission notice (including the next
12d514b0f3Smrg * paragraph) shall be included in all copies or substantial portions of the
13d514b0f3Smrg * Software.
14d514b0f3Smrg *
15d514b0f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16d514b0f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17d514b0f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18d514b0f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19d514b0f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20d514b0f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21d514b0f3Smrg * SOFTWARE.
22d514b0f3Smrg *
23d514b0f3Smrg * Authors:
24d514b0f3Smrg *    Jeremy White <jwhite@codeweavers.com>
25d514b0f3Smrg */
26d514b0f3Smrg
27d514b0f3Smrg/*----------------------------------------------------------------------------
28d514b0f3Smrg  Deferred Frames Per Second (dfps) Support File
29d514b0f3Smrg
30d514b0f3Smrg    By default, The xorg-video-qxl driver transmits all of the video
31d514b0f3Smrg  operation across the wire.  While this has the greatest fidelity, and
32d514b0f3Smrg  lends itself well to a variety of optimizations and behavior tuning,
33d514b0f3Smrg  it does not always use bandwidth efficiently.
34d514b0f3Smrg
35d514b0f3Smrg  This file implements a 'deferred frames' mode which instead renders
36d514b0f3Smrg  everything to a frame buffer, and then periodically sends only updated
37d514b0f3Smrg  portions of the screen.
38d514b0f3Smrg
39d514b0f3Smrg  For some use cases, this proves to be far more efficient with network
40d514b0f3Smrg  resources.
41d514b0f3Smrg----------------------------------------------------------------------------*/
42d514b0f3Smrg
43d514b0f3Smrg#include <xorg-server.h>
44d514b0f3Smrg#include "qxl.h"
45d514b0f3Smrg#include "dfps.h"
46d514b0f3Smrg
47d514b0f3Smrgtypedef struct _dfps_info_t
48d514b0f3Smrg{
49d514b0f3Smrg    RegionRec   updated_region;
50d514b0f3Smrg
51d514b0f3Smrg    PixmapPtr   copy_src;
52d514b0f3Smrg    Pixel       solid_pixel;
53d514b0f3Smrg    GCPtr       pgc;
54d514b0f3Smrg} dfps_info_t;
55d514b0f3Smrg
56d514b0f3Smrgstatic void dfps_ticker(void *opaque);
57d514b0f3Smrg
58d514b0f3Smrgstatic inline dfps_info_t *dfps_get_info (PixmapPtr pixmap)
59d514b0f3Smrg{
60d514b0f3Smrg#if HAS_DEVPRIVATEKEYREC
61d514b0f3Smrg    return dixGetPrivate(&pixmap->devPrivates, &uxa_pixmap_index);
62d514b0f3Smrg#else
63d514b0f3Smrg    return dixLookupPrivate(&pixmap->devPrivates, &uxa_pixmap_index);
64d514b0f3Smrg#endif
65d514b0f3Smrg}
66d514b0f3Smrg
67d514b0f3Smrgstatic inline void dfps_set_info (PixmapPtr pixmap, dfps_info_t *info)
68d514b0f3Smrg{
69d514b0f3Smrg    dixSetPrivate(&pixmap->devPrivates, &uxa_pixmap_index, info);
70d514b0f3Smrg}
71d514b0f3Smrgtypedef struct FrameTimer {
72d514b0f3Smrg    OsTimerPtr xorg_timer;
73d514b0f3Smrg    FrameTimerFunc func;
74d514b0f3Smrg    void *opaque; // also stored in xorg_timer, but needed for timer_start
75d514b0f3Smrg} Timer;
76d514b0f3Smrg
77d514b0f3Smrgstatic CARD32 xorg_timer_callback(
78d514b0f3Smrg    OsTimerPtr xorg_timer,
79d514b0f3Smrg    CARD32 time,
80d514b0f3Smrg    pointer arg)
81d514b0f3Smrg{
82d514b0f3Smrg    FrameTimer *timer = (FrameTimer*)arg;
83d514b0f3Smrg
84d514b0f3Smrg    timer->func(timer->opaque);
85d514b0f3Smrg    return 0; // if non zero xorg does a TimerSet, we don't want that.
86d514b0f3Smrg}
87d514b0f3Smrg
88d514b0f3Smrgstatic FrameTimer* timer_add(FrameTimerFunc func, void *opaque)
89d514b0f3Smrg{
90d514b0f3Smrg    FrameTimer *timer = calloc(sizeof(FrameTimer), 1);
91d514b0f3Smrg
92d514b0f3Smrg    timer->xorg_timer = TimerSet(NULL, 0, 1e9 /* TODO: infinity? */, xorg_timer_callback, timer);
93d514b0f3Smrg    timer->func = func;
94d514b0f3Smrg    timer->opaque = opaque;
95d514b0f3Smrg    return timer;
96d514b0f3Smrg}
97d514b0f3Smrg
98d514b0f3Smrgstatic void timer_start(FrameTimer *timer, uint32_t ms)
99d514b0f3Smrg{
100d514b0f3Smrg    TimerSet(timer->xorg_timer, 0 /* flags */, ms, xorg_timer_callback, timer);
101d514b0f3Smrg}
102d514b0f3Smrg
103d514b0f3Smrgvoid dfps_start_ticker(qxl_screen_t *qxl)
104d514b0f3Smrg{
105d514b0f3Smrg    qxl->frames_timer = timer_add(dfps_ticker, qxl);
106d514b0f3Smrg    timer_start(qxl->frames_timer, 1000 / qxl->deferred_fps);
107d514b0f3Smrg}
108d514b0f3Smrg
109d514b0f3Smrgstatic void dfps_ticker(void *opaque)
110d514b0f3Smrg{
111d514b0f3Smrg    qxl_screen_t *qxl = (qxl_screen_t *) opaque;
112d514b0f3Smrg    dfps_info_t *info = NULL;
113d514b0f3Smrg    PixmapPtr pixmap;
114d514b0f3Smrg
115d514b0f3Smrg    pixmap = qxl->pScrn->pScreen->GetScreenPixmap(qxl->pScrn->pScreen);
116d514b0f3Smrg    if (pixmap)
117d514b0f3Smrg        info = dfps_get_info(pixmap);
118d514b0f3Smrg    if (info)
119d514b0f3Smrg    {
120d514b0f3Smrg        qxl_surface_upload_primary_regions(qxl, pixmap, &info->updated_region);
121d514b0f3Smrg        RegionUninit(&info->updated_region);
122d514b0f3Smrg        RegionInit(&info->updated_region, NULL, 0);
123d514b0f3Smrg    }
124d514b0f3Smrg    timer_start(qxl->frames_timer, 1000 / qxl->deferred_fps);
125d514b0f3Smrg}
126d514b0f3Smrg
127d514b0f3Smrg
128d514b0f3Smrgstatic Bool unaccel (void)
129d514b0f3Smrg{
130d514b0f3Smrg    return FALSE;
131d514b0f3Smrg}
132d514b0f3Smrg
133d514b0f3Smrgstatic Bool is_main_pixmap(PixmapPtr pixmap)
134d514b0f3Smrg{
135d514b0f3Smrg    ScreenPtr screen = pixmap->drawable.pScreen;
136d514b0f3Smrg    if (screen && pixmap == screen->GetScreenPixmap(screen))
137d514b0f3Smrg        return TRUE;
138d514b0f3Smrg    return FALSE;
139d514b0f3Smrg}
140d514b0f3Smrg
141d514b0f3Smrg
142d514b0f3Smrg/* Establish a maximum number of disparate regions we'll track before we just
143d514b0f3Smrg   treat the entire bounding rectangle as having changed.
144d514b0f3Smrg
145d514b0f3Smrg   The number 20 seemed intuitive, and also produced the best results in
146d514b0f3Smrg   benchmarking x11perf -circle10 -repeat 1
147d514b0f3Smrg*/
148d514b0f3Smrg#define DFPS_MAX_UPDATE_REGIONS 20
149d514b0f3Smrgstatic void dfps_update_box(RegionPtr dest, int x_1, int x_2, int y_1, int y_2);
150d514b0f3Smrg
151d514b0f3Smrgstatic void dfps_update_region(RegionPtr dest, RegionPtr src)
152d514b0f3Smrg{
153d514b0f3Smrg    Bool throwaway_bool;
154d514b0f3Smrg
155d514b0f3Smrg    RegionAppend(dest, src);
156d514b0f3Smrg    RegionValidate(dest, &throwaway_bool);
157d514b0f3Smrg    if (RegionNumRects(dest) > DFPS_MAX_UPDATE_REGIONS)
158d514b0f3Smrg    {
159d514b0f3Smrg        struct pixman_box16 box = * (RegionExtents(dest));
160d514b0f3Smrg        RegionUninit(dest);
161d514b0f3Smrg        RegionInit(dest, NULL, 0);
162d514b0f3Smrg        dfps_update_box(dest, box.x1, box.x2, box.y1, box.y2);
163d514b0f3Smrg    }
164d514b0f3Smrg}
165d514b0f3Smrg
166d514b0f3Smrgstatic void dfps_update_box(RegionPtr dest, int x_1, int x_2, int y_1, int y_2)
167d514b0f3Smrg{
168d514b0f3Smrg    struct pixman_box16 box;
169d514b0f3Smrg    RegionPtr region;
170d514b0f3Smrg
171d514b0f3Smrg    box.x1 = x_1; box.x2 = x_2; box.y1 = y_1; box.y2 = y_2;
172d514b0f3Smrg    region = RegionCreate(&box, 1);
173d514b0f3Smrg
174d514b0f3Smrg    dfps_update_region(dest, region);
175d514b0f3Smrg
176d514b0f3Smrg    RegionUninit(region);
177d514b0f3Smrg    RegionDestroy(region);
178d514b0f3Smrg}
179d514b0f3Smrg
180d514b0f3Smrgstatic Bool dfps_prepare_solid (PixmapPtr pixmap, int alu, Pixel planemask, Pixel fg)
181d514b0f3Smrg{
182d514b0f3Smrg    dfps_info_t *info;
183d514b0f3Smrg
184d514b0f3Smrg    if (!(info = dfps_get_info (pixmap)))
185d514b0f3Smrg        return FALSE;
186d514b0f3Smrg
187d514b0f3Smrg    info->solid_pixel = fg;
188d514b0f3Smrg    info->pgc = GetScratchGC(pixmap->drawable.depth, pixmap->drawable.pScreen);
189d514b0f3Smrg    if (! info->pgc)
190d514b0f3Smrg        return FALSE;
191d514b0f3Smrg
192d514b0f3Smrg    info->pgc->alu = alu;
193d514b0f3Smrg    info->pgc->planemask = planemask;
194d514b0f3Smrg    info->pgc->fgPixel = fg;
195d514b0f3Smrg    info->pgc->fillStyle = FillSolid;
196d514b0f3Smrg
197d514b0f3Smrg    fbValidateGC(info->pgc, GCForeground | GCPlaneMask, &pixmap->drawable);
198d514b0f3Smrg
199d514b0f3Smrg    return TRUE;
200d514b0f3Smrg}
201d514b0f3Smrg
202d514b0f3Smrgstatic void dfps_solid (PixmapPtr pixmap, int x_1, int y_1, int x_2, int y_2)
203d514b0f3Smrg{
204d514b0f3Smrg    dfps_info_t *info;
205d514b0f3Smrg
206d514b0f3Smrg    if (!(info = dfps_get_info (pixmap)))
207d514b0f3Smrg        return;
208d514b0f3Smrg
209d514b0f3Smrg    /* Draw to the frame buffer */
210d514b0f3Smrg    fbFill(&pixmap->drawable, info->pgc, x_1, y_1, x_2 - x_1, y_2 - y_1);
211d514b0f3Smrg
212d514b0f3Smrg    /* Track the updated region */
213d514b0f3Smrg    if (is_main_pixmap(pixmap))
214d514b0f3Smrg        dfps_update_box(&info->updated_region, x_1, x_2, y_1, y_2);
215d514b0f3Smrg    return;
216d514b0f3Smrg}
217d514b0f3Smrg
218d514b0f3Smrgstatic void dfps_done_solid (PixmapPtr pixmap)
219d514b0f3Smrg{
220d514b0f3Smrg    dfps_info_t *info;
221d514b0f3Smrg
222d514b0f3Smrg    if ((info = dfps_get_info (pixmap)))
223d514b0f3Smrg    {
224d514b0f3Smrg        FreeScratchGC(info->pgc);
225d514b0f3Smrg        info->pgc = NULL;
226d514b0f3Smrg    }
227d514b0f3Smrg}
228d514b0f3Smrg
229d514b0f3Smrgstatic Bool dfps_prepare_copy (PixmapPtr source, PixmapPtr dest,
230d514b0f3Smrg                  int xdir, int ydir, int alu,
231d514b0f3Smrg                  Pixel planemask)
232d514b0f3Smrg{
233d514b0f3Smrg    dfps_info_t *info;
234d514b0f3Smrg
235d514b0f3Smrg    if (!(info = dfps_get_info (dest)))
236d514b0f3Smrg        return FALSE;
237d514b0f3Smrg
238d514b0f3Smrg    info->copy_src = source;
239d514b0f3Smrg
240d514b0f3Smrg    info->pgc = GetScratchGC(dest->drawable.depth, dest->drawable.pScreen);
241d514b0f3Smrg    if (! info->pgc)
242d514b0f3Smrg        return FALSE;
243d514b0f3Smrg
244d514b0f3Smrg    info->pgc->alu = alu;
245d514b0f3Smrg    info->pgc->planemask = planemask;
246d514b0f3Smrg
247d514b0f3Smrg    fbValidateGC(info->pgc, GCPlaneMask, &dest->drawable);
248d514b0f3Smrg
249d514b0f3Smrg    return TRUE;
250d514b0f3Smrg}
251d514b0f3Smrg
252d514b0f3Smrgstatic void dfps_copy (PixmapPtr dest,
253d514b0f3Smrg          int src_x1, int src_y1,
254d514b0f3Smrg          int dest_x1, int dest_y1,
255d514b0f3Smrg          int width, int height)
256d514b0f3Smrg{
257d514b0f3Smrg    dfps_info_t *info;
258d514b0f3Smrg
259d514b0f3Smrg    if (!(info = dfps_get_info (dest)))
260d514b0f3Smrg        return;
261d514b0f3Smrg
262d514b0f3Smrg    /* Render into to the frame buffer */
263d514b0f3Smrg    fbCopyArea(&info->copy_src->drawable, &dest->drawable, info->pgc, src_x1, src_y1, width, height, dest_x1, dest_y1);
264d514b0f3Smrg
265d514b0f3Smrg    /* Update the tracking region */
266d514b0f3Smrg    if (is_main_pixmap(dest))
267d514b0f3Smrg        dfps_update_box(&info->updated_region, dest_x1, dest_x1 + width, dest_y1, dest_y1 + height);
268d514b0f3Smrg}
269d514b0f3Smrg
270d514b0f3Smrgstatic void dfps_done_copy (PixmapPtr dest)
271d514b0f3Smrg{
272d514b0f3Smrg    dfps_info_t *info;
273d514b0f3Smrg
274d514b0f3Smrg    if ((info = dfps_get_info (dest)))
275d514b0f3Smrg    {
276d514b0f3Smrg        FreeScratchGC(info->pgc);
277d514b0f3Smrg        info->pgc = NULL;
278d514b0f3Smrg    }
279d514b0f3Smrg}
280d514b0f3Smrg
281d514b0f3Smrgstatic Bool dfps_put_image (PixmapPtr dest, int x, int y, int w, int h,
282d514b0f3Smrg               char *src, int src_pitch)
283d514b0f3Smrg{
284d514b0f3Smrg    dfps_info_t *info;
285d514b0f3Smrg    FbBits *dst;
286d514b0f3Smrg    FbStride dst_stride;
287d514b0f3Smrg    int dst_bpp;
288d514b0f3Smrg
289d514b0f3Smrg    if (!(info = dfps_get_info (dest)))
290d514b0f3Smrg        return FALSE;
291d514b0f3Smrg
292d514b0f3Smrg    if (is_main_pixmap(dest))
293d514b0f3Smrg        dfps_update_box(&info->updated_region, x, x + w, y, y + h);
294d514b0f3Smrg
295d514b0f3Smrg    fbPrepareAccess(dest);
296d514b0f3Smrg    fbGetPixmapBitsData(dest, dst, dst_stride, dst_bpp);
297d514b0f3Smrg    fbBlt((FbBits *) src, src_pitch / sizeof(FbStip), 0, dst + (y * dst_stride), dst_stride,
298d514b0f3Smrg           x * dst_bpp, w * dst_bpp, h, GXcopy, FB_ALLONES, dst_bpp, FALSE, FALSE);
299d514b0f3Smrg    fbFinishAccess(dest);
300d514b0f3Smrg
301d514b0f3Smrg    return TRUE;
302d514b0f3Smrg}
303d514b0f3Smrg
304d514b0f3Smrg
305d514b0f3Smrgstatic Bool dfps_prepare_access (PixmapPtr pixmap, RegionPtr region, uxa_access_t requested_access)
306d514b0f3Smrg{
307d514b0f3Smrg    fbPrepareAccess(pixmap);
308d514b0f3Smrg    if (requested_access == UXA_ACCESS_RW)
309d514b0f3Smrg    {
310d514b0f3Smrg        dfps_info_t *info;
311d514b0f3Smrg
312d514b0f3Smrg        if (!(info = dfps_get_info (pixmap)))
313d514b0f3Smrg            return FALSE;
314d514b0f3Smrg
315d514b0f3Smrg        if (is_main_pixmap(pixmap))
316d514b0f3Smrg            dfps_update_region(&info->updated_region, region);
317d514b0f3Smrg    }
318d514b0f3Smrg    return TRUE;
319d514b0f3Smrg}
320d514b0f3Smrg
321d514b0f3Smrgstatic void dfps_finish_access (PixmapPtr pixmap)
322d514b0f3Smrg{
323d514b0f3Smrg    fbFinishAccess(pixmap);
324d514b0f3Smrg}
325d514b0f3Smrg
326d514b0f3Smrgstatic Bool dfps_pixmap_is_offscreen (PixmapPtr pixmap)
327d514b0f3Smrg{
328d514b0f3Smrg    return !!dfps_get_info(pixmap);
329d514b0f3Smrg}
330d514b0f3Smrg
331d514b0f3Smrgstatic void dfps_set_screen_pixmap (PixmapPtr pixmap)
332d514b0f3Smrg{
333d514b0f3Smrg    pixmap->drawable.pScreen->devPrivate = pixmap;
334d514b0f3Smrg}
335d514b0f3Smrg
336d514b0f3Smrgstatic void dfps_clear_pixmap(PixmapPtr pixmap, int w, int h)
337d514b0f3Smrg{
338d514b0f3Smrg    GCPtr pgc;
339d514b0f3Smrg    pgc = GetScratchGC(pixmap->drawable.depth, pixmap->drawable.pScreen);
340d514b0f3Smrg    if (pgc)
341d514b0f3Smrg    {
342d514b0f3Smrg        fbFill(&pixmap->drawable, pgc, 0, 0, w, h);
343d514b0f3Smrg        FreeScratchGC(pgc);
344d514b0f3Smrg    }
345d514b0f3Smrg}
346d514b0f3Smrg
347d514b0f3Smrgstatic PixmapPtr dfps_create_pixmap (ScreenPtr screen, int w, int h, int depth, unsigned usage)
348d514b0f3Smrg{
349d514b0f3Smrg    PixmapPtr pixmap;
350d514b0f3Smrg    dfps_info_t *info;
351d514b0f3Smrg
352d514b0f3Smrg    info = calloc(1, sizeof(*info));
353d514b0f3Smrg    if (!info)
354d514b0f3Smrg        return FALSE;
355d514b0f3Smrg    RegionInit(&info->updated_region, NULL, 0);
356d514b0f3Smrg
357d514b0f3Smrg    pixmap = fbCreatePixmap (screen, w, h, depth, usage);
358d514b0f3Smrg    if (pixmap)
359d514b0f3Smrg    {
360d514b0f3Smrg        dfps_clear_pixmap(pixmap, w, h);
361d514b0f3Smrg        dfps_set_info(pixmap, info);
362d514b0f3Smrg    }
363d514b0f3Smrg    else
364d514b0f3Smrg        free(info);
365d514b0f3Smrg
366d514b0f3Smrg    return pixmap;
367d514b0f3Smrg}
368d514b0f3Smrg
369d514b0f3Smrgstatic Bool dfps_destroy_pixmap (PixmapPtr pixmap)
370d514b0f3Smrg{
371d514b0f3Smrg    if (pixmap->refcnt == 1)
372d514b0f3Smrg    {
373d514b0f3Smrg        dfps_info_t *info = dfps_get_info (pixmap);
374d514b0f3Smrg        if (info)
375d514b0f3Smrg            free(info);
376d514b0f3Smrg        dfps_set_info(pixmap, NULL);
377d514b0f3Smrg    }
378d514b0f3Smrg
379d514b0f3Smrg    return fbDestroyPixmap (pixmap);
380d514b0f3Smrg}
381d514b0f3Smrg
382d514b0f3Smrgvoid dfps_set_uxa_functions(qxl_screen_t *qxl, ScreenPtr screen)
383d514b0f3Smrg{
384d514b0f3Smrg    /* Solid fill */
385d514b0f3Smrg    //qxl->uxa->check_solid = dfps_check_solid;
386d514b0f3Smrg    qxl->uxa->prepare_solid = dfps_prepare_solid;
387d514b0f3Smrg    qxl->uxa->solid = dfps_solid;
388d514b0f3Smrg    qxl->uxa->done_solid = dfps_done_solid;
389d514b0f3Smrg
390d514b0f3Smrg    /* Copy */
391d514b0f3Smrg    //qxl->uxa->check_copy = qxl_check_copy;
392d514b0f3Smrg    qxl->uxa->prepare_copy = dfps_prepare_copy;
393d514b0f3Smrg    qxl->uxa->copy = dfps_copy;
394d514b0f3Smrg    qxl->uxa->done_copy = dfps_done_copy;
395d514b0f3Smrg
396d514b0f3Smrg    /* Composite */
397d514b0f3Smrg    qxl->uxa->check_composite = (typeof(qxl->uxa->check_composite))unaccel;
398d514b0f3Smrg    qxl->uxa->check_composite_target = (typeof(qxl->uxa->check_composite_target))unaccel;
399d514b0f3Smrg    qxl->uxa->check_composite_texture = (typeof(qxl->uxa->check_composite_texture))unaccel;
400d514b0f3Smrg    qxl->uxa->prepare_composite = (typeof(qxl->uxa->prepare_composite))unaccel;
401d514b0f3Smrg    qxl->uxa->composite = (typeof(qxl->uxa->composite))unaccel;
402d514b0f3Smrg    qxl->uxa->done_composite = (typeof(qxl->uxa->done_composite))unaccel;
403d514b0f3Smrg
404d514b0f3Smrg    /* PutImage */
405d514b0f3Smrg    qxl->uxa->put_image = dfps_put_image;
406d514b0f3Smrg
407d514b0f3Smrg    /* Prepare access */
408d514b0f3Smrg    qxl->uxa->prepare_access = dfps_prepare_access;
409d514b0f3Smrg    qxl->uxa->finish_access = dfps_finish_access;
410d514b0f3Smrg
411d514b0f3Smrg    /* General screen information */
412d514b0f3Smrg    qxl->uxa->pixmap_is_offscreen = dfps_pixmap_is_offscreen;
413d514b0f3Smrg
414d514b0f3Smrg    screen->SetScreenPixmap = dfps_set_screen_pixmap;
415d514b0f3Smrg    screen->CreatePixmap = dfps_create_pixmap;
416d514b0f3Smrg    screen->DestroyPixmap = dfps_destroy_pixmap;
417d514b0f3Smrg}
418