]> git.pld-linux.org Git - packages/xorg-driver-video-intel.git/blame - git.patch
Build with DRI3 support by default, Release: 5
[packages/xorg-driver-video-intel.git] / git.patch
CommitLineData
96bae86b
JR
1diff --git a/Makefile.am b/Makefile.am
2index 418fdc9..853e622 100644
3--- a/Makefile.am
4+++ b/Makefile.am
5@@ -25,7 +25,7 @@ SUBDIRS = man libobj xvmc src tools
6 MAINTAINERCLEANFILES = ChangeLog INSTALL
7
8 if HAVE_X11
9-SUBDIRS += test
10+SUBDIRS += test benchmarks
11 endif
12
13 .PHONY: ChangeLog INSTALL
14diff --git a/NEWS b/NEWS
15index 604b9cc..0e20033 100644
16--- a/NEWS
17+++ b/NEWS
18@@ -21,7 +21,7 @@ should make one more snapshot before an imminent release.
19 Before kernel 3.19, O_NONBLOCK support is broken and so we must avoid
20 reading if we are not expecting an event.
21
22- * Backwards compatibilty fix for fake triple buffering with PRIME and
23+ * Backwards compatibility fix for fake triple buffering with PRIME and
24 Xorg-1.15
25 https://bugs.freedesktop.org/show_bug.cgi?id=85144#c12
26
27@@ -51,7 +51,7 @@ should make one more snapshot before an imminent release.
28 Snapshot 2.99.916 (2014-09-08)
29 ==============================
30 Quick update for MST in UXA - we need to hook up the RandR outputs for
31-dynamicaly added connectors.
32+dynamically added connectors.
33
34
35 Snapshot 2.99.915 (2014-09-08)
36@@ -503,7 +503,7 @@ release.
37 backlight property is queried whilst the connector is disabled
38 https://bugs.freedesktop.org/show_bug.cgi?id=70406
39
40- * Pad GETCONNECTOR ioctl for compatability between 32/64-bit userspace
41+ * Pad GETCONNECTOR ioctl for compatibility between 32/64-bit userspace
42 and kernel
43
44 * Handle long glyph runs correctly
45@@ -523,7 +523,7 @@ snapshot beforehand to push out the bug fixes from the last week.
46
47 * Fix video output using sprites when changing the image size
48
49- * Apply more restrictive tile constaints for 915g class devices
50+ * Apply more restrictive tile constraints for 915g class devices
51 https://bugs.launchpad.net/ubuntu/+source/xserver-xorg-video-intel/+bug/1232546
52
53 * Ensure all overlapping rectangles are drawn for XRenderFillRectangles
54@@ -1132,7 +1132,7 @@ operation.
55 * Explicitly prevent ring-switching for synchronized rendering to
56 scanouts (for vsync).
57
58- * Clip dirty region to slave pixmaps (otherwise UDL is nigh unusuable)
59+ * Clip dirty region to slave pixmaps (otherwise UDL is nigh unusable)
60 https://bugs.freedesktop.org/show_bug.cgi?id=59539
61
62
63@@ -1226,7 +1226,7 @@ Release 2.20.15 (2012-12-03)
64 ============================
65 And lo, enabling more of the common acceleration paths for gen4 revealed
66 another lurking bug - something is wrong with how we prepare Y-tiling
67-surfaces for rendering. For the time being, we can surreptiously disable
68+surfaces for rendering. For the time being, we can surreptitiously disable
69 them for gen4 and avoid hitting GPU hangs.
70
71 * Avoid clobbering the render state after failing to convert the
72@@ -1515,7 +1515,7 @@ Release 2.20.5 (2012-08-26)
73 Another silly bug found, another small bugfix release. The goal was for
74 the driver to bind to all Intel devices supported by the kernel.
75 Unfortunately we were too successful and started claiming Pouslbo,
76-Medfield and Cedarview devices which are still encumbered by propietary
77+Medfield and Cedarview devices which are still encumbered by proprietary
78 IP and not supported by this driver.
79
80 Bugs fixed since 2.20.4:
81diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore
82new file mode 100644
83index 0000000..301c012
84--- /dev/null
85+++ b/benchmarks/.gitignore
86@@ -0,0 +1,2 @@
87+dri2-swap
88+dri3-swap
89diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am
90new file mode 100644
91index 0000000..4976e8a
92--- /dev/null
93+++ b/benchmarks/Makefile.am
94@@ -0,0 +1,14 @@
95+AM_CFLAGS = @CWARNFLAGS@ $(X11_CFLAGS) $(DRM_CFLAGS)
96+LDADD = $(X11_LIBS) $(DRM_LIBS) $(CLOCK_GETTIME_LIBS)
97+
98+check_PROGRAMS =
99+
100+if DRI2
101+check_PROGRAMS += dri2-swap
102+endif
103+
104+if DRI3
105+check_PROGRAMS += dri3-swap
106+AM_CFLAGS += $(X11_DRI3_CFLAGS)
107+LDADD += $(X11_DRI3_LIBS)
108+endif
109diff --git a/benchmarks/dri2-swap.c b/benchmarks/dri2-swap.c
110new file mode 100644
111index 0000000..3d9d30a
112--- /dev/null
113+++ b/benchmarks/dri2-swap.c
114@@ -0,0 +1,588 @@
115+/*
116+ * Copyright (c) 2015 Intel Corporation
117+ *
118+ * Permission is hereby granted, free of charge, to any person obtaining a
119+ * copy of this software and associated documentation files (the "Software"),
120+ * to deal in the Software without restriction, including without limitation
121+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
122+ * and/or sell copies of the Software, and to permit persons to whom the
123+ * Software is furnished to do so, subject to the following conditions:
124+ *
125+ * The above copyright notice and this permission notice (including the next
126+ * paragraph) shall be included in all copies or substantial portions of the
127+ * Software.
128+ *
129+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
130+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
131+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
132+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
133+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
134+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
135+ * SOFTWARE.
136+ *
137+ */
138+
139+#ifdef HAVE_CONFIG_H
140+#include "config.h"
141+#endif
142+
143+#include <X11/Xlib.h>
144+#include <X11/Xatom.h>
145+#include <X11/Xlib-xcb.h>
146+#include <X11/Xutil.h>
147+#include <X11/Xlibint.h>
148+#include <X11/extensions/dpms.h>
149+#include <X11/extensions/randr.h>
150+#include <X11/extensions/Xcomposite.h>
151+#include <X11/extensions/Xdamage.h>
152+#include <X11/extensions/Xrandr.h>
153+#include <xcb/xcb.h>
154+#include <xcb/dri2.h>
155+#include <xf86drm.h>
156+
157+#include <stdio.h>
158+#include <string.h>
159+#include <fcntl.h>
160+#include <unistd.h>
161+#include <assert.h>
162+#include <errno.h>
163+#include <setjmp.h>
164+#include <signal.h>
165+
166+#include <X11/Xlibint.h>
167+#include <X11/extensions/Xext.h>
168+#include <X11/extensions/extutil.h>
169+#include <X11/extensions/dri2proto.h>
170+#include <X11/extensions/dri2tokens.h>
171+#include <X11/extensions/Xfixes.h>
172+
173+static char dri2ExtensionName[] = DRI2_NAME;
174+static XExtensionInfo *dri2Info;
175+static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info)
176+
177+static Bool
178+DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire);
179+static Status
180+DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire);
181+static int
182+DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code);
183+
184+static /* const */ XExtensionHooks dri2ExtensionHooks = {
185+ NULL, /* create_gc */
186+ NULL, /* copy_gc */
187+ NULL, /* flush_gc */
188+ NULL, /* free_gc */
189+ NULL, /* create_font */
190+ NULL, /* free_font */
191+ DRI2CloseDisplay, /* close_display */
192+ DRI2WireToEvent, /* wire_to_event */
193+ DRI2EventToWire, /* event_to_wire */
194+ DRI2Error, /* error */
195+ NULL, /* error_string */
196+};
197+
198+static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay,
199+ dri2Info,
200+ dri2ExtensionName,
201+ &dri2ExtensionHooks,
202+ 0, NULL)
203+
204+static Bool
205+DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire)
206+{
207+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
208+
209+ XextCheckExtension(dpy, info, dri2ExtensionName, False);
210+
211+ switch ((wire->u.u.type & 0x7f) - info->codes->first_event) {
212+#ifdef X_DRI2SwapBuffers
213+ case DRI2_BufferSwapComplete:
214+ return False;
215+#endif
216+#ifdef DRI2_InvalidateBuffers
217+ case DRI2_InvalidateBuffers:
218+ return False;
219+#endif
220+ default:
221+ /* client doesn't support server event */
222+ break;
223+ }
224+
225+ return False;
226+}
227+
228+/* We don't actually support this. It doesn't make sense for clients to
229+ * send each other DRI2 events.
230+ */
231+static Status
232+DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire)
233+{
234+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
235+
236+ XextCheckExtension(dpy, info, dri2ExtensionName, False);
237+
238+ switch (event->type) {
239+ default:
240+ /* client doesn't support server event */
241+ break;
242+ }
243+
244+ return Success;
245+}
246+
247+static int
248+DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code)
249+{
250+ if (err->majorCode == codes->major_opcode &&
251+ err->errorCode == BadDrawable &&
252+ err->minorCode == X_DRI2CopyRegion)
253+ return True;
254+
255+ /* If the X drawable was destroyed before the GLX drawable, the
256+ * DRI2 drawble will be gone by the time we call
257+ * DRI2DestroyDrawable. So just ignore BadDrawable here. */
258+ if (err->majorCode == codes->major_opcode &&
259+ err->errorCode == BadDrawable &&
260+ err->minorCode == X_DRI2DestroyDrawable)
261+ return True;
262+
263+ /* If the server is non-local DRI2Connect will raise BadRequest.
264+ * Swallow this so that DRI2Connect can signal this in its return code */
265+ if (err->majorCode == codes->major_opcode &&
266+ err->minorCode == X_DRI2Connect &&
267+ err->errorCode == BadRequest) {
268+ *ret_code = False;
269+ return True;
270+ }
271+
272+ return False;
273+}
274+
275+static Bool
276+DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase)
277+{
278+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
279+
280+ if (XextHasExtension(info)) {
281+ *eventBase = info->codes->first_event;
282+ *errorBase = info->codes->first_error;
283+ return True;
284+ }
285+
286+ return False;
287+}
288+
289+static Bool
290+DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName)
291+{
292+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
293+ xDRI2ConnectReply rep;
294+ xDRI2ConnectReq *req;
295+
296+ XextCheckExtension(dpy, info, dri2ExtensionName, False);
297+
298+ LockDisplay(dpy);
299+ GetReq(DRI2Connect, req);
300+ req->reqType = info->codes->major_opcode;
301+ req->dri2ReqType = X_DRI2Connect;
302+ req->window = window;
303+ req->driverType = DRI2DriverDRI;
304+ if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
305+ UnlockDisplay(dpy);
306+ SyncHandle();
307+ return False;
308+ }
309+
310+ if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) {
311+ UnlockDisplay(dpy);
312+ SyncHandle();
313+ return False;
314+ }
315+
316+ *driverName = Xmalloc(rep.driverNameLength + 1);
317+ if (*driverName == NULL) {
318+ _XEatData(dpy,
319+ ((rep.driverNameLength + 3) & ~3) +
320+ ((rep.deviceNameLength + 3) & ~3));
321+ UnlockDisplay(dpy);
322+ SyncHandle();
323+ return False;
324+ }
325+ _XReadPad(dpy, *driverName, rep.driverNameLength);
326+ (*driverName)[rep.driverNameLength] = '\0';
327+
328+ *deviceName = Xmalloc(rep.deviceNameLength + 1);
329+ if (*deviceName == NULL) {
330+ Xfree(*driverName);
331+ _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3));
332+ UnlockDisplay(dpy);
333+ SyncHandle();
334+ return False;
335+ }
336+ _XReadPad(dpy, *deviceName, rep.deviceNameLength);
337+ (*deviceName)[rep.deviceNameLength] = '\0';
338+
339+ UnlockDisplay(dpy);
340+ SyncHandle();
341+
342+ return True;
343+}
344+
345+static Bool
346+DRI2Authenticate(Display * dpy, XID window, unsigned int magic)
347+{
348+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
349+ xDRI2AuthenticateReq *req;
350+ xDRI2AuthenticateReply rep;
351+
352+ XextCheckExtension(dpy, info, dri2ExtensionName, False);
353+
354+ LockDisplay(dpy);
355+ GetReq(DRI2Authenticate, req);
356+ req->reqType = info->codes->major_opcode;
357+ req->dri2ReqType = X_DRI2Authenticate;
358+ req->window = window;
359+ req->magic = magic;
360+
361+ if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
362+ UnlockDisplay(dpy);
363+ SyncHandle();
364+ return False;
365+ }
366+
367+ UnlockDisplay(dpy);
368+ SyncHandle();
369+
370+ return rep.authenticated;
371+}
372+
373+static void
374+DRI2CreateDrawable(Display * dpy, XID drawable)
375+{
376+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
377+ xDRI2CreateDrawableReq *req;
378+
379+ XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
380+
381+ LockDisplay(dpy);
382+ GetReq(DRI2CreateDrawable, req);
383+ req->reqType = info->codes->major_opcode;
384+ req->dri2ReqType = X_DRI2CreateDrawable;
385+ req->drawable = drawable;
386+ UnlockDisplay(dpy);
387+ SyncHandle();
388+}
389+
390+static void DRI2SwapInterval(Display *dpy, XID drawable, int interval)
391+{
392+ XExtDisplayInfo *info = DRI2FindDisplay(dpy);
393+ xDRI2SwapIntervalReq *req;
394+
395+ XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
396+
397+ LockDisplay(dpy);
398+ GetReq(DRI2SwapInterval, req);
399+ req->reqType = info->codes->major_opcode;
400+ req->dri2ReqType = X_DRI2SwapInterval;
401+ req->drawable = drawable;
402+ req->interval = interval;
403+ UnlockDisplay(dpy);
404+ SyncHandle();
405+}
406+
407+static int _x_error_occurred;
408+
409+static int
410+_check_error_handler(Display *display,
411+ XErrorEvent *event)
412+{
413+ fprintf(stderr,
414+ "X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
415+ DisplayString(display),
416+ event->serial,
417+ event->error_code,
418+ event->request_code,
419+ event->minor_code);
420+ _x_error_occurred++;
421+ return False; /* ignored */
422+}
423+
424+static double elapsed(const struct timespec *start,
425+ const struct timespec *end)
426+{
427+ return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000;
428+}
429+
430+static void run(Display *dpy, Window win)
431+{
432+ xcb_connection_t *c = XGetXCBConnection(dpy);
433+ struct timespec start, end;
434+ int n, completed = 0;
435+
436+ clock_gettime(CLOCK_MONOTONIC, &start);
437+ do {
438+ for (n = 0; n < 1000; n++) {
439+ unsigned int attachments[] = { DRI2BufferBackLeft };
440+ unsigned int seq[2];
441+
442+ seq[0] = xcb_dri2_swap_buffers_unchecked(c, win,
443+ 0, 0, 0, 0, 0, 0).sequence;
444+
445+
446+ seq[1] = xcb_dri2_get_buffers_unchecked(c, win,
447+ 1, 1, attachments).sequence;
448+
449+ xcb_flush(c);
450+ xcb_discard_reply(c, seq[0]);
451+ xcb_discard_reply(c, seq[1]);
452+ completed++;
453+ }
454+ clock_gettime(CLOCK_MONOTONIC, &end);
455+ } while (end.tv_sec < start.tv_sec + 10);
456+
457+ printf("%f\n", completed / (elapsed(&start, &end) / 1000000));
458+}
459+
460+static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
461+{
462+ XRRScreenResources *res;
463+
464+ res = XRRGetScreenResourcesCurrent(dpy, window);
465+ if (res == NULL)
466+ res = XRRGetScreenResources(dpy, window);
467+
468+ return res;
469+}
470+
471+static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
472+{
473+ int i;
474+
475+ for (i = 0; i < res->nmode; i++) {
476+ if (res->modes[i].id == id)
477+ return &res->modes[i];
478+ }
479+
480+ return NULL;
481+}
482+
483+static int dri2_open(Display *dpy)
484+{
485+ drm_auth_t auth;
486+ char *driver, *device;
487+ int fd;
488+
489+ if (!DRI2QueryExtension(dpy, &fd, &fd))
490+ return -1;
491+
492+ if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device))
493+ return -1;
494+
495+ fd = open(device, O_RDWR);
496+ if (fd < 0)
497+ return -1;
498+
499+ if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
500+ return -1;
501+
502+ if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic))
503+ return -1;
504+
505+ return fd;
506+}
507+
508+static void fullscreen(Display *dpy, Window win)
509+{
510+ Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
511+ XChangeProperty(dpy, win,
512+ XInternAtom(dpy, "_NET_WM_STATE", False),
513+ XA_ATOM, 32, PropModeReplace,
514+ (unsigned char *)&atom, 1);
515+}
516+
517+static int has_composite(Display *dpy)
518+{
519+ int event, error;
520+ int major, minor;
521+
522+ if (!XDamageQueryExtension (dpy, &event, &error))
523+ return 0;
524+
525+ if (!XCompositeQueryExtension(dpy, &event, &error))
526+ return 0;
527+
528+ XCompositeQueryVersion(dpy, &major, &minor);
529+
530+ return major > 0 || minor >= 4;
531+}
532+
533+int main(int argc, char **argv)
534+{
535+ Display *dpy;
536+ Window root, win;
537+ XRRScreenResources *res;
538+ XRRCrtcInfo **original_crtc;
539+ XSetWindowAttributes attr;
540+ enum window { ROOT, FULLSCREEN, WINDOW } w = FULLSCREEN;
541+ enum visible {REDIRECTED, NORMAL } v = NORMAL;
542+ enum display { OFF, ON } d = OFF;
543+ int width, height;
544+ int i, fd;
545+ int c;
546+
547+ while ((c = getopt(argc, argv, "d:v:w:")) != -1) {
548+ switch (c) {
549+ case 'd':
550+ if (strcmp(optarg, "off") == 0)
551+ d = OFF;
552+ else if (strcmp(optarg, "on") == 0)
553+ d = ON;
554+ else
555+ abort();
556+ break;
557+
558+ case 'v':
559+ if (strcmp(optarg, "redirected") == 0)
560+ v = REDIRECTED;
561+ else if (strcmp(optarg, "normal") == 0)
562+ v = NORMAL;
563+ else
564+ abort();
565+ break;
566+
567+ case 'w':
568+ if (strcmp(optarg, "fullscreen") == 0)
569+ w = FULLSCREEN;
570+ else if (strcmp(optarg, "window") == 0)
571+ w = WINDOW;
572+ else if (strcmp(optarg, "root") == 0)
573+ w = ROOT;
574+ else
575+ abort();
576+ break;
577+ }
578+ }
579+
580+ attr.override_redirect = 1;
581+
582+ dpy = XOpenDisplay(NULL);
583+ if (dpy == NULL)
584+ return 77;
585+
586+ width = DisplayWidth(dpy, DefaultScreen(dpy));
587+ height = DisplayHeight(dpy, DefaultScreen(dpy));
588+
589+ fd = dri2_open(dpy);
590+ if (fd < 0)
591+ return 77;
592+
593+ if (DPMSQueryExtension(dpy, &i, &i))
594+ DPMSDisable(dpy);
595+
596+ root = DefaultRootWindow(dpy);
597+
598+ signal(SIGALRM, SIG_IGN);
599+ XSetErrorHandler(_check_error_handler);
600+
601+ res = NULL;
602+ if (XRRQueryVersion(dpy, &i, &i))
603+ res = _XRRGetScreenResourcesCurrent(dpy, root);
604+ if (res == NULL)
605+ return 77;
606+
607+ if (v == REDIRECTED && !has_composite(dpy))
608+ return 77;
609+
610+ original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc);
611+ for (i = 0; i < res->ncrtc; i++)
612+ original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
613+
614+ for (i = 0; i < res->ncrtc; i++)
615+ XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
616+ 0, 0, None, RR_Rotate_0, NULL, 0);
617+
618+ DRI2CreateDrawable(dpy, root);
619+ DRI2SwapInterval(dpy, root, 0);
620+
621+ if (d != OFF) {
622+ for (i = 0; i < res->noutput; i++) {
623+ XRROutputInfo *output;
624+ XRRModeInfo *mode;
625+
626+ output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
627+ if (output == NULL)
628+ continue;
629+
630+ mode = NULL;
631+ if (res->nmode)
632+ mode = lookup_mode(res, output->modes[0]);
633+ if (mode == NULL)
634+ continue;
635+
636+ XRRSetCrtcConfig(dpy, res, output->crtcs[0], CurrentTime,
637+ 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1);
638+ width = mode->width;
639+ height = mode->height;
640+ break;
641+ }
642+ if (i == res->noutput) {
643+ _x_error_occurred = 77;
644+ goto restore;
645+ }
646+ }
647+
648+ if (w == ROOT) {
649+ run(dpy, root);
650+ } else if (w == FULLSCREEN) {
651+ win = XCreateWindow(dpy, root,
652+ 0, 0, width, height, 0,
653+ DefaultDepth(dpy, DefaultScreen(dpy)),
654+ InputOutput,
655+ DefaultVisual(dpy, DefaultScreen(dpy)),
656+ CWOverrideRedirect, &attr);
657+ DRI2CreateDrawable(dpy, win);
658+ DRI2SwapInterval(dpy, win, 0);
659+ if (v == REDIRECTED) {
660+ XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
661+ XDamageCreate(dpy, win, XDamageReportRawRectangles);
662+ } else
663+ fullscreen(dpy, win);
664+ XMapWindow(dpy, win);
665+ run(dpy, win);
666+ } else if (w == WINDOW) {
667+ win = XCreateWindow(dpy, root,
668+ 0, 0, width/2, height/2, 0,
669+ DefaultDepth(dpy, DefaultScreen(dpy)),
670+ InputOutput,
671+ DefaultVisual(dpy, DefaultScreen(dpy)),
672+ CWOverrideRedirect, &attr);
673+ DRI2CreateDrawable(dpy, win);
674+ DRI2SwapInterval(dpy, win, 0);
675+ if (v == REDIRECTED) {
676+ XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
677+ XDamageCreate(dpy, win, XDamageReportRawRectangles);
678+ }
679+ XMapWindow(dpy, win);
680+ run(dpy, win);
681+ }
682+
683+restore:
684+ for (i = 0; i < res->ncrtc; i++)
685+ XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
686+ 0, 0, None, RR_Rotate_0, NULL, 0);
687+
688+ for (i = 0; i < res->ncrtc; i++)
689+ XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
690+ original_crtc[i]->x,
691+ original_crtc[i]->y,
692+ original_crtc[i]->mode,
693+ original_crtc[i]->rotation,
694+ original_crtc[i]->outputs,
695+ original_crtc[i]->noutput);
696+
697+ if (DPMSQueryExtension(dpy, &i, &i))
698+ DPMSEnable(dpy);
699+
700+ XSync(dpy, True);
701+ return _x_error_occurred;
702+}
703diff --git a/benchmarks/dri3-swap.c b/benchmarks/dri3-swap.c
704new file mode 100644
705index 0000000..4dd423b
706--- /dev/null
707+++ b/benchmarks/dri3-swap.c
708@@ -0,0 +1,595 @@
709+/*
710+ * Copyright (c) 2015 Intel Corporation
711+ *
712+ * Permission is hereby granted, free of charge, to any person obtaining a
713+ * copy of this software and associated documentation files (the "Software"),
714+ * to deal in the Software without restriction, including without limitation
715+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
716+ * and/or sell copies of the Software, and to permit persons to whom the
717+ * Software is furnished to do so, subject to the following conditions:
718+ *
719+ * The above copyright notice and this permission notice (including the next
720+ * paragraph) shall be included in all copies or substantial portions of the
721+ * Software.
722+ *
723+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
724+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
725+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
726+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
727+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
728+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
729+ * SOFTWARE.
730+ *
731+ */
732+
733+#ifdef HAVE_CONFIG_H
734+#include "config.h"
735+#endif
736+
737+#include <X11/Xlib.h>
738+#include <X11/Xatom.h>
739+#include <X11/Xlib-xcb.h>
740+#include <X11/xshmfence.h>
741+#include <X11/Xutil.h>
742+#include <X11/Xlibint.h>
743+#include <X11/extensions/Xcomposite.h>
744+#include <X11/extensions/Xdamage.h>
745+#include <X11/extensions/dpms.h>
746+#include <X11/extensions/randr.h>
747+#include <X11/extensions/Xrandr.h>
748+#include <xcb/xcb.h>
749+#include <xcb/present.h>
750+#include <xcb/dri3.h>
751+#include <xcb/xfixes.h>
752+#include <xf86drm.h>
753+#include <i915_drm.h>
754+
755+#include <stdio.h>
756+#include <string.h>
757+#include <fcntl.h>
758+#include <unistd.h>
759+#include <assert.h>
760+#include <errno.h>
761+#include <setjmp.h>
762+#include <signal.h>
763+
764+struct dri3_fence {
765+ XID xid;
766+ void *addr;
767+};
768+
769+static int _x_error_occurred;
770+static uint32_t stamp;
771+
772+struct list {
773+ struct list *next, *prev;
774+};
775+
776+static void
777+list_init(struct list *list)
778+{
779+ list->next = list->prev = list;
780+}
781+
782+static inline void
783+__list_add(struct list *entry,
784+ struct list *prev,
785+ struct list *next)
786+{
787+ next->prev = entry;
788+ entry->next = next;
789+ entry->prev = prev;
790+ prev->next = entry;
791+}
792+
793+static inline void
794+list_add(struct list *entry, struct list *head)
795+{
796+ __list_add(entry, head, head->next);
797+}
798+
799+static inline void
800+__list_del(struct list *prev, struct list *next)
801+{
802+ next->prev = prev;
803+ prev->next = next;
804+}
805+
806+static inline void
807+_list_del(struct list *entry)
808+{
809+ __list_del(entry->prev, entry->next);
810+}
811+
812+static inline void
813+list_move(struct list *list, struct list *head)
814+{
815+ if (list->prev != head) {
816+ _list_del(list);
817+ list_add(list, head);
818+ }
819+}
820+
821+#define __container_of(ptr, sample, member) \
822+ (void *)((char *)(ptr) - ((char *)&(sample)->member - (char *)(sample)))
823+
824+#define list_for_each_entry(pos, head, member) \
825+ for (pos = __container_of((head)->next, pos, member); \
826+ &pos->member != (head); \
827+ pos = __container_of(pos->member.next, pos, member))
828+
829+static int
830+_check_error_handler(Display *display,
831+ XErrorEvent *event)
832+{
833+ printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
834+ DisplayString(display),
835+ event->serial,
836+ event->error_code,
837+ event->request_code,
838+ event->minor_code);
839+ _x_error_occurred++;
840+ return False; /* ignored */
841+}
842+
843+static int dri3_create_fence(Display *dpy,
844+ Pixmap pixmap,
845+ struct dri3_fence *fence)
846+{
847+ xcb_connection_t *c = XGetXCBConnection(dpy);
848+ struct dri3_fence f;
849+ int fd;
850+
851+ fd = xshmfence_alloc_shm();
852+ if (fd < 0)
853+ return -1;
854+
855+ f.addr = xshmfence_map_shm(fd);
856+ if (f.addr == NULL) {
857+ close(fd);
858+ return -1;
859+ }
860+
861+ f.xid = xcb_generate_id(c);
862+ xcb_dri3_fence_from_fd(c, pixmap, f.xid, 0, fd);
863+
864+ *fence = f;
865+ return 0;
866+}
867+
868+static double elapsed(const struct timespec *start,
869+ const struct timespec *end)
870+{
871+ return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000;
872+}
873+
874+struct buffer {
875+ struct list link;
876+ Pixmap pixmap;
877+ struct dri3_fence fence;
878+ int fd;
879+ int busy;
880+};
881+
882+static void run(Display *dpy, Window win)
883+{
884+ xcb_connection_t *c = XGetXCBConnection(dpy);
885+ struct timespec start, end;
886+#define N_BACK 8
887+ struct buffer buffer[N_BACK];
888+ struct list mru;
889+ Window root;
890+ unsigned int width, height;
891+ unsigned border, depth;
892+ unsigned present_flags = XCB_PRESENT_OPTION_ASYNC;
893+ xcb_xfixes_region_t update = 0;
894+ int completed = 0;
895+ int queued = 0;
896+ uint32_t eid;
897+ void *Q;
898+ int i, n;
899+
900+ list_init(&mru);
901+
902+ XGetGeometry(dpy, win,
903+ &root, &i, &n, &width, &height, &border, &depth);
904+
905+ _x_error_occurred = 0;
906+
907+ for (n = 0; n < N_BACK; n++) {
908+ xcb_dri3_buffer_from_pixmap_reply_t *reply;
909+ int *fds;
910+
911+ buffer[n].pixmap =
912+ XCreatePixmap(dpy, win, width, height, depth);
913+ buffer[n].fence.xid = 0;
914+ buffer[n].fd = -1;
915+
916+ if (dri3_create_fence(dpy, win, &buffer[n].fence))
917+ return;
918+
919+ reply = xcb_dri3_buffer_from_pixmap_reply (c,
920+ xcb_dri3_buffer_from_pixmap(c, buffer[n].pixmap),
921+ NULL);
922+ if (reply == NULL)
923+ return;
924+
925+ fds = xcb_dri3_buffer_from_pixmap_reply_fds (c, reply);
926+ buffer[n].fd = fds[0];
927+ free(reply);
928+
929+ /* start idle */
930+ xshmfence_trigger(buffer[n].fence.addr);
931+ buffer[n].busy = 0;
932+ list_add(&buffer[n].link, &mru);
933+ }
934+
935+ eid = xcb_generate_id(c);
936+ xcb_present_select_input(c, eid, win,
937+ XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY |
938+ XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
939+ Q = xcb_register_for_special_xge(c, &xcb_present_id, eid, &stamp);
940+
941+ clock_gettime(CLOCK_MONOTONIC, &start);
942+ do {
943+ for (n = 0; n < 1000; n++) {
944+ struct buffer *tmp, *b = NULL;
945+ list_for_each_entry(tmp, &mru, link) {
946+ if (!tmp->busy) {
947+ b = tmp;
948+ break;
949+ }
950+ }
951+ while (b == NULL) {
952+ xcb_present_generic_event_t *ev;
953+
954+ ev = (xcb_present_generic_event_t *)
955+ xcb_wait_for_special_event(c, Q);
956+ if (ev == NULL)
957+ abort();
958+
959+ do {
960+ switch (ev->evtype) {
961+ case XCB_PRESENT_COMPLETE_NOTIFY:
962+ completed++;
963+ queued--;
964+ break;
965+
966+ case XCB_PRESENT_EVENT_IDLE_NOTIFY:
967+ {
968+ xcb_present_idle_notify_event_t *ie = (xcb_present_idle_notify_event_t *)ev;
969+ assert(ie->serial < N_BACK);
970+ buffer[ie->serial].busy = 0;
971+ if (b == NULL)
972+ b = &buffer[ie->serial];
973+ break;
974+ }
975+ }
976+ free(ev);
977+ } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
978+ }
979+
980+ b->busy = 1;
981+ if (b->fence.xid) {
982+ xshmfence_await(b->fence.addr);
983+ xshmfence_reset(b->fence.addr);
984+ }
985+ xcb_present_pixmap(c, win, b->pixmap, b - buffer,
986+ 0, /* valid */
987+ update, /* update */
988+ 0, /* x_off */
989+ 0, /* y_off */
990+ None,
991+ None, /* wait fence */
992+ b->fence.xid,
993+ present_flags,
994+ 0, /* target msc */
995+ 0, /* divisor */
996+ 0, /* remainder */
997+ 0, NULL);
998+ list_move(&b->link, &mru);
999+ queued++;
1000+ xcb_flush(c);
1001+ }
1002+ clock_gettime(CLOCK_MONOTONIC, &end);
1003+ } while (end.tv_sec < start.tv_sec + 10);
1004+
1005+ while (queued) {
1006+ xcb_present_generic_event_t *ev;
1007+
1008+ ev = (xcb_present_generic_event_t *)
1009+ xcb_wait_for_special_event(c, Q);
1010+ if (ev == NULL)
1011+ abort();
1012+
1013+ do {
1014+ switch (ev->evtype) {
1015+ case XCB_PRESENT_COMPLETE_NOTIFY:
1016+ completed++;
1017+ queued--;
1018+ break;
1019+
1020+ case XCB_PRESENT_EVENT_IDLE_NOTIFY:
1021+ break;
1022+ }
1023+ free(ev);
1024+ } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
1025+ }
1026+ clock_gettime(CLOCK_MONOTONIC, &end);
1027+
1028+ printf("%f\n", completed / (elapsed(&start, &end) / 1000000));
1029+}
1030+
1031+static int has_present(Display *dpy)
1032+{
1033+ xcb_connection_t *c = XGetXCBConnection(dpy);
1034+ xcb_generic_error_t *error = NULL;
1035+ void *reply;
1036+
1037+ reply = xcb_present_query_version_reply(c,
1038+ xcb_present_query_version(c,
1039+ XCB_PRESENT_MAJOR_VERSION,
1040+ XCB_PRESENT_MINOR_VERSION),
1041+ &error);
1042+
1043+ free(reply);
1044+ free(error);
1045+ if (reply == NULL) {
1046+ fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy));
1047+ return 0;
1048+ }
1049+
1050+ return 1;
1051+}
1052+
1053+static int has_composite(Display *dpy)
1054+{
1055+ int event, error;
1056+ int major, minor;
1057+
1058+ if (!XDamageQueryExtension (dpy, &event, &error))
1059+ return 0;
1060+
1061+ if (!XCompositeQueryExtension(dpy, &event, &error))
1062+ return 0;
1063+
1064+ XCompositeQueryVersion(dpy, &major, &minor);
1065+
1066+ return major > 0 || minor >= 4;
1067+}
1068+
1069+static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
1070+{
1071+ XRRScreenResources *res;
1072+
1073+ res = XRRGetScreenResourcesCurrent(dpy, window);
1074+ if (res == NULL)
1075+ res = XRRGetScreenResources(dpy, window);
1076+
1077+ return res;
1078+}
1079+
1080+static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
1081+{
1082+ int i;
1083+
1084+ for (i = 0; i < res->nmode; i++) {
1085+ if (res->modes[i].id == id)
1086+ return &res->modes[i];
1087+ }
1088+
1089+ return NULL;
1090+}
1091+
1092+static void fullscreen(Display *dpy, Window win)
1093+{
1094+ Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
1095+ XChangeProperty(dpy, win,
1096+ XInternAtom(dpy, "_NET_WM_STATE", False),
1097+ XA_ATOM, 32, PropModeReplace,
1098+ (unsigned char *)&atom, 1);
1099+}
1100+
1101+static int dri3_query_version(Display *dpy, int *major, int *minor)
1102+{
1103+ xcb_connection_t *c = XGetXCBConnection(dpy);
1104+ xcb_dri3_query_version_reply_t *reply;
1105+ xcb_generic_error_t *error;
1106+
1107+ *major = *minor = -1;
1108+
1109+ reply = xcb_dri3_query_version_reply(c,
1110+ xcb_dri3_query_version(c,
1111+ XCB_DRI3_MAJOR_VERSION,
1112+ XCB_DRI3_MINOR_VERSION),
1113+ &error);
1114+ free(error);
1115+ if (reply == NULL)
1116+ return -1;
1117+
1118+ *major = reply->major_version;
1119+ *minor = reply->minor_version;
1120+ free(reply);
1121+
1122+ return 0;
1123+}
1124+
1125+static int has_dri3(Display *dpy)
1126+{
1127+ const xcb_query_extension_reply_t *ext;
1128+ int major, minor;
1129+
1130+ ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id);
1131+ if (ext == NULL || !ext->present)
1132+ return 0;
1133+
1134+ if (dri3_query_version(dpy, &major, &minor) < 0)
1135+ return 0;
1136+
1137+ return major >= 0;
1138+}
1139+
1140+int main(int argc, char **argv)
1141+{
1142+ Display *dpy;
1143+ Window root, win;
1144+ XRRScreenResources *res;
1145+ XRRCrtcInfo **original_crtc;
1146+ XSetWindowAttributes attr;
1147+ enum window { ROOT, FULLSCREEN, WINDOW } w = FULLSCREEN;
1148+ enum visible {REDIRECTED, NORMAL } v = NORMAL;
1149+ enum display { OFF, ON } d = OFF;
1150+ int width, height;
1151+ int i;
1152+
1153+ while ((i = getopt(argc, argv, "d:v:w:")) != -1) {
1154+ switch (i) {
1155+ case 'd':
1156+ if (strcmp(optarg, "off") == 0)
1157+ d = OFF;
1158+ else if (strcmp(optarg, "on") == 0)
1159+ d = ON;
1160+ else
1161+ abort();
1162+ break;
1163+
1164+ case 'v':
1165+ if (strcmp(optarg, "redirected") == 0)
1166+ v = REDIRECTED;
1167+ else if (strcmp(optarg, "normal") == 0)
1168+ v = NORMAL;
1169+ else
1170+ abort();
1171+ break;
1172+
1173+ case 'w':
1174+ if (strcmp(optarg, "fullscreen") == 0)
1175+ w = FULLSCREEN;
1176+ else if (strcmp(optarg, "window") == 0)
1177+ w = WINDOW;
1178+ else if (strcmp(optarg, "root") == 0)
1179+ w = ROOT;
1180+ else
1181+ abort();
1182+ break;
1183+ }
1184+ }
1185+
1186+ attr.override_redirect = 1;
1187+
1188+ dpy = XOpenDisplay(NULL);
1189+ if (dpy == NULL)
1190+ return 77;
1191+
1192+ width = DisplayWidth(dpy, DefaultScreen(dpy));
1193+ height = DisplayHeight(dpy, DefaultScreen(dpy));
1194+
1195+ if (!has_present(dpy))
1196+ return 77;
1197+
1198+ if (!has_dri3(dpy))
1199+ return 77;
1200+
1201+ if (DPMSQueryExtension(dpy, &i, &i))
1202+ DPMSDisable(dpy);
1203+
1204+ root = DefaultRootWindow(dpy);
1205+
1206+ signal(SIGALRM, SIG_IGN);
1207+ XSetErrorHandler(_check_error_handler);
1208+
1209+ res = NULL;
1210+ if (XRRQueryVersion(dpy, &i, &i))
1211+ res = _XRRGetScreenResourcesCurrent(dpy, root);
1212+ if (res == NULL)
1213+ return 77;
1214+
1215+ if (v == REDIRECTED && !has_composite(dpy))
1216+ return 77;
1217+
1218+ original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc);
1219+ for (i = 0; i < res->ncrtc; i++)
1220+ original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
1221+
1222+ for (i = 0; i < res->ncrtc; i++)
1223+ XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
1224+ 0, 0, None, RR_Rotate_0, NULL, 0);
1225+
1226+ if (d != OFF) {
1227+ for (i = 0; i < res->noutput; i++) {
1228+ XRROutputInfo *output;
1229+ XRRModeInfo *mode;
1230+
1231+ output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
1232+ if (output == NULL)
1233+ continue;
1234+
1235+ mode = NULL;
1236+ if (res->nmode)
1237+ mode = lookup_mode(res, output->modes[0]);
1238+ if (mode == NULL)
1239+ continue;
1240+
1241+ XRRSetCrtcConfig(dpy, res, output->crtcs[0], CurrentTime,
1242+ 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1);
1243+ width = mode->width;
1244+ height = mode->height;
1245+ break;
1246+ }
1247+ if (i == res->noutput) {
1248+ _x_error_occurred = 77;
1249+ goto restore;
1250+ }
1251+ }
1252+
1253+ if (w == ROOT) {
1254+ run(dpy, root);
1255+ } else if (w == FULLSCREEN) {
1256+ win = XCreateWindow(dpy, root,
1257+ 0, 0, width, height, 0,
1258+ DefaultDepth(dpy, DefaultScreen(dpy)),
1259+ InputOutput,
1260+ DefaultVisual(dpy, DefaultScreen(dpy)),
1261+ CWOverrideRedirect, &attr);
1262+ if (v == REDIRECTED) {
1263+ XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
1264+ XDamageCreate(dpy, win, XDamageReportRawRectangles);
1265+ } else
1266+ fullscreen(dpy, win);
1267+ XMapWindow(dpy, win);
1268+ run(dpy, win);
1269+ } else if (w == WINDOW) {
1270+ win = XCreateWindow(dpy, root,
1271+ 0, 0, width/2, height/2, 0,
1272+ DefaultDepth(dpy, DefaultScreen(dpy)),
1273+ InputOutput,
1274+ DefaultVisual(dpy, DefaultScreen(dpy)),
1275+ CWOverrideRedirect, &attr);
1276+ if (v == REDIRECTED) {
1277+ XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
1278+ XDamageCreate(dpy, win, XDamageReportRawRectangles);
1279+ }
1280+ XMapWindow(dpy, win);
1281+ run(dpy, win);
1282+ }
1283+
1284+restore:
1285+ for (i = 0; i < res->ncrtc; i++)
1286+ XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
1287+ 0, 0, None, RR_Rotate_0, NULL, 0);
1288+
1289+ for (i = 0; i < res->ncrtc; i++)
1290+ XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
1291+ original_crtc[i]->x,
1292+ original_crtc[i]->y,
1293+ original_crtc[i]->mode,
1294+ original_crtc[i]->rotation,
1295+ original_crtc[i]->outputs,
1296+ original_crtc[i]->noutput);
1297+
1298+ if (DPMSQueryExtension(dpy, &i, &i))
1299+ DPMSEnable(dpy);
1300+
1301+ XSync(dpy, True);
1302+ return _x_error_occurred;
1303+}
1304diff --git a/configure.ac b/configure.ac
1305index 61bea43..9aa7d97 100644
1306--- a/configure.ac
1307+++ b/configure.ac
1308@@ -195,18 +195,24 @@ AC_ARG_ENABLE(udev,
1309 [UDEV="$enableval"],
1310 [UDEV=auto])
1311
1312+udev_msg=" disabled"
1313 if test "x$UDEV" != "xno"; then
1314 PKG_CHECK_MODULES(UDEV, [libudev], [udev="yes"], [udev="no"])
1315+ AC_CHECK_HEADERS([sys/stat.h], [], [udev="no"])
1316 if test "x$UDEV" = "xyes" -a "x$udev" != "xyes"; then
1317 AC_MSG_ERROR([udev support requested but not found (libudev)])
1318 fi
1319 if test "x$udev" = "xyes"; then
1320 AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection])
1321+ udev_msg=" yes"
1322+ else
1323+ udev_msg=" no"
1324 fi
1325 fi
1326
1327-PKG_CHECK_MODULES(X11, [x11 xrender xrandr xext xfixes cairo cairo-xlib-xrender pixman-1 libpng], [x11="yes"], [x11="no"])
1328+PKG_CHECK_MODULES(X11, [x11 x11-xcb xcb-dri2 xcomposite xdamage xrender xrandr xext xfixes cairo cairo-xlib-xrender pixman-1 libpng], [x11="yes"], [x11="no"])
1329 AM_CONDITIONAL(HAVE_X11, test "x$x11" = "xyes")
1330+echo X11_CLFAGS="$X11_CLFAGS" X11_LIBS="$X11_LIBS"
1331
1332 cpuid="yes"
1333 AC_TRY_LINK([
1334@@ -270,7 +276,7 @@ if test "x$shm" = "xyes"; then
1335 AC_DEFINE([HAVE_MIT_SHM], 1, [Define to 1 if MIT-SHM is available])
1336 fi
1337
1338-PKG_CHECK_MODULES(X11_DRI3, [xcb-dri3 xcb-sync xcb-present x11-xcb xshmfence x11 xrender xext libdrm], [x11_dri3="yes"], [x11_dri3="no"])
1339+PKG_CHECK_MODULES(X11_DRI3, [xcb-dri3 xcb-sync xcb-xfixes xcb-present x11-xcb xshmfence x11 xcomposite xdamage xrender xrandr xxf86vm xext libdrm], [x11_dri3="yes"], [x11_dri3="no"])
1340 AM_CONDITIONAL(X11_DRI3, test "x$x11_dri3" = "xyes" -a "x$shm" = "xyes")
1341 AM_CONDITIONAL(X11_SHM, test "x$shm" = "xyes")
1342
1343@@ -307,6 +313,8 @@ if test "x$tools" != "xno"; then
1344 tools="no"
1345 fi
1346
1347+ PKG_CHECK_MODULES(TOOL_CURSOR, [xfixes x11 libpng], [cursor="yes"], [ivo="no"])
1348+
1349 IVO_CFLAGS="$IVO_CFLAGS $extra_cflags"
1350 fi
1351 if test "x$tools" != "xno"; then
1352@@ -315,6 +323,7 @@ fi
1353 AC_MSG_CHECKING([whether to build additional tools])
1354 AC_MSG_RESULT([$tools])
1355 AM_CONDITIONAL(BUILD_TOOLS, test "x$tools" != "xno")
1356+AM_CONDITIONAL(BUILD_TOOL_CURSOR, test "x$cursor" = "xyes")
1357
1358 # Define a configure option for an alternate module directory
1359 AC_ARG_WITH(xorg-module-dir,
1360@@ -339,10 +348,20 @@ AC_ARG_ENABLE(dri2,
1361 [DRI2=$enableval],
1362 [DRI2=yes])
1363 AC_ARG_ENABLE(dri3,
1364- AS_HELP_STRING([--enable-dri3],
1365- [Enable DRI3 support [[default=no]]]),
1366+ AS_HELP_STRING([--disable-dri3],
1367+ [Disable DRI3 support [[default=yes]]]),
1368 [DRI3=$enableval],
1369- [DRI3=no])
1370+ [DRI3=yes])
1371+AC_ARG_WITH(default-dri,
1372+ AS_HELP_STRING([--with-default-dri],
1373+ [Select the default maximum DRI level [default 2]]),
1374+ [DRI_DEFAULT=$withval],
1375+ [DRI_DEFAULT=2])
1376+if test "x$DRI_DEFAULT" = "x0"; then
1377+ AC_DEFINE(DEFAULT_DRI_LEVEL, 0,[Default DRI level])
1378+else
1379+ AC_DEFINE(DEFAULT_DRI_LEVEL, ~0, [Default DRI level])
1380+fi
1381
1382 AC_ARG_ENABLE(xvmc, AS_HELP_STRING([--disable-xvmc],
1383 [Disable XvMC support [[default=yes]]]),
1384@@ -375,14 +394,12 @@ AC_ARG_ENABLE(ums-only,
1385 required_xorg_server_version=1.6
1386 required_pixman_version=0.16
1387
1388-if pkg-config --exists 'pixman-1 >= 0.27.1'; then
1389- AC_DEFINE([HAS_PIXMAN_GLYPHS], 1, [Enable pixman glyph cache])
1390-fi
1391-
1392-if pkg-config --exists 'pixman-1 >= 0.24.0'; then
1393- AC_DEFINE([HAS_PIXMAN_TRIANGLES], 1, [Enable pixman triangle rasterisation])
1394-fi
1395-
1396+PKG_CHECK_EXISTS([pixman-1 >= 0.24.0],
1397+ AC_DEFINE([HAS_PIXMAN_TRIANGLES], 1, [Enable pixman triangle rasterisation])
1398+ [])
1399+PKG_CHECK_EXISTS([pixman-1 >= 0.27.1],
1400+ [AC_DEFINE([HAS_PIXMAN_GLYPHS], 1, [Enable pixman glyph cache])],
1401+ [])
1402 # Store the list of server defined optional extensions in REQUIRED_MODULES
1403 XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
1404 XORG_DRIVER_CHECK_EXT(RENDER, renderproto)
1405@@ -398,24 +415,25 @@ AC_ARG_ENABLE(sna,
1406 [SNA="$enableval"],
1407 [SNA=auto])
1408
1409+AC_CHECK_HEADERS([dev/wscons/wsconsio.h])
1410+AC_FUNC_ALLOCA
1411+AC_HEADER_MAJOR
1412+
1413 if test "x$SNA" != "xno"; then
1414 AC_DEFINE(USE_SNA, 1, [Enable SNA support])
1415 AC_CHECK_HEADERS([sys/sysinfo.h], AC_CHECK_MEMBERS([struct sysinfo.totalram], [], [], [[#include <sys/sysinfo.h>]]))
1416 fi
1417
1418 uxa_requires_libdrm=2.4.52
1419+uxa_requires_pixman=0.24.0
1420+
1421 AC_ARG_ENABLE(uxa,
1422 AS_HELP_STRING([--enable-uxa],
1423 [Enable Unified Acceleration Architecture (UXA) [default=auto]]),
1424 [UXA="$enableval"],
1425 [UXA=auto])
1426 if test "x$UXA" = "xauto"; then
1427- if ! pkg-config --exists "libdrm_intel >= $uxa_requires_libdrm"; then
1428- UXA=no
1429- fi
1430- if ! pkg-config --exists 'pixman-1 >= 0.24.0'; then
1431- UXA=no
1432- fi
1433+ PKG_CHECK_EXISTS([libdrm_intel >= $uxa_requires_libdrm pixman-1 >= $uxa_requires_pixman], [], [UXA=no])
1434 fi
1435 if test "x$UXA" != "xno"; then
1436 AC_DEFINE(USE_UXA, 1, [Enable UXA support])
1437@@ -426,6 +444,8 @@ fi
1438
1439 PKG_CHECK_MODULES(XORG, [xorg-server >= $required_xorg_server_version xproto fontsproto pixman-1 >= $required_pixman_version $REQUIRED_MODULES])
1440 ABI_VERSION=`$PKG_CONFIG --variable=abi_videodrv xorg-server`
1441+XSERVER_VERSION=`$PKG_CONFIG --modversion xorg-server`
1442+PIXMAN_VERSION=`$PKG_CONFIG --modversion pixman-1`
1443
1444 if test "x$ONLY_UMS" = "xyes"; then
1445 UMS="yes"
1446@@ -519,7 +539,12 @@ AC_MSG_RESULT([$have_dri1])
1447 AM_CONDITIONAL(DRI1, test "x$have_dri1" != "xno")
1448 if test "x$have_dri1" != "xno"; then
1449 AC_DEFINE(HAVE_DRI1,1,[Enable DRI1 driver support])
1450- dri_msg="$dri_msg DRI1"
1451+ str="DRI1"
1452+ if test "x$DRI_DEFAULT" = "x1"; then
1453+ AC_DEFINE(DEFAULT_DRI_LEVEL,1,[Default DRI level])
1454+ str="*$str"
1455+ fi
1456+ dri_msg="$dri_msg $str"
1457 else
1458 DRI1_CFLAGS=""
1459 DRI1_LIBS=""
1460@@ -576,7 +601,12 @@ AM_CONDITIONAL(DRI2, test "x$have_dri2" != "xno")
1461 AC_MSG_RESULT([$have_dri2])
1462 if test "x$have_dri2" != "xno"; then
1463 AC_DEFINE(HAVE_DRI2,1,[Enable DRI2 driver support])
1464- dri_msg="$dri_msg DRI2"
1465+ str="DRI2"
1466+ if test "x$DRI_DEFAULT" = "x2"; then
1467+ AC_DEFINE(DEFAULT_DRI_LEVEL,2,[Default DRI level])
1468+ str="*$str"
1469+ fi
1470+ dri_msg="$dri_msg $str"
1471 else
1472 if test "x$DRI" = "xyes" -a "x$DRI2" != "xno" -a "x$KMS" = "xyes"; then
1473 AC_MSG_ERROR([DRI2 requested but prerequisites not found])
1474@@ -591,13 +621,21 @@ AM_CONDITIONAL(DRI3, test "x$have_dri3" != "xno")
1475 AC_MSG_RESULT([$have_dri3])
1476 if test "x$have_dri3" != "xno"; then
1477 AC_DEFINE(HAVE_DRI3,1,[Enable DRI3 driver support])
1478- dri_msg="$dri_msg DRI3"
1479+ str="DRI3"
1480+ if test "x$DRI_DEFAULT" = "x3"; then
1481+ AC_DEFINE(DEFAULT_DRI_LEVEL,3,[Default DRI level])
1482+ str="*$str"
1483+ fi
1484+ dri_msg="$dri_msg $str"
1485 else
1486 if test "x$DRI" = "xyes" -a "x$DRI3" != "xno" -a "x$KMS" = "xyes"; then
1487 AC_MSG_ERROR([DRI3 requested but prerequisites not found])
1488 fi
1489 fi
1490
1491+AC_MSG_CHECKING([default DRI support])
1492+AC_MSG_RESULT([$DEFAULT_DRI_DEFAULT])
1493+
1494 AC_CHECK_HEADERS([X11/extensions/dpmsconst.h])
1495
1496 PRESENT="no"
1497@@ -711,27 +749,6 @@ if test "x$TEARFREE" = "xyes"; then
1498 xp_msg="$xp_msg TearFree"
1499 fi
1500
1501-AC_ARG_ENABLE(rendernode,
1502- AS_HELP_STRING([--enable-rendernode],
1503- [Enable use of render nodes (experimental) [default=no]]),
1504- [RENDERNODE="$enableval"],
1505- [RENDERNODE="no"])
1506-AM_CONDITIONAL(USE_RENDERNODE, test "x$RENDERNODE" = "xyes")
1507-if test "x$RENDERNODE" = "xyes"; then
1508- AC_DEFINE(USE_RENDERNODE,1,[Assume "rendernode" support])
1509- xp_msg="$xp_msg rendernode"
1510-fi
1511-
1512-AC_ARG_ENABLE(wc-mmap,
1513- AS_HELP_STRING([--enable-wc-mmap],
1514- [Enable use of WriteCombining mmaps [default=no]]),
1515- [WC_MMAP="$enableval"],
1516- [WC_MMAP="no"])
1517-if test "x$WC_MMAP" = "xyes"; then
1518- AC_DEFINE(USE_WC_MMAP,1,[Enable use of WriteCombining mmaps])
1519- xp_msg="$xp_msg mmap(wc)"
1520-fi
1521-
1522 AC_ARG_ENABLE(create2,
1523 AS_HELP_STRING([--enable-create2],
1524 [Enable use of create2 ioctl (experimental) [default=no]]),
1525@@ -848,6 +865,7 @@ AC_CONFIG_FILES([
1526 xvmc/shader/mc/Makefile
1527 xvmc/shader/vld/Makefile
1528 test/Makefile
1529+ benchmarks/Makefile
1530 tools/Makefile
1531 tools/org.x.xf86-video-intel.backlight-helper.policy
1532 ])
1533@@ -855,7 +873,7 @@ AC_OUTPUT
1534
1535 echo ""
1536 echo ""
1537-test -e `pwd $0`/README && cat `pwd $0`/README
1538+cat $srcdir/README
1539
1540 accel_msg=""
1541 if test "x$SNA" != "xno"; then
1542@@ -895,13 +913,15 @@ fi
1543
1544 echo ""
1545 echo "AC_PACKAGE_STRING will be compiled with:"
1546-echo " Xorg Video ABI version: $ABI_VERSION"
1547+echo " Xorg Video ABI version: $ABI_VERSION (xorg-server-$XSERVER_VERSION)"
1548+echo " pixman version: pixman-1-$PIXMAN_VERSION"
1549 echo " Acceleration backends:$accel_msg"
1550 echo " Additional debugging support?$debug_msg"
1551 echo " Support for Kernel Mode Setting? $KMS"
1552 echo " Support for legacy User Mode Setting (for i810)? $UMS"
1553 echo " Support for Direct Rendering Infrastructure:$dri_msg"
1554 echo " Support for Xv motion compensation (XvMC and libXvMC):$xvmc_msg"
1555+echo " Support for display hotplug notifications (udev):$udev_msg"
1556 echo " Build additional tools and utilities?$tools_msg"
1557 if test -n "$xp_msg"; then
1558 echo " Experimental support:$xp_msg"
1559diff --git a/libobj/alloca.c b/libobj/alloca.c
1560new file mode 100644
1561index 0000000..883e1e9
1562--- /dev/null
1563+++ b/libobj/alloca.c
1564@@ -0,0 +1,4 @@
1565+void *alloca(size_t sz)
1566+{
1567+ return NULL;
1568+}
1569diff --git a/man/intel.man b/man/intel.man
1570index 1751520..8da496e 100644
1571--- a/man/intel.man
1572+++ b/man/intel.man
1573@@ -112,8 +112,8 @@ The default is 8192 if AGP allocable memory is < 128 MB, 16384 if < 192 MB,
1574 24576 if higher. DRI require at least a value of 16384. Higher values may give
1575 better 3D performance, at expense of available system memory.
1576 .TP
1577-.BI "Option \*qNoAccel\*q \*q" boolean \*q
1578-Disable or enable acceleration.
1579+.BI "Option \*qAccel\*q \*q" boolean \*q
1580+Enable or disable acceleration.
1581 .IP
1582 Default: acceleration is enabled.
1583
1584@@ -122,8 +122,8 @@ The following driver
1585 .B Options
1586 are supported for the 830M and later chipsets:
1587 .TP
1588-.BI "Option \*qNoAccel\*q \*q" boolean \*q
1589-Disable or enable acceleration.
1590+.BI "Option \*qAccel\*q \*q" boolean \*q
1591+Enable or disable acceleration.
1592 .IP
1593 Default: acceleration is enabled.
1594 .TP
1595@@ -201,6 +201,16 @@ that choice by specifying the entry under /sys/class/backlight to use.
1596 .IP
1597 Default: Automatic selection.
1598 .TP
1599+.BI "Option \*qCustomEDID\*q \*q" string \*q
1600+Override the probed EDID on particular outputs. Sometimes the manufacturer
1601+supplied EDID is corrupt or lacking a few usable modes and supplying a
1602+corrected EDID may be easier than specifying every modeline. This option
1603+allows to pass the path to load an EDID from per output. The format is a
1604+comma separated string of output:path pairs, e.g.
1605+DP1:/path/to/dp1.edid,DP2:/path/to/dp2.edid
1606+.IP
1607+Default: No override, use manufacturer supplied EDIDs.
1608+.TP
1609 .BI "Option \*qFallbackDebug\*q \*q" boolean \*q
1610 Enable printing of debugging information on acceleration fallbacks to the
1611 server log.
1612@@ -225,6 +235,15 @@ i.e. perform synchronous rendering.
1613 .IP
1614 Default: Disabled
1615 .TP
1616+.BI "Option \*qHWRotation\*q \*q" boolean \*q
1617+Override the use of native hardware rotation and force the use of software,
1618+but GPU accelerated where possible, rotation. On some platforms the hardware
1619+can scanout directly into a rotated output bypassing the intermediate rendering
1620+and extra allocations required for software implemented rotation (i.e. native
1621+rotation uses less resources, is quicker and uses less power). This allows you
1622+to disable the native rotation in case of errors.
1623+.IP
1624+Default: Enabled (use hardware rotation)
1625 .TP
1626 .BI "Option \*qVSync\*q \*q" boolean \*q
1627 This option controls the use of commands to synchronise rendering with the
1628@@ -324,13 +343,29 @@ Default: 0
1629 .BI "Option \*qZaphodHeads\*q \*q" string \*q
1630 .IP
1631 Specify the randr output(s) to use with zaphod mode for a particular driver
1632-instance. If you this option you must use it with all instances of the
1633-driver
1634+instance. If you set this option you must use it with all instances of the
1635+driver. By default, each head is assigned only one CRTC (which limits
1636+using multiple outputs with that head to cloned mode). CRTC can be manually
1637+assigned to individual heads by preceding the output names with a comma
1638+delimited list of pipe numbers followed by a colon. Note that different pipes
1639+may be limited in their functionality and some outputs may only work with
1640+different pipes.
1641 .br
1642 For example:
1643+
1644+.RS
1645 .B
1646 Option \*qZaphodHeads\*q \*qLVDS1,VGA1\*q
1647-will assign xrandr outputs LVDS1 and VGA0 to this instance of the driver.
1648+
1649+will assign xrandr outputs LVDS1 and VGA1 to this instance of the driver.
1650+.RE
1651+
1652+.RS
1653+.B
1654+Option \*qZaphodHeads\*q \*q0,2:HDMI1,DP2\*q
1655+
1656+will assign xrandr outputs HDMI1 and DP2 and CRTCs 0 and 2 to this instance of the driver.
1657+.RE
1658
1659 .SH OUTPUT CONFIGURATION
1660 On 830M and better chipsets, the driver supports runtime configuration of
1661@@ -431,11 +466,11 @@ First DVI SDVO output
1662 Second DVI SDVO output
1663
1664 .SS "TMDS-1", "TMDS-2", "HDMI-1", "HDMI-2"
1665-DVI/HDMI outputs. Avaliable common properties include:
1666+DVI/HDMI outputs. Available common properties include:
1667 .TP
1668 \fBBROADCAST_RGB\fP - method used to set RGB color range
1669 Adjusting this property allows you to set RGB color range on each
1670-channel in order to match HDTV requirment(default 0 for full
1671+channel in order to match HDTV requirement(default 0 for full
1672 range). Setting 1 means RGB color range is 16-235, 0 means RGB color
1673 range is 0-255 on each channel. (Full range is 0-255, not 16-235)
1674
1675diff --git a/src/backlight.c b/src/backlight.c
1676index 9f23986..d020a7c 100644
1677--- a/src/backlight.c
1678+++ b/src/backlight.c
1679@@ -34,6 +34,12 @@
1680 #include <sys/stat.h>
1681 #include <sys/ioctl.h>
1682
1683+#if MAJOR_IN_MKDEV
1684+#include <sys/mkdev.h>
1685+#elif MAJOR_IN_SYSMACROS
1686+#include <sys/sysmacros.h>
1687+#endif
1688+
1689 #include <stdio.h>
1690 #include <stdlib.h>
1691 #include <string.h>
1692@@ -84,7 +90,7 @@ void backlight_init(struct backlight *b)
1693 b->has_power = 0;
1694 }
1695
1696-#ifdef __OpenBSD__
1697+#ifdef HAVE_DEV_WSCONS_WSCONSIO_H
1698
1699 #include <dev/wscons/wsconsio.h>
1700 #include <xf86Priv.h>
1701@@ -146,12 +152,9 @@ int backlight_open(struct backlight *b, char *iface)
1702 return param.curval;
1703 }
1704
1705-enum backlight_type backlight_exists(const char *iface)
1706+int backlight_exists(const char *iface)
1707 {
1708- if (iface != NULL)
1709- return BL_NONE;
1710-
1711- return BL_PLATFORM;
1712+ return iface == NULL;
1713 }
1714
1715 int backlight_on(struct backlight *b)
1716@@ -244,10 +247,10 @@ static const char *known_interfaces[] = {
1717 "intel_backlight",
1718 };
1719
1720-static enum backlight_type __backlight_type(const char *iface)
1721+static int __backlight_type(const char *iface)
1722 {
1723 char buf[1024];
1724- int fd, v;
1725+ int fd, v, i;
1726
1727 v = -1;
1728 fd = __backlight_open(iface, "type", O_RDONLY);
1729@@ -261,39 +264,41 @@ static enum backlight_type __backlight_type(const char *iface)
1730 buf[v] = '\0';
1731
1732 if (strcmp(buf, "raw") == 0)
1733- v = BL_RAW;
1734+ v = BL_RAW << 8;
1735 else if (strcmp(buf, "platform") == 0)
1736- v = BL_PLATFORM;
1737+ v = BL_PLATFORM << 8;
1738 else if (strcmp(buf, "firmware") == 0)
1739- v = BL_FIRMWARE;
1740+ v = BL_FIRMWARE << 8;
1741 else
1742- v = BL_NAMED;
1743+ v = BL_NAMED << 8;
1744 } else
1745- v = BL_NAMED;
1746+ v = BL_NAMED << 8;
1747
1748- if (v == BL_NAMED) {
1749- int i;
1750- for (i = 0; i < ARRAY_SIZE(known_interfaces); i++) {
1751- if (strcmp(iface, known_interfaces[i]) == 0)
1752- break;
1753- }
1754- v += i;
1755+ for (i = 0; i < ARRAY_SIZE(known_interfaces); i++) {
1756+ if (strcmp(iface, known_interfaces[i]) == 0)
1757+ break;
1758 }
1759+ v += i;
1760
1761 return v;
1762 }
1763
1764-enum backlight_type backlight_exists(const char *iface)
1765+static int __backlight_exists(const char *iface)
1766 {
1767 if (__backlight_read(iface, "brightness") < 0)
1768- return BL_NONE;
1769+ return -1;
1770
1771 if (__backlight_read(iface, "max_brightness") <= 0)
1772- return BL_NONE;
1773+ return -1;
1774
1775 return __backlight_type(iface);
1776 }
1777
1778+int backlight_exists(const char *iface)
1779+{
1780+ return __backlight_exists(iface) != -1;
1781+}
1782+
1783 static int __backlight_init(struct backlight *b, char *iface, int fd)
1784 {
1785 b->fd = fd_move_cloexec(fd_set_nonblock(fd));
1786@@ -399,7 +404,10 @@ __backlight_find(void)
1787 continue;
1788
1789 /* Fallback to priority list of known iface for old kernels */
1790- v = backlight_exists(de->d_name);
1791+ v = __backlight_exists(de->d_name);
1792+ if (v < 0)
1793+ continue;
1794+
1795 if (v < best_type) {
1796 char *copy = strdup(de->d_name);
1797 if (copy) {
1798@@ -416,14 +424,17 @@ __backlight_find(void)
1799
1800 int backlight_open(struct backlight *b, char *iface)
1801 {
1802- int level;
1803+ int level, type;
1804
1805 if (iface == NULL)
1806 iface = __backlight_find();
1807 if (iface == NULL)
1808 goto err;
1809
1810- b->type = __backlight_type(iface);
1811+ type = __backlight_type(iface);
1812+ if (type < 0)
1813+ goto err;
1814+ b->type = type >> 8;
1815
1816 b->max = __backlight_read(iface, "max_brightness");
1817 if (b->max <= 0)
1818@@ -517,7 +528,7 @@ void backlight_disable(struct backlight *b)
1819 void backlight_close(struct backlight *b)
1820 {
1821 backlight_disable(b);
1822- if (b->pid)
1823+ if (b->pid > 0)
1824 waitpid(b->pid, NULL, 0);
1825 }
1826
1827@@ -543,7 +554,10 @@ char *backlight_find_for_device(struct pci_device *pci)
1828 if (*de->d_name == '.')
1829 continue;
1830
1831- v = backlight_exists(de->d_name);
1832+ v = __backlight_exists(de->d_name);
1833+ if (v < 0)
1834+ continue;
1835+
1836 if (v < best_type) {
1837 char *copy = strdup(de->d_name);
1838 if (copy) {
1839diff --git a/src/backlight.h b/src/backlight.h
1840index bb0e28b..ba17755 100644
1841--- a/src/backlight.h
1842+++ b/src/backlight.h
1843@@ -43,7 +43,7 @@ struct backlight {
1844 int pid, fd;
1845 };
1846
1847-enum backlight_type backlight_exists(const char *iface);
1848+int backlight_exists(const char *iface);
1849
1850 void backlight_init(struct backlight *backlight);
1851 int backlight_open(struct backlight *backlight, char *iface);
1852diff --git a/src/compat-api.h b/src/compat-api.h
1853index d09e1fb..293e9d7 100644
1854--- a/src/compat-api.h
1855+++ b/src/compat-api.h
1856@@ -39,7 +39,13 @@
1857
1858 #ifndef XF86_HAS_SCRN_CONV
1859 #define xf86ScreenToScrn(s) xf86Screens[(s)->myNum]
1860+#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,1,0,0,0)
1861 #define xf86ScrnToScreen(s) screenInfo.screens[(s)->scrnIndex]
1862+#else
1863+#define xf86ScrnToScreen(s) ((s)->pScreen)
1864+#endif
1865+#else
1866+#define xf86ScrnToScreen(s) ((s)->pScreen)
1867 #endif
1868
1869 #ifndef XF86_SCRN_INTERFACE
1870@@ -131,6 +137,17 @@ region_rects(const RegionRec *r)
1871 return r->data ? (const BoxRec *)(r->data + 1) : &r->extents;
1872 }
1873
1874+inline static void
1875+region_get_boxes(const RegionRec *r, const BoxRec **s, const BoxRec **e)
1876+{
1877+ int n;
1878+ if (r->data)
1879+ *s = region_boxptr(r), n = r->data->numRects;
1880+ else
1881+ *s = &r->extents, n = 1;
1882+ *e = *s + n;
1883+}
1884+
1885 #ifndef INCLUDE_LEGACY_REGION_DEFINES
1886 #define RegionCreate(r, s) REGION_CREATE(NULL, r, s)
1887 #define RegionBreak(r) REGION_BREAK(NULL, r)
1888@@ -223,4 +240,14 @@ static inline void FreePixmap(PixmapPtr pixmap)
1889 dstx, dsty)
1890 #endif
1891
1892+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
1893+#define isGPU(S) (S)->is_gpu
1894+#else
1895+#define isGPU(S) 0
1896+#endif
1897+
1898+#endif
1899+
1900+#if HAS_DIRTYTRACKING_ROTATION
1901+#define PixmapSyncDirtyHelper(d, dd) PixmapSyncDirtyHelper(d)
1902 #endif
1903diff --git a/src/i915_pciids.h b/src/i915_pciids.h
1904index 180ad0e..f1a113e 100644
1905--- a/src/i915_pciids.h
1906+++ b/src/i915_pciids.h
1907@@ -208,40 +208,41 @@
1908 #define INTEL_VLV_D_IDS(info) \
1909 INTEL_VGA_DEVICE(0x0155, info)
1910
1911-#define _INTEL_BDW_M(gt, id, info) \
1912- INTEL_VGA_DEVICE((((gt) - 1) << 4) | (id), info)
1913-#define _INTEL_BDW_D(gt, id, info) \
1914- INTEL_VGA_DEVICE((((gt) - 1) << 4) | (id), info)
1915-
1916-#define _INTEL_BDW_M_IDS(gt, info) \
1917- _INTEL_BDW_M(gt, 0x1602, info), /* ULT */ \
1918- _INTEL_BDW_M(gt, 0x1606, info), /* ULT */ \
1919- _INTEL_BDW_M(gt, 0x160B, info), /* Iris */ \
1920- _INTEL_BDW_M(gt, 0x160E, info) /* ULX */
1921-
1922-#define _INTEL_BDW_D_IDS(gt, info) \
1923- _INTEL_BDW_D(gt, 0x160A, info), /* Server */ \
1924- _INTEL_BDW_D(gt, 0x160D, info) /* Workstation */
1925-
1926-#define INTEL_BDW_GT12M_IDS(info) \
1927- _INTEL_BDW_M_IDS(1, info), \
1928- _INTEL_BDW_M_IDS(2, info)
1929+#define INTEL_BDW_GT12M_IDS(info) \
1930+ INTEL_VGA_DEVICE(0x1602, info), /* GT1 ULT */ \
1931+ INTEL_VGA_DEVICE(0x1606, info), /* GT1 ULT */ \
1932+ INTEL_VGA_DEVICE(0x160B, info), /* GT1 Iris */ \
1933+ INTEL_VGA_DEVICE(0x160E, info), /* GT1 ULX */ \
1934+ INTEL_VGA_DEVICE(0x1612, info), /* GT2 Halo */ \
1935+ INTEL_VGA_DEVICE(0x1616, info), /* GT2 ULT */ \
1936+ INTEL_VGA_DEVICE(0x161B, info), /* GT2 ULT */ \
1937+ INTEL_VGA_DEVICE(0x161E, info) /* GT2 ULX */
1938
1939 #define INTEL_BDW_GT12D_IDS(info) \
1940- _INTEL_BDW_D_IDS(1, info), \
1941- _INTEL_BDW_D_IDS(2, info)
1942+ INTEL_VGA_DEVICE(0x160A, info), /* GT1 Server */ \
1943+ INTEL_VGA_DEVICE(0x160D, info), /* GT1 Workstation */ \
1944+ INTEL_VGA_DEVICE(0x161A, info), /* GT2 Server */ \
1945+ INTEL_VGA_DEVICE(0x161D, info) /* GT2 Workstation */
1946
1947 #define INTEL_BDW_GT3M_IDS(info) \
1948- _INTEL_BDW_M_IDS(3, info)
1949+ INTEL_VGA_DEVICE(0x1622, info), /* ULT */ \
1950+ INTEL_VGA_DEVICE(0x1626, info), /* ULT */ \
1951+ INTEL_VGA_DEVICE(0x162B, info), /* Iris */ \
1952+ INTEL_VGA_DEVICE(0x162E, info) /* ULX */
1953
1954 #define INTEL_BDW_GT3D_IDS(info) \
1955- _INTEL_BDW_D_IDS(3, info)
1956+ INTEL_VGA_DEVICE(0x162A, info), /* Server */ \
1957+ INTEL_VGA_DEVICE(0x162D, info) /* Workstation */
1958
1959 #define INTEL_BDW_RSVDM_IDS(info) \
1960- _INTEL_BDW_M_IDS(4, info)
1961+ INTEL_VGA_DEVICE(0x1632, info), /* ULT */ \
1962+ INTEL_VGA_DEVICE(0x1636, info), /* ULT */ \
1963+ INTEL_VGA_DEVICE(0x163B, info), /* Iris */ \
1964+ INTEL_VGA_DEVICE(0x163E, info) /* ULX */
1965
1966 #define INTEL_BDW_RSVDD_IDS(info) \
1967- _INTEL_BDW_D_IDS(4, info)
1968+ INTEL_VGA_DEVICE(0x163A, info), /* Server */ \
1969+ INTEL_VGA_DEVICE(0x163D, info) /* Workstation */
1970
1971 #define INTEL_BDW_M_IDS(info) \
1972 INTEL_BDW_GT12M_IDS(info), \
1973@@ -259,21 +260,71 @@
1974 INTEL_VGA_DEVICE(0x22b2, info), \
1975 INTEL_VGA_DEVICE(0x22b3, info)
1976
1977-#define INTEL_SKL_IDS(info) \
1978- INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \
1979+#define INTEL_SKL_GT1_IDS(info) \
1980 INTEL_VGA_DEVICE(0x1906, info), /* ULT GT1 */ \
1981- INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \
1982- INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \
1983 INTEL_VGA_DEVICE(0x190E, info), /* ULX GT1 */ \
1984+ INTEL_VGA_DEVICE(0x1902, info), /* DT GT1 */ \
1985+ INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \
1986+ INTEL_VGA_DEVICE(0x190A, info) /* SRV GT1 */
1987+
1988+#define INTEL_SKL_GT2_IDS(info) \
1989+ INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \
1990+ INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \
1991 INTEL_VGA_DEVICE(0x191E, info), /* ULX GT2 */ \
1992 INTEL_VGA_DEVICE(0x1912, info), /* DT GT2 */ \
1993- INTEL_VGA_DEVICE(0x1902, info), /* DT GT1 */ \
1994 INTEL_VGA_DEVICE(0x191B, info), /* Halo GT2 */ \
1995- INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \
1996- INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \
1997 INTEL_VGA_DEVICE(0x191A, info), /* SRV GT2 */ \
1998- INTEL_VGA_DEVICE(0x192A, info), /* SRV GT3 */ \
1999- INTEL_VGA_DEVICE(0x190A, info), /* SRV GT1 */ \
2000 INTEL_VGA_DEVICE(0x191D, info) /* WKS GT2 */
2001
2002+#define INTEL_SKL_GT3_IDS(info) \
2003+ INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \
2004+ INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \
2005+ INTEL_VGA_DEVICE(0x192A, info) /* SRV GT3 */ \
2006+
2007+#define INTEL_SKL_IDS(info) \
2008+ INTEL_SKL_GT1_IDS(info), \
2009+ INTEL_SKL_GT2_IDS(info), \
2010+ INTEL_SKL_GT3_IDS(info)
2011+
2012+#define INTEL_BXT_IDS(info) \
2013+ INTEL_VGA_DEVICE(0x0A84, info), \
2014+ INTEL_VGA_DEVICE(0x1A84, info), \
2015+ INTEL_VGA_DEVICE(0x5A84, info)
2016+
2017+#define INTEL_KBL_GT1_IDS(info) \
2018+ INTEL_VGA_DEVICE(0x5913, info), /* ULT GT1.5 */ \
2019+ INTEL_VGA_DEVICE(0x5915, info), /* ULX GT1.5 */ \
2020+ INTEL_VGA_DEVICE(0x5917, info), /* DT GT1.5 */ \
2021+ INTEL_VGA_DEVICE(0x5906, info), /* ULT GT1 */ \
2022+ INTEL_VGA_DEVICE(0x590E, info), /* ULX GT1 */ \
2023+ INTEL_VGA_DEVICE(0x5902, info), /* DT GT1 */ \
2024+ INTEL_VGA_DEVICE(0x590B, info), /* Halo GT1 */ \
2025+ INTEL_VGA_DEVICE(0x590A, info) /* SRV GT1 */
2026+
2027+#define INTEL_KBL_GT2_IDS(info) \
2028+ INTEL_VGA_DEVICE(0x5916, info), /* ULT GT2 */ \
2029+ INTEL_VGA_DEVICE(0x5921, info), /* ULT GT2F */ \
2030+ INTEL_VGA_DEVICE(0x591E, info), /* ULX GT2 */ \
2031+ INTEL_VGA_DEVICE(0x5912, info), /* DT GT2 */ \
2032+ INTEL_VGA_DEVICE(0x591B, info), /* Halo GT2 */ \
2033+ INTEL_VGA_DEVICE(0x591A, info), /* SRV GT2 */ \
2034+ INTEL_VGA_DEVICE(0x591D, info) /* WKS GT2 */
2035+
2036+#define INTEL_KBL_GT3_IDS(info) \
2037+ INTEL_VGA_DEVICE(0x5926, info), /* ULT GT3 */ \
2038+ INTEL_VGA_DEVICE(0x592B, info), /* Halo GT3 */ \
2039+ INTEL_VGA_DEVICE(0x592A, info) /* SRV GT3 */
2040+
2041+#define INTEL_KBL_GT4_IDS(info) \
2042+ INTEL_VGA_DEVICE(0x5932, info), /* DT GT4 */ \
2043+ INTEL_VGA_DEVICE(0x593B, info), /* Halo GT4 */ \
2044+ INTEL_VGA_DEVICE(0x593A, info), /* SRV GT4 */ \
2045+ INTEL_VGA_DEVICE(0x593D, info) /* WKS GT4 */
2046+
2047+#define INTEL_KBL_IDS(info) \
2048+ INTEL_KBL_GT1_IDS(info), \
2049+ INTEL_KBL_GT2_IDS(info), \
2050+ INTEL_KBL_GT3_IDS(info), \
2051+ INTEL_KBL_GT4_IDS(info)
2052+
2053 #endif /* _I915_PCIIDS_H */
2054diff --git a/src/intel_device.c b/src/intel_device.c
2055index 140e153..54c1443 100644
2056--- a/src/intel_device.c
2057+++ b/src/intel_device.c
2058@@ -38,6 +38,12 @@
2059 #include <dirent.h>
2060 #include <errno.h>
2061
2062+#if MAJOR_IN_MKDEV
2063+#include <sys/mkdev.h>
2064+#elif MAJOR_IN_SYSMACROS
2065+#include <sys/sysmacros.h>
2066+#endif
2067+
2068 #include <pciaccess.h>
2069
2070 #include <xorg-server.h>
2071@@ -197,9 +203,15 @@ static inline struct intel_device *intel_device(ScrnInfoPtr scrn)
2072 return xf86GetEntityPrivate(scrn->entityList[0], intel_device_key)->ptr;
2073 }
2074
2075+static const char *kernel_module_names[] ={
2076+ "i915",
2077+ NULL,
2078+};
2079+
2080 static int is_i915_device(int fd)
2081 {
2082 drm_version_t version;
2083+ const char **kn;
2084 char name[5] = "";
2085
2086 memset(&version, 0, sizeof(version));
2087@@ -209,7 +221,22 @@ static int is_i915_device(int fd)
2088 if (drmIoctl(fd, DRM_IOCTL_VERSION, &version))
2089 return 0;
2090
2091- return strcmp("i915", name) == 0;
2092+ for (kn = kernel_module_names; *kn; kn++)
2093+ if (strcmp(*kn, name) == 0)
2094+ return 1;
2095+
2096+ return 0;
2097+}
2098+
2099+static int load_i915_kernel_module(void)
2100+{
2101+ const char **kn;
2102+
2103+ for (kn = kernel_module_names; *kn; kn++)
2104+ if (xf86LoadKernelModule(*kn) == 0)
2105+ return 0;
2106+
2107+ return -1;
2108 }
2109
2110 static int is_i915_gem(int fd)
2111@@ -336,7 +363,7 @@ static int __intel_open_device__pci(const struct pci_device *pci)
2112
2113 sprintf(path + base, "driver");
2114 if (stat(path, &st)) {
2115- if (xf86LoadKernelModule("i915"))
2116+ if (load_i915_kernel_module())
2117 return -1;
2118 (void)xf86LoadKernelModule("fbcon");
2119 }
2120@@ -399,7 +426,7 @@ static int __intel_open_device__legacy(const struct pci_device *pci)
2121
2122 ret = drmCheckModesettingSupported(id);
2123 if (ret) {
2124- if (xf86LoadKernelModule("i915"))
2125+ if (load_i915_kernel_module() == 0)
2126 ret = drmCheckModesettingSupported(id);
2127 if (ret)
2128 return -1;
2129@@ -461,9 +488,9 @@ static int is_render_node(int fd, struct stat *st)
2130
2131 static char *find_render_node(int fd)
2132 {
2133-#if defined(USE_RENDERNODE)
2134 struct stat master, render;
2135 char buf[128];
2136+ int i;
2137
2138 /* Are we a render-node ourselves? */
2139 if (is_render_node(fd, &master))
2140@@ -472,9 +499,17 @@ static char *find_render_node(int fd)
2141 sprintf(buf, "/dev/dri/renderD%d", (int)((master.st_rdev | 0x80) & 0xbf));
2142 if (stat(buf, &render) == 0 &&
2143 master.st_mode == render.st_mode &&
2144- render.st_rdev == ((master.st_rdev | 0x80) & 0xbf))
2145+ render.st_rdev == (master.st_rdev | 0x80))
2146 return strdup(buf);
2147-#endif
2148+
2149+ /* Misaligned card <-> renderD, do a full search */
2150+ for (i = 0; i < 16; i++) {
2151+ sprintf(buf, "/dev/dri/renderD%d", i + 128);
2152+ if (stat(buf, &render) == 0 &&
2153+ master.st_mode == render.st_mode &&
2154+ render.st_rdev == (master.st_rdev | 0x80))
2155+ return strdup(buf);
2156+ }
2157
2158 return NULL;
2159 }
2160@@ -672,6 +707,12 @@ struct intel_device *intel_get_device(ScrnInfoPtr scrn, int *fd)
2161 return dev;
2162 }
2163
2164+const char *intel_get_master_name(struct intel_device *dev)
2165+{
2166+ assert(dev && dev->master_node);
2167+ return dev->master_node;
2168+}
2169+
2170 const char *intel_get_client_name(struct intel_device *dev)
2171 {
2172 assert(dev && dev->render_node);
2173diff --git a/src/intel_driver.h b/src/intel_driver.h
2174index 28ed1a0..fc9beaf 100644
2175--- a/src/intel_driver.h
2176+++ b/src/intel_driver.h
2177@@ -127,6 +127,7 @@ int intel_open_device(int entity_num,
2178 int __intel_peek_fd(ScrnInfoPtr scrn);
2179 struct intel_device *intel_get_device(ScrnInfoPtr scrn, int *fd);
2180 int intel_has_render_node(struct intel_device *dev);
2181+const char *intel_get_master_name(struct intel_device *dev);
2182 const char *intel_get_client_name(struct intel_device *dev);
2183 int intel_get_client_fd(struct intel_device *dev);
2184 int intel_get_device_id(struct intel_device *dev);
2185diff --git a/src/intel_list.h b/src/intel_list.h
2186index 51af825..c8a3187 100644
2187--- a/src/intel_list.h
2188+++ b/src/intel_list.h
2189@@ -306,8 +306,7 @@ list_is_empty(const struct list *head)
2190 list_entry((ptr)->prev, type, member)
2191
2192 #define __container_of(ptr, sample, member) \
2193- (void *)((char *)(ptr) \
2194- - ((char *)&(sample)->member - (char *)(sample)))
2195+ (void *)((char *)(ptr) - ((char *)&(sample)->member - (char *)(sample)))
2196 /**
2197 * Loop through the list given by head and set pos to struct in the list.
2198 *
2199@@ -392,17 +391,50 @@ static inline void list_move_tail(struct list *list, struct list *head)
2200 #define list_last_entry(ptr, type, member) \
2201 list_entry((ptr)->prev, type, member)
2202
2203-#define list_for_each_entry_reverse(pos, head, member) \
2204+#define list_for_each_entry_reverse(pos, head, member) \
2205 for (pos = __container_of((head)->prev, pos, member); \
2206 &pos->member != (head); \
2207 pos = __container_of(pos->member.prev, pos, member))
2208
2209 #endif
2210
2211+#define list_for_each_entry_safe_from(pos, tmp, head, member) \
2212+ for (tmp = __container_of(pos->member.next, pos, member); \
2213+ &pos->member != (head); \
2214+ pos = tmp, tmp = __container_of(tmp->member.next, tmp, member))
2215+
2216 #undef container_of
2217 #define container_of(ptr, type, member) \
2218 ((type *)((char *)(ptr) - (char *) &((type *)0)->member))
2219
2220+static inline void __list_splice(const struct list *list,
2221+ struct list *prev,
2222+ struct list *next)
2223+{
2224+ struct list *first = list->next;
2225+ struct list *last = list->prev;
2226+
2227+ first->prev = prev;
2228+ prev->next = first;
2229+
2230+ last->next = next;
2231+ next->prev = last;
2232+}
2233+
2234+static inline void list_splice(const struct list *list,
2235+ struct list *head)
2236+{
2237+ if (!list_is_empty(list))
2238+ __list_splice(list, head, head->next);
2239+}
2240+
2241+static inline void list_splice_tail(const struct list *list,
2242+ struct list *head)
2243+{
2244+ if (!list_is_empty(list))
2245+ __list_splice(list, head->prev, head);
2246+}
2247+
2248 static inline int list_is_singular(const struct list *list)
2249 {
2250 return list->next == list->prev;
2251diff --git a/src/intel_module.c b/src/intel_module.c
2252index 102d52a..60835b9 100644
2253--- a/src/intel_module.c
2254+++ b/src/intel_module.c
2255@@ -126,6 +126,13 @@ static const struct intel_device_info intel_skylake_info = {
2256 .gen = 0110,
2257 };
2258
2259+static const struct intel_device_info intel_broxton_info = {
2260+ .gen = 0111,
2261+};
2262+
2263+static const struct intel_device_info intel_kabylake_info = {
2264+ .gen = 0112,
2265+};
2266
2267 static const SymTabRec intel_chipsets[] = {
2268 {PCI_CHIP_I810, "i810"},
2269@@ -234,30 +241,36 @@ static const SymTabRec intel_chipsets[] = {
2270 {0x0157, "HD Graphics"},
2271
2272 /* Broadwell Marketing names */
2273- {0x1602, "HD graphics"},
2274- {0x1606, "HD graphics"},
2275- {0x160B, "HD graphics"},
2276- {0x160A, "HD graphics"},
2277- {0x160D, "HD graphics"},
2278- {0x160E, "HD graphics"},
2279- {0x1612, "HD graphics 5600"},
2280- {0x1616, "HD graphics 5500"},
2281- {0x161B, "HD graphics"},
2282- {0x161A, "HD graphics"},
2283- {0x161D, "HD graphics"},
2284- {0x161E, "HD graphics 5300"},
2285- {0x1622, "Iris Pro graphics 6200"},
2286- {0x1626, "HD graphics 6000"},
2287- {0x162B, "Iris graphics 6100"},
2288- {0x162A, "Iris Pro graphics P6300"},
2289- {0x162D, "HD graphics"},
2290- {0x162E, "HD graphics"},
2291- {0x1632, "HD graphics"},
2292- {0x1636, "HD graphics"},
2293- {0x163B, "HD graphics"},
2294- {0x163A, "HD graphics"},
2295- {0x163D, "HD graphics"},
2296- {0x163E, "HD graphics"},
2297+ {0x1602, "HD Graphics"},
2298+ {0x1606, "HD Graphics"},
2299+ {0x160B, "HD Graphics"},
2300+ {0x160A, "HD Graphics"},
2301+ {0x160D, "HD Graphics"},
2302+ {0x160E, "HD Graphics"},
2303+ {0x1612, "HD Graphics 5600"},
2304+ {0x1616, "HD Graphics 5500"},
2305+ {0x161B, "HD Graphics"},
2306+ {0x161A, "HD Graphics"},
2307+ {0x161D, "HD Graphics"},
2308+ {0x161E, "HD Graphics 5300"},
2309+ {0x1622, "Iris Pro Graphics 6200"},
2310+ {0x1626, "HD Graphics 6000"},
2311+ {0x162B, "Iris Graphics 6100"},
2312+ {0x162A, "Iris Pro Graphics P6300"},
2313+ {0x162D, "HD Graphics"},
2314+ {0x162E, "HD Graphics"},
2315+ {0x1632, "HD Graphics"},
2316+ {0x1636, "HD Graphics"},
2317+ {0x163B, "HD Graphics"},
2318+ {0x163A, "HD Graphics"},
2319+ {0x163D, "HD Graphics"},
2320+ {0x163E, "HD Graphics"},
2321+
2322+ /* Cherryview (Cherrytrail/Braswell) */
2323+ {0x22b0, "HD Graphics"},
2324+ {0x22b1, "HD Graphics"},
2325+ {0x22b2, "HD Graphics"},
2326+ {0x22b3, "HD Graphics"},
2327
2328 /* When adding new identifiers, also update:
2329 * 1. intel_identify()
2330@@ -318,6 +331,10 @@ static const struct pci_id_match intel_device_match[] = {
2331
2332 INTEL_SKL_IDS(&intel_skylake_info),
2333
2334+ INTEL_BXT_IDS(&intel_broxton_info),
2335+
2336+ INTEL_KBL_IDS(&intel_kabylake_info),
2337+
2338 INTEL_VGA_DEVICE(PCI_MATCH_ANY, &intel_generic_info),
2339 #endif
2340
2341@@ -508,6 +525,9 @@ static enum accel_method { NOACCEL, SNA, UXA } get_accel_method(void)
2342 if (hosted())
2343 return SNA;
2344
2345+ if (xf86configptr == NULL) /* X -configure */
2346+ return SNA;
2347+
2348 dev = _xf86findDriver("intel", xf86configptr->conf_device_lst);
2349 if (dev && dev->dev_option_lst) {
2350 const char *s;
2351@@ -582,10 +602,17 @@ intel_scrn_create(DriverPtr driver,
2352 case NOACCEL:
2353 #endif
2354 case UXA:
2355- return intel_init_scrn(scrn);
2356+ return intel_init_scrn(scrn);
2357 #endif
2358
2359- default: break;
2360+ default:
2361+#if USE_SNA
2362+ return sna_init_scrn(scrn, entity_num);
2363+#elif USE_UXA
2364+ return intel_init_scrn(scrn);
2365+#else
2366+ break;
2367+#endif
2368 }
2369 #endif
2370
2371diff --git a/src/intel_options.c b/src/intel_options.c
2372index ff8541a..7f253ac 100644
2373--- a/src/intel_options.c
2374+++ b/src/intel_options.c
2375@@ -2,18 +2,24 @@
2376 #include "config.h"
2377 #endif
2378
2379+#include <xorg-server.h>
2380+#include <xorgVersion.h>
2381+#include <xf86Parser.h>
2382+
2383 #include "intel_options.h"
2384
2385 const OptionInfoRec intel_options[] = {
2386- {OPTION_ACCEL_DISABLE, "NoAccel", OPTV_BOOLEAN, {0}, 0},
2387+ {OPTION_ACCEL_ENABLE, "Accel", OPTV_BOOLEAN, {0}, 0},
2388 {OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, 0},
2389 {OPTION_BACKLIGHT, "Backlight", OPTV_STRING, {0}, 0},
2390+ {OPTION_EDID, "CustomEDID", OPTV_STRING, {0}, 0},
2391 {OPTION_DRI, "DRI", OPTV_STRING, {0}, 0},
2392 {OPTION_PRESENT, "Present", OPTV_BOOLEAN, {0}, 1},
2393 {OPTION_COLOR_KEY, "ColorKey", OPTV_INTEGER, {0}, 0},
2394 {OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, 0},
2395 {OPTION_TILING_2D, "Tiling", OPTV_BOOLEAN, {0}, 1},
2396 {OPTION_TILING_FB, "LinearFramebuffer", OPTV_BOOLEAN, {0}, 0},
2397+ {OPTION_ROTATION, "HWRotation", OPTV_BOOLEAN, {0}, 1},
2398 {OPTION_VSYNC, "VSync", OPTV_BOOLEAN, {0}, 1},
2399 {OPTION_PAGEFLIP, "PageFlip", OPTV_BOOLEAN, {0}, 1},
2400 {OPTION_SWAPBUFFERS_WAIT, "SwapbuffersWait", OPTV_BOOLEAN, {0}, 1},
2401@@ -21,7 +27,6 @@ const OptionInfoRec intel_options[] = {
2402 {OPTION_PREFER_OVERLAY, "XvPreferOverlay", OPTV_BOOLEAN, {0}, 0},
2403 {OPTION_HOTPLUG, "HotPlug", OPTV_BOOLEAN, {0}, 1},
2404 {OPTION_REPROBE, "ReprobeOutputs", OPTV_BOOLEAN, {0}, 0},
2405- {OPTION_DELETE_DP12, "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, 0},
2406 #ifdef INTEL_XVMC
2407 {OPTION_XVMC, "XvMC", OPTV_BOOLEAN, {0}, 1},
2408 #endif
2409@@ -54,3 +59,85 @@ OptionInfoPtr intel_options_get(ScrnInfoPtr scrn)
2410
2411 return options;
2412 }
2413+
2414+Bool intel_option_cast_to_bool(OptionInfoPtr options, int id, Bool val)
2415+{
2416+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
2417+ xf86getBoolValue(&val, xf86GetOptValString(options, id));
2418+#endif
2419+ return val;
2420+}
2421+
2422+static int
2423+namecmp(const char *s1, const char *s2)
2424+{
2425+ char c1, c2;
2426+
2427+ if (!s1 || *s1 == 0) {
2428+ if (!s2 || *s2 == 0)
2429+ return 0;
2430+ else
2431+ return 1;
2432+ }
2433+
2434+ while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
2435+ s1++;
2436+
2437+ while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
2438+ s2++;
2439+
2440+ c1 = isupper(*s1) ? tolower(*s1) : *s1;
2441+ c2 = isupper(*s2) ? tolower(*s2) : *s2;
2442+ while (c1 == c2) {
2443+ if (c1 == '\0')
2444+ return 0;
2445+
2446+ s1++;
2447+ while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
2448+ s1++;
2449+
2450+ s2++;
2451+ while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
2452+ s2++;
2453+
2454+ c1 = isupper(*s1) ? tolower(*s1) : *s1;
2455+ c2 = isupper(*s2) ? tolower(*s2) : *s2;
2456+ }
2457+
2458+ return c1 - c2;
2459+}
2460+
2461+unsigned intel_option_cast_to_unsigned(OptionInfoPtr options, int id, unsigned val)
2462+{
2463+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
2464+ const char *str = xf86GetOptValString(options, id);
2465+#else
2466+ const char *str = NULL;
2467+#endif
2468+ unsigned v;
2469+
2470+ if (str == NULL || *str == '\0')
2471+ return val;
2472+
2473+ if (namecmp(str, "on") == 0)
2474+ return val;
2475+ if (namecmp(str, "true") == 0)
2476+ return val;
2477+ if (namecmp(str, "yes") == 0)
2478+ return val;
2479+
2480+ if (namecmp(str, "0") == 0)
2481+ return 0;
2482+ if (namecmp(str, "off") == 0)
2483+ return 0;
2484+ if (namecmp(str, "false") == 0)
2485+ return 0;
2486+ if (namecmp(str, "no") == 0)
2487+ return 0;
2488+
2489+ v = atoi(str);
2490+ if (v)
2491+ return v;
2492+
2493+ return val;
2494+}
2495diff --git a/src/intel_options.h b/src/intel_options.h
2496index 7e2cbd9..43635f1 100644
2497--- a/src/intel_options.h
2498+++ b/src/intel_options.h
2499@@ -12,15 +12,17 @@
2500 */
2501
2502 enum intel_options {
2503- OPTION_ACCEL_DISABLE,
2504+ OPTION_ACCEL_ENABLE,
2505 OPTION_ACCEL_METHOD,
2506 OPTION_BACKLIGHT,
2507+ OPTION_EDID,
2508 OPTION_DRI,
2509 OPTION_PRESENT,
2510 OPTION_VIDEO_KEY,
2511 OPTION_COLOR_KEY,
2512 OPTION_TILING_2D,
2513 OPTION_TILING_FB,
2514+ OPTION_ROTATION,
2515 OPTION_VSYNC,
2516 OPTION_PAGEFLIP,
2517 OPTION_SWAPBUFFERS_WAIT,
2518@@ -28,7 +30,6 @@ enum intel_options {
2519 OPTION_PREFER_OVERLAY,
2520 OPTION_HOTPLUG,
2521 OPTION_REPROBE,
2522- OPTION_DELETE_DP12,
2523 #if defined(XvMCExtension) && defined(ENABLE_XVMC)
2524 OPTION_XVMC,
2525 #define INTEL_XVMC 1
2526@@ -51,5 +52,7 @@ enum intel_options {
2527
2528 extern const OptionInfoRec intel_options[];
2529 OptionInfoPtr intel_options_get(ScrnInfoPtr scrn);
2530+unsigned intel_option_cast_to_unsigned(OptionInfoPtr, int id, unsigned val);
2531+Bool intel_option_cast_to_bool(OptionInfoPtr, int id, Bool val);
2532
2533 #endif /* INTEL_OPTIONS_H */
2534diff --git a/src/legacy/i810/i810_common.h b/src/legacy/i810/i810_common.h
2535index 4cc10e8..8355708 100644
2536--- a/src/legacy/i810/i810_common.h
2537+++ b/src/legacy/i810/i810_common.h
2538@@ -52,7 +52,7 @@
2539
2540 #define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1))
2541
2542-/* Using usleep() makes things noticably slow. */
2543+/* Using usleep() makes things noticeably slow. */
2544 #if 0
2545 #define DELAY(x) usleep(x)
2546 #else
2547@@ -185,7 +185,7 @@ enum {
2548 * - zbuffer linear offset and pitch -- also invarient
2549 * - drawing origin in back and depth buffers.
2550 *
2551- * Keep the depth/back buffer state here to acommodate private buffers
2552+ * Keep the depth/back buffer state here to accommodate private buffers
2553 * in the future.
2554 */
2555 #define I810_DESTREG_DI0 0 /* CMD_OP_DESTBUFFER_INFO (2 dwords) */
2556diff --git a/src/legacy/i810/i810_hwmc.c b/src/legacy/i810/i810_hwmc.c
2557index 7cb9c1a..58661b0 100644
2558--- a/src/legacy/i810/i810_hwmc.c
2559+++ b/src/legacy/i810/i810_hwmc.c
2560@@ -171,7 +171,7 @@ static XF86MCAdaptorPtr ppAdapt[1] =
2561 *
2562 * I810InitMC
2563 *
2564- * Initialize the hardware motion compenstation extention for this
2565+ * Initialize the hardware motion compensation extension for this
2566 * hardware. The initialization routines want the address of the pointers
2567 * to the structures, not the address of the structures. This means we
2568 * allocate (or create static?) the pointer memory and pass that
2569diff --git a/src/legacy/i810/i810_memory.c b/src/legacy/i810/i810_memory.c
2570index c3de277..6f27483 100644
2571--- a/src/legacy/i810/i810_memory.c
2572+++ b/src/legacy/i810/i810_memory.c
2573@@ -76,7 +76,7 @@ I810AllocateGARTMemory(ScrnInfoPtr pScrn)
2574 unsigned long size = pScrn->videoRam * 1024UL;
2575 I810Ptr pI810 = I810PTR(pScrn);
2576 int key;
2577- long tom = 0;
2578+ unsigned long tom = 0;
2579 unsigned long physical;
2580
2581 if (!xf86AgpGARTSupported() || !xf86AcquireGART(pScrn->scrnIndex)) {
2582@@ -132,8 +132,8 @@ I810AllocateGARTMemory(ScrnInfoPtr pScrn)
2583 * Keep it 512K aligned for the sake of tiled regions.
2584 */
2585
2586- tom += 0x7ffff;
2587- tom &= ~0x7ffff;
2588+ tom += 0x7ffffUL;
2589+ tom &= ~0x7ffffUL;
2590
2591 if ((key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 1, NULL)) != -1) {
2592 pI810->DcacheOffset = tom;
2593diff --git a/src/legacy/i810/i810_reg.h b/src/legacy/i810/i810_reg.h
2594index 54faeb3..fa091c5 100644
2595--- a/src/legacy/i810/i810_reg.h
2596+++ b/src/legacy/i810/i810_reg.h
2597@@ -245,7 +245,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2598 * not sure they refer to local (graphics) memory.
2599 *
2600 * These details are for the local memory control registers,
2601- * (pp301-310). The test machines are not equiped with local memory,
2602+ * (pp301-310). The test machines are not equipped with local memory,
2603 * so nothing is tested. Only a single row seems to be supported.
2604 */
2605 #define DRAM_ROW_TYPE 0x3000
2606diff --git a/src/legacy/i810/xvmc/I810XvMC.c b/src/legacy/i810/xvmc/I810XvMC.c
2607index e6b63d3..a538e99 100644
2608--- a/src/legacy/i810/xvmc/I810XvMC.c
2609+++ b/src/legacy/i810/xvmc/I810XvMC.c
2610@@ -61,7 +61,7 @@ static int event_base;
2611 // Arguments: pI810XvMC private data structure from the current context.
2612 // Notes: We faked the drmMapBufs for the i810's security so now we have
2613 // to insert an allocated page into the correct spot in the faked
2614-// list to keep up appearences.
2615+// list to keep up appearances.
2616 // Concept for this function was taken from Mesa sources.
2617 // Returns: drmBufPtr containing the information about the allocated page.
2618 ***************************************************************************/
2619@@ -188,7 +188,7 @@ _X_EXPORT Status XvMCCreateContext(Display *display, XvPortID port,
2620
2621 /* Check for drm */
2622 if(! drmAvailable()) {
2623- printf("Direct Rendering is not avilable on this system!\n");
2624+ printf("Direct Rendering is not available on this system!\n");
2625 return BadAlloc;
2626 }
2627
2628@@ -3279,7 +3279,7 @@ _X_EXPORT Status XvMCSyncSurface(Display *display,XvMCSurface *surface) {
2629 // display - Connection to X server
2630 // surface - Surface to flush
2631 // Info:
2632-// This command is a noop for i810 becuase we always dispatch buffers in
2633+// This command is a noop for i810 because we always dispatch buffers in
2634 // render. There is little gain to be had with 4k buffers.
2635 // Returns: Status
2636 ***************************************************************************/
2637diff --git a/src/render_program/exa_wm.g4i b/src/render_program/exa_wm.g4i
2638index 5d3d45b..587b581 100644
2639--- a/src/render_program/exa_wm.g4i
2640+++ b/src/render_program/exa_wm.g4i
2641@@ -57,7 +57,7 @@ define(`mask_dw_dy', `g6.4<0,1,0>F')
2642 define(`mask_wo', `g6.12<0,1,0>F')
2643
2644 /*
2645- * Local variables. Pairs must be aligned on even reg boundry
2646+ * Local variables. Pairs must be aligned on even reg boundary
2647 */
2648
2649 /* this holds the X dest coordinates */
2650diff --git a/src/render_program/exa_wm_yuv_rgb.g8a b/src/render_program/exa_wm_yuv_rgb.g8a
2651index 7def093..34973ba 100644
2652--- a/src/render_program/exa_wm_yuv_rgb.g8a
2653+++ b/src/render_program/exa_wm_yuv_rgb.g8a
2654@@ -76,7 +76,7 @@ add (16) Cbn<1>F Cb<8,8,1>F -0.501961F { compr align1 };
2655 /*
2656 * R = Y + Cr * 1.596
2657 */
2658-mov (8) acc0<1>F Yn<8,8,1>F { compr align1 };
2659+mov (8) acc0<1>F Yn_01<8,8,1>F { compr align1 };
2660 mac.sat(8) src_sample_r_01<1>F Crn_01<8,8,1>F 1.596F { compr align1 };
2661
2662 mov (8) acc0<1>F Yn_23<8,8,1>F { compr align1 };
2663@@ -84,7 +84,7 @@ mac.sat(8) src_sample_r_23<1>F Crn_23<8,8,1>F 1.596F { compr align1 };
2664 /*
2665 * G = Crn * -0.813 + Cbn * -0.392 + Y
2666 */
2667-mov (8) acc0<1>F Yn_23<8,8,1>F { compr align1 };
2668+mov (8) acc0<1>F Yn_01<8,8,1>F { compr align1 };
2669 mac (8) acc0<1>F Crn_01<8,8,1>F -0.813F { compr align1 };
2670 mac.sat(8) src_sample_g_01<1>F Cbn_01<8,8,1>F -0.392F { compr align1 };
2671
2672diff --git a/src/render_program/exa_wm_yuv_rgb.g8b b/src/render_program/exa_wm_yuv_rgb.g8b
2673index 4494953..2cd6fc4 100644
2674--- a/src/render_program/exa_wm_yuv_rgb.g8b
2675+++ b/src/render_program/exa_wm_yuv_rgb.g8b
2676@@ -6,7 +6,7 @@
2677 { 0x80600048, 0x21c03ae8, 0x3e8d02c0, 0x3fcc49ba },
2678 { 0x00600001, 0x24003ae0, 0x008d0320, 0x00000000 },
2679 { 0x80600048, 0x21e03ae8, 0x3e8d02e0, 0x3fcc49ba },
2680- { 0x00600001, 0x24003ae0, 0x008d0320, 0x00000000 },
2681+ { 0x00600001, 0x24003ae0, 0x008d0300, 0x00000000 },
2682 { 0x00600048, 0x24003ae0, 0x3e8d02c0, 0xbf5020c5 },
2683 { 0x80600048, 0x22003ae8, 0x3e8d0340, 0xbec8b439 },
2684 { 0x00600001, 0x24003ae0, 0x008d0320, 0x00000000 },
2685diff --git a/src/sna/blt.c b/src/sna/blt.c
2686index b5bfee6..2dae9c2 100644
2687--- a/src/sna/blt.c
2688+++ b/src/sna/blt.c
2689@@ -30,6 +30,7 @@
2690 #endif
2691
2692 #include "sna.h"
2693+#include <pixman.h>
2694
2695 #if __x86_64__
2696 #define USE_SSE2 1
2697@@ -333,420 +334,270 @@ memcpy_from_tiled_x__swizzle_0(const void *src, void *dst, int bpp,
2698 }
2699 }
2700
2701-fast_memcpy static void
2702-memcpy_to_tiled_x__swizzle_9(const void *src, void *dst, int bpp,
2703- int32_t src_stride, int32_t dst_stride,
2704- int16_t src_x, int16_t src_y,
2705- int16_t dst_x, int16_t dst_y,
2706- uint16_t width, uint16_t height)
2707-{
2708- const unsigned tile_width = 512;
2709- const unsigned tile_height = 8;
2710- const unsigned tile_size = 4096;
2711-
2712- const unsigned cpp = bpp / 8;
2713- const unsigned stride_tiles = dst_stride / tile_width;
2714- const unsigned swizzle_pixels = 64 / cpp;
2715- const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
2716- const unsigned tile_mask = (1 << tile_pixels) - 1;
2717-
2718- unsigned x, y;
2719-
2720- DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
2721- __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
2722-
2723- src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
2724-
2725- for (y = 0; y < height; ++y) {
2726- const uint32_t dy = y + dst_y;
2727- const uint32_t tile_row =
2728- (dy / tile_height * stride_tiles * tile_size +
2729- (dy & (tile_height-1)) * tile_width);
2730- const uint8_t *src_row = (const uint8_t *)src + src_stride * y;
2731- uint32_t dx = dst_x, offset;
2732-
2733- x = width * cpp;
2734- if (dx & (swizzle_pixels - 1)) {
2735- const uint32_t swizzle_bound_pixels = ALIGN(dx + 1, swizzle_pixels);
2736- const uint32_t length = min(dst_x + width, swizzle_bound_pixels) - dx;
2737- offset = tile_row +
2738- (dx >> tile_pixels) * tile_size +
2739- (dx & tile_mask) * cpp;
2740- offset ^= (offset >> 3) & 64;
2741-
2742- memcpy((char *)dst + offset, src_row, length * cpp);
2743-
2744- src_row += length * cpp;
2745- x -= length * cpp;
2746- dx += length;
2747- }
2748- while (x >= 64) {
2749- offset = tile_row +
2750- (dx >> tile_pixels) * tile_size +
2751- (dx & tile_mask) * cpp;
2752- offset ^= (offset >> 3) & 64;
2753-
2754- memcpy((char *)dst + offset, src_row, 64);
2755-
2756- src_row += 64;
2757- x -= 64;
2758- dx += swizzle_pixels;
2759- }
2760- if (x) {
2761- offset = tile_row +
2762- (dx >> tile_pixels) * tile_size +
2763- (dx & tile_mask) * cpp;
2764- offset ^= (offset >> 3) & 64;
2765- memcpy((char *)dst + offset, src_row, x);
2766- }
2767- }
2768+#define memcpy_to_tiled_x(swizzle) \
2769+fast_memcpy static void \
2770+memcpy_to_tiled_x__##swizzle (const void *src, void *dst, int bpp, \
2771+ int32_t src_stride, int32_t dst_stride, \
2772+ int16_t src_x, int16_t src_y, \
2773+ int16_t dst_x, int16_t dst_y, \
2774+ uint16_t width, uint16_t height) \
2775+{ \
2776+ const unsigned tile_width = 512; \
2777+ const unsigned tile_height = 8; \
2778+ const unsigned tile_size = 4096; \
2779+ const unsigned cpp = bpp / 8; \
2780+ const unsigned stride_tiles = dst_stride / tile_width; \
2781+ const unsigned swizzle_pixels = 64 / cpp; \
2782+ const unsigned tile_pixels = ffs(tile_width / cpp) - 1; \
2783+ const unsigned tile_mask = (1 << tile_pixels) - 1; \
2784+ unsigned x, y; \
2785+ DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n", \
2786+ __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride)); \
2787+ src = (const uint8_t *)src + src_y * src_stride + src_x * cpp; \
2788+ for (y = 0; y < height; ++y) { \
2789+ const uint32_t dy = y + dst_y; \
2790+ const uint32_t tile_row = \
2791+ (dy / tile_height * stride_tiles * tile_size + \
2792+ (dy & (tile_height-1)) * tile_width); \
2793+ const uint8_t *src_row = (const uint8_t *)src + src_stride * y; \
2794+ uint32_t dx = dst_x; \
2795+ x = width * cpp; \
2796+ if (dx & (swizzle_pixels - 1)) { \
2797+ const uint32_t swizzle_bound_pixels = ALIGN(dx + 1, swizzle_pixels); \
2798+ const uint32_t length = min(dst_x + width, swizzle_bound_pixels) - dx; \
2799+ uint32_t offset = \
2800+ tile_row + \
2801+ (dx >> tile_pixels) * tile_size + \
2802+ (dx & tile_mask) * cpp; \
2803+ memcpy((char *)dst + swizzle(offset), src_row, length * cpp); \
2804+ src_row += length * cpp; \
2805+ x -= length * cpp; \
2806+ dx += length; \
2807+ } \
2808+ while (x >= 64) { \
2809+ uint32_t offset = \
2810+ tile_row + \
2811+ (dx >> tile_pixels) * tile_size + \
2812+ (dx & tile_mask) * cpp; \
2813+ memcpy((char *)dst + swizzle(offset), src_row, 64); \
2814+ src_row += 64; \
2815+ x -= 64; \
2816+ dx += swizzle_pixels; \
2817+ } \
2818+ if (x) { \
2819+ uint32_t offset = \
2820+ tile_row + \
2821+ (dx >> tile_pixels) * tile_size + \
2822+ (dx & tile_mask) * cpp; \
2823+ memcpy((char *)dst + swizzle(offset), src_row, x); \
2824+ } \
2825+ } \
2826 }
2827
2828-fast_memcpy static void
2829-memcpy_from_tiled_x__swizzle_9(const void *src, void *dst, int bpp,
2830- int32_t src_stride, int32_t dst_stride,
2831- int16_t src_x, int16_t src_y,
2832- int16_t dst_x, int16_t dst_y,
2833- uint16_t width, uint16_t height)
2834-{
2835- const unsigned tile_width = 512;
2836- const unsigned tile_height = 8;
2837- const unsigned tile_size = 4096;
2838-
2839- const unsigned cpp = bpp / 8;
2840- const unsigned stride_tiles = src_stride / tile_width;
2841- const unsigned swizzle_pixels = 64 / cpp;
2842- const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
2843- const unsigned tile_mask = (1 << tile_pixels) - 1;
2844+#define memcpy_from_tiled_x(swizzle) \
2845+fast_memcpy static void \
2846+memcpy_from_tiled_x__##swizzle (const void *src, void *dst, int bpp, \
2847+ int32_t src_stride, int32_t dst_stride, \
2848+ int16_t src_x, int16_t src_y, \
2849+ int16_t dst_x, int16_t dst_y, \
2850+ uint16_t width, uint16_t height) \
2851+{ \
2852+ const unsigned tile_width = 512; \
2853+ const unsigned tile_height = 8; \
2854+ const unsigned tile_size = 4096; \
2855+ const unsigned cpp = bpp / 8; \
2856+ const unsigned stride_tiles = src_stride / tile_width; \
2857+ const unsigned swizzle_pixels = 64 / cpp; \
2858+ const unsigned tile_pixels = ffs(tile_width / cpp) - 1; \
2859+ const unsigned tile_mask = (1 << tile_pixels) - 1; \
2860+ unsigned x, y; \
2861+ DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n", \
2862+ __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride)); \
2863+ dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp; \
2864+ for (y = 0; y < height; ++y) { \
2865+ const uint32_t sy = y + src_y; \
2866+ const uint32_t tile_row = \
2867+ (sy / tile_height * stride_tiles * tile_size + \
2868+ (sy & (tile_height-1)) * tile_width); \
2869+ uint8_t *dst_row = (uint8_t *)dst + dst_stride * y; \
2870+ uint32_t sx = src_x; \
2871+ x = width * cpp; \
2872+ if (sx & (swizzle_pixels - 1)) { \
2873+ const uint32_t swizzle_bound_pixels = ALIGN(sx + 1, swizzle_pixels); \
2874+ const uint32_t length = min(src_x + width, swizzle_bound_pixels) - sx; \
2875+ uint32_t offset = \
2876+ tile_row + \
2877+ (sx >> tile_pixels) * tile_size + \
2878+ (sx & tile_mask) * cpp; \
2879+ memcpy(dst_row, (const char *)src + swizzle(offset), length * cpp); \
2880+ dst_row += length * cpp; \
2881+ x -= length * cpp; \
2882+ sx += length; \
2883+ } \
2884+ while (x >= 64) { \
2885+ uint32_t offset = \
2886+ tile_row + \
2887+ (sx >> tile_pixels) * tile_size + \
2888+ (sx & tile_mask) * cpp; \
2889+ memcpy(dst_row, (const char *)src + swizzle(offset), 64); \
2890+ dst_row += 64; \
2891+ x -= 64; \
2892+ sx += swizzle_pixels; \
2893+ } \
2894+ if (x) { \
2895+ uint32_t offset = \
2896+ tile_row + \
2897+ (sx >> tile_pixels) * tile_size + \
2898+ (sx & tile_mask) * cpp; \
2899+ memcpy(dst_row, (const char *)src + swizzle(offset), x); \
2900+ } \
2901+ } \
2902+}
2903
2904- unsigned x, y;
2905+#define swizzle_9(X) ((X) ^ (((X) >> 3) & 64))
2906+memcpy_to_tiled_x(swizzle_9)
2907+memcpy_from_tiled_x(swizzle_9)
2908+#undef swizzle_9
2909
2910- DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
2911- __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
2912-
2913- dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
2914-
2915- for (y = 0; y < height; ++y) {
2916- const uint32_t sy = y + src_y;
2917- const uint32_t tile_row =
2918- (sy / tile_height * stride_tiles * tile_size +
2919- (sy & (tile_height-1)) * tile_width);
2920- uint8_t *dst_row = (uint8_t *)dst + dst_stride * y;
2921- uint32_t sx = src_x, offset;
2922-
2923- x = width * cpp;
2924- if (sx & (swizzle_pixels - 1)) {
2925- const uint32_t swizzle_bound_pixels = ALIGN(sx + 1, swizzle_pixels);
2926- const uint32_t length = min(src_x + width, swizzle_bound_pixels) - sx;
2927- offset = tile_row +
2928- (sx >> tile_pixels) * tile_size +
2929- (sx & tile_mask) * cpp;
2930- offset ^= (offset >> 3) & 64;
2931-
2932- memcpy(dst_row, (const char *)src + offset, length * cpp);
2933-
2934- dst_row += length * cpp;
2935- x -= length * cpp;
2936- sx += length;
2937- }
2938- while (x >= 64) {
2939- offset = tile_row +
2940- (sx >> tile_pixels) * tile_size +
2941- (sx & tile_mask) * cpp;
2942- offset ^= (offset >> 3) & 64;
2943+#define swizzle_9_10(X) ((X) ^ ((((X) ^ ((X) >> 1)) >> 3) & 64))
2944+memcpy_to_tiled_x(swizzle_9_10)
2945+memcpy_from_tiled_x(swizzle_9_10)
2946+#undef swizzle_9_10
2947
2948- memcpy(dst_row, (const char *)src + offset, 64);
2949+#define swizzle_9_11(X) ((X) ^ ((((X) ^ ((X) >> 2)) >> 3) & 64))
2950+memcpy_to_tiled_x(swizzle_9_11)
2951+memcpy_from_tiled_x(swizzle_9_11)
2952+#undef swizzle_9_11
2953
2954- dst_row += 64;
2955- x -= 64;
2956- sx += swizzle_pixels;
2957- }
2958- if (x) {
2959- offset = tile_row +
2960- (sx >> tile_pixels) * tile_size +
2961- (sx & tile_mask) * cpp;
2962- offset ^= (offset >> 3) & 64;
2963- memcpy(dst_row, (const char *)src + offset, x);
2964- }
2965- }
2966-}
2967+#define swizzle_9_10_11(X) ((X) ^ ((((X) ^ ((X) >> 1) ^ ((X) >> 2)) >> 3) & 64))
2968+memcpy_to_tiled_x(swizzle_9_10_11)
2969+memcpy_from_tiled_x(swizzle_9_10_11)
2970+#undef swizzle_9_10_11
2971
2972-fast_memcpy static void
2973-memcpy_to_tiled_x__swizzle_9_10(const void *src, void *dst, int bpp,
2974- int32_t src_stride, int32_t dst_stride,
2975- int16_t src_x, int16_t src_y,
2976- int16_t dst_x, int16_t dst_y,
2977- uint16_t width, uint16_t height)
2978+static fast_memcpy void
2979+memcpy_to_tiled_x__gen2(const void *src, void *dst, int bpp,
2980+ int32_t src_stride, int32_t dst_stride,
2981+ int16_t src_x, int16_t src_y,
2982+ int16_t dst_x, int16_t dst_y,
2983+ uint16_t width, uint16_t height)
2984 {
2985- const unsigned tile_width = 512;
2986- const unsigned tile_height = 8;
2987- const unsigned tile_size = 4096;
2988+ const unsigned tile_width = 128;
2989+ const unsigned tile_height = 16;
2990+ const unsigned tile_size = 2048;
2991
2992 const unsigned cpp = bpp / 8;
2993- const unsigned stride_tiles = dst_stride / tile_width;
2994- const unsigned swizzle_pixels = 64 / cpp;
2995- const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
2996- const unsigned tile_mask = (1 << tile_pixels) - 1;
2997-
2998- unsigned x, y;
2999+ const unsigned tile_pixels = tile_width / cpp;
3000+ const unsigned tile_shift = ffs(tile_pixels) - 1;
3001+ const unsigned tile_mask = tile_pixels - 1;
3002
3003 DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
3004 __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
3005+ assert(src != dst);
3006
3007- src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
3008-
3009- for (y = 0; y < height; ++y) {
3010- const uint32_t dy = y + dst_y;
3011- const uint32_t tile_row =
3012- (dy / tile_height * stride_tiles * tile_size +
3013- (dy & (tile_height-1)) * tile_width);
3014- const uint8_t *src_row = (const uint8_t *)src + src_stride * y;
3015- uint32_t dx = dst_x, offset;
3016-
3017- x = width * cpp;
3018- if (dx & (swizzle_pixels - 1)) {
3019- const uint32_t swizzle_bound_pixels = ALIGN(dx + 1, swizzle_pixels);
3020- const uint32_t length = min(dst_x + width, swizzle_bound_pixels) - dx;
3021- offset = tile_row +
3022- (dx >> tile_pixels) * tile_size +
3023- (dx & tile_mask) * cpp;
3024- offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
3025-
3026- memcpy((char *)dst + offset, src_row, length * cpp);
3027-
3028- src_row += length * cpp;
3029- x -= length * cpp;
3030- dx += length;
3031- }
3032- while (x >= 64) {
3033- offset = tile_row +
3034- (dx >> tile_pixels) * tile_size +
3035- (dx & tile_mask) * cpp;
3036- offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
3037-
3038- memcpy((char *)dst + offset, src_row, 64);
3039-
3040- src_row += 64;
3041- x -= 64;
3042- dx += swizzle_pixels;
3043- }
3044- if (x) {
3045- offset = tile_row +
3046- (dx >> tile_pixels) * tile_size +
3047- (dx & tile_mask) * cpp;
3048- offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
3049- memcpy((char *)dst + offset, src_row, x);
3050- }
3051- }
3052-}
3053-
3054-fast_memcpy static void
3055-memcpy_from_tiled_x__swizzle_9_10(const void *src, void *dst, int bpp,
3056- int32_t src_stride, int32_t dst_stride,
3057- int16_t src_x, int16_t src_y,
3058- int16_t dst_x, int16_t dst_y,
3059- uint16_t width, uint16_t height)
3060-{
3061- const unsigned tile_width = 512;
3062- const unsigned tile_height = 8;
3063- const unsigned tile_size = 4096;
3064-
3065- const unsigned cpp = bpp / 8;
3066- const unsigned stride_tiles = src_stride / tile_width;
3067- const unsigned swizzle_pixels = 64 / cpp;
3068- const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
3069- const unsigned tile_mask = (1 << tile_pixels) - 1;
3070+ if (src_x | src_y)
3071+ src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
3072+ assert(src_stride >= width * cpp);
3073+ src_stride -= width * cpp;
3074
3075- unsigned x, y;
3076+ while (height--) {
3077+ unsigned w = width * cpp;
3078+ uint8_t *tile_row = dst;
3079
3080- DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
3081- __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
3082+ tile_row += dst_y / tile_height * dst_stride * tile_height;
3083+ tile_row += (dst_y & (tile_height-1)) * tile_width;
3084+ if (dst_x) {
3085+ tile_row += (dst_x >> tile_shift) * tile_size;
3086+ if (dst_x & tile_mask) {
3087+ const unsigned x = (dst_x & tile_mask) * cpp;
3088+ const unsigned len = min(tile_width - x, w);
3089+ memcpy(tile_row + x, src, len);
3090
3091- dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
3092-
3093- for (y = 0; y < height; ++y) {
3094- const uint32_t sy = y + src_y;
3095- const uint32_t tile_row =
3096- (sy / tile_height * stride_tiles * tile_size +
3097- (sy & (tile_height-1)) * tile_width);
3098- uint8_t *dst_row = (uint8_t *)dst + dst_stride * y;
3099- uint32_t sx = src_x, offset;
3100-
3101- x = width * cpp;
3102- if (sx & (swizzle_pixels - 1)) {
3103- const uint32_t swizzle_bound_pixels = ALIGN(sx + 1, swizzle_pixels);
3104- const uint32_t length = min(src_x + width, swizzle_bound_pixels) - sx;
3105- offset = tile_row +
3106- (sx >> tile_pixels) * tile_size +
3107- (sx & tile_mask) * cpp;
3108- offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
3109-
3110- memcpy(dst_row, (const char *)src + offset, length * cpp);
3111-
3112- dst_row += length * cpp;
3113- x -= length * cpp;
3114- sx += length;
3115+ tile_row += tile_size;
3116+ src = (const uint8_t *)src + len;
3117+ w -= len;
3118+ }
3119 }
3120- while (x >= 64) {
3121- offset = tile_row +
3122- (sx >> tile_pixels) * tile_size +
3123- (sx & tile_mask) * cpp;
3124- offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
3125-
3126- memcpy(dst_row, (const char *)src + offset, 64);
3127+ while (w >= tile_width) {
3128+ memcpy(tile_row, src, tile_width);
3129
3130- dst_row += 64;
3131- x -= 64;
3132- sx += swizzle_pixels;
3133- }
3134- if (x) {
3135- offset = tile_row +
3136- (sx >> tile_pixels) * tile_size +
3137- (sx & tile_mask) * cpp;
3138- offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
3139- memcpy(dst_row, (const char *)src + offset, x);
3140+ tile_row += tile_size;
3141+ src = (const uint8_t *)src + tile_width;
3142+ w -= tile_width;
3143 }
3144+ memcpy(tile_row, src, w);
3145+ src = (const uint8_t *)src + src_stride + w;
3146+ dst_y++;
3147 }
3148 }
3149
3150-fast_memcpy static void
3151-memcpy_to_tiled_x__swizzle_9_11(const void *src, void *dst, int bpp,
3152- int32_t src_stride, int32_t dst_stride,
3153- int16_t src_x, int16_t src_y,
3154- int16_t dst_x, int16_t dst_y,
3155- uint16_t width, uint16_t height)
3156+static fast_memcpy void
3157+memcpy_from_tiled_x__gen2(const void *src, void *dst, int bpp,
3158+ int32_t src_stride, int32_t dst_stride,
3159+ int16_t src_x, int16_t src_y,
3160+ int16_t dst_x, int16_t dst_y,
3161+ uint16_t width, uint16_t height)
3162 {
3163- const unsigned tile_width = 512;
3164- const unsigned tile_height = 8;
3165- const unsigned tile_size = 4096;
3166+ const unsigned tile_width = 128;
3167+ const unsigned tile_height = 16;
3168+ const unsigned tile_size = 2048;
3169
3170 const unsigned cpp = bpp / 8;
3171- const unsigned stride_tiles = dst_stride / tile_width;
3172- const unsigned swizzle_pixels = 64 / cpp;
3173- const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
3174- const unsigned tile_mask = (1 << tile_pixels) - 1;
3175-
3176- unsigned x, y;
3177+ const unsigned tile_pixels = tile_width / cpp;
3178+ const unsigned tile_shift = ffs(tile_pixels) - 1;
3179+ const unsigned tile_mask = tile_pixels - 1;
3180
3181 DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
3182 __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
3183+ assert(src != dst);
3184
3185- src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
3186-
3187- for (y = 0; y < height; ++y) {
3188- const uint32_t dy = y + dst_y;
3189- const uint32_t tile_row =
3190- (dy / tile_height * stride_tiles * tile_size +
3191- (dy & (tile_height-1)) * tile_width);
3192- const uint8_t *src_row = (const uint8_t *)src + src_stride * y;
3193- uint32_t dx = dst_x, offset;
3194-
3195- x = width * cpp;
3196- if (dx & (swizzle_pixels - 1)) {
3197- const uint32_t swizzle_bound_pixels = ALIGN(dx + 1, swizzle_pixels);
3198- const uint32_t length = min(dst_x + width, swizzle_bound_pixels) - dx;
3199- offset = tile_row +
3200- (dx >> tile_pixels) * tile_size +
3201- (dx & tile_mask) * cpp;
3202- offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
3203- memcpy((char *)dst + offset, src_row, length * cpp);
3204-
3205- src_row += length * cpp;
3206- x -= length * cpp;
3207- dx += length;
3208- }
3209- while (x >= 64) {
3210- offset = tile_row +
3211- (dx >> tile_pixels) * tile_size +
3212- (dx & tile_mask) * cpp;
3213- offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
3214-
3215- memcpy((char *)dst + offset, src_row, 64);
3216-
3217- src_row += 64;
3218- x -= 64;
3219- dx += swizzle_pixels;
3220- }
3221- if (x) {
3222- offset = tile_row +
3223- (dx >> tile_pixels) * tile_size +
3224- (dx & tile_mask) * cpp;
3225- offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
3226- memcpy((char *)dst + offset, src_row, x);
3227- }
3228- }
3229-}
3230-
3231-fast_memcpy static void
3232-memcpy_from_tiled_x__swizzle_9_11(const void *src, void *dst, int bpp,
3233- int32_t src_stride, int32_t dst_stride,
3234- int16_t src_x, int16_t src_y,
3235- int16_t dst_x, int16_t dst_y,
3236- uint16_t width, uint16_t height)
3237-{
3238- const unsigned tile_width = 512;
3239- const unsigned tile_height = 8;
3240- const unsigned tile_size = 4096;
3241-
3242- const unsigned cpp = bpp / 8;
3243- const unsigned stride_tiles = src_stride / tile_width;
3244- const unsigned swizzle_pixels = 64 / cpp;
3245- const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
3246- const unsigned tile_mask = (1 << tile_pixels) - 1;
3247+ if (dst_x | dst_y)
3248+ dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
3249+ assert(dst_stride >= width * cpp);
3250+ dst_stride -= width * cpp;
3251
3252- unsigned x, y;
3253+ while (height--) {
3254+ unsigned w = width * cpp;
3255+ const uint8_t *tile_row = src;
3256
3257- DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
3258- __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
3259+ tile_row += src_y / tile_height * src_stride * tile_height;
3260+ tile_row += (src_y & (tile_height-1)) * tile_width;
3261+ if (src_x) {
3262+ tile_row += (src_x >> tile_shift) * tile_size;
3263+ if (src_x & tile_mask) {
3264+ const unsigned x = (src_x & tile_mask) * cpp;
3265+ const unsigned len = min(tile_width - x, w);
3266+ memcpy(dst, tile_row + x, len);
3267
3268- dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
3269-
3270- for (y = 0; y < height; ++y) {
3271- const uint32_t sy = y + src_y;
3272- const uint32_t tile_row =
3273- (sy / tile_height * stride_tiles * tile_size +
3274- (sy & (tile_height-1)) * tile_width);
3275- uint8_t *dst_row = (uint8_t *)dst + dst_stride * y;
3276- uint32_t sx = src_x, offset;
3277-
3278- x = width * cpp;
3279- if (sx & (swizzle_pixels - 1)) {
3280- const uint32_t swizzle_bound_pixels = ALIGN(sx + 1, swizzle_pixels);
3281- const uint32_t length = min(src_x + width, swizzle_bound_pixels) - sx;
3282- offset = tile_row +
3283- (sx >> tile_pixels) * tile_size +
3284- (sx & tile_mask) * cpp;
3285- offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
3286- memcpy(dst_row, (const char *)src + offset, length * cpp);
3287-
3288- dst_row += length * cpp;
3289- x -= length * cpp;
3290- sx += length;
3291+ tile_row += tile_size;
3292+ dst = (uint8_t *)dst + len;
3293+ w -= len;
3294+ }
3295 }
3296- while (x >= 64) {
3297- offset = tile_row +
3298- (sx >> tile_pixels) * tile_size +
3299- (sx & tile_mask) * cpp;
3300- offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
3301-
3302- memcpy(dst_row, (const char *)src + offset, 64);
3303+ while (w >= tile_width) {
3304+ memcpy(dst, tile_row, tile_width);
3305
3306- dst_row += 64;
3307- x -= 64;
3308- sx += swizzle_pixels;
3309- }
3310- if (x) {
3311- offset = tile_row +
3312- (sx >> tile_pixels) * tile_size +
3313- (sx & tile_mask) * cpp;
3314- offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
3315- memcpy(dst_row, (const char *)src + offset, x);
3316+ tile_row += tile_size;
3317+ dst = (uint8_t *)dst + tile_width;
3318+ w -= tile_width;
3319 }
3320+ memcpy(dst, tile_row, w);
3321+ dst = (uint8_t *)dst + dst_stride + w;
3322+ src_y++;
3323 }
3324 }
3325
3326 void choose_memcpy_tiled_x(struct kgem *kgem, int swizzling)
3327 {
3328+ if (kgem->gen < 030) {
3329+ if (swizzling == I915_BIT_6_SWIZZLE_NONE) {
3330+ DBG(("%s: gen2, no swizzling\n", __FUNCTION__));
3331+ kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__gen2;
3332+ kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__gen2;
3333+ } else
3334+ DBG(("%s: no detiling with swizzle functions for gen2\n", __FUNCTION__));
3335+ return;
3336+ }
3337+
3338 switch (swizzling) {
3339 default:
3340 DBG(("%s: unknown swizzling, %d\n", __FUNCTION__, swizzling));
3341@@ -771,6 +622,11 @@ void choose_memcpy_tiled_x(struct kgem *kgem, int swizzling)
3342 kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__swizzle_9_11;
3343 kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__swizzle_9_11;
3344 break;
3345+ case I915_BIT_6_SWIZZLE_9_10_11:
3346+ DBG(("%s: 6^9^10^11 swizzling\n", __FUNCTION__));
3347+ kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__swizzle_9_10_11;
3348+ kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__swizzle_9_10_11;
3349+ break;
3350 }
3351 }
3352
3353@@ -1118,3 +974,241 @@ memcpy_xor(const void *src, void *dst, int bpp,
3354 }
3355 }
3356 }
3357+
3358+#define BILINEAR_INTERPOLATION_BITS 4
3359+static inline int
3360+bilinear_weight(pixman_fixed_t x)
3361+{
3362+ return (x >> (16 - BILINEAR_INTERPOLATION_BITS)) &
3363+ ((1 << BILINEAR_INTERPOLATION_BITS) - 1);
3364+}
3365+
3366+#if BILINEAR_INTERPOLATION_BITS <= 4
3367+/* Inspired by Filter_32_opaque from Skia */
3368+static inline uint32_t
3369+bilinear_interpolation(uint32_t tl, uint32_t tr,
3370+ uint32_t bl, uint32_t br,
3371+ int distx, int disty)
3372+{
3373+ int distxy, distxiy, distixy, distixiy;
3374+ uint32_t lo, hi;
3375+
3376+ distx <<= (4 - BILINEAR_INTERPOLATION_BITS);
3377+ disty <<= (4 - BILINEAR_INTERPOLATION_BITS);
3378+
3379+ distxy = distx * disty;
3380+ distxiy = (distx << 4) - distxy; /* distx * (16 - disty) */
3381+ distixy = (disty << 4) - distxy; /* disty * (16 - distx) */
3382+ distixiy =
3383+ 16 * 16 - (disty << 4) -
3384+ (distx << 4) + distxy; /* (16 - distx) * (16 - disty) */
3385+
3386+ lo = (tl & 0xff00ff) * distixiy;
3387+ hi = ((tl >> 8) & 0xff00ff) * distixiy;
3388+
3389+ lo += (tr & 0xff00ff) * distxiy;
3390+ hi += ((tr >> 8) & 0xff00ff) * distxiy;
3391+
3392+ lo += (bl & 0xff00ff) * distixy;
3393+ hi += ((bl >> 8) & 0xff00ff) * distixy;
3394+
3395+ lo += (br & 0xff00ff) * distxy;
3396+ hi += ((br >> 8) & 0xff00ff) * distxy;
3397+
3398+ return ((lo >> 8) & 0xff00ff) | (hi & ~0xff00ff);
3399+}
3400+#elif SIZEOF_LONG > 4
3401+static inline uint32_t
3402+bilinear_interpolation(uint32_t tl, uint32_t tr,
3403+ uint32_t bl, uint32_t br,
3404+ int distx, int disty)
3405+{
3406+ uint64_t distxy, distxiy, distixy, distixiy;
3407+ uint64_t tl64, tr64, bl64, br64;
3408+ uint64_t f, r;
3409+
3410+ distx <<= (8 - BILINEAR_INTERPOLATION_BITS);
3411+ disty <<= (8 - BILINEAR_INTERPOLATION_BITS);
3412+
3413+ distxy = distx * disty;
3414+ distxiy = distx * (256 - disty);
3415+ distixy = (256 - distx) * disty;
3416+ distixiy = (256 - distx) * (256 - disty);
3417+
3418+ /* Alpha and Blue */
3419+ tl64 = tl & 0xff0000ff;
3420+ tr64 = tr & 0xff0000ff;
3421+ bl64 = bl & 0xff0000ff;
3422+ br64 = br & 0xff0000ff;
3423+
3424+ f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
3425+ r = f & 0x0000ff0000ff0000ull;
3426+
3427+ /* Red and Green */
3428+ tl64 = tl;
3429+ tl64 = ((tl64 << 16) & 0x000000ff00000000ull) | (tl64 & 0x0000ff00ull);
3430+
3431+ tr64 = tr;
3432+ tr64 = ((tr64 << 16) & 0x000000ff00000000ull) | (tr64 & 0x0000ff00ull);
3433+
3434+ bl64 = bl;
3435+ bl64 = ((bl64 << 16) & 0x000000ff00000000ull) | (bl64 & 0x0000ff00ull);
3436+
3437+ br64 = br;
3438+ br64 = ((br64 << 16) & 0x000000ff00000000ull) | (br64 & 0x0000ff00ull);
3439+
3440+ f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
3441+ r |= ((f >> 16) & 0x000000ff00000000ull) | (f & 0xff000000ull);
3442+
3443+ return (uint32_t)(r >> 16);
3444+}
3445+#else
3446+static inline uint32_t
3447+bilinear_interpolation(uint32_t tl, uint32_t tr,
3448+ uint32_t bl, uint32_t br,
3449+ int distx, int disty)
3450+{
3451+ int distxy, distxiy, distixy, distixiy;
3452+ uint32_t f, r;
3453+
3454+ distx <<= (8 - BILINEAR_INTERPOLATION_BITS);
3455+ disty <<= (8 - BILINEAR_INTERPOLATION_BITS);
3456+
3457+ distxy = distx * disty;
3458+ distxiy = (distx << 8) - distxy; /* distx * (256 - disty) */
3459+ distixy = (disty << 8) - distxy; /* disty * (256 - distx) */
3460+ distixiy =
3461+ 256 * 256 - (disty << 8) -
3462+ (distx << 8) + distxy; /* (256 - distx) * (256 - disty) */
3463+
3464+ /* Blue */
3465+ r = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy +
3466+ (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy);
3467+
3468+ /* Green */
3469+ f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy +
3470+ (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy);
3471+ r |= f & 0xff000000;
3472+
3473+ tl >>= 16;
3474+ tr >>= 16;
3475+ bl >>= 16;
3476+ br >>= 16;
3477+ r >>= 16;
3478+
3479+ /* Red */
3480+ f = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy +
3481+ (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy);
3482+ r |= f & 0x00ff0000;
3483+
3484+ /* Alpha */
3485+ f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy +
3486+ (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy);
3487+ r |= f & 0xff000000;
3488+
3489+ return r;
3490+}
3491+#endif
3492+
3493+static inline uint32_t convert_pixel(const uint8_t *p, int x)
3494+{
3495+ return ((uint32_t *)p)[x];
3496+}
3497+
3498+fast void
3499+affine_blt(const void *src, void *dst, int bpp,
3500+ int16_t src_x, int16_t src_y,
3501+ int16_t src_width, int16_t src_height,
3502+ int32_t src_stride,
3503+ int16_t dst_x, int16_t dst_y,
3504+ uint16_t dst_width, uint16_t dst_height,
3505+ int32_t dst_stride,
3506+ const struct pixman_f_transform *t)
3507+{
3508+ static const uint8_t zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
3509+ const pixman_fixed_t ux = pixman_double_to_fixed(t->m[0][0]);
3510+ const pixman_fixed_t uy = pixman_double_to_fixed(t->m[1][0]);
3511+ int i, j;
3512+
3513+ assert(bpp == 32);
3514+
3515+ for (j = 0; j < dst_height; j++) {
3516+ pixman_fixed_t x, y;
3517+ struct pixman_f_vector v;
3518+ uint32_t *b;
3519+
3520+ /* reference point is the center of the pixel */
3521+ v.v[0] = dst_x + 0.5;
3522+ v.v[1] = dst_y + j + 0.5;
3523+ v.v[2] = 1.0;
3524+
3525+ pixman_f_transform_point_3d(t, &v);
3526+
3527+ x = pixman_double_to_fixed(v.v[0]);
3528+ x += pixman_int_to_fixed(src_x - dst_x);
3529+ y = pixman_double_to_fixed(v.v[1]);
3530+ y += pixman_int_to_fixed(src_y - dst_y);
3531+
3532+ b = (uint32_t*)((uint8_t *)dst + (dst_y + j) * dst_stride + dst_x * bpp / 8);
3533+ for (i = 0; i < dst_width; i++) {
3534+ const uint8_t *row1;
3535+ const uint8_t *row2;
3536+ int x1, y1, x2, y2;
3537+ uint32_t tl, tr, bl, br;
3538+ int32_t fx, fy;
3539+
3540+ x1 = x - pixman_fixed_1/2;
3541+ y1 = y - pixman_fixed_1/2;
3542+
3543+ fx = bilinear_weight(x1);
3544+ fy = bilinear_weight(y1);
3545+
3546+ x1 = pixman_fixed_to_int(x1);
3547+ x2 = x1 + 1;
3548+ y1 = pixman_fixed_to_int(y1);
3549+ y2 = y1 + 1;
3550+
3551+ if (x1 >= src_width || x2 < 0 ||
3552+ y1 >= src_height || y2 < 0) {
3553+ b[i] = 0;
3554+ goto next;
3555+ }
3556+
3557+ if (y2 == 0) {
3558+ row1 = zero;
3559+ } else {
3560+ row1 = (uint8_t *)src + src_stride * y1;
3561+ row1 += bpp / 8 * x1;
3562+ }
3563+
3564+ if (y1 == src_height - 1) {
3565+ row2 = zero;
3566+ } else {
3567+ row2 = (uint8_t *)src + src_stride * y2;
3568+ row2 += bpp / 8 * x1;
3569+ }
3570+
3571+ if (x2 == 0) {
3572+ tl = 0;
3573+ bl = 0;
3574+ } else {
3575+ tl = convert_pixel(row1, 0);
3576+ bl = convert_pixel(row2, 0);
3577+ }
3578+
3579+ if (x1 == src_width - 1) {
3580+ tr = 0;
3581+ br = 0;
3582+ } else {
3583+ tr = convert_pixel(row1, 1);
3584+ br = convert_pixel(row2, 1);
3585+ }
3586+
3587+ b[i] = bilinear_interpolation(tl, tr, bl, br, fx, fy);
3588+
3589+next:
3590+ x += ux;
3591+ y += uy;
3592+ }
3593+ }
3594+}
3595diff --git a/src/sna/brw/brw_eu_emit.c b/src/sna/brw/brw_eu_emit.c
3596index 00c984d..2f33022 100644
3597--- a/src/sna/brw/brw_eu_emit.c
3598+++ b/src/sna/brw/brw_eu_emit.c
3599@@ -700,7 +700,7 @@ push_if_stack(struct brw_compile *p, struct brw_instruction *inst)
3600 *
3601 * When the matching 'else' instruction is reached (presumably by
3602 * countdown of the instruction count patched in by our ELSE/ENDIF
3603- * functions), the relevent flags are inverted.
3604+ * functions), the relevant flags are inverted.
3605 *
3606 * When the matching 'endif' instruction is reached, the flags are
3607 * popped off. If the stack is now empty, normal execution resumes.
3608diff --git a/src/sna/compiler.h b/src/sna/compiler.h
3609index ff41217..c723137 100644
3610--- a/src/sna/compiler.h
3611+++ b/src/sna/compiler.h
3612@@ -39,6 +39,7 @@
3613 #define pure __attribute__((pure))
3614 #define tightly_packed __attribute__((__packed__))
3615 #define flatten __attribute__((flatten))
3616+#define nonnull __attribute__((nonnull))
3617 #define page_aligned __attribute__((aligned(4096)))
3618 #else
3619 #define likely(expr) (expr)
3620@@ -51,6 +52,7 @@
3621 #define pure
3622 #define tighly_packed
3623 #define flatten
3624+#define nonnull
3625 #define page_aligned
3626 #endif
3627
3628@@ -61,20 +63,18 @@
3629 #define sse4_2 __attribute__((target("sse4.2,sse2,fpmath=sse")))
3630 #endif
3631
3632-#if HAS_GCC(4, 7)
3633-#define avx2 __attribute__((target("avx2,sse4.2,sse2,fpmath=sse")))
3634-#endif
3635-
3636 #if HAS_GCC(4, 6) && defined(__OPTIMIZE__)
3637 #define fast __attribute__((optimize("Ofast")))
3638 #else
3639 #define fast
3640 #endif
3641
3642-#if HAS_GCC(4, 6) && defined(__OPTIMIZE__)
3643-#define fast_memcpy __attribute__((optimize("Ofast"))) __attribute__((target("inline-all-stringops")))
3644-#elif HAS_GCC(4, 5) && defined(__OPTIMIZE__)
3645-#define fast_memcpy __attribute__((target("inline-all-stringops")))
3646+#if HAS_GCC(4, 7)
3647+#define avx2 fast __attribute__((target("avx2,avx,sse4.2,sse2,fpmath=sse")))
3648+#endif
3649+
3650+#if HAS_GCC(4, 5) && defined(__OPTIMIZE__)
3651+#define fast_memcpy fast __attribute__((target("inline-all-stringops")))
3652 #else
3653 #define fast_memcpy
3654 #endif
3655diff --git a/src/sna/fb/fb.h b/src/sna/fb/fb.h
3656index 8bf9008..9043174 100644
3657--- a/src/sna/fb/fb.h
3658+++ b/src/sna/fb/fb.h
3659@@ -24,10 +24,6 @@
3660 #ifndef FB_H
3661 #define FB_H
3662
3663-#ifdef HAVE_CONFIG_H
3664-#include "config.h"
3665-#endif
3666-
3667 #include <xorg-server.h>
3668 #include <servermd.h>
3669 #include <gcstruct.h>
3670diff --git a/src/sna/fb/fbpict.h b/src/sna/fb/fbpict.h
3671index 932032f..2087777 100644
3672--- a/src/sna/fb/fbpict.h
3673+++ b/src/sna/fb/fbpict.h
3674@@ -24,10 +24,6 @@
3675 #ifndef FBPICT_H
3676 #define FBPICT_H
3677
3678-#ifdef HAVE_CONFIG_H
3679-#include "config.h"
3680-#endif
3681-
3682 #include <xorg-server.h>
3683 #include <picturestr.h>
3684
3685diff --git a/src/sna/gen2_render.c b/src/sna/gen2_render.c
3686index 1104f46..12b741c 100644
3687--- a/src/sna/gen2_render.c
3688+++ b/src/sna/gen2_render.c
3689@@ -1572,12 +1572,12 @@ gen2_composite_picture(struct sna *sna,
3690 if (channel->repeat &&
3691 (x >= 0 &&
3692 y >= 0 &&
3693- x + w < pixmap->drawable.width &&
3694- y + h < pixmap->drawable.height)) {
3695+ x + w <= pixmap->drawable.width &&
3696+ y + h <= pixmap->drawable.height)) {
3697 struct sna_pixmap *priv = sna_pixmap(pixmap);
3698 if (priv && priv->clear) {
3699 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
3700- return gen2_composite_solid_init(sna, channel, priv->clear_color);
3701+ return gen2_composite_solid_init(sna, channel, solid_color(picture->format, priv->clear_color));
3702 }
3703 }
3704 } else
3705diff --git a/src/sna/gen3_render.c b/src/sna/gen3_render.c
3706index 78289f0..2d3fb1e 100644
3707--- a/src/sna/gen3_render.c
3708+++ b/src/sna/gen3_render.c
3709@@ -531,6 +531,7 @@ gen3_emit_composite_primitive_affine_gradient(struct sna *sna,
3710
3711 v = sna->render.vertices + sna->render.vertex_used;
3712 sna->render.vertex_used += 12;
3713+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3714
3715 v[0] = dst_x + r->width;
3716 v[1] = dst_y + r->height;
3717@@ -596,6 +597,7 @@ gen3_emit_composite_primitive_identity_source(struct sna *sna,
3718
3719 v = sna->render.vertices + sna->render.vertex_used;
3720 sna->render.vertex_used += 12;
3721+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3722
3723 v[8] = v[4] = r->dst.x + op->dst.x;
3724 v[0] = v[4] + w;
3725@@ -643,6 +645,7 @@ gen3_emit_composite_primitive_identity_source_no_offset(struct sna *sna,
3726
3727 v = sna->render.vertices + sna->render.vertex_used;
3728 sna->render.vertex_used += 12;
3729+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3730
3731 v[8] = v[4] = r->dst.x;
3732 v[9] = r->dst.y;
3733@@ -693,6 +696,7 @@ gen3_emit_composite_primitive_affine_source(struct sna *sna,
3734
3735 v = sna->render.vertices + sna->render.vertex_used;
3736 sna->render.vertex_used += 12;
3737+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3738
3739 v[0] = dst_x + r->width;
3740 v[5] = v[1] = dst_y + r->height;
3741@@ -756,6 +760,7 @@ gen3_emit_composite_primitive_constant_identity_mask(struct sna *sna,
3742
3743 v = sna->render.vertices + sna->render.vertex_used;
3744 sna->render.vertex_used += 12;
3745+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3746
3747 v[8] = v[4] = r->dst.x + op->dst.x;
3748 v[0] = v[4] + w;
3749@@ -781,6 +786,7 @@ gen3_emit_composite_primitive_constant_identity_mask_no_offset(struct sna *sna,
3750
3751 v = sna->render.vertices + sna->render.vertex_used;
3752 sna->render.vertex_used += 12;
3753+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3754
3755 v[8] = v[4] = r->dst.x;
3756 v[9] = r->dst.y;
3757@@ -817,6 +823,7 @@ gen3_emit_composite_primitive_identity_source_mask(struct sna *sna,
3758
3759 v = sna->render.vertices + sna->render.vertex_used;
3760 sna->render.vertex_used += 18;
3761+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3762
3763 v[0] = dst_x + w;
3764 v[1] = dst_y + h;
3765@@ -862,6 +869,7 @@ gen3_emit_composite_primitive_affine_source_mask(struct sna *sna,
3766
3767 v = sna->render.vertices + sna->render.vertex_used;
3768 sna->render.vertex_used += 18;
3769+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3770
3771 v[0] = dst_x + w;
3772 v[1] = dst_y + h;
3773@@ -978,6 +986,7 @@ gen3_emit_composite_primitive_constant__sse2(struct sna *sna,
3774
3775 v = sna->render.vertices + sna->render.vertex_used;
3776 sna->render.vertex_used += 6;
3777+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3778
3779 v[4] = v[2] = r->dst.x + op->dst.x;
3780 v[5] = r->dst.y + op->dst.y;
3781@@ -1013,6 +1022,7 @@ gen3_emit_composite_primitive_identity_gradient__sse2(struct sna *sna,
3782
3783 v = sna->render.vertices + sna->render.vertex_used;
3784 sna->render.vertex_used += 12;
3785+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3786
3787 x = r->dst.x + op->dst.x;
3788 y = r->dst.y + op->dst.y;
3789@@ -1067,6 +1077,7 @@ gen3_emit_composite_primitive_affine_gradient__sse2(struct sna *sna,
3790
3791 v = sna->render.vertices + sna->render.vertex_used;
3792 sna->render.vertex_used += 12;
3793+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3794
3795 v[0] = dst_x + r->width;
3796 v[1] = dst_y + r->height;
3797@@ -1132,6 +1143,7 @@ gen3_emit_composite_primitive_identity_source__sse2(struct sna *sna,
3798
3799 v = sna->render.vertices + sna->render.vertex_used;
3800 sna->render.vertex_used += 12;
3801+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3802
3803 v[8] = v[4] = r->dst.x + op->dst.x;
3804 v[0] = v[4] + w;
3805@@ -1179,6 +1191,7 @@ gen3_emit_composite_primitive_identity_source_no_offset__sse2(struct sna *sna,
3806
3807 v = sna->render.vertices + sna->render.vertex_used;
3808 sna->render.vertex_used += 12;
3809+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3810
3811 v[8] = v[4] = r->dst.x;
3812 v[9] = r->dst.y;
3813@@ -1229,6 +1242,7 @@ gen3_emit_composite_primitive_affine_source__sse2(struct sna *sna,
3814
3815 v = sna->render.vertices + sna->render.vertex_used;
3816 sna->render.vertex_used += 12;
3817+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3818
3819 v[0] = dst_x + r->width;
3820 v[5] = v[1] = dst_y + r->height;
3821@@ -1292,6 +1306,7 @@ gen3_emit_composite_primitive_constant_identity_mask__sse2(struct sna *sna,
3822
3823 v = sna->render.vertices + sna->render.vertex_used;
3824 sna->render.vertex_used += 12;
3825+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3826
3827 v[8] = v[4] = r->dst.x + op->dst.x;
3828 v[0] = v[4] + w;
3829@@ -1317,6 +1332,7 @@ gen3_emit_composite_primitive_constant_identity_mask_no_offset__sse2(struct sna
3830
3831 v = sna->render.vertices + sna->render.vertex_used;
3832 sna->render.vertex_used += 12;
3833+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3834
3835 v[8] = v[4] = r->dst.x;
3836 v[9] = r->dst.y;
3837@@ -1353,6 +1369,7 @@ gen3_emit_composite_primitive_identity_source_mask__sse2(struct sna *sna,
3838
3839 v = sna->render.vertices + sna->render.vertex_used;
3840 sna->render.vertex_used += 18;
3841+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3842
3843 v[0] = dst_x + w;
3844 v[1] = dst_y + h;
3845@@ -1398,6 +1415,7 @@ gen3_emit_composite_primitive_affine_source_mask__sse2(struct sna *sna,
3846
3847 v = sna->render.vertices + sna->render.vertex_used;
3848 sna->render.vertex_used += 18;
3849+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3850
3851 v[0] = dst_x + w;
3852 v[1] = dst_y + h;
3853@@ -2233,6 +2251,7 @@ static void gen3_vertex_flush(struct sna *sna)
3854 static int gen3_vertex_finish(struct sna *sna)
3855 {
3856 struct kgem_bo *bo;
3857+ unsigned hint, size;
3858
3859 DBG(("%s: used=%d/%d, vbo active? %d\n",
3860 __FUNCTION__, sna->render.vertex_used, sna->render.vertex_size,
3861@@ -2243,6 +2262,7 @@ static int gen3_vertex_finish(struct sna *sna)
3862
3863 sna_vertex_wait__locked(&sna->render);
3864
3865+ hint = CREATE_GTT_MAP;
3866 bo = sna->render.vbo;
3867 if (bo) {
3868 DBG(("%s: reloc = %d\n", __FUNCTION__,
3869@@ -2251,7 +2271,7 @@ static int gen3_vertex_finish(struct sna *sna)
3870 if (sna->render.vertex_reloc[0]) {
3871 sna->kgem.batch[sna->render.vertex_reloc[0]] =
3872 kgem_add_reloc(&sna->kgem, sna->render.vertex_reloc[0],
3873- bo, I915_GEM_DOMAIN_VERTEX << 16, 0);
3874+ bo, I915_GEM_DOMAIN_VERTEX << 16 | KGEM_RELOC_FENCED, 0);
3875
3876 sna->render.vertex_reloc[0] = 0;
3877 }
3878@@ -2260,17 +2280,29 @@ static int gen3_vertex_finish(struct sna *sna)
3879 sna->render.vbo = NULL;
3880
3881 kgem_bo_destroy(&sna->kgem, bo);
3882+ hint |= CREATE_CACHED | CREATE_NO_THROTTLE;
3883 }
3884
3885+ size = 256*1024;
3886 sna->render.vertices = NULL;
3887- sna->render.vbo = kgem_create_linear(&sna->kgem,
3888- 256*1024, CREATE_GTT_MAP);
3889- if (sna->render.vbo)
3890+ sna->render.vbo = kgem_create_linear(&sna->kgem, size, hint);
3891+ while (sna->render.vbo == NULL && size > sizeof(sna->render.vertex_data)) {
3892+ size /= 2;
3893+ sna->render.vbo = kgem_create_linear(&sna->kgem, size, hint);
3894+ }
3895+ if (sna->render.vbo == NULL)
3896+ sna->render.vbo = kgem_create_linear(&sna->kgem,
3897+ 256*1024, CREATE_GTT_MAP);
3898+ if (sna->render.vbo &&
3899+ kgem_check_bo(&sna->kgem, sna->render.vbo, NULL))
3900 sna->render.vertices = kgem_bo_map(&sna->kgem, sna->render.vbo);
3901 if (sna->render.vertices == NULL) {
3902- if (sna->render.vbo)
3903+ if (sna->render.vbo) {
3904 kgem_bo_destroy(&sna->kgem, sna->render.vbo);
3905- sna->render.vbo = NULL;
3906+ sna->render.vbo = NULL;
3907+ }
3908+ sna->render.vertices = sna->render.vertex_data;
3909+ sna->render.vertex_size = ARRAY_SIZE(sna->render.vertex_data);
3910 return 0;
3911 }
3912 assert(sna->render.vbo->snoop == false);
3913@@ -2280,8 +2312,14 @@ static int gen3_vertex_finish(struct sna *sna)
3914 sna->render.vertex_data,
3915 sizeof(float)*sna->render.vertex_used);
3916 }
3917- sna->render.vertex_size = 64 * 1024 - 1;
3918- return sna->render.vertex_size - sna->render.vertex_used;
3919+
3920+ size = __kgem_bo_size(sna->render.vbo)/4;
3921+ if (size >= UINT16_MAX)
3922+ size = UINT16_MAX - 1;
3923+ assert(size > sna->render.vertex_used);
3924+
3925+ sna->render.vertex_size = size;
3926+ return size - sna->render.vertex_used;
3927 }
3928
3929 static void gen3_vertex_close(struct sna *sna)
3930@@ -2345,7 +2383,7 @@ static void gen3_vertex_close(struct sna *sna)
3931 DBG(("%s: reloc = %d\n", __FUNCTION__, sna->render.vertex_reloc[0]));
3932 sna->kgem.batch[sna->render.vertex_reloc[0]] =
3933 kgem_add_reloc(&sna->kgem, sna->render.vertex_reloc[0],
3934- bo, I915_GEM_DOMAIN_VERTEX << 16, delta);
3935+ bo, I915_GEM_DOMAIN_VERTEX << 16 | KGEM_RELOC_FENCED, delta);
3936 sna->render.vertex_reloc[0] = 0;
3937
3938 if (sna->render.vbo == NULL) {
3939@@ -2580,6 +2618,7 @@ gen3_render_composite_boxes(struct sna *sna,
3940
3941 v = sna->render.vertices + sna->render.vertex_used;
3942 sna->render.vertex_used += nbox_this_time * op->floats_per_rect;
3943+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3944
3945 op->emit_boxes(op, box, nbox_this_time, v);
3946 box += nbox_this_time;
3947@@ -2604,6 +2643,7 @@ gen3_render_composite_boxes__thread(struct sna *sna,
3948
3949 v = sna->render.vertices + sna->render.vertex_used;
3950 sna->render.vertex_used += nbox_this_time * op->floats_per_rect;
3951+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3952
3953 sna_vertex_acquire__locked(&sna->render);
3954 sna_vertex_unlock(&sna->render);
3955@@ -3065,7 +3105,7 @@ gen3_composite_picture(struct sna *sna,
3956
3957 if (sna_picture_is_clear(picture, x, y, w, h, &color)) {
3958 DBG(("%s: clear drawable [%08x]\n", __FUNCTION__, color));
3959- return gen3_init_solid(channel, color_convert(color, picture->format, PICT_a8r8g8b8));
3960+ return gen3_init_solid(channel, solid_color(picture->format, color));
3961 }
3962
3963 if (!gen3_check_repeat(picture))
3964@@ -3097,12 +3137,12 @@ gen3_composite_picture(struct sna *sna,
3965 if (channel->repeat ||
3966 (x >= 0 &&
3967 y >= 0 &&
3968- x + w < pixmap->drawable.width &&
3969- y + h < pixmap->drawable.height)) {
3970+ x + w <= pixmap->drawable.width &&
3971+ y + h <= pixmap->drawable.height)) {
3972 struct sna_pixmap *priv = sna_pixmap(pixmap);
3973 if (priv && priv->clear) {
3974 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
3975- return gen3_init_solid(channel, priv->clear_color);
3976+ return gen3_init_solid(channel, solid_color(picture->format, priv->clear_color));
3977 }
3978 }
3979 } else {
3980@@ -3862,6 +3902,7 @@ gen3_emit_composite_spans_primitive_zero(struct sna *sna,
3981 {
3982 float *v = sna->render.vertices + sna->render.vertex_used;
3983 sna->render.vertex_used += 6;
3984+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3985
3986 v[0] = op->base.dst.x + box->x2;
3987 v[1] = op->base.dst.y + box->y2;
3988@@ -3901,6 +3942,7 @@ gen3_emit_composite_spans_primitive_zero_no_offset(struct sna *sna,
3989 {
3990 float *v = sna->render.vertices + sna->render.vertex_used;
3991 sna->render.vertex_used += 6;
3992+ assert(sna->render.vertex_used <= sna->render.vertex_size);
3993
3994 v[0] = box->x2;
3995 v[3] = v[1] = box->y2;
3996@@ -3932,6 +3974,7 @@ gen3_emit_composite_spans_primitive_constant(struct sna *sna,
3997 {
3998 float *v = sna->render.vertices + sna->render.vertex_used;
3999 sna->render.vertex_used += 9;
4000+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4001
4002 v[0] = op->base.dst.x + box->x2;
4003 v[6] = v[3] = op->base.dst.x + box->x1;
4004@@ -3966,6 +4009,7 @@ gen3_emit_composite_spans_primitive_constant_no_offset(struct sna *sna,
4005 {
4006 float *v = sna->render.vertices + sna->render.vertex_used;
4007 sna->render.vertex_used += 9;
4008+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4009
4010 v[0] = box->x2;
4011 v[6] = v[3] = box->x1;
4012@@ -3999,6 +4043,7 @@ gen3_emit_composite_spans_primitive_identity_source(struct sna *sna,
4013 {
4014 float *v = sna->render.vertices + sna->render.vertex_used;
4015 sna->render.vertex_used += 15;
4016+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4017
4018 v[0] = op->base.dst.x + box->x2;
4019 v[1] = op->base.dst.y + box->y2;
4020@@ -4060,6 +4105,7 @@ gen3_emit_composite_spans_primitive_affine_source(struct sna *sna,
4021
4022 v = sna->render.vertices + sna->render.vertex_used;
4023 sna->render.vertex_used += 15;
4024+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4025
4026 v[0] = op->base.dst.x + box->x2;
4027 v[6] = v[1] = op->base.dst.y + box->y2;
4028@@ -4125,6 +4171,7 @@ gen3_emit_composite_spans_primitive_identity_gradient(struct sna *sna,
4029 {
4030 float *v = sna->render.vertices + sna->render.vertex_used;
4031 sna->render.vertex_used += 15;
4032+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4033
4034 v[0] = op->base.dst.x + box->x2;
4035 v[1] = op->base.dst.y + box->y2;
4036@@ -4184,6 +4231,7 @@ gen3_emit_composite_spans_primitive_constant__sse2(struct sna *sna,
4037 {
4038 float *v = sna->render.vertices + sna->render.vertex_used;
4039 sna->render.vertex_used += 9;
4040+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4041
4042 v[0] = op->base.dst.x + box->x2;
4043 v[6] = v[3] = op->base.dst.x + box->x1;
4044@@ -4229,6 +4277,7 @@ gen3_render_composite_spans_constant_box__sse2(struct sna *sna,
4045
4046 v = sna->render.vertices + sna->render.vertex_used;
4047 sna->render.vertex_used += 9;
4048+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4049
4050 v[0] = box->x2;
4051 v[6] = v[3] = box->x1;
4052@@ -4259,6 +4308,7 @@ gen3_render_composite_spans_constant_thread__sse2__boxes(struct sna *sna,
4053
4054 v = sna->render.vertices + sna->render.vertex_used;
4055 sna->render.vertex_used += nbox_this_time * 9;
4056+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4057
4058 sna_vertex_acquire__locked(&sna->render);
4059 sna_vertex_unlock(&sna->render);
4060@@ -4287,6 +4337,7 @@ gen3_emit_composite_spans_primitive_constant__sse2__no_offset(struct sna *sna,
4061 {
4062 float *v = sna->render.vertices + sna->render.vertex_used;
4063 sna->render.vertex_used += 9;
4064+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4065
4066 v[0] = box->x2;
4067 v[6] = v[3] = box->x1;
4068@@ -4320,6 +4371,7 @@ gen3_emit_composite_spans_primitive_identity_source__sse2(struct sna *sna,
4069 {
4070 float *v = sna->render.vertices + sna->render.vertex_used;
4071 sna->render.vertex_used += 15;
4072+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4073
4074 v[0] = op->base.dst.x + box->x2;
4075 v[1] = op->base.dst.y + box->y2;
4076@@ -4380,6 +4432,7 @@ gen3_emit_composite_spans_primitive_affine_source__sse2(struct sna *sna,
4077
4078 v = sna->render.vertices + sna->render.vertex_used;
4079 sna->render.vertex_used += 15;
4080+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4081
4082 v[0] = op->base.dst.x + box->x2;
4083 v[6] = v[1] = op->base.dst.y + box->y2;
4084@@ -4445,6 +4498,7 @@ gen3_emit_composite_spans_primitive_identity_gradient__sse2(struct sna *sna,
4085 {
4086 float *v = sna->render.vertices + sna->render.vertex_used;
4087 sna->render.vertex_used += 15;
4088+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4089
4090 v[0] = op->base.dst.x + box->x2;
4091 v[1] = op->base.dst.y + box->y2;
4092@@ -4504,6 +4558,7 @@ gen3_emit_composite_spans_primitive_affine_gradient__sse2(struct sna *sna,
4093 PictTransform *transform = op->base.src.transform;
4094 float *v = sna->render.vertices + sna->render.vertex_used;
4095 sna->render.vertex_used += 15;
4096+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4097
4098 v[0] = op->base.dst.x + box->x2;
4099 v[1] = op->base.dst.y + box->y2;
4100@@ -4577,6 +4632,7 @@ gen3_emit_composite_spans_primitive_affine_gradient(struct sna *sna,
4101 PictTransform *transform = op->base.src.transform;
4102 float *v = sna->render.vertices + sna->render.vertex_used;
4103 sna->render.vertex_used += 15;
4104+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4105
4106 v[0] = op->base.dst.x + box->x2;
4107 v[1] = op->base.dst.y + box->y2;
4108@@ -4676,6 +4732,7 @@ gen3_render_composite_spans_constant_box(struct sna *sna,
4109
4110 v = sna->render.vertices + sna->render.vertex_used;
4111 sna->render.vertex_used += 9;
4112+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4113
4114 v[0] = box->x2;
4115 v[6] = v[3] = box->x1;
4116@@ -4706,6 +4763,7 @@ gen3_render_composite_spans_constant_thread_boxes(struct sna *sna,
4117
4118 v = sna->render.vertices + sna->render.vertex_used;
4119 sna->render.vertex_used += nbox_this_time * 9;
4120+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4121
4122 sna_vertex_acquire__locked(&sna->render);
4123 sna_vertex_unlock(&sna->render);
4124@@ -4795,6 +4853,7 @@ gen3_render_composite_spans_boxes__thread(struct sna *sna,
4125
4126 v = sna->render.vertices + sna->render.vertex_used;
4127 sna->render.vertex_used += nbox_this_time * op->base.floats_per_rect;
4128+ assert(sna->render.vertex_used <= sna->render.vertex_size);
4129
4130 sna_vertex_acquire__locked(&sna->render);
4131 sna_vertex_unlock(&sna->render);
4132@@ -5436,17 +5495,7 @@ gen3_render_video(struct sna *sna,
4133 pix_yoff = -dstRegion->extents.y1;
4134 copy = 1;
4135 } else {
4136- /* Set up the offset for translating from the given region
4137- * (in screen coordinates) to the backing pixmap.
4138- */
4139-#ifdef COMPOSITE
4140- pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
4141- pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
4142-#else
4143- pix_xoff = 0;
4144- pix_yoff = 0;
4145-#endif
4146-
4147+ pix_xoff = pix_yoff = 0;
4148 dst_width = pixmap->drawable.width;
4149 dst_height = pixmap->drawable.height;
4150 }
4151@@ -5502,16 +5551,9 @@ gen3_render_video(struct sna *sna,
4152 } while (nbox);
4153
4154 if (copy) {
4155-#ifdef COMPOSITE
4156- pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
4157- pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
4158-#else
4159- pix_xoff = 0;
4160- pix_yoff = 0;
4161-#endif
4162 sna_blt_copy_boxes(sna, GXcopy,
4163 dst_bo, -dstRegion->extents.x1, -dstRegion->extents.y1,
4164- priv->gpu_bo, pix_xoff, pix_yoff,
4165+ priv->gpu_bo, 0, 0,
4166 pixmap->drawable.bitsPerPixel,
4167 region_rects(dstRegion),
4168 region_num_rects(dstRegion));
4169@@ -5519,21 +5561,8 @@ gen3_render_video(struct sna *sna,
4170 kgem_bo_destroy(&sna->kgem, dst_bo);
4171 }
4172
4173- if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
4174- if ((pix_xoff | pix_yoff) == 0) {
4175- sna_damage_add(&priv->gpu_damage, dstRegion);
4176- sna_damage_subtract(&priv->cpu_damage, dstRegion);
4177- } else {
4178- sna_damage_add_boxes(&priv->gpu_damage,
4179- region_rects(dstRegion),
4180- region_num_rects(dstRegion),
4181- pix_xoff, pix_yoff);
4182- sna_damage_subtract_boxes(&priv->cpu_damage,
4183- region_rects(dstRegion),
4184- region_num_rects(dstRegion),
4185- pix_xoff, pix_yoff);
4186- }
4187- }
4188+ if (!DAMAGE_IS_ALL(priv->gpu_damage))
4189+ sna_damage_add(&priv->gpu_damage, dstRegion);
4190
4191 return true;
4192 }
4193diff --git a/src/sna/gen4_render.c b/src/sna/gen4_render.c
4194index 6c2d380..552da49 100644
4195--- a/src/sna/gen4_render.c
4196+++ b/src/sna/gen4_render.c
4197@@ -1405,8 +1405,8 @@ gen4_render_video(struct sna *sna,
4198 int src_height = frame->src.y2 - frame->src.y1;
4199 float src_offset_x, src_offset_y;
4200 float src_scale_x, src_scale_y;
4201- int nbox, pix_xoff, pix_yoff;
4202 const BoxRec *box;
4203+ int nbox;
4204
4205 DBG(("%s: %dx%d -> %dx%d\n", __FUNCTION__,
4206 src_width, src_height, dst_width, dst_height));
4207@@ -1445,17 +1445,6 @@ gen4_render_video(struct sna *sna,
4208 gen4_align_vertex(sna, &tmp);
4209 gen4_video_bind_surfaces(sna, &tmp);
4210
4211- /* Set up the offset for translating from the given region (in screen
4212- * coordinates) to the backing pixmap.
4213- */
4214-#ifdef COMPOSITE
4215- pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
4216- pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
4217-#else
4218- pix_xoff = 0;
4219- pix_yoff = 0;
4220-#endif
4221-
4222 src_scale_x = (float)src_width / dst_width / frame->width;
4223 src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
4224
4225@@ -1473,34 +1462,26 @@ gen4_render_video(struct sna *sna,
4226 nbox -= n;
4227
4228 do {
4229- BoxRec r;
4230-
4231- r.x1 = box->x1 + pix_xoff;
4232- r.x2 = box->x2 + pix_xoff;
4233- r.y1 = box->y1 + pix_yoff;
4234- r.y2 = box->y2 + pix_yoff;
4235-
4236- OUT_VERTEX(r.x2, r.y2);
4237+ OUT_VERTEX(box->x2, box->y2);
4238 OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
4239 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
4240
4241- OUT_VERTEX(r.x1, r.y2);
4242+ OUT_VERTEX(box->x1, box->y2);
4243 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
4244 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
4245
4246- OUT_VERTEX(r.x1, r.y1);
4247+ OUT_VERTEX(box->x1, box->y1);
4248 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
4249 OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
4250
4251- if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
4252- sna_damage_add_box(&priv->gpu_damage, &r);
4253- sna_damage_subtract_box(&priv->cpu_damage, &r);
4254- }
4255 box++;
4256 } while (--n);
4257 } while (nbox);
4258 gen4_vertex_flush(sna);
4259
4260+ if (!DAMAGE_IS_ALL(priv->gpu_damage))
4261+ sna_damage_add(&priv->gpu_damage, dstRegion);
4262+
4263 return true;
4264 }
4265
4266@@ -1585,12 +1566,14 @@ gen4_composite_picture(struct sna *sna,
4267 if (channel->repeat &&
4268 (x >= 0 &&
4269 y >= 0 &&
4270- x + w < pixmap->drawable.width &&
4271- y + h < pixmap->drawable.height)) {
4272+ x + w <= pixmap->drawable.width &&
4273+ y + h <= pixmap->drawable.height)) {
4274 struct sna_pixmap *priv = sna_pixmap(pixmap);
4275 if (priv && priv->clear) {
4276 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
4277- return gen4_channel_init_solid(sna, channel, priv->clear_color);
4278+ return gen4_channel_init_solid(sna, channel,
4279+ solid_color(picture->format,
4280+ priv->clear_color));
4281 }
4282 }
4283 } else
4284@@ -2738,6 +2721,20 @@ gen4_render_fill_boxes(struct sna *sna,
4285 tmp.dst.format = format;
4286 tmp.dst.bo = dst_bo;
4287
4288+ sna_render_composite_redirect_init(&tmp);
4289+ if (too_large(dst->width, dst->height)) {
4290+ BoxRec extents;
4291+
4292+ boxes_extents(box, n, &extents);
4293+ if (!sna_render_composite_redirect(sna, &tmp,
4294+ extents.x1, extents.y1,
4295+ extents.x2 - extents.x1,
4296+ extents.y2 - extents.y1,
4297+ n > 1))
4298+ return sna_tiling_fill_boxes(sna, op, format, color,
4299+ dst, dst_bo, box, n);
4300+ }
4301+
4302 gen4_channel_init_solid(sna, &tmp.src, pixel);
4303
4304 tmp.is_affine = true;
4305@@ -2748,8 +2745,10 @@ gen4_render_fill_boxes(struct sna *sna,
4306
4307 if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
4308 kgem_submit(&sna->kgem);
4309- if (!kgem_check_bo(&sna->kgem, dst_bo, NULL))
4310+ if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
4311+ kgem_bo_destroy(&sna->kgem, tmp.src.bo);
4312 return false;
4313+ }
4314 }
4315
4316 gen4_align_vertex(sna, &tmp);
4317@@ -2765,6 +2764,7 @@ gen4_render_fill_boxes(struct sna *sna,
4318
4319 gen4_vertex_flush(sna);
4320 kgem_bo_destroy(&sna->kgem, tmp.src.bo);
4321+ sna_render_composite_redirect_done(sna, &tmp);
4322 return true;
4323 }
4324
4325diff --git a/src/sna/gen5_render.c b/src/sna/gen5_render.c
4326index 37cf1ff..e162f9f 100644
4327--- a/src/sna/gen5_render.c
4328+++ b/src/sna/gen5_render.c
4329@@ -1355,8 +1355,8 @@ gen5_render_video(struct sna *sna,
4330 int src_height = frame->src.y2 - frame->src.y1;
4331 float src_offset_x, src_offset_y;
4332 float src_scale_x, src_scale_y;
4333- int nbox, pix_xoff, pix_yoff;
4334 const BoxRec *box;
4335+ int nbox;
4336
4337 DBG(("%s: %dx%d -> %dx%d\n", __FUNCTION__,
4338 src_width, src_height, dst_width, dst_height));
4339@@ -1395,17 +1395,6 @@ gen5_render_video(struct sna *sna,
4340 gen5_align_vertex(sna, &tmp);
4341 gen5_video_bind_surfaces(sna, &tmp);
4342
4343- /* Set up the offset for translating from the given region (in screen
4344- * coordinates) to the backing pixmap.
4345- */
4346-#ifdef COMPOSITE
4347- pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
4348- pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
4349-#else
4350- pix_xoff = 0;
4351- pix_yoff = 0;
4352-#endif
4353-
4354 src_scale_x = (float)src_width / dst_width / frame->width;
4355 src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
4356
4357@@ -1415,35 +1404,27 @@ gen5_render_video(struct sna *sna,
4358 box = region_rects(dstRegion);
4359 nbox = region_num_rects(dstRegion);
4360 while (nbox--) {
4361- BoxRec r;
4362-
4363- r.x1 = box->x1 + pix_xoff;
4364- r.x2 = box->x2 + pix_xoff;
4365- r.y1 = box->y1 + pix_yoff;
4366- r.y2 = box->y2 + pix_yoff;
4367-
4368 gen5_get_rectangles(sna, &tmp, 1, gen5_video_bind_surfaces);
4369
4370- OUT_VERTEX(r.x2, r.y2);
4371+ OUT_VERTEX(box->x2, box->y2);
4372 OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
4373 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
4374
4375- OUT_VERTEX(r.x1, r.y2);
4376+ OUT_VERTEX(box->x1, box->y2);
4377 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
4378 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
4379
4380- OUT_VERTEX(r.x1, r.y1);
4381+ OUT_VERTEX(box->x1, box->y1);
4382 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
4383 OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
4384
4385- if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
4386- sna_damage_add_box(&priv->gpu_damage, &r);
4387- sna_damage_subtract_box(&priv->cpu_damage, &r);
4388- }
4389 box++;
4390 }
4391-
4392 gen4_vertex_flush(sna);
4393+
4394+ if (!DAMAGE_IS_ALL(priv->gpu_damage))
4395+ sna_damage_add(&priv->gpu_damage, dstRegion);
4396+
4397 return true;
4398 }
4399
4400@@ -1524,12 +1505,12 @@ gen5_composite_picture(struct sna *sna,
4401 if (channel->repeat ||
4402 (x >= 0 &&
4403 y >= 0 &&
4404- x + w < pixmap->drawable.width &&
4405- y + h < pixmap->drawable.height)) {
4406+ x + w <= pixmap->drawable.width &&
4407+ y + h <= pixmap->drawable.height)) {
4408 struct sna_pixmap *priv = sna_pixmap(pixmap);
4409 if (priv && priv->clear) {
4410 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
4411- return gen4_channel_init_solid(sna, channel, priv->clear_color);
4412+ return gen4_channel_init_solid(sna, channel, solid_color(picture->format, priv->clear_color));
4413 }
4414 }
4415 } else
4416@@ -2734,6 +2715,19 @@ gen5_render_fill_boxes(struct sna *sna,
4417 tmp.dst.format = format;
4418 tmp.dst.bo = dst_bo;
4419
4420+ if (too_large(dst->width, dst->height)) {
4421+ BoxRec extents;
4422+
4423+ boxes_extents(box, n, &extents);
4424+ if (!sna_render_composite_redirect(sna, &tmp,
4425+ extents.x1, extents.y1,
4426+ extents.x2 - extents.x1,
4427+ extents.y2 - extents.y1,
4428+ n > 1))
4429+ return sna_tiling_fill_boxes(sna, op, format, color,
4430+ dst, dst_bo, box, n);
4431+ }
4432+
4433 tmp.src.bo = sna_render_get_solid(sna, pixel);
4434 tmp.src.filter = SAMPLER_FILTER_NEAREST;
4435 tmp.src.repeat = SAMPLER_EXTEND_REPEAT;
4436@@ -2780,6 +2774,7 @@ gen5_render_fill_boxes(struct sna *sna,
4437
4438 gen4_vertex_flush(sna);
4439 kgem_bo_destroy(&sna->kgem, tmp.src.bo);
4440+ sna_render_composite_redirect_done(sna, &tmp);
4441 return true;
4442 }
4443
4444diff --git a/src/sna/gen6_common.h b/src/sna/gen6_common.h
4445index 6668620..898cda8 100644
4446--- a/src/sna/gen6_common.h
4447+++ b/src/sna/gen6_common.h
4448@@ -30,8 +30,8 @@
4449
4450 #include "sna.h"
4451
4452-#define NO_RING_SWITCH 0
4453-#define PREFER_RENDER 0
4454+#define NO_RING_SWITCH(sna) (!(sna)->kgem.has_semaphores)
4455+#define PREFER_RENDER 0 /* -1 -> BLT, 1 -> RENDER */
4456
4457 static inline bool is_uncached(struct sna *sna,
4458 struct kgem_bo *bo)
4459@@ -46,40 +46,25 @@ inline static bool can_switch_to_blt(struct sna *sna,
4460 if (sna->kgem.ring != KGEM_RENDER)
4461 return true;
4462
4463- if (NO_RING_SWITCH)
4464+ if (NO_RING_SWITCH(sna))
4465 return false;
4466
4467- if (!sna->kgem.has_semaphores)
4468- return false;
4469-
4470- if (flags & COPY_LAST)
4471- return true;
4472-
4473 if (bo && RQ_IS_BLT(bo->rq))
4474 return true;
4475
4476- if (sna->render_state.gt < 2)
4477- return true;
4478-
4479- return kgem_ring_is_idle(&sna->kgem, KGEM_BLT);
4480-}
4481+ if (bo && bo->tiling == I915_TILING_Y)
4482+ return false;
4483
4484-inline static bool can_switch_to_render(struct sna *sna,
4485- struct kgem_bo *bo)
4486-{
4487- if (sna->kgem.ring == KGEM_RENDER)
4488+ if (sna->render_state.gt < 2)
4489 return true;
4490
4491- if (NO_RING_SWITCH)
4492+ if (bo && RQ_IS_RENDER(bo->rq))
4493 return false;
4494
4495- if (!sna->kgem.has_semaphores)
4496- return false;
4497-
4498- if (bo && !RQ_IS_BLT(bo->rq) && !is_uncached(sna, bo))
4499+ if (flags & COPY_LAST)
4500 return true;
4501
4502- return !kgem_ring_is_idle(&sna->kgem, KGEM_RENDER);
4503+ return kgem_ring_is_idle(&sna->kgem, KGEM_BLT);
4504 }
4505
4506 static inline bool untiled_tlb_miss(struct kgem_bo *bo)
4507@@ -90,57 +75,95 @@ static inline bool untiled_tlb_miss(struct kgem_bo *bo)
4508 return bo->tiling == I915_TILING_NONE && bo->pitch >= 4096;
4509 }
4510
4511-static int prefer_blt_bo(struct sna *sna, struct kgem_bo *bo)
4512+static int prefer_blt_bo(struct sna *sna,
4513+ struct kgem_bo *src,
4514+ struct kgem_bo *dst)
4515 {
4516+ assert(dst != NULL);
4517+
4518 if (PREFER_RENDER)
4519 return PREFER_RENDER < 0;
4520
4521- if (bo->rq)
4522- return RQ_IS_BLT(bo->rq);
4523+ if (dst->rq)
4524+ return RQ_IS_BLT(dst->rq);
4525
4526 if (sna->flags & SNA_POWERSAVE)
4527 return true;
4528
4529- return bo->tiling == I915_TILING_NONE || is_uncached(sna, bo);
4530-}
4531+ if (src) {
4532+ if (sna->render_state.gt > 1)
4533+ return false;
4534
4535-inline static bool force_blt_ring(struct sna *sna)
4536-{
4537- if (sna->flags & SNA_POWERSAVE)
4538+ if (src->rq)
4539+ return RQ_IS_BLT(src->rq);
4540+
4541+ if (src->tiling == I915_TILING_Y)
4542+ return false;
4543+ } else {
4544+ if (sna->render_state.gt > 2)
4545+ return false;
4546+ }
4547+
4548+ if (sna->render_state.gt < 2)
4549 return true;
4550
4551+ return dst->tiling == I915_TILING_NONE || is_uncached(sna, dst);
4552+}
4553+
4554+inline static bool force_blt_ring(struct sna *sna, struct kgem_bo *bo)
4555+{
4556 if (sna->kgem.mode == KGEM_RENDER)
4557 return false;
4558
4559+ if (NO_RING_SWITCH(sna))
4560+ return sna->kgem.ring == KGEM_BLT;
4561+
4562+ if (bo->tiling == I915_TILING_Y)
4563+ return false;
4564+
4565+ if (sna->flags & SNA_POWERSAVE)
4566+ return true;
4567+
4568 if (sna->render_state.gt < 2)
4569 return true;
4570
4571 return false;
4572 }
4573
4574-inline static bool prefer_blt_ring(struct sna *sna,
4575- struct kgem_bo *bo,
4576- unsigned flags)
4577+nonnull inline static bool
4578+prefer_blt_ring(struct sna *sna, struct kgem_bo *bo, unsigned flags)
4579 {
4580 if (PREFER_RENDER)
4581 return PREFER_RENDER < 0;
4582
4583- assert(!force_blt_ring(sna));
4584- assert(!kgem_bo_is_render(bo));
4585+ assert(!force_blt_ring(sna, bo));
4586+ assert(!kgem_bo_is_render(bo) || NO_RING_SWITCH(sna));
4587+
4588+ if (kgem_bo_is_blt(bo))
4589+ return true;
4590
4591 return can_switch_to_blt(sna, bo, flags);
4592 }
4593
4594-inline static bool prefer_render_ring(struct sna *sna,
4595- struct kgem_bo *bo)
4596+nonnull inline static bool
4597+prefer_render_ring(struct sna *sna, struct kgem_bo *bo)
4598 {
4599+ if (sna->kgem.ring == KGEM_RENDER)
4600+ return true;
4601+
4602+ if (sna->kgem.ring != KGEM_NONE && NO_RING_SWITCH(sna))
4603+ return false;
4604+
4605+ if (kgem_bo_is_render(bo))
4606+ return true;
4607+
4608 if (sna->flags & SNA_POWERSAVE)
4609 return false;
4610
4611- if (sna->render_state.gt < 2)
4612- return false;
4613+ if (!prefer_blt_bo(sna, NULL, bo))
4614+ return true;
4615
4616- return can_switch_to_render(sna, bo);
4617+ return !kgem_ring_is_idle(&sna->kgem, KGEM_RENDER);
4618 }
4619
4620 inline static bool
4621@@ -153,25 +176,20 @@ prefer_blt_composite(struct sna *sna, struct sna_composite_op *tmp)
4622 untiled_tlb_miss(tmp->src.bo))
4623 return true;
4624
4625- if (force_blt_ring(sna))
4626+ if (force_blt_ring(sna, tmp->dst.bo))
4627 return true;
4628
4629- if (kgem_bo_is_render(tmp->dst.bo) ||
4630- kgem_bo_is_render(tmp->src.bo))
4631- return false;
4632-
4633 if (prefer_render_ring(sna, tmp->dst.bo))
4634 return false;
4635
4636 if (!prefer_blt_ring(sna, tmp->dst.bo, 0))
4637 return false;
4638
4639- return prefer_blt_bo(sna, tmp->dst.bo) || prefer_blt_bo(sna, tmp->src.bo);
4640+ return prefer_blt_bo(sna, tmp->src.bo, tmp->dst.bo);
4641 }
4642
4643-static inline bool prefer_blt_fill(struct sna *sna,
4644- struct kgem_bo *bo,
4645- unsigned flags)
4646+nonnull static inline bool
4647+prefer_blt_fill(struct sna *sna, struct kgem_bo *bo, unsigned flags)
4648 {
4649 if (PREFER_RENDER)
4650 return PREFER_RENDER < 0;
4651@@ -179,13 +197,10 @@ static inline bool prefer_blt_fill(struct sna *sna,
4652 if (untiled_tlb_miss(bo))
4653 return true;
4654
4655- if (force_blt_ring(sna))
4656+ if (force_blt_ring(sna, bo))
4657 return true;
4658
4659 if ((flags & (FILL_POINTS | FILL_SPANS)) == 0) {
4660- if (kgem_bo_is_render(bo))
4661- return false;
4662-
4663 if (prefer_render_ring(sna, bo))
4664 return false;
4665
4666@@ -196,7 +211,7 @@ static inline bool prefer_blt_fill(struct sna *sna,
4667 return true;
4668 }
4669
4670- return prefer_blt_bo(sna, bo);
4671+ return prefer_blt_bo(sna, NULL, bo);
4672 }
4673
4674 void gen6_render_context_switch(struct kgem *kgem, int new_mode);
4675diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c
4676index 2504468..ee17593 100644
4677--- a/src/sna/gen6_render.c
4678+++ b/src/sna/gen6_render.c
4679@@ -1633,9 +1633,9 @@ gen6_render_video(struct sna *sna,
4680 int src_height = frame->src.y2 - frame->src.y1;
4681 float src_offset_x, src_offset_y;
4682 float src_scale_x, src_scale_y;
4683- int nbox, pix_xoff, pix_yoff;
4684 unsigned filter;
4685 const BoxRec *box;
4686+ int nbox;
4687
4688 DBG(("%s: src=(%d, %d), dst=(%d, %d), %dx[(%d, %d), (%d, %d)...]\n",
4689 __FUNCTION__,
4690@@ -1686,17 +1686,6 @@ gen6_render_video(struct sna *sna,
4691 gen6_align_vertex(sna, &tmp);
4692 gen6_emit_video_state(sna, &tmp);
4693
4694- /* Set up the offset for translating from the given region (in screen
4695- * coordinates) to the backing pixmap.
4696- */
4697-#ifdef COMPOSITE
4698- pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
4699- pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
4700-#else
4701- pix_xoff = 0;
4702- pix_yoff = 0;
4703-#endif
4704-
4705 src_scale_x = (float)src_width / dst_width / frame->width;
4706 src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
4707
4708@@ -1706,35 +1695,27 @@ gen6_render_video(struct sna *sna,
4709 box = region_rects(dstRegion);
4710 nbox = region_num_rects(dstRegion);
4711 while (nbox--) {
4712- BoxRec r;
4713-
4714- r.x1 = box->x1 + pix_xoff;
4715- r.x2 = box->x2 + pix_xoff;
4716- r.y1 = box->y1 + pix_yoff;
4717- r.y2 = box->y2 + pix_yoff;
4718-
4719 gen6_get_rectangles(sna, &tmp, 1, gen6_emit_video_state);
4720
4721- OUT_VERTEX(r.x2, r.y2);
4722+ OUT_VERTEX(box->x2, box->y2);
4723 OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
4724 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
4725
4726- OUT_VERTEX(r.x1, r.y2);
4727+ OUT_VERTEX(box->x1, box->y2);
4728 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
4729 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
4730
4731- OUT_VERTEX(r.x1, r.y1);
4732+ OUT_VERTEX(box->x1, box->y1);
4733 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
4734 OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
4735
4736- if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
4737- sna_damage_add_box(&priv->gpu_damage, &r);
4738- sna_damage_subtract_box(&priv->cpu_damage, &r);
4739- }
4740 box++;
4741 }
4742-
4743 gen4_vertex_flush(sna);
4744+
4745+ if (!DAMAGE_IS_ALL(priv->gpu_damage))
4746+ sna_damage_add(&priv->gpu_damage, dstRegion);
4747+
4748 return true;
4749 }
4750
4751@@ -1815,12 +1796,12 @@ gen6_composite_picture(struct sna *sna,
4752 if (channel->repeat &&
4753 (x >= 0 &&
4754 y >= 0 &&
4755- x + w < pixmap->drawable.width &&
4756- y + h < pixmap->drawable.height)) {
4757+ x + w <= pixmap->drawable.width &&
4758+ y + h <= pixmap->drawable.height)) {
4759 struct sna_pixmap *priv = sna_pixmap(pixmap);
4760 if (priv && priv->clear) {
4761 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
4762- return gen4_channel_init_solid(sna, channel, priv->clear_color);
4763+ return gen4_channel_init_solid(sna, channel, solid_color(picture->format, priv->clear_color));
4764 }
4765 }
4766 } else
4767@@ -1965,46 +1946,77 @@ gen6_composite_set_target(struct sna *sna,
4768
4769 static bool
4770 try_blt(struct sna *sna,
4771- PicturePtr dst, PicturePtr src,
4772- int width, int height)
4773+ uint8_t op,
4774+ PicturePtr src,
4775+ PicturePtr mask,
4776+ PicturePtr dst,
4777+ int16_t src_x, int16_t src_y,
4778+ int16_t msk_x, int16_t msk_y,
4779+ int16_t dst_x, int16_t dst_y,
4780+ int16_t width, int16_t height,
4781+ unsigned flags,
4782+ struct sna_composite_op *tmp)
4783 {
4784 struct kgem_bo *bo;
4785
4786 if (sna->kgem.mode == KGEM_BLT) {
4787 DBG(("%s: already performing BLT\n", __FUNCTION__));
4788- return true;
4789+ goto execute;
4790 }
4791
4792 if (too_large(width, height)) {
4793 DBG(("%s: operation too large for 3D pipe (%d, %d)\n",
4794 __FUNCTION__, width, height));
4795- return true;
4796+ goto execute;
4797 }
4798
4799 bo = __sna_drawable_peek_bo(dst->pDrawable);
4800 if (bo == NULL)
4801- return true;
4802- if (bo->rq)
4803- return RQ_IS_BLT(bo->rq);
4804+ goto execute;
4805+
4806+ if (untiled_tlb_miss(bo))
4807+ goto execute;
4808+
4809+ if (bo->rq) {
4810+ if (RQ_IS_BLT(bo->rq))
4811+ goto execute;
4812+
4813+ return false;
4814+ }
4815+
4816+ if (bo->tiling == I915_TILING_Y)
4817+ goto upload;
4818+
4819+ if (src->pDrawable == dst->pDrawable &&
4820+ can_switch_to_blt(sna, bo, 0))
4821+ goto execute;
4822
4823 if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0))
4824- return true;
4825+ goto execute;
4826
4827 if (src->pDrawable) {
4828- bo = __sna_drawable_peek_bo(src->pDrawable);
4829- if (bo == NULL)
4830- return true;
4831+ struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable);
4832+ if (s == NULL)
4833+ goto execute;
4834
4835- if (prefer_blt_bo(sna, bo))
4836- return true;
4837+ if (prefer_blt_bo(sna, s, bo))
4838+ goto execute;
4839 }
4840
4841 if (sna->kgem.ring == KGEM_BLT) {
4842 DBG(("%s: already performing BLT\n", __FUNCTION__));
4843- return true;
4844+ goto execute;
4845 }
4846
4847- return false;
4848+upload:
4849+ flags |= COMPOSITE_UPLOAD;
4850+execute:
4851+ return sna_blt_composite(sna, op,
4852+ src, dst,
4853+ src_x, src_y,
4854+ dst_x, dst_y,
4855+ width, height,
4856+ flags, tmp);
4857 }
4858
4859 static bool
4860@@ -2234,13 +2246,13 @@ gen6_render_composite(struct sna *sna,
4861 width, height, sna->kgem.ring));
4862
4863 if (mask == NULL &&
4864- try_blt(sna, dst, src, width, height) &&
4865- sna_blt_composite(sna, op,
4866- src, dst,
4867- src_x, src_y,
4868- dst_x, dst_y,
4869- width, height,
4870- flags, tmp))
4871+ try_blt(sna, op,
4872+ src, mask, dst,
4873+ src_x, src_y,
4874+ msk_x, msk_y,
4875+ dst_x, dst_y,
4876+ width, height,
4877+ flags, tmp))
4878 return true;
4879
4880 if (gen6_composite_fallback(sna, src, mask, dst))
4881@@ -2676,27 +2688,35 @@ static inline bool prefer_blt_copy(struct sna *sna,
4882 if (sna->kgem.ring == KGEM_BLT)
4883 return true;
4884
4885- if (src_bo == dst_bo && can_switch_to_blt(sna, dst_bo, flags))
4886+ if (flags & COPY_DRI && !sna->kgem.has_semaphores)
4887+ return false;
4888+
4889+ if ((flags & COPY_SMALL || src_bo == dst_bo) &&
4890+ can_switch_to_blt(sna, dst_bo, flags))
4891 return true;
4892
4893 if (untiled_tlb_miss(src_bo) ||
4894 untiled_tlb_miss(dst_bo))
4895 return true;
4896
4897- if (force_blt_ring(sna))
4898+ if (force_blt_ring(sna, dst_bo))
4899 return true;
4900
4901 if (kgem_bo_is_render(dst_bo) ||
4902 kgem_bo_is_render(src_bo))
4903 return false;
4904
4905+ if (flags & COPY_LAST &&
4906+ can_switch_to_blt(sna, dst_bo, flags))
4907+ return true;
4908+
4909 if (prefer_render_ring(sna, dst_bo))
4910 return false;
4911
4912 if (!prefer_blt_ring(sna, dst_bo, flags))
4913 return false;
4914
4915- return prefer_blt_bo(sna, src_bo) || prefer_blt_bo(sna, dst_bo);
4916+ return prefer_blt_bo(sna, src_bo, dst_bo);
4917 }
4918
4919 static bool
4920@@ -2758,8 +2778,7 @@ fallback_blt:
4921 assert(src->depth == dst->depth);
4922 assert(src->width == dst->width);
4923 assert(src->height == dst->height);
4924- return sna_render_copy_boxes__overlap(sna, alu,
4925- src, src_bo,
4926+ return sna_render_copy_boxes__overlap(sna, alu, dst, dst_bo,
4927 src_dx, src_dy,
4928 dst_dx, dst_dy,
4929 box, n, &extents);
4930diff --git a/src/sna/gen7_render.c b/src/sna/gen7_render.c
4931index 2ecfd64..1c420a7 100644
4932--- a/src/sna/gen7_render.c
4933+++ b/src/sna/gen7_render.c
4934@@ -60,8 +60,6 @@
4935 #define NO_FILL_ONE 0
4936 #define NO_FILL_CLEAR 0
4937
4938-#define NO_RING_SWITCH 0
4939-
4940 #define USE_8_PIXEL_DISPATCH 1
4941 #define USE_16_PIXEL_DISPATCH 1
4942 #define USE_32_PIXEL_DISPATCH 0
4943@@ -149,7 +147,7 @@ static const struct gt_info hsw_gt1_info = {
4944 .max_vs_threads = 70,
4945 .max_gs_threads = 70,
4946 .max_wm_threads =
4947- (102 - 1) << HSW_PS_MAX_THREADS_SHIFT |
4948+ (70 - 1) << HSW_PS_MAX_THREADS_SHIFT |
4949 1 << HSW_PS_SAMPLE_MASK_SHIFT,
4950 .urb = { 128, 640, 256, 8 },
4951 .gt = 1,
4952@@ -810,7 +808,7 @@ gen7_emit_cc(struct sna *sna, uint32_t blend_offset)
4953
4954 DBG(("%s: blend = %x\n", __FUNCTION__, blend_offset));
4955
4956- /* XXX can have upto 8 blend states preload, selectable via
4957+ /* XXX can have up to 8 blend states preload, selectable via
4958 * Render Target Index. What other side-effects of Render Target Index?
4959 */
4960
4961@@ -1841,9 +1839,9 @@ gen7_render_video(struct sna *sna,
4962 int src_height = frame->src.y2 - frame->src.y1;
4963 float src_offset_x, src_offset_y;
4964 float src_scale_x, src_scale_y;
4965- int nbox, pix_xoff, pix_yoff;
4966 unsigned filter;
4967 const BoxRec *box;
4968+ int nbox;
4969
4970 DBG(("%s: src=(%d, %d), dst=(%d, %d), %dx[(%d, %d), (%d, %d)...]\n",
4971 __FUNCTION__,
4972@@ -1896,17 +1894,6 @@ gen7_render_video(struct sna *sna,
4973 gen7_align_vertex(sna, &tmp);
4974 gen7_emit_video_state(sna, &tmp);
4975
4976- /* Set up the offset for translating from the given region (in screen
4977- * coordinates) to the backing pixmap.
4978- */
4979-#ifdef COMPOSITE
4980- pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
4981- pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
4982-#else
4983- pix_xoff = 0;
4984- pix_yoff = 0;
4985-#endif
4986-
4987 DBG(("%s: src=(%d, %d)x(%d, %d); frame=(%dx%d), dst=(%dx%d)\n",
4988 __FUNCTION__,
4989 frame->src.x1, frame->src.y1,
4990@@ -1928,45 +1915,36 @@ gen7_render_video(struct sna *sna,
4991 box = region_rects(dstRegion);
4992 nbox = region_num_rects(dstRegion);
4993 while (nbox--) {
4994- BoxRec r;
4995-
4996- DBG(("%s: dst=(%d, %d), (%d, %d) + (%d, %d); src=(%f, %f), (%f, %f)\n",
4997+ DBG(("%s: dst=(%d, %d), (%d, %d); src=(%f, %f), (%f, %f)\n",
4998 __FUNCTION__,
4999 box->x1, box->y1,
5000 box->x2, box->y2,
5001- pix_xoff, pix_yoff,
5002 box->x1 * src_scale_x + src_offset_x,
5003 box->y1 * src_scale_y + src_offset_y,
5004 box->x2 * src_scale_x + src_offset_x,
5005 box->y2 * src_scale_y + src_offset_y));
5006
5007- r.x1 = box->x1 + pix_xoff;
5008- r.x2 = box->x2 + pix_xoff;
5009- r.y1 = box->y1 + pix_yoff;
5010- r.y2 = box->y2 + pix_yoff;
5011-
5012 gen7_get_rectangles(sna, &tmp, 1, gen7_emit_video_state);
5013
5014- OUT_VERTEX(r.x2, r.y2);
5015+ OUT_VERTEX(box->x2, box->y2);
5016 OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
5017 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
5018
5019- OUT_VERTEX(r.x1, r.y2);
5020+ OUT_VERTEX(box->x1, box->y2);
5021 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
5022 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
5023
5024- OUT_VERTEX(r.x1, r.y1);
5025+ OUT_VERTEX(box->x1, box->y1);
5026 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
5027 OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
5028
5029- if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
5030- sna_damage_add_box(&priv->gpu_damage, &r);
5031- sna_damage_subtract_box(&priv->cpu_damage, &r);
5032- }
5033 box++;
5034 }
5035-
5036 gen4_vertex_flush(sna);
5037+
5038+ if (!DAMAGE_IS_ALL(priv->gpu_damage))
5039+ sna_damage_add(&priv->gpu_damage, dstRegion);
5040+
5041 return true;
5042 }
5043
5044@@ -2048,12 +2026,13 @@ gen7_composite_picture(struct sna *sna,
5045 if (channel->repeat ||
5046 (x >= 0 &&
5047 y >= 0 &&
5048- x + w < pixmap->drawable.width &&
5049- y + h < pixmap->drawable.height)) {
5050+ x + w <= pixmap->drawable.width &&
5051+ y + h <= pixmap->drawable.height)) {
5052 struct sna_pixmap *priv = sna_pixmap(pixmap);
5053 if (priv && priv->clear) {
5054 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
5055- return gen4_channel_init_solid(sna, channel, priv->clear_color);
5056+ return gen4_channel_init_solid(sna, channel,
5057+ solid_color(picture->format, priv->clear_color));
5058 }
5059 }
5060 } else
5061@@ -2185,46 +2164,78 @@ gen7_composite_set_target(struct sna *sna,
5062
5063 static bool
5064 try_blt(struct sna *sna,
5065- PicturePtr dst, PicturePtr src,
5066- int width, int height)
5067+ uint8_t op,
5068+ PicturePtr src,
5069+ PicturePtr mask,
5070+ PicturePtr dst,
5071+ int16_t src_x, int16_t src_y,
5072+ int16_t msk_x, int16_t msk_y,
5073+ int16_t dst_x, int16_t dst_y,
5074+ int16_t width, int16_t height,
5075+ unsigned flags,
5076+ struct sna_composite_op *tmp)
5077 {
5078 struct kgem_bo *bo;
5079
5080 if (sna->kgem.mode == KGEM_BLT) {
5081 DBG(("%s: already performing BLT\n", __FUNCTION__));
5082- return true;
5083+ goto execute;
5084 }
5085
5086 if (too_large(width, height)) {
5087 DBG(("%s: operation too large for 3D pipe (%d, %d)\n",
5088 __FUNCTION__, width, height));
5089- return true;
5090+ goto execute;
5091 }
5092
5093 bo = __sna_drawable_peek_bo(dst->pDrawable);
5094 if (bo == NULL)
5095- return true;
5096- if (bo->rq)
5097- return RQ_IS_BLT(bo->rq);
5098+ goto execute;
5099+
5100+ if (untiled_tlb_miss(bo))
5101+ goto execute;
5102+
5103+ if (bo->rq) {
5104+ if (RQ_IS_BLT(bo->rq))
5105+ goto execute;
5106+
5107+ return false;
5108+ }
5109+
5110+ if (bo->tiling == I915_TILING_Y)
5111+ goto upload;
5112+
5113+ if (src->pDrawable == dst->pDrawable &&
5114+ (sna->render_state.gt < 3 || width*height < 1024) &&
5115+ can_switch_to_blt(sna, bo, 0))
5116+ goto execute;
5117
5118 if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0))
5119- return true;
5120+ goto execute;
5121
5122 if (src->pDrawable) {
5123- bo = __sna_drawable_peek_bo(src->pDrawable);
5124- if (bo == NULL)
5125- return true;
5126+ struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable);
5127+ if (s == NULL)
5128+ goto upload;
5129
5130- if (prefer_blt_bo(sna, bo))
5131- return true;
5132+ if (prefer_blt_bo(sna, s, bo))
5133+ goto execute;
5134 }
5135
5136 if (sna->kgem.ring == KGEM_BLT) {
5137 DBG(("%s: already performing BLT\n", __FUNCTION__));
5138- return true;
5139+ goto execute;
5140 }
5141
5142- return false;
5143+upload:
5144+ flags |= COMPOSITE_UPLOAD;
5145+execute:
5146+ return sna_blt_composite(sna, op,
5147+ src, dst,
5148+ src_x, src_y,
5149+ dst_x, dst_y,
5150+ width, height,
5151+ flags, tmp);
5152 }
5153
5154 static bool
5155@@ -2454,13 +2465,13 @@ gen7_render_composite(struct sna *sna,
5156 width, height, sna->kgem.mode, sna->kgem.ring));
5157
5158 if (mask == NULL &&
5159- try_blt(sna, dst, src, width, height) &&
5160- sna_blt_composite(sna, op,
5161- src, dst,
5162- src_x, src_y,
5163- dst_x, dst_y,
5164- width, height,
5165- flags, tmp))
5166+ try_blt(sna, op,
5167+ src, mask, dst,
5168+ src_x, src_y,
5169+ msk_x, msk_y,
5170+ dst_x, dst_y,
5171+ width, height,
5172+ flags, tmp))
5173 return true;
5174
5175 if (gen7_composite_fallback(sna, src, mask, dst))
5176@@ -2878,27 +2889,37 @@ prefer_blt_copy(struct sna *sna,
5177
5178 assert((flags & COPY_SYNC) == 0);
5179
5180- if (src_bo == dst_bo && can_switch_to_blt(sna, dst_bo, flags))
5181- return true;
5182-
5183 if (untiled_tlb_miss(src_bo) ||
5184 untiled_tlb_miss(dst_bo))
5185 return true;
5186
5187- if (force_blt_ring(sna))
5188+ if (flags & COPY_DRI && !sna->kgem.has_semaphores)
5189+ return false;
5190+
5191+ if (force_blt_ring(sna, dst_bo))
5192+ return true;
5193+
5194+ if ((flags & COPY_SMALL ||
5195+ (sna->render_state.gt < 3 && src_bo == dst_bo)) &&
5196+ can_switch_to_blt(sna, dst_bo, flags))
5197 return true;
5198
5199 if (kgem_bo_is_render(dst_bo) ||
5200 kgem_bo_is_render(src_bo))
5201 return false;
5202
5203+ if (flags & COPY_LAST &&
5204+ sna->render_state.gt < 3 &&
5205+ can_switch_to_blt(sna, dst_bo, flags))
5206+ return true;
5207+
5208 if (prefer_render_ring(sna, dst_bo))
5209 return false;
5210
5211 if (!prefer_blt_ring(sna, dst_bo, flags))
5212 return false;
5213
5214- return prefer_blt_bo(sna, src_bo) || prefer_blt_bo(sna, dst_bo);
5215+ return prefer_blt_bo(sna, src_bo, dst_bo);
5216 }
5217
5218 static bool
5219@@ -2946,7 +2967,7 @@ fallback_blt:
5220 &extents)) {
5221 bool big = too_large(extents.x2-extents.x1, extents.y2-extents.y1);
5222
5223- if ((big || can_switch_to_blt(sna, dst_bo, flags)) &&
5224+ if ((big || !prefer_render_ring(sna, dst_bo)) &&
5225 sna_blt_copy_boxes(sna, alu,
5226 src_bo, src_dx, src_dy,
5227 dst_bo, dst_dx, dst_dy,
5228@@ -2961,8 +2982,7 @@ fallback_blt:
5229 assert(src->depth == dst->depth);
5230 assert(src->width == dst->width);
5231 assert(src->height == dst->height);
5232- return sna_render_copy_boxes__overlap(sna, alu,
5233- src, src_bo,
5234+ return sna_render_copy_boxes__overlap(sna, alu, dst, dst_bo,
5235 src_dx, src_dy,
5236 dst_dx, dst_dy,
5237 box, n, &extents);
5238diff --git a/src/sna/gen8_render.c b/src/sna/gen8_render.c
5239index 6eb1145..0631e0a 100644
5240--- a/src/sna/gen8_render.c
5241+++ b/src/sna/gen8_render.c
5242@@ -205,6 +205,33 @@ static const struct blendinfo {
5243 #define OUT_VERTEX(x,y) vertex_emit_2s(sna, x,y)
5244 #define OUT_VERTEX_F(v) vertex_emit(sna, v)
5245
5246+struct gt_info {
5247+ const char *name;
5248+ struct {
5249+ int max_vs_entries;
5250+ } urb;
5251+};
5252+
5253+static const struct gt_info bdw_gt_info = {
5254+ .name = "Broadwell (gen8)",
5255+ .urb = { .max_vs_entries = 960 },
5256+};
5257+
5258+static bool is_bdw(struct sna *sna)
5259+{
5260+ return sna->kgem.gen == 0100;
5261+}
5262+
5263+static const struct gt_info chv_gt_info = {
5264+ .name = "Cherryview (gen8)",
5265+ .urb = { .max_vs_entries = 640 },
5266+};
5267+
5268+static bool is_chv(struct sna *sna)
5269+{
5270+ return sna->kgem.gen == 0101;
5271+}
5272+
5273 static inline bool too_large(int width, int height)
5274 {
5275 return width > GEN8_MAX_SIZE || height > GEN8_MAX_SIZE;
5276@@ -462,7 +489,7 @@ gen8_emit_urb(struct sna *sna)
5277 {
5278 /* num of VS entries must be divisible by 8 if size < 9 */
5279 OUT_BATCH(GEN8_3DSTATE_URB_VS | (2 - 2));
5280- OUT_BATCH(960 << URB_ENTRY_NUMBER_SHIFT |
5281+ OUT_BATCH(sna->render_state.gen8.info->urb.max_vs_entries << URB_ENTRY_NUMBER_SHIFT |
5282 (2 - 1) << URB_ENTRY_SIZE_SHIFT |
5283 4 << URB_STARTING_ADDRESS_SHIFT);
5284
5285@@ -873,7 +900,7 @@ gen8_emit_cc(struct sna *sna, uint32_t blend)
5286 assert(blend / GEN8_BLENDFACTOR_COUNT > 0);
5287 assert(blend % GEN8_BLENDFACTOR_COUNT > 0);
5288
5289- /* XXX can have upto 8 blend states preload, selectable via
5290+ /* XXX can have up to 8 blend states preload, selectable via
5291 * Render Target Index. What other side-effects of Render Target Index?
5292 */
5293
5294@@ -1876,12 +1903,12 @@ gen8_composite_picture(struct sna *sna,
5295 if (channel->repeat ||
5296 (x >= 0 &&
5297 y >= 0 &&
5298- x + w < pixmap->drawable.width &&
5299- y + h < pixmap->drawable.height)) {
5300+ x + w <= pixmap->drawable.width &&
5301+ y + h <= pixmap->drawable.height)) {
5302 struct sna_pixmap *priv = sna_pixmap(pixmap);
5303 if (priv && priv->clear) {
5304 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
5305- return gen4_channel_init_solid(sna, channel, priv->clear_color);
5306+ return gen4_channel_init_solid(sna, channel, solid_color(picture->format, priv->clear_color));
5307 }
5308 }
5309 } else
5310@@ -2002,46 +2029,78 @@ gen8_composite_set_target(struct sna *sna,
5311
5312 static bool
5313 try_blt(struct sna *sna,
5314- PicturePtr dst, PicturePtr src,
5315- int width, int height)
5316+ uint8_t op,
5317+ PicturePtr src,
5318+ PicturePtr mask,
5319+ PicturePtr dst,
5320+ int16_t src_x, int16_t src_y,
5321+ int16_t msk_x, int16_t msk_y,
5322+ int16_t dst_x, int16_t dst_y,
5323+ int16_t width, int16_t height,
5324+ unsigned flags,
5325+ struct sna_composite_op *tmp)
5326 {
5327 struct kgem_bo *bo;
5328
5329 if (sna->kgem.mode == KGEM_BLT) {
5330 DBG(("%s: already performing BLT\n", __FUNCTION__));
5331- return true;
5332+ goto execute;
5333 }
5334
5335 if (too_large(width, height)) {
5336 DBG(("%s: operation too large for 3D pipe (%d, %d)\n",
5337 __FUNCTION__, width, height));
5338- return true;
5339+ goto execute;
5340 }
5341
5342 bo = __sna_drawable_peek_bo(dst->pDrawable);
5343 if (bo == NULL)
5344- return true;
5345- if (bo->rq)
5346- return RQ_IS_BLT(bo->rq);
5347+ goto execute;
5348+
5349+ if (untiled_tlb_miss(bo))
5350+ goto execute;
5351+
5352+ if (bo->rq) {
5353+ if (RQ_IS_BLT(bo->rq))
5354+ goto execute;
5355+
5356+ return false;
5357+ }
5358+
5359+ if (bo->tiling == I915_TILING_Y)
5360+ goto upload;
5361
5362 if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0))
5363- return true;
5364+ goto execute;
5365+
5366+ if (src->pDrawable == dst->pDrawable &&
5367+ (sna->render_state.gt < 3 || width*height < 1024) &&
5368+ can_switch_to_blt(sna, bo, 0))
5369+ goto execute;
5370
5371 if (src->pDrawable) {
5372- bo = __sna_drawable_peek_bo(src->pDrawable);
5373- if (bo == NULL)
5374- return true;
5375+ struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable);
5376+ if (s == NULL)
5377+ goto upload;
5378
5379- if (prefer_blt_bo(sna, bo))
5380- return RQ_IS_BLT(bo->rq);
5381+ if (prefer_blt_bo(sna, s, bo))
5382+ goto execute;
5383 }
5384
5385 if (sna->kgem.ring == KGEM_BLT) {
5386 DBG(("%s: already performing BLT\n", __FUNCTION__));
5387- return true;
5388+ goto execute;
5389 }
5390
5391- return false;
5392+upload:
5393+ flags |= COMPOSITE_UPLOAD;
5394+execute:
5395+ return sna_blt_composite(sna, op,
5396+ src, dst,
5397+ src_x, src_y,
5398+ dst_x, dst_y,
5399+ width, height,
5400+ flags, tmp);
5401 }
5402
5403 static bool
5404@@ -2271,13 +2330,13 @@ gen8_render_composite(struct sna *sna,
5405 width, height, sna->kgem.mode, sna->kgem.ring));
5406
5407 if (mask == NULL &&
5408- try_blt(sna, dst, src, width, height) &&
5409- sna_blt_composite(sna, op,
5410- src, dst,
5411- src_x, src_y,
5412- dst_x, dst_y,
5413- width, height,
5414- flags, tmp))
5415+ try_blt(sna, op,
5416+ src, mask, dst,
5417+ src_x, src_y,
5418+ msk_x, msk_y,
5419+ dst_x, dst_y,
5420+ width, height,
5421+ flags, tmp))
5422 return true;
5423
5424 if (gen8_composite_fallback(sna, src, mask, dst))
5425@@ -2700,27 +2759,37 @@ prefer_blt_copy(struct sna *sna,
5426
5427 assert((flags & COPY_SYNC) == 0);
5428
5429- if (src_bo == dst_bo && can_switch_to_blt(sna, dst_bo, flags))
5430- return true;
5431-
5432 if (untiled_tlb_miss(src_bo) ||
5433 untiled_tlb_miss(dst_bo))
5434 return true;
5435
5436- if (force_blt_ring(sna))
5437+ if (flags & COPY_DRI && !sna->kgem.has_semaphores)
5438+ return false;
5439+
5440+ if (force_blt_ring(sna, dst_bo))
5441+ return true;
5442+
5443+ if ((flags & COPY_SMALL ||
5444+ (sna->render_state.gt < 3 && src_bo == dst_bo)) &&
5445+ can_switch_to_blt(sna, dst_bo, flags))
5446 return true;
5447
5448 if (kgem_bo_is_render(dst_bo) ||
5449 kgem_bo_is_render(src_bo))
5450 return false;
5451
5452+ if (flags & COPY_LAST &&
5453+ sna->render_state.gt < 3 &&
5454+ can_switch_to_blt(sna, dst_bo, flags))
5455+ return true;
5456+
5457 if (prefer_render_ring(sna, dst_bo))
5458 return false;
5459
5460 if (!prefer_blt_ring(sna, dst_bo, flags))
5461 return false;
5462
5463- return prefer_blt_bo(sna, src_bo) || prefer_blt_bo(sna, dst_bo);
5464+ return prefer_blt_bo(sna, src_bo, dst_bo);
5465 }
5466
5467 static bool
5468@@ -2770,7 +2839,7 @@ fallback_blt:
5469 &extents)) {
5470 bool big = too_large(extents.x2-extents.x1, extents.y2-extents.y1);
5471
5472- if ((big || can_switch_to_blt(sna, dst_bo, flags)) &&
5473+ if ((big || !prefer_render_ring(sna, dst_bo)) &&
5474 sna_blt_copy_boxes(sna, alu,
5475 src_bo, src_dx, src_dy,
5476 dst_bo, dst_dx, dst_dy,
5477@@ -2785,8 +2854,7 @@ fallback_blt:
5478 assert(src->depth == dst->depth);
5479 assert(src->width == dst->width);
5480 assert(src->height == dst->height);
5481- return sna_render_copy_boxes__overlap(sna, alu,
5482- src, src_bo,
5483+ return sna_render_copy_boxes__overlap(sna, alu, dst, dst_bo,
5484 src_dx, src_dy,
5485 dst_dx, dst_dy,
5486 box, n, &extents);
5487@@ -3712,9 +3780,9 @@ gen8_render_video(struct sna *sna,
5488 int src_height = frame->src.y2 - frame->src.y1;
5489 float src_offset_x, src_offset_y;
5490 float src_scale_x, src_scale_y;
5491- int nbox, pix_xoff, pix_yoff;
5492 unsigned filter;
5493 const BoxRec *box;
5494+ int nbox;
5495
5496 DBG(("%s: src=(%d, %d), dst=(%d, %d), %dx[(%d, %d), (%d, %d)...]\n",
5497 __FUNCTION__,
5498@@ -3770,17 +3838,6 @@ gen8_render_video(struct sna *sna,
5499 gen8_align_vertex(sna, &tmp);
5500 gen8_emit_video_state(sna, &tmp);
5501
5502- /* Set up the offset for translating from the given region (in screen
5503- * coordinates) to the backing pixmap.
5504- */
5505-#ifdef COMPOSITE
5506- pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
5507- pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
5508-#else
5509- pix_xoff = 0;
5510- pix_yoff = 0;
5511-#endif
5512-
5513 DBG(("%s: src=(%d, %d)x(%d, %d); frame=(%dx%d), dst=(%dx%d)\n",
5514 __FUNCTION__,
5515 frame->src.x1, frame->src.y1,
5516@@ -3802,45 +3859,36 @@ gen8_render_video(struct sna *sna,
5517 box = region_rects(dstRegion);
5518 nbox = region_num_rects(dstRegion);
5519 while (nbox--) {
5520- BoxRec r;
5521-
5522 DBG(("%s: dst=(%d, %d), (%d, %d) + (%d, %d); src=(%f, %f), (%f, %f)\n",
5523 __FUNCTION__,
5524 box->x1, box->y1,
5525 box->x2, box->y2,
5526- pix_xoff, pix_yoff,
5527 box->x1 * src_scale_x + src_offset_x,
5528 box->y1 * src_scale_y + src_offset_y,
5529 box->x2 * src_scale_x + src_offset_x,
5530 box->y2 * src_scale_y + src_offset_y));
5531
5532- r.x1 = box->x1 + pix_xoff;
5533- r.x2 = box->x2 + pix_xoff;
5534- r.y1 = box->y1 + pix_yoff;
5535- r.y2 = box->y2 + pix_yoff;
5536-
5537 gen8_get_rectangles(sna, &tmp, 1, gen8_emit_video_state);
5538
5539- OUT_VERTEX(r.x2, r.y2);
5540+ OUT_VERTEX(box->x2, box->y2);
5541 OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
5542 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
5543
5544- OUT_VERTEX(r.x1, r.y2);
5545+ OUT_VERTEX(box->x1, box->y2);
5546 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
5547 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
5548
5549- OUT_VERTEX(r.x1, r.y1);
5550+ OUT_VERTEX(box->x1, box->y1);
5551 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
5552 OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
5553
5554- if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
5555- sna_damage_add_box(&priv->gpu_damage, &r);
5556- sna_damage_subtract_box(&priv->cpu_damage, &r);
5557- }
5558 box++;
5559 }
5560-
5561 gen8_vertex_flush(sna);
5562+
5563+ if (!DAMAGE_IS_ALL(priv->gpu_damage))
5564+ sna_damage_add(&priv->gpu_damage, dstRegion);
5565+
5566 return true;
5567 }
5568 #endif
5569@@ -3896,6 +3944,13 @@ static bool gen8_render_setup(struct sna *sna)
5570 state->gt = ((devid >> 4) & 0xf) + 1;
5571 DBG(("%s: gt=%d\n", __FUNCTION__, state->gt));
5572
5573+ if (is_bdw(sna))
5574+ state->info = &bdw_gt_info;
5575+ else if (is_chv(sna))
5576+ state->info = &chv_gt_info;
5577+ else
5578+ return false;
5579+
5580 sna_static_stream_init(&general);
5581
5582 /* Zero pad the start. If you see an offset of 0x0 in the batchbuffer
5583@@ -4007,5 +4062,5 @@ const char *gen8_render_init(struct sna *sna, const char *backend)
5584
5585 sna->render.max_3d_size = GEN8_MAX_SIZE;
5586 sna->render.max_3d_pitch = 1 << 18;
5587- return "Broadwell";
5588+ return sna->render_state.gen8.info->name;
5589 }
5590diff --git a/src/sna/kgem.c b/src/sna/kgem.c
5591index 78ed540..fefa475 100644
5592--- a/src/sna/kgem.c
5593+++ b/src/sna/kgem.c
5594@@ -84,6 +84,9 @@ search_snoop_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags);
5595 #define DBG_NO_HANDLE_LUT 0
5596 #define DBG_NO_WT 0
5597 #define DBG_NO_WC_MMAP 0
5598+#define DBG_NO_BLT_Y 0
5599+#define DBG_NO_SCANOUT_Y 0
5600+#define DBG_NO_DETILING 0
5601 #define DBG_DUMP 0
5602 #define DBG_NO_MALLOC_CACHE 0
5603
5604@@ -96,11 +99,6 @@ search_snoop_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags);
5605 #define SHOW_BATCH_BEFORE 0
5606 #define SHOW_BATCH_AFTER 0
5607
5608-#if !USE_WC_MMAP
5609-#undef DBG_NO_WC_MMAP
5610-#define DBG_NO_WC_MMAP 1
5611-#endif
5612-
5613 #if 0
5614 #define ASSERT_IDLE(kgem__, handle__) assert(!__kgem_busy(kgem__, handle__))
5615 #define ASSERT_MAYBE_IDLE(kgem__, handle__, expect__) assert(!(expect__) || !__kgem_busy(kgem__, handle__))
5616@@ -187,6 +185,15 @@ struct local_i915_gem_caching {
5617 #define LOCAL_IOCTL_I915_GEM_SET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_SET_CACHING, struct local_i915_gem_caching)
5618 #define LOCAL_IOCTL_I915_GEM_GET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_GET_CACHING, struct local_i915_gem_caching)
5619
5620+struct local_i915_gem_mmap {
5621+ uint32_t handle;
5622+ uint32_t pad;
5623+ uint64_t offset;
5624+ uint64_t size;
5625+ uint64_t addr_ptr;
5626+};
5627+#define LOCAL_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct local_i915_gem_mmap)
5628+
5629 struct local_i915_gem_mmap2 {
5630 uint32_t handle;
5631 uint32_t pad;
5632@@ -216,6 +223,12 @@ static struct kgem_bo *__kgem_freed_bo;
5633 static struct kgem_request *__kgem_freed_request;
5634 static struct drm_i915_gem_exec_object2 _kgem_dummy_exec;
5635
5636+static inline struct sna *__to_sna(struct kgem *kgem)
5637+{
5638+ /* minor layering violations */
5639+ return container_of(kgem, struct sna, kgem);
5640+}
5641+
5642 static inline int bytes(struct kgem_bo *bo)
5643 {
5644 return __kgem_bo_size(bo);
5645@@ -224,25 +237,31 @@ static inline int bytes(struct kgem_bo *bo)
5646 #define bucket(B) (B)->size.pages.bucket
5647 #define num_pages(B) (B)->size.pages.count
5648
5649-static int do_ioctl(int fd, unsigned long req, void *arg)
5650+static int __do_ioctl(int fd, unsigned long req, void *arg)
5651 {
5652- int err;
5653-
5654-restart:
5655- if (ioctl(fd, req, arg) == 0)
5656- return 0;
5657+ do {
5658+ int err;
5659
5660- err = errno;
5661+ switch ((err = errno)) {
5662+ case EAGAIN:
5663+ sched_yield();
5664+ case EINTR:
5665+ break;
5666+ default:
5667+ return -err;
5668+ }
5669
5670- if (err == EINTR)
5671- goto restart;
5672+ if (likely(ioctl(fd, req, arg) == 0))
5673+ return 0;
5674+ } while (1);
5675+}
5676
5677- if (err == EAGAIN) {
5678- sched_yield();
5679- goto restart;
5680- }
5681+inline static int do_ioctl(int fd, unsigned long req, void *arg)
5682+{
5683+ if (likely(ioctl(fd, req, arg) == 0))
5684+ return 0;
5685
5686- return -err;
5687+ return __do_ioctl(fd, req, arg);
5688 }
5689
5690 #ifdef DEBUG_MEMORY
5691@@ -266,6 +285,9 @@ static void assert_tiling(struct kgem *kgem, struct kgem_bo *bo)
5692
5693 assert(bo);
5694
5695+ if (!kgem->can_fence && kgem->gen >= 040 && bo->tiling)
5696+ return; /* lies */
5697+
5698 VG_CLEAR(tiling);
5699 tiling.handle = bo->handle;
5700 tiling.tiling_mode = bo->tiling;
5701@@ -273,7 +295,7 @@ static void assert_tiling(struct kgem *kgem, struct kgem_bo *bo)
5702 assert(tiling.tiling_mode == bo->tiling);
5703 }
5704
5705-static void assert_cacheing(struct kgem *kgem, struct kgem_bo *bo)
5706+static void assert_caching(struct kgem *kgem, struct kgem_bo *bo)
5707 {
5708 struct local_i915_gem_caching arg;
5709 int expect = kgem->has_llc ? SNOOPED : UNCACHED;
5710@@ -294,24 +316,117 @@ static void assert_bo_retired(struct kgem_bo *bo)
5711 assert(bo->refcnt);
5712 assert(bo->rq == NULL);
5713 assert(bo->exec == NULL);
5714+ assert(!bo->needs_flush);
5715 assert(list_is_empty(&bo->request));
5716 }
5717 #else
5718 #define assert_tiling(kgem, bo)
5719-#define assert_cacheing(kgem, bo)
5720+#define assert_caching(kgem, bo)
5721 #define assert_bo_retired(bo)
5722 #endif
5723
5724+static int __find_debugfs(struct kgem *kgem)
5725+{
5726+ int i;
5727+
5728+ for (i = 0; i < DRM_MAX_MINOR; i++) {
5729+ char path[80];
5730+
5731+ sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i);
5732+ if (access(path, R_OK) == 0)
5733+ return i;
5734+
5735+ sprintf(path, "/debug/dri/%d/i915_wedged", i);
5736+ if (access(path, R_OK) == 0)
5737+ return i;
5738+ }
5739+
5740+ return -1;
5741+}
5742+
5743+static int kgem_get_minor(struct kgem *kgem)
5744+{
5745+ struct stat st;
5746+
5747+ if (fstat(kgem->fd, &st))
5748+ return __find_debugfs(kgem);
5749+
5750+ if (!S_ISCHR(st.st_mode))
5751+ return __find_debugfs(kgem);
5752+
5753+ return st.st_rdev & 0x63;
5754+}
5755+
5756+static bool find_hang_state(struct kgem *kgem, char *path, int maxlen)
5757+{
5758+ int minor = kgem_get_minor(kgem);
5759+
5760+ /* Search for our hang state in a few canonical locations.
5761+ * In the unlikely event of having multiple devices, we
5762+ * will need to check which minor actually corresponds to ours.
5763+ */
5764+
5765+ snprintf(path, maxlen, "/sys/class/drm/card%d/error", minor);
5766+ if (access(path, R_OK) == 0)
5767+ return true;
5768+
5769+ snprintf(path, maxlen, "/sys/kernel/debug/dri/%d/i915_error_state", minor);
5770+ if (access(path, R_OK) == 0)
5771+ return true;
5772+
5773+ snprintf(path, maxlen, "/debug/dri/%d/i915_error_state", minor);
5774+ if (access(path, R_OK) == 0)
5775+ return true;
5776+
5777+ path[0] = '\0';
5778+ return false;
5779+}
5780+
5781+static bool has_error_state(struct kgem *kgem, char *path)
5782+{
5783+ bool ret = false;
5784+ char no;
5785+ int fd;
5786+
5787+ fd = open(path, O_RDONLY);
5788+ if (fd >= 0) {
5789+ ret = read(fd, &no, 1) == 1 && no != 'N';
5790+ close(fd);
5791+ }
5792+
5793+ return ret;
5794+}
5795+
5796+static int kgem_get_screen_index(struct kgem *kgem)
5797+{
5798+ return __to_sna(kgem)->scrn->scrnIndex;
5799+}
5800+
5801 static void
5802 __kgem_set_wedged(struct kgem *kgem)
5803 {
5804+ static int once;
5805+ char path[256];
5806+
5807+ if (kgem->wedged)
5808+ return;
5809+
5810+ if (!once &&
5811+ find_hang_state(kgem, path, sizeof(path)) &&
5812+ has_error_state(kgem, path)) {
5813+ xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
5814+ "When reporting this, please include %s and the full dmesg.\n",
5815+ path);
5816+ once = 1;
5817+ }
5818+
5819 kgem->wedged = true;
5820- sna_render_mark_wedged(container_of(kgem, struct sna, kgem));
5821+ sna_render_mark_wedged(__to_sna(kgem));
5822 }
5823
5824 static void kgem_sna_reset(struct kgem *kgem)
5825 {
5826- struct sna *sna = container_of(kgem, struct sna, kgem);
5827+ struct sna *sna = __to_sna(kgem);
5828
5829 sna->render.reset(sna);
5830 sna->blt_state.fill_bo = 0;
5831@@ -319,7 +434,7 @@ static void kgem_sna_reset(struct kgem *kgem)
5832
5833 static void kgem_sna_flush(struct kgem *kgem)
5834 {
5835- struct sna *sna = container_of(kgem, struct sna, kgem);
5836+ struct sna *sna = __to_sna(kgem);
5837
5838 sna->render.flush(sna);
5839
5840@@ -327,22 +442,40 @@ static void kgem_sna_flush(struct kgem *kgem)
5841 sna_render_flush_solid(sna);
5842 }
5843
5844-static bool gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
5845+static bool kgem_set_tiling(struct kgem *kgem, struct kgem_bo *bo,
5846+ int tiling, int stride)
5847 {
5848 struct drm_i915_gem_set_tiling set_tiling;
5849 int err;
5850
5851+ if (tiling == bo->tiling) {
5852+ if (tiling == I915_TILING_NONE) {
5853+ bo->pitch = stride;
5854+ return true;
5855+ }
5856+ if (stride == bo->pitch)
5857+ return true;
5858+ }
5859+
5860 if (DBG_NO_TILING)
5861 return false;
5862
5863 VG_CLEAR(set_tiling);
5864 restart:
5865- set_tiling.handle = handle;
5866+ set_tiling.handle = bo->handle;
5867 set_tiling.tiling_mode = tiling;
5868- set_tiling.stride = stride;
5869+ set_tiling.stride = tiling ? stride : 0;
5870
5871- if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0)
5872- return true;
5873+ if (ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) {
5874+ bo->tiling = set_tiling.tiling_mode;
5875+ bo->pitch = set_tiling.tiling_mode ? set_tiling.stride : stride;
5876+ DBG(("%s: handle=%d, tiling=%d [%d], pitch=%d [%d]: %d\n",
5877+ __FUNCTION__, bo->handle,
5878+ bo->tiling, tiling,
5879+ bo->pitch, stride,
5880+ set_tiling.tiling_mode == tiling));
5881+ return set_tiling.tiling_mode == tiling;
5882+ }
5883
5884 err = errno;
5885 if (err == EINTR)
5886@@ -353,6 +486,8 @@ restart:
5887 goto restart;
5888 }
5889
5890+ ERR(("%s: failed to set-tiling(tiling=%d, pitch=%d) for handle=%d: %d\n",
5891+ __FUNCTION__, tiling, stride, bo->handle, err));
5892 return false;
5893 }
5894
5895@@ -437,10 +572,15 @@ static void *__kgem_bo_map__gtt(struct kgem *kgem, struct kgem_bo *bo)
5896 DBG(("%s(handle=%d, size=%d)\n", __FUNCTION__,
5897 bo->handle, bytes(bo)));
5898
5899+ if (bo->tiling && !kgem->can_fence)
5900+ return NULL;
5901+
5902 VG_CLEAR(gtt);
5903 retry_gtt:
5904 gtt.handle = bo->handle;
5905 if ((err = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &gtt))) {
5906+ DBG(("%s: failed %d, throttling/cleaning caches\n",
5907+ __FUNCTION__, err));
5908 assert(err != EINVAL);
5909
5910 (void)__kgem_throttle_retire(kgem, 0);
5911@@ -460,6 +600,8 @@ retry_mmap:
5912 kgem->fd, gtt.offset);
5913 if (ptr == MAP_FAILED) {
5914 err = errno;
5915+ DBG(("%s: failed %d, throttling/cleaning caches\n",
5916+ __FUNCTION__, err));
5917 assert(err != EINVAL);
5918
5919 if (__kgem_throttle_retire(kgem, 0))
5920@@ -498,6 +640,8 @@ retry_wc:
5921 wc.size = bytes(bo);
5922 wc.flags = I915_MMAP_WC;
5923 if ((err = do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_MMAP_v2, &wc))) {
5924+ DBG(("%s: failed %d, throttling/cleaning caches\n",
5925+ __FUNCTION__, err));
5926 assert(err != EINVAL);
5927
5928 if (__kgem_throttle_retire(kgem, 0))
5929@@ -519,16 +663,19 @@ retry_wc:
5930
5931 static void *__kgem_bo_map__cpu(struct kgem *kgem, struct kgem_bo *bo)
5932 {
5933- struct drm_i915_gem_mmap mmap_arg;
5934+ struct local_i915_gem_mmap arg;
5935 int err;
5936
5937+ VG_CLEAR(arg);
5938+ arg.offset = 0;
5939+
5940 retry:
5941- VG_CLEAR(mmap_arg);
5942- mmap_arg.handle = bo->handle;
5943- mmap_arg.offset = 0;
5944- mmap_arg.size = bytes(bo);
5945- if ((err = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg))) {
5946- assert(err != EINVAL);
5947+ arg.handle = bo->handle;
5948+ arg.size = bytes(bo);
5949+ if ((err = do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_MMAP, &arg))) {
5950+ DBG(("%s: failed %d, throttling/cleaning caches\n",
5951+ __FUNCTION__, err));
5952+ assert(err != -EINVAL || bo->prime);
5953
5954 if (__kgem_throttle_retire(kgem, 0))
5955 goto retry;
5956@@ -536,15 +683,16 @@ retry:
5957 if (kgem_cleanup_cache(kgem))
5958 goto retry;
5959
5960- ERR(("%s: failed to mmap handle=%d, %d bytes, into CPU domain: %d\n",
5961- __FUNCTION__, bo->handle, bytes(bo), -err));
5962+ ERR(("%s: failed to mmap handle=%d (prime? %d), %d bytes, into CPU domain: %d\n",
5963+ __FUNCTION__, bo->handle, bo->prime, bytes(bo), -err));
5964+ bo->purged = 1;
5965 return NULL;
5966 }
5967
5968- VG(VALGRIND_MAKE_MEM_DEFINED(mmap_arg.addr_ptr, bytes(bo)));
5969+ VG(VALGRIND_MAKE_MEM_DEFINED(arg.addr_ptr, bytes(bo)));
5970
5971 DBG(("%s: caching CPU vma for %d\n", __FUNCTION__, bo->handle));
5972- return bo->map__cpu = (void *)(uintptr_t)mmap_arg.addr_ptr;
5973+ return bo->map__cpu = (void *)(uintptr_t)arg.addr_ptr;
5974 }
5975
5976 static int gem_write(int fd, uint32_t handle,
5977@@ -634,16 +782,10 @@ static void kgem_bo_retire(struct kgem *kgem, struct kgem_bo *bo)
5978 assert(bo->exec == NULL);
5979 assert(list_is_empty(&bo->vma));
5980
5981- if (bo->rq) {
5982- __kgem_bo_clear_busy(bo);
5983- kgem_retire(kgem);
5984- assert_bo_retired(bo);
5985- } else {
5986- assert(bo->exec == NULL);
5987- assert(list_is_empty(&bo->request));
5988- assert(!bo->needs_flush);
5989- ASSERT_IDLE(kgem, bo->handle);
5990- }
5991+ if (bo->rq)
5992+ __kgem_retire_requests_upto(kgem, bo);
5993+ ASSERT_IDLE(kgem, bo->handle);
5994+ assert_bo_retired(bo);
5995 }
5996
5997 static void kgem_bo_maybe_retire(struct kgem *kgem, struct kgem_bo *bo)
5998@@ -655,10 +797,8 @@ static void kgem_bo_maybe_retire(struct kgem *kgem, struct kgem_bo *bo)
5999 assert(list_is_empty(&bo->vma));
6000
6001 if (bo->rq) {
6002- if (!__kgem_busy(kgem, bo->handle)) {
6003- __kgem_bo_clear_busy(bo);
6004- kgem_retire(kgem);
6005- }
6006+ if (!__kgem_busy(kgem, bo->handle))
6007+ __kgem_retire_requests_upto(kgem, bo);
6008 } else {
6009 assert(!bo->needs_flush);
6010 ASSERT_IDLE(kgem, bo->handle);
6011@@ -694,6 +834,8 @@ retry:
6012 }
6013
6014 if ((err = gem_write(kgem->fd, bo->handle, 0, length, data))) {
6015+ DBG(("%s: failed %d, throttling/cleaning caches\n",
6016+ __FUNCTION__, err));
6017 assert(err != EINVAL);
6018
6019 (void)__kgem_throttle_retire(kgem, 0);
6020@@ -728,27 +870,21 @@ static uint32_t gem_create(int fd, int num_pages)
6021 return create.handle;
6022 }
6023
6024-static bool
6025+static void
6026 kgem_bo_set_purgeable(struct kgem *kgem, struct kgem_bo *bo)
6027 {
6028-#if DBG_NO_MADV
6029- return true;
6030-#else
6031+#if !DBG_NO_MADV
6032 struct drm_i915_gem_madvise madv;
6033
6034 assert(bo->exec == NULL);
6035- assert(!bo->purged);
6036
6037 VG_CLEAR(madv);
6038 madv.handle = bo->handle;
6039 madv.madv = I915_MADV_DONTNEED;
6040 if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) {
6041- bo->purged = 1;
6042- kgem->need_purge |= !madv.retained && bo->domain == DOMAIN_GPU;
6043- return madv.retained;
6044+ bo->purged = true;
6045+ kgem->need_purge |= !madv.retained && bo->domain != DOMAIN_CPU;
6046 }
6047-
6048- return true;
6049 #endif
6050 }
6051
6052@@ -788,7 +924,7 @@ kgem_bo_clear_purgeable(struct kgem *kgem, struct kgem_bo *bo)
6053 madv.madv = I915_MADV_WILLNEED;
6054 if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) {
6055 bo->purged = !madv.retained;
6056- kgem->need_purge |= !madv.retained && bo->domain == DOMAIN_GPU;
6057+ kgem->need_purge |= !madv.retained && bo->domain != DOMAIN_CPU;
6058 return madv.retained;
6059 }
6060
6061@@ -869,13 +1005,17 @@ static struct kgem_request *__kgem_request_alloc(struct kgem *kgem)
6062 {
6063 struct kgem_request *rq;
6064
6065- rq = __kgem_freed_request;
6066- if (rq) {
6067- __kgem_freed_request = *(struct kgem_request **)rq;
6068+ if (unlikely(kgem->wedged)) {
6069+ rq = &kgem->static_request;
6070 } else {
6071- rq = malloc(sizeof(*rq));
6072- if (rq == NULL)
6073- rq = &kgem->static_request;
6074+ rq = __kgem_freed_request;
6075+ if (rq) {
6076+ __kgem_freed_request = *(struct kgem_request **)rq;
6077+ } else {
6078+ rq = malloc(sizeof(*rq));
6079+ if (rq == NULL)
6080+ rq = &kgem->static_request;
6081+ }
6082 }
6083
6084 list_init(&rq->buffers);
6085@@ -925,11 +1065,11 @@ total_ram_size(void)
6086 #ifdef HAVE_STRUCT_SYSINFO_TOTALRAM
6087 struct sysinfo info;
6088 if (sysinfo(&info) == 0)
6089- return info.totalram * info.mem_unit;
6090+ return (size_t)info.totalram * info.mem_unit;
6091 #endif
6092
6093 #ifdef _SC_PHYS_PAGES
6094- return sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGE_SIZE);
6095+ return (size_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGE_SIZE);
6096 #endif
6097
6098 return 0;
6099@@ -1187,7 +1327,7 @@ static bool test_has_caching(struct kgem *kgem)
6100
6101 static bool test_has_userptr(struct kgem *kgem)
6102 {
6103- uint32_t handle;
6104+ struct local_i915_gem_userptr arg;
6105 void *ptr;
6106
6107 if (DBG_NO_USERPTR)
6108@@ -1200,11 +1340,23 @@ static bool test_has_userptr(struct kgem *kgem)
6109 if (posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE))
6110 return false;
6111
6112- handle = gem_userptr(kgem->fd, ptr, PAGE_SIZE, false);
6113- gem_close(kgem->fd, handle);
6114- free(ptr);
6115+ VG_CLEAR(arg);
6116+ arg.user_ptr = (uintptr_t)ptr;
6117+ arg.user_size = PAGE_SIZE;
6118+ arg.flags = I915_USERPTR_UNSYNCHRONIZED;
6119
6120- return handle != 0;
6121+ if (DBG_NO_UNSYNCHRONIZED_USERPTR ||
6122+ do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_USERPTR, &arg)) {
6123+ arg.flags &= ~I915_USERPTR_UNSYNCHRONIZED;
6124+ if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_USERPTR, &arg))
6125+ arg.handle = 0;
6126+ /* Leak the userptr bo to keep the mmu_notifier alive */
6127+ } else {
6128+ gem_close(kgem->fd, arg.handle);
6129+ free(ptr);
6130+ }
6131+
6132+ return arg.handle != 0;
6133 }
6134
6135 static bool test_has_create2(struct kgem *kgem)
6136@@ -1227,67 +1379,146 @@ static bool test_has_create2(struct kgem *kgem)
6137 #endif
6138 }
6139
6140-static bool test_has_secure_batches(struct kgem *kgem)
6141+static bool test_can_blt_y(struct kgem *kgem)
6142 {
6143- if (DBG_NO_SECURE_BATCHES)
6144+ struct drm_i915_gem_exec_object2 object;
6145+ uint32_t batch[] = {
6146+#define MI_LOAD_REGISTER_IMM (0x22<<23 | (3-2))
6147+#define BCS_SWCTRL 0x22200
6148+#define BCS_SRC_Y (1 << 0)
6149+#define BCS_DST_Y (1 << 1)
6150+ MI_LOAD_REGISTER_IMM,
6151+ BCS_SWCTRL,
6152+ (BCS_SRC_Y | BCS_DST_Y) << 16 | (BCS_SRC_Y | BCS_DST_Y),
6153+
6154+ MI_LOAD_REGISTER_IMM,
6155+ BCS_SWCTRL,
6156+ (BCS_SRC_Y | BCS_DST_Y) << 16,
6157+
6158+ MI_BATCH_BUFFER_END,
6159+ 0,
6160+ };
6161+ int ret;
6162+
6163+ if (DBG_NO_BLT_Y)
6164 return false;
6165
6166- return gem_param(kgem, LOCAL_I915_PARAM_HAS_SECURE_BATCHES) > 0;
6167+ if (kgem->gen < 060)
6168+ return false;
6169+
6170+ memset(&object, 0, sizeof(object));
6171+ object.handle = gem_create(kgem->fd, 1);
6172+
6173+ ret = gem_write(kgem->fd, object.handle, 0, sizeof(batch), batch);
6174+ if (ret == 0) {
6175+ struct drm_i915_gem_execbuffer2 execbuf;
6176+
6177+ memset(&execbuf, 0, sizeof(execbuf));
6178+ execbuf.buffers_ptr = (uintptr_t)&object;
6179+ execbuf.buffer_count = 1;
6180+ execbuf.flags = KGEM_BLT;
6181+
6182+ ret = do_ioctl(kgem->fd,
6183+ DRM_IOCTL_I915_GEM_EXECBUFFER2,
6184+ &execbuf);
6185+ }
6186+ gem_close(kgem->fd, object.handle);
6187+
6188+ return ret == 0;
6189 }
6190
6191-static bool test_has_pinned_batches(struct kgem *kgem)
6192+static bool gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
6193 {
6194- if (DBG_NO_PINNED_BATCHES)
6195+ struct drm_i915_gem_set_tiling set_tiling;
6196+
6197+ if (DBG_NO_TILING)
6198 return false;
6199
6200- return gem_param(kgem, LOCAL_I915_PARAM_HAS_PINNED_BATCHES) > 0;
6201-}
6202+ VG_CLEAR(set_tiling);
6203+ set_tiling.handle = handle;
6204+ set_tiling.tiling_mode = tiling;
6205+ set_tiling.stride = stride;
6206
6207-static int kgem_get_screen_index(struct kgem *kgem)
6208-{
6209- struct sna *sna = container_of(kgem, struct sna, kgem);
6210- return sna->scrn->scrnIndex;
6211+ if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0)
6212+ return set_tiling.tiling_mode == tiling;
6213+
6214+ return false;
6215 }
6216
6217-static int __find_debugfs(struct kgem *kgem)
6218+static bool test_can_scanout_y(struct kgem *kgem)
6219 {
6220- int i;
6221-
6222- for (i = 0; i < DRM_MAX_MINOR; i++) {
6223- char path[80];
6224+ struct drm_mode_fb_cmd arg;
6225+ bool ret = false;
6226
6227- sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i);
6228- if (access(path, R_OK) == 0)
6229- return i;
6230+ if (DBG_NO_SCANOUT_Y)
6231+ return false;
6232
6233- sprintf(path, "/debug/dri/%d/i915_wedged", i);
6234- if (access(path, R_OK) == 0)
6235- return i;
6236- }
6237+ VG_CLEAR(arg);
6238+ arg.width = 32;
6239+ arg.height = 32;
6240+ arg.pitch = 4*32;
6241+ arg.bpp = 32;
6242+ arg.depth = 24;
6243+ arg.handle = gem_create(kgem->fd, 1);
6244+
6245+ if (gem_set_tiling(kgem->fd, arg.handle, I915_TILING_Y, arg.pitch))
6246+ ret = do_ioctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &arg) == 0;
6247+ if (!ret) {
6248+ struct local_mode_fb_cmd2 {
6249+ uint32_t fb_id;
6250+ uint32_t width, height;
6251+ uint32_t pixel_format;
6252+ uint32_t flags;
6253+
6254+ uint32_t handles[4];
6255+ uint32_t pitches[4];
6256+ uint32_t offsets[4];
6257+ uint64_t modifiers[4];
6258+ } f;
6259+#define LOCAL_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct local_mode_fb_cmd2)
6260+ memset(&f, 0, sizeof(f));
6261+ f.width = arg.width;
6262+ f.height = arg.height;
6263+ f.handles[0] = arg.handle;
6264+ f.pitches[0] = arg.pitch;
6265+ f.modifiers[0] = (uint64_t)1 << 56 | 2; /* MOD_Y_TILED */
6266+ f.pixel_format = 'X' | 'R' << 8 | '2' << 16 | '4' << 24; /* XRGB8888 */
6267+ f.flags = 1 << 1; /* + modifier */
6268+ if (drmIoctl(kgem->fd, LOCAL_IOCTL_MODE_ADDFB2, &f) == 0) {
6269+ ret = true;
6270+ arg.fb_id = f.fb_id;
6271+ }
6272+ }
6273+ do_ioctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &arg.fb_id);
6274+ gem_close(kgem->fd, arg.handle);
6275
6276- return -1;
6277+ return ret;
6278 }
6279
6280-static int kgem_get_minor(struct kgem *kgem)
6281+static bool test_has_secure_batches(struct kgem *kgem)
6282 {
6283- struct stat st;
6284+ if (DBG_NO_SECURE_BATCHES)
6285+ return false;
6286
6287- if (fstat(kgem->fd, &st))
6288- return __find_debugfs(kgem);
6289+ return gem_param(kgem, LOCAL_I915_PARAM_HAS_SECURE_BATCHES) > 0;
6290+}
6291
6292- if (!S_ISCHR(st.st_mode))
6293- return __find_debugfs(kgem);
6294+static bool test_has_pinned_batches(struct kgem *kgem)
6295+{
6296+ if (DBG_NO_PINNED_BATCHES)
6297+ return false;
6298
6299- return st.st_rdev & 0x63;
6300+ return gem_param(kgem, LOCAL_I915_PARAM_HAS_PINNED_BATCHES) > 0;
6301 }
6302
6303 static bool kgem_init_pinned_batches(struct kgem *kgem)
6304 {
6305 int count[2] = { 16, 4 };
6306 int size[2] = { 1, 4 };
6307+ int ret = 0;
6308 int n, i;
6309
6310- if (kgem->wedged)
6311+ if (unlikely(kgem->wedged))
6312 return true;
6313
6314 for (n = 0; n < ARRAY_SIZE(count); n++) {
6315@@ -1311,7 +1542,8 @@ static bool kgem_init_pinned_batches(struct kgem *kgem)
6316 }
6317
6318 pin.alignment = 0;
6319- if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_PIN, &pin)) {
6320+ ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_PIN, &pin);
6321+ if (ret) {
6322 gem_close(kgem->fd, pin.handle);
6323 free(bo);
6324 goto err;
6325@@ -1333,6 +1565,16 @@ err:
6326 }
6327 }
6328
6329+ /* If we fail to pin some memory for 830gm/845g, we need to disable
6330+ * acceleration as otherwise the machine will eventually fail. However,
6331+ * the kernel started arbitrarily rejecting PIN, so hope for the best
6332+ * if the ioctl no longer works.
6333+ */
6334+ if (ret != -ENODEV && kgem->gen == 020)
6335+ return false;
6336+
6337+ kgem->has_pinned_batches = false;
6338+
6339 /* For simplicity populate the lists with a single unpinned bo */
6340 for (n = 0; n < ARRAY_SIZE(count); n++) {
6341 struct kgem_bo *bo;
6342@@ -1340,18 +1582,18 @@ err:
6343
6344 handle = gem_create(kgem->fd, size[n]);
6345 if (handle == 0)
6346- break;
6347+ return false;
6348
6349 bo = __kgem_bo_alloc(handle, size[n]);
6350 if (bo == NULL) {
6351 gem_close(kgem->fd, handle);
6352- break;
6353+ return false;
6354 }
6355
6356 debug_alloc__bo(kgem, bo);
6357 list_add(&bo->list, &kgem->pinned_batches[n]);
6358 }
6359- return false;
6360+ return true;
6361 }
6362
6363 static void kgem_init_swizzling(struct kgem *kgem)
6364@@ -1364,7 +1606,7 @@ static void kgem_init_swizzling(struct kgem *kgem)
6365 } tiling;
6366 #define LOCAL_IOCTL_I915_GEM_GET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct local_i915_gem_get_tiling_v2)
6367
6368- VG_CLEAR(tiling);
6369+ memset(&tiling, 0, sizeof(tiling));
6370 tiling.handle = gem_create(kgem->fd, 1);
6371 if (!tiling.handle)
6372 return;
6373@@ -1375,12 +1617,21 @@ static void kgem_init_swizzling(struct kgem *kgem)
6374 if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_GET_TILING, &tiling))
6375 goto out;
6376
6377- if (kgem->gen < 50 && tiling.phys_swizzle_mode != tiling.swizzle_mode)
6378+ DBG(("%s: swizzle_mode=%d, phys_swizzle_mode=%d\n",
6379+ __FUNCTION__, tiling.swizzle_mode, tiling.phys_swizzle_mode));
6380+
6381+ kgem->can_fence =
6382+ !DBG_NO_TILING &&
6383+ tiling.swizzle_mode != I915_BIT_6_SWIZZLE_UNKNOWN;
6384+
6385+ if (kgem->gen < 050 && tiling.phys_swizzle_mode != tiling.swizzle_mode)
6386 goto out;
6387
6388- choose_memcpy_tiled_x(kgem, tiling.swizzle_mode);
6389+ if (!DBG_NO_DETILING)
6390+ choose_memcpy_tiled_x(kgem, tiling.swizzle_mode);
6391 out:
6392 gem_close(kgem->fd, tiling.handle);
6393+ DBG(("%s: can fence?=%d\n", __FUNCTION__, kgem->can_fence));
6394 }
6395
6396 static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
6397@@ -1399,6 +1650,7 @@ static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
6398 bo->handle, (long long)bo->presumed_offset));
6399 for (n = 0; n < kgem->nreloc__self; n++) {
6400 int i = kgem->reloc__self[n];
6401+ uint64_t addr;
6402
6403 assert(kgem->reloc[i].target_handle == ~0U);
6404 kgem->reloc[i].target_handle = bo->target_handle;
6405@@ -1412,13 +1664,17 @@ static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
6406
6407 kgem->reloc[i].delta -= shrink;
6408 }
6409- kgem->batch[kgem->reloc[i].offset/sizeof(uint32_t)] =
6410- kgem->reloc[i].delta + bo->presumed_offset;
6411+ addr = (int)kgem->reloc[i].delta + bo->presumed_offset;
6412+ kgem->batch[kgem->reloc[i].offset/sizeof(uint32_t)] = addr;
6413+ if (kgem->gen >= 0100)
6414+ kgem->batch[kgem->reloc[i].offset/sizeof(uint32_t) + 1] = addr >> 32;
6415 }
6416
6417 if (n == 256) {
6418 for (n = kgem->reloc__self[255]; n < kgem->nreloc; n++) {
6419 if (kgem->reloc[n].target_handle == ~0U) {
6420+ uint64_t addr;
6421+
6422 kgem->reloc[n].target_handle = bo->target_handle;
6423 kgem->reloc[n].presumed_offset = bo->presumed_offset;
6424
6425@@ -1429,8 +1685,11 @@ static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
6426 kgem->reloc[n].delta - shrink));
6427 kgem->reloc[n].delta -= shrink;
6428 }
6429- kgem->batch[kgem->reloc[n].offset/sizeof(uint32_t)] =
6430- kgem->reloc[n].delta + bo->presumed_offset;
6431+
6432+ addr = (int)kgem->reloc[n].delta + bo->presumed_offset;
6433+ kgem->batch[kgem->reloc[n].offset/sizeof(uint32_t)] = addr;
6434+ if (kgem->gen >= 0100)
6435+ kgem->batch[kgem->reloc[n].offset/sizeof(uint32_t) + 1] = addr >> 32;
6436 }
6437 }
6438 }
6439@@ -1444,6 +1703,44 @@ static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
6440 }
6441 }
6442
6443+static int kgem_bo_wait(struct kgem *kgem, struct kgem_bo *bo)
6444+{
6445+ struct local_i915_gem_wait {
6446+ uint32_t handle;
6447+ uint32_t flags;
6448+ int64_t timeout;
6449+ } wait;
6450+#define LOCAL_I915_GEM_WAIT 0x2c
6451+#define LOCAL_IOCTL_I915_GEM_WAIT DRM_IOWR(DRM_COMMAND_BASE + LOCAL_I915_GEM_WAIT, struct local_i915_gem_wait)
6452+ int ret;
6453+
6454+ DBG(("%s: waiting for handle=%d\n", __FUNCTION__, bo->handle));
6455+ if (bo->rq == NULL)
6456+ return 0;
6457+
6458+ VG_CLEAR(wait);
6459+ wait.handle = bo->handle;
6460+ wait.flags = 0;
6461+ wait.timeout = -1;
6462+ ret = do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_WAIT, &wait);
6463+ if (ret) {
6464+ struct drm_i915_gem_set_domain set_domain;
6465+
6466+ VG_CLEAR(set_domain);
6467+ set_domain.handle = bo->handle;
6468+ set_domain.read_domains = I915_GEM_DOMAIN_GTT;
6469+ set_domain.write_domain = I915_GEM_DOMAIN_GTT;
6470+ ret = do_ioctl(kgem->fd,
6471+ DRM_IOCTL_I915_GEM_SET_DOMAIN,
6472+ &set_domain);
6473+ }
6474+
6475+ if (ret == 0)
6476+ __kgem_retire_requests_upto(kgem, bo);
6477+
6478+ return ret;
6479+}
6480+
6481 static struct kgem_bo *kgem_new_batch(struct kgem *kgem)
6482 {
6483 struct kgem_bo *last;
6484@@ -1464,20 +1761,41 @@ static struct kgem_bo *kgem_new_batch(struct kgem *kgem)
6485 if (!kgem->has_llc)
6486 flags |= CREATE_UNCACHED;
6487
6488+restart:
6489 kgem->batch_bo = kgem_create_linear(kgem,
6490 sizeof(uint32_t)*kgem->batch_size,
6491 flags);
6492 if (kgem->batch_bo)
6493 kgem->batch = kgem_bo_map__cpu(kgem, kgem->batch_bo);
6494 if (kgem->batch == NULL) {
6495- DBG(("%s: unable to map batch bo, mallocing(size=%d)\n",
6496- __FUNCTION__,
6497- sizeof(uint32_t)*kgem->batch_size));
6498+ int ring = kgem->ring == KGEM_BLT;
6499+ assert(ring < ARRAY_SIZE(kgem->requests));
6500+
6501 if (kgem->batch_bo) {
6502 kgem_bo_destroy(kgem, kgem->batch_bo);
6503 kgem->batch_bo = NULL;
6504 }
6505
6506+ if (!list_is_empty(&kgem->requests[ring])) {
6507+ struct kgem_request *rq;
6508+
6509+ rq = list_first_entry(&kgem->requests[ring],
6510+ struct kgem_request, list);
6511+ assert(rq->ring == ring);
6512+ assert(rq->bo);
6513+ assert(RQ(rq->bo->rq) == rq);
6514+ if (kgem_bo_wait(kgem, rq->bo) == 0)
6515+ goto restart;
6516+ }
6517+
6518+ if (flags & CREATE_NO_THROTTLE) {
6519+ flags &= ~CREATE_NO_THROTTLE;
6520+ if (kgem_cleanup_cache(kgem))
6521+ goto restart;
6522+ }
6523+
6524+ DBG(("%s: unable to map batch bo, mallocing(size=%d)\n",
6525+ __FUNCTION__, sizeof(uint32_t)*kgem->batch_size));
6526 if (posix_memalign((void **)&kgem->batch, PAGE_SIZE,
6527 ALIGN(sizeof(uint32_t) * kgem->batch_size, PAGE_SIZE))) {
6528 ERR(("%s: batch allocation failed, disabling acceleration\n", __FUNCTION__));
6529@@ -1495,18 +1813,79 @@ static struct kgem_bo *kgem_new_batch(struct kgem *kgem)
6530 return last;
6531 }
6532
6533-void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
6534+static void
6535+no_retire(struct kgem *kgem)
6536+{
6537+ (void)kgem;
6538+}
6539+
6540+static void
6541+no_expire(struct kgem *kgem)
6542+{
6543+ (void)kgem;
6544+}
6545+
6546+static void
6547+no_context_switch(struct kgem *kgem, int new_mode)
6548+{
6549+ (void)kgem;
6550+ (void)new_mode;
6551+}
6552+
6553+static uint64_t get_gtt_size(int fd)
6554 {
6555 struct drm_i915_gem_get_aperture aperture;
6556+ struct local_i915_gem_context_param {
6557+ uint32_t context;
6558+ uint32_t size;
6559+ uint64_t param;
6560+#define LOCAL_CONTEXT_PARAM_BAN_PERIOD 0x1
6561+#define LOCAL_CONTEXT_PARAM_NO_ZEROMAP 0x2
6562+#define LOCAL_CONTEXT_PARAM_GTT_SIZE 0x3
6563+ uint64_t value;
6564+ } p;
6565+#define LOCAL_I915_GEM_CONTEXT_GETPARAM 0x34
6566+#define LOCAL_IOCTL_I915_GEM_CONTEXT_GETPARAM DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_CONTEXT_GETPARAM, struct local_i915_gem_context_param)
6567+
6568+ memset(&aperture, 0, sizeof(aperture));
6569+
6570+ memset(&p, 0, sizeof(p));
6571+ p.param = LOCAL_CONTEXT_PARAM_GTT_SIZE;
6572+ if (drmIoctl(fd, LOCAL_IOCTL_I915_GEM_CONTEXT_GETPARAM, &p) == 0)
6573+ aperture.aper_size = p.value;
6574+ if (aperture.aper_size == 0)
6575+ (void)drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
6576+ if (aperture.aper_size == 0)
6577+ aperture.aper_size = 64*1024*1024;
6578+
6579+ DBG(("%s: aperture size %lld, available now %lld\n",
6580+ __FUNCTION__,
6581+ (long long)aperture.aper_size,
6582+ (long long)aperture.aper_available_size));
6583+
6584+ /* clamp aperture to uint32_t for simplicity */
6585+ if (aperture.aper_size > 0xc0000000)
6586+ aperture.aper_size = 0xc0000000;
6587+
6588+ return aperture.aper_size;
6589+}
6590+
6591+void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
6592+{
6593 size_t totalram;
6594 unsigned half_gpu_max;
6595 unsigned int i, j;
6596+ uint64_t gtt_size;
6597
6598 DBG(("%s: fd=%d, gen=%d\n", __FUNCTION__, fd, gen));
6599
6600 kgem->fd = fd;
6601 kgem->gen = gen;
6602
6603+ kgem->retire = no_retire;
6604+ kgem->expire = no_expire;
6605+ kgem->context_switch = no_context_switch;
6606+
6607 list_init(&kgem->requests[0]);
6608 list_init(&kgem->requests[1]);
6609 list_init(&kgem->batch_buffers);
6610@@ -1586,10 +1965,18 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
6611 DBG(("%s: can blt to cpu? %d\n", __FUNCTION__,
6612 kgem->can_blt_cpu));
6613
6614+ kgem->can_blt_y = test_can_blt_y(kgem);
6615+ DBG(("%s: can blit to Y-tiled surfaces? %d\n", __FUNCTION__,
6616+ kgem->can_blt_y));
6617+
6618 kgem->can_render_y = gen != 021 && (gen >> 3) != 4;
6619 DBG(("%s: can render to Y-tiled surfaces? %d\n", __FUNCTION__,
6620 kgem->can_render_y));
6621
6622+ kgem->can_scanout_y = test_can_scanout_y(kgem);
6623+ DBG(("%s: can scanout Y-tiled surfaces? %d\n", __FUNCTION__,
6624+ kgem->can_scanout_y));
6625+
6626 kgem->has_secure_batches = test_has_secure_batches(kgem);
6627 DBG(("%s: can use privileged batchbuffers? %d\n", __FUNCTION__,
6628 kgem->has_secure_batches));
6629@@ -1620,7 +2007,7 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
6630 if (!kgem->has_relaxed_delta && kgem->batch_size > 4*1024)
6631 kgem->batch_size = 4*1024;
6632
6633- if (!kgem_init_pinned_batches(kgem) && gen == 020) {
6634+ if (!kgem_init_pinned_batches(kgem)) {
6635 xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING,
6636 "Unable to reserve memory for GPU, disabling acceleration.\n");
6637 __kgem_set_wedged(kgem);
6638@@ -1640,35 +2027,24 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
6639 !DBG_NO_CPU && (kgem->has_llc | kgem->has_userptr | kgem->has_caching),
6640 kgem->has_llc, kgem->has_caching, kgem->has_userptr));
6641
6642- VG_CLEAR(aperture);
6643- aperture.aper_size = 0;
6644- (void)do_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
6645- if (aperture.aper_size == 0)
6646- aperture.aper_size = 64*1024*1024;
6647-
6648- DBG(("%s: aperture size %lld, available now %lld\n",
6649- __FUNCTION__,
6650- (long long)aperture.aper_size,
6651- (long long)aperture.aper_available_size));
6652-
6653- kgem->aperture_total = aperture.aper_size;
6654- kgem->aperture_high = aperture.aper_size * 3/4;
6655- kgem->aperture_low = aperture.aper_size * 1/3;
6656+ gtt_size = get_gtt_size(fd);
6657+ kgem->aperture_total = gtt_size;
6658+ kgem->aperture_high = gtt_size * 3/4;
6659+ kgem->aperture_low = gtt_size * 1/3;
6660 if (gen < 033) {
6661 /* Severe alignment penalties */
6662 kgem->aperture_high /= 2;
6663 kgem->aperture_low /= 2;
6664 }
6665- DBG(("%s: aperture low=%d [%d], high=%d [%d]\n", __FUNCTION__,
6666+ DBG(("%s: aperture low=%u [%u], high=%u [%u]\n", __FUNCTION__,
6667 kgem->aperture_low, kgem->aperture_low / (1024*1024),
6668 kgem->aperture_high, kgem->aperture_high / (1024*1024)));
6669
6670 kgem->aperture_mappable = 256 * 1024 * 1024;
6671 if (dev != NULL)
6672 kgem->aperture_mappable = agp_aperture_size(dev, gen);
6673- if (kgem->aperture_mappable == 0 ||
6674- kgem->aperture_mappable > aperture.aper_size)
6675- kgem->aperture_mappable = aperture.aper_size;
6676+ if (kgem->aperture_mappable == 0 || kgem->aperture_mappable > gtt_size)
6677+ kgem->aperture_mappable = gtt_size;
6678 DBG(("%s: aperture mappable=%d [%d MiB]\n", __FUNCTION__,
6679 kgem->aperture_mappable, kgem->aperture_mappable / (1024*1024)));
6680
6681@@ -1697,7 +2073,7 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
6682 __FUNCTION__));
6683 totalram = kgem->aperture_total;
6684 }
6685- DBG(("%s: total ram=%ld\n", __FUNCTION__, (long)totalram));
6686+ DBG(("%s: total ram=%lld\n", __FUNCTION__, (long long)totalram));
6687 if (kgem->max_object_size > totalram / 2)
6688 kgem->max_object_size = totalram / 2;
6689 if (kgem->max_gpu_size > totalram / 4)
6690@@ -1749,11 +2125,11 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
6691 if (DBG_NO_CPU)
6692 kgem->max_cpu_size = 0;
6693
6694- DBG(("%s: maximum object size=%d\n",
6695+ DBG(("%s: maximum object size=%u\n",
6696 __FUNCTION__, kgem->max_object_size));
6697- DBG(("%s: large object thresold=%d\n",
6698+ DBG(("%s: large object thresold=%u\n",
6699 __FUNCTION__, kgem->large_object_size));
6700- DBG(("%s: max object sizes (gpu=%d, cpu=%d, tile upload=%d, copy=%d)\n",
6701+ DBG(("%s: max object sizes (gpu=%u, cpu=%u, tile upload=%u, copy=%u)\n",
6702 __FUNCTION__,
6703 kgem->max_gpu_size, kgem->max_cpu_size,
6704 kgem->max_upload_tile_size, kgem->max_copy_tile_size));
6705@@ -2043,8 +2419,34 @@ static void kgem_add_bo(struct kgem *kgem, struct kgem_bo *bo)
6706 kgem->flush |= bo->flush;
6707 }
6708
6709+static void kgem_clear_swctrl(struct kgem *kgem)
6710+{
6711+ uint32_t *b;
6712+
6713+ if (kgem->bcs_state == 0)
6714+ return;
6715+
6716+ DBG(("%s: clearin SWCTRL LRI from %x\n",
6717+ __FUNCTION__, kgem->bcs_state));
6718+
6719+ b = kgem->batch + kgem->nbatch;
6720+ kgem->nbatch += 7;
6721+
6722+ *b++ = MI_FLUSH_DW;
6723+ *b++ = 0;
6724+ *b++ = 0;
6725+ *b++ = 0;
6726+
6727+ *b++ = MI_LOAD_REGISTER_IMM;
6728+ *b++ = BCS_SWCTRL;
6729+ *b++ = (BCS_SRC_Y | BCS_DST_Y) << 16;
6730+
6731+ kgem->bcs_state = 0;
6732+}
6733+
6734 static uint32_t kgem_end_batch(struct kgem *kgem)
6735 {
6736+ kgem_clear_swctrl(kgem);
6737 kgem->batch[kgem->nbatch++] = MI_BATCH_BUFFER_END;
6738 if (kgem->nbatch & 1)
6739 kgem->batch[kgem->nbatch++] = MI_NOOP;
6740@@ -2150,13 +2552,16 @@ inline static void kgem_bo_move_to_inactive(struct kgem *kgem,
6741 assert(!bo->snoop);
6742 assert(!bo->flush);
6743 assert(!bo->needs_flush);
6744+ assert(!bo->delta);
6745 assert(list_is_empty(&bo->vma));
6746 assert_tiling(kgem, bo);
6747- assert_cacheing(kgem, bo);
6748+ assert_caching(kgem, bo);
6749 ASSERT_IDLE(kgem, bo->handle);
6750
6751 if (bucket(bo) >= NUM_CACHE_BUCKETS) {
6752 if (bo->map__gtt) {
6753+ DBG(("%s: relinquishing large GTT mapping for handle=%d\n",
6754+ __FUNCTION__, bo->handle));
6755 munmap(bo->map__gtt, bytes(bo));
6756 bo->map__gtt = NULL;
6757 }
6758@@ -2167,6 +2572,8 @@ inline static void kgem_bo_move_to_inactive(struct kgem *kgem,
6759 assert(list_is_empty(&bo->vma));
6760 list_move(&bo->list, &kgem->inactive[bucket(bo)]);
6761 if (bo->map__gtt && !kgem_bo_can_map(kgem, bo)) {
6762+ DBG(("%s: relinquishing old GTT mapping for handle=%d\n",
6763+ __FUNCTION__, bo->handle));
6764 munmap(bo->map__gtt, bytes(bo));
6765 bo->map__gtt = NULL;
6766 }
6767@@ -2191,6 +2598,10 @@ static struct kgem_bo *kgem_bo_replace_io(struct kgem_bo *bo)
6768 return bo;
6769
6770 assert(!bo->snoop);
6771+ assert(!bo->purged);
6772+ assert(!bo->scanout);
6773+ assert(!bo->delta);
6774+
6775 if (__kgem_freed_bo) {
6776 base = __kgem_freed_bo;
6777 __kgem_freed_bo = *(struct kgem_bo **)base;
6778@@ -2221,6 +2632,7 @@ inline static void kgem_bo_remove_from_inactive(struct kgem *kgem,
6779 list_del(&bo->list);
6780 assert(bo->rq == NULL);
6781 assert(bo->exec == NULL);
6782+ assert(!bo->purged);
6783 if (!list_is_empty(&bo->vma)) {
6784 assert(bo->map__gtt || bo->map__wc || bo->map__cpu);
6785 list_del(&bo->vma);
6786@@ -2305,7 +2717,6 @@ static void kgem_bo_move_to_scanout(struct kgem *kgem, struct kgem_bo *bo)
6787 list_move(&bo->list, &kgem->scanout);
6788
6789 kgem->need_expire = true;
6790-
6791 }
6792
6793 static void kgem_bo_move_to_snoop(struct kgem *kgem, struct kgem_bo *bo)
6794@@ -2316,6 +2727,8 @@ static void kgem_bo_move_to_snoop(struct kgem *kgem, struct kgem_bo *bo)
6795 assert(!bo->needs_flush);
6796 assert(bo->refcnt == 0);
6797 assert(bo->exec == NULL);
6798+ assert(!bo->purged);
6799+ assert(!bo->delta);
6800
6801 if (DBG_NO_SNOOP_CACHE) {
6802 kgem_bo_free(kgem, bo);
6803@@ -2351,8 +2764,7 @@ static bool kgem_bo_move_to_cache(struct kgem *kgem, struct kgem_bo *bo)
6804 kgem_bo_move_to_snoop(kgem, bo);
6805 } else if (bo->scanout) {
6806 kgem_bo_move_to_scanout(kgem, bo);
6807- } else if ((bo = kgem_bo_replace_io(bo))->reusable &&
6808- kgem_bo_set_purgeable(kgem, bo)) {
6809+ } else if ((bo = kgem_bo_replace_io(bo))->reusable) {
6810 kgem_bo_move_to_inactive(kgem, bo);
6811 retired = true;
6812 } else
6813@@ -2429,7 +2841,7 @@ void kgem_bo_undo(struct kgem *kgem, struct kgem_bo *bo)
6814 DBG(("%s: only handle in batch, discarding last operations for handle=%d\n",
6815 __FUNCTION__, bo->handle));
6816
6817- assert(bo->exec == &kgem->exec[0]);
6818+ assert(bo->exec == &_kgem_dummy_exec || bo->exec == &kgem->exec[0]);
6819 assert(kgem->exec[0].handle == bo->handle);
6820 assert(RQ(bo->rq) == kgem->next_request);
6821
6822@@ -2457,16 +2869,23 @@ void kgem_bo_pair_undo(struct kgem *kgem, struct kgem_bo *a, struct kgem_bo *b)
6823
6824 if (a == NULL || b == NULL)
6825 return;
6826+ assert(a != b);
6827 if (a->exec == NULL || b->exec == NULL)
6828 return;
6829
6830- DBG(("%s: only handles in batch, discarding last operations for handle=%d and handle=%d\n",
6831- __FUNCTION__, a->handle, b->handle));
6832+ DBG(("%s: only handles in batch, discarding last operations for handle=%d (index=%d) and handle=%d (index=%d)\n",
6833+ __FUNCTION__,
6834+ a->handle, a->proxy ? -1 : a->exec - kgem->exec,
6835+ b->handle, b->proxy ? -1 : b->exec - kgem->exec));
6836
6837- assert(a->exec == &kgem->exec[0] || a->exec == &kgem->exec[1]);
6838+ assert(a->exec == &_kgem_dummy_exec ||
6839+ a->exec == &kgem->exec[0] ||
6840+ a->exec == &kgem->exec[1]);
6841 assert(a->handle == kgem->exec[0].handle || a->handle == kgem->exec[1].handle);
6842 assert(RQ(a->rq) == kgem->next_request);
6843- assert(b->exec == &kgem->exec[0] || b->exec == &kgem->exec[1]);
6844+ assert(b->exec == &_kgem_dummy_exec ||
6845+ b->exec == &kgem->exec[0] ||
6846+ b->exec == &kgem->exec[1]);
6847 assert(b->handle == kgem->exec[0].handle || b->handle == kgem->exec[1].handle);
6848 assert(RQ(b->rq) == kgem->next_request);
6849
6850@@ -2532,7 +2951,7 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
6851 assert(bo->snoop == false);
6852 assert(bo->io == false);
6853 assert(bo->scanout == false);
6854- assert_cacheing(kgem, bo);
6855+ assert_caching(kgem, bo);
6856
6857 kgem_bo_undo(kgem, bo);
6858 assert(bo->refcnt == 0);
6859@@ -2556,9 +2975,6 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
6860 assert(list_is_empty(&bo->request));
6861
6862 if (bo->map__cpu == NULL || bucket(bo) >= NUM_CACHE_BUCKETS) {
6863- if (!kgem_bo_set_purgeable(kgem, bo))
6864- goto destroy;
6865-
6866 if (!kgem->has_llc && bo->domain == DOMAIN_CPU)
6867 goto destroy;
6868
6869@@ -2647,7 +3063,7 @@ static bool kgem_retire__flushing(struct kgem *kgem)
6870 int count = 0;
6871 list_for_each_entry(bo, &kgem->flushing, request)
6872 count++;
6873- DBG(("%s: %d bo on flushing list\n", __FUNCTION__, count));
6874+ DBG(("%s: %d bo on flushing list, retired? %d\n", __FUNCTION__, count, retired));
6875 }
6876 #endif
6877
6878@@ -2656,6 +3072,34 @@ static bool kgem_retire__flushing(struct kgem *kgem)
6879 return retired;
6880 }
6881
6882+static bool __kgem_bo_flush(struct kgem *kgem, struct kgem_bo *bo)
6883+{
6884+ struct drm_i915_gem_busy busy;
6885+
6886+ if (!bo->needs_flush)
6887+ return false;
6888+
6889+ bo->needs_flush = false;
6890+
6891+ VG_CLEAR(busy);
6892+ busy.handle = bo->handle;
6893+ busy.busy = !kgem->wedged;
6894+ (void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
6895+ DBG(("%s: handle=%d, busy=%d, wedged=%d\n",
6896+ __FUNCTION__, bo->handle, busy.busy, kgem->wedged));
6897+
6898+ if (busy.busy == 0)
6899+ return false;
6900+
6901+ DBG(("%s: moving %d to flushing\n",
6902+ __FUNCTION__, bo->handle));
6903+ list_add(&bo->request, &kgem->flushing);
6904+ bo->rq = MAKE_REQUEST(kgem, !!(busy.busy & ~0x1ffff));
6905+ bo->needs_flush = busy.busy & 0xffff;
6906+ kgem->need_retire = true;
6907+ return true;
6908+}
6909+
6910 static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq)
6911 {
6912 bool retired = false;
6913@@ -2663,6 +3107,8 @@ static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq)
6914 DBG(("%s: request %d complete\n",
6915 __FUNCTION__, rq->bo->handle));
6916 assert(RQ(rq->bo->rq) == rq);
6917+ assert(rq != (struct kgem_request *)kgem);
6918+ assert(rq != &kgem->static_request);
6919
6920 if (rq == kgem->fence[rq->ring])
6921 kgem->fence[rq->ring] = NULL;
6922@@ -2680,19 +3126,14 @@ static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq)
6923
6924 list_del(&bo->request);
6925
6926- if (bo->needs_flush)
6927- bo->needs_flush = __kgem_busy(kgem, bo->handle);
6928- if (bo->needs_flush) {
6929- DBG(("%s: moving %d to flushing\n",
6930+ if (unlikely(__kgem_bo_flush(kgem, bo))) {
6931+ assert(bo != rq->bo);
6932+ DBG(("%s: movied %d to flushing\n",
6933 __FUNCTION__, bo->handle));
6934- list_add(&bo->request, &kgem->flushing);
6935- bo->rq = MAKE_REQUEST(kgem, RQ_RING(bo->rq));
6936- kgem->need_retire = true;
6937 continue;
6938 }
6939
6940 bo->domain = DOMAIN_NONE;
6941- bo->gtt_dirty = false;
6942 bo->rq = NULL;
6943 if (bo->refcnt)
6944 continue;
6945@@ -2706,14 +3147,8 @@ static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq)
6946 assert(rq->bo->refcnt > 0);
6947
6948 if (--rq->bo->refcnt == 0) {
6949- if (kgem_bo_set_purgeable(kgem, rq->bo)) {
6950- kgem_bo_move_to_inactive(kgem, rq->bo);
6951- retired = true;
6952- } else {
6953- DBG(("%s: closing %d\n",
6954- __FUNCTION__, rq->bo->handle));
6955- kgem_bo_free(kgem, rq->bo);
6956- }
6957+ kgem_bo_move_to_inactive(kgem, rq->bo);
6958+ retired = true;
6959 }
6960
6961 __kgem_request_free(rq);
6962@@ -2724,13 +3159,18 @@ static bool kgem_retire__requests_ring(struct kgem *kgem, int ring)
6963 {
6964 bool retired = false;
6965
6966+ assert(ring < ARRAY_SIZE(kgem->requests));
6967 while (!list_is_empty(&kgem->requests[ring])) {
6968 struct kgem_request *rq;
6969
6970+ DBG(("%s: retiring ring %d\n", __FUNCTION__, ring));
6971+
6972 rq = list_first_entry(&kgem->requests[ring],
6973 struct kgem_request,
6974 list);
6975 assert(rq->ring == ring);
6976+ assert(rq->bo);
6977+ assert(RQ(rq->bo->rq) == rq);
6978 if (__kgem_busy(kgem, rq->bo->handle))
6979 break;
6980
6981@@ -2751,8 +3191,8 @@ static bool kgem_retire__requests_ring(struct kgem *kgem, int ring)
6982 struct kgem_request,
6983 list)->bo;
6984
6985- DBG(("%s: ring=%d, %d outstanding requests, oldest=%d\n",
6986- __FUNCTION__, ring, count, bo ? bo->handle : 0));
6987+ DBG(("%s: ring=%d, %d outstanding requests, oldest=%d, retired? %d\n",
6988+ __FUNCTION__, ring, count, bo ? bo->handle : 0, retired));
6989 }
6990 #endif
6991
6992@@ -2824,6 +3264,8 @@ bool __kgem_ring_is_idle(struct kgem *kgem, int ring)
6993 rq = list_last_entry(&kgem->requests[ring],
6994 struct kgem_request, list);
6995 assert(rq->ring == ring);
6996+ assert(rq->bo);
6997+ assert(RQ(rq->bo->rq) == rq);
6998 if (__kgem_busy(kgem, rq->bo->handle)) {
6999 DBG(("%s: last requests handle=%d still busy\n",
7000 __FUNCTION__, rq->bo->handle));
7001@@ -2845,23 +3287,30 @@ bool __kgem_ring_is_idle(struct kgem *kgem, int ring)
7002 return true;
7003 }
7004
7005-void __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo)
7006+bool __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo)
7007 {
7008- struct kgem_request *rq = bo->rq, *tmp;
7009- struct list *requests = &kgem->requests[RQ_RING(rq) == I915_EXEC_BLT];
7010+ struct kgem_request * const rq = RQ(bo->rq), *tmp;
7011+ struct list *requests = &kgem->requests[rq->ring];
7012+
7013+ DBG(("%s(handle=%d, ring=%d)\n", __FUNCTION__, bo->handle, rq->ring));
7014
7015- rq = RQ(rq);
7016 assert(rq != &kgem->static_request);
7017 if (rq == (struct kgem_request *)kgem) {
7018 __kgem_bo_clear_busy(bo);
7019- return;
7020+ return false;
7021 }
7022
7023+ assert(rq->ring < ARRAY_SIZE(kgem->requests));
7024 do {
7025 tmp = list_first_entry(requests, struct kgem_request, list);
7026 assert(tmp->ring == rq->ring);
7027 __kgem_retire_rq(kgem, tmp);
7028 } while (tmp != rq);
7029+
7030+ assert(bo->needs_flush || bo->rq == NULL);
7031+ assert(bo->needs_flush || list_is_empty(&bo->request));
7032+ assert(bo->needs_flush || bo->domain == DOMAIN_NONE);
7033+ return bo->rq;
7034 }
7035
7036 #if 0
7037@@ -2932,6 +3381,7 @@ static void kgem_commit(struct kgem *kgem)
7038 bo->binding.offset = 0;
7039 bo->domain = DOMAIN_GPU;
7040 bo->gpu_dirty = false;
7041+ bo->gtt_dirty = false;
7042
7043 if (bo->proxy) {
7044 /* proxies are not used for domain tracking */
7045@@ -2955,6 +3405,23 @@ static void kgem_commit(struct kgem *kgem)
7046 kgem_throttle(kgem);
7047 }
7048
7049+ while (!list_is_empty(&rq->buffers)) {
7050+ bo = list_first_entry(&rq->buffers,
7051+ struct kgem_bo,
7052+ request);
7053+
7054+ assert(RQ(bo->rq) == rq);
7055+ assert(bo->exec == NULL);
7056+ assert(bo->domain == DOMAIN_GPU);
7057+
7058+ list_del(&bo->request);
7059+ bo->domain = DOMAIN_NONE;
7060+ bo->rq = NULL;
7061+
7062+ if (bo->refcnt == 0)
7063+ _kgem_bo_destroy(kgem, bo);
7064+ }
7065+
7066 kgem_retire(kgem);
7067 assert(list_is_empty(&rq->buffers));
7068
7069@@ -2964,7 +3431,9 @@ static void kgem_commit(struct kgem *kgem)
7070 gem_close(kgem->fd, rq->bo->handle);
7071 kgem_cleanup_cache(kgem);
7072 } else {
7073+ assert(rq != (struct kgem_request *)kgem);
7074 assert(rq->ring < ARRAY_SIZE(kgem->requests));
7075+ assert(rq->bo);
7076 list_add_tail(&rq->list, &kgem->requests[rq->ring]);
7077 kgem->need_throttle = kgem->need_retire = 1;
7078
7079@@ -2988,8 +3457,10 @@ static void kgem_close_inactive(struct kgem *kgem)
7080 {
7081 unsigned int i;
7082
7083- for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++)
7084+ for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) {
7085 kgem_close_list(kgem, &kgem->inactive[i]);
7086+ assert(list_is_empty(&kgem->inactive[i]));
7087+ }
7088 }
7089
7090 static void kgem_finish_buffers(struct kgem *kgem)
7091@@ -3079,10 +3550,13 @@ static void kgem_finish_buffers(struct kgem *kgem)
7092 kgem->has_handle_lut ? bo->base.target_handle : shrink->handle;
7093 for (n = 0; n < kgem->nreloc; n++) {
7094 if (kgem->reloc[n].target_handle == bo->base.target_handle) {
7095+ uint64_t addr = (int)kgem->reloc[n].delta + shrink->presumed_offset;
7096+ kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] = addr;
7097+ if (kgem->gen >= 0100)
7098+ kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0]) + 1] = addr >> 32;
7099+
7100 kgem->reloc[n].target_handle = shrink->target_handle;
7101 kgem->reloc[n].presumed_offset = shrink->presumed_offset;
7102- kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] =
7103- kgem->reloc[n].delta + shrink->presumed_offset;
7104 }
7105 }
7106
7107@@ -3124,10 +3598,13 @@ static void kgem_finish_buffers(struct kgem *kgem)
7108 kgem->has_handle_lut ? bo->base.target_handle : shrink->handle;
7109 for (n = 0; n < kgem->nreloc; n++) {
7110 if (kgem->reloc[n].target_handle == bo->base.target_handle) {
7111+ uint64_t addr = (int)kgem->reloc[n].delta + shrink->presumed_offset;
7112+ kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] = addr;
7113+ if (kgem->gen >= 0100)
7114+ kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0]) + 1] = addr >> 32;
7115+
7116 kgem->reloc[n].target_handle = shrink->target_handle;
7117 kgem->reloc[n].presumed_offset = shrink->presumed_offset;
7118- kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] =
7119- kgem->reloc[n].delta + shrink->presumed_offset;
7120 }
7121 }
7122
7123@@ -3195,6 +3672,9 @@ static void kgem_cleanup(struct kgem *kgem)
7124 kgem_bo_free(kgem, bo);
7125 }
7126
7127+ if (--rq->bo->refcnt == 0)
7128+ kgem_bo_free(kgem, rq->bo);
7129+
7130 __kgem_request_free(rq);
7131 }
7132 }
7133@@ -3210,7 +3690,9 @@ kgem_batch_write(struct kgem *kgem,
7134 char *ptr;
7135 int ret;
7136
7137- ASSERT_IDLE(kgem, bo->handle);
7138+ assert(bo->exec == NULL);
7139+ assert(bo->rq == NULL);
7140+ assert(!__kgem_busy(kgem, bo->handle));
7141
7142 #if DBG_NO_EXEC
7143 {
7144@@ -3359,67 +3841,66 @@ static int compact_batch_surface(struct kgem *kgem, int *shrink)
7145 {
7146 int size, n;
7147
7148- if (!kgem->has_relaxed_delta)
7149- return kgem->batch_size * sizeof(uint32_t);
7150+ if (!kgem->has_relaxed_delta)
7151+ return kgem->batch_size * sizeof(uint32_t);
7152+
7153+ /* See if we can pack the contents into one or two pages */
7154+ n = ALIGN(kgem->batch_size, 1024);
7155+ size = n - kgem->surface + kgem->nbatch;
7156+ size = ALIGN(size, 1024);
7157+
7158+ *shrink = (n - size) * sizeof(uint32_t);
7159+ return size * sizeof(uint32_t);
7160+}
7161+
7162+static struct kgem_bo *first_available(struct kgem *kgem, struct list *list)
7163+{
7164+ struct kgem_bo *bo;
7165+
7166+ list_for_each_entry(bo, list, list) {
7167+ assert(bo->refcnt > 0);
7168+
7169+ if (bo->rq) {
7170+ assert(RQ(bo->rq)->bo == bo);
7171+ if (__kgem_busy(kgem, bo->handle))
7172+ break;
7173+
7174+ __kgem_retire_rq(kgem, RQ(bo->rq));
7175+ assert(bo->rq == NULL);
7176+ }
7177+
7178+ if (bo->refcnt > 1)
7179+ continue;
7180
7181- /* See if we can pack the contents into one or two pages */
7182- n = ALIGN(kgem->batch_size, 1024);
7183- size = n - kgem->surface + kgem->nbatch;
7184- size = ALIGN(size, 1024);
7185+ list_move_tail(&bo->list, list);
7186+ return kgem_bo_reference(bo);
7187+ }
7188
7189- *shrink = (n - size) * sizeof(uint32_t);
7190- return size * sizeof(uint32_t);
7191+ return NULL;
7192 }
7193
7194 static struct kgem_bo *
7195 kgem_create_batch(struct kgem *kgem)
7196 {
7197-#if !DBG_NO_SHRINK_BATCHES
7198- struct drm_i915_gem_set_domain set_domain;
7199 struct kgem_bo *bo;
7200- int shrink = 0;
7201- int size;
7202+ int size, shrink = 0;
7203
7204+#if !DBG_NO_SHRINK_BATCHES
7205 if (kgem->surface != kgem->batch_size)
7206 size = compact_batch_surface(kgem, &shrink);
7207 else
7208 size = kgem->nbatch * sizeof(uint32_t);
7209
7210 if (size <= 4096) {
7211- bo = list_first_entry(&kgem->pinned_batches[0],
7212- struct kgem_bo,
7213- list);
7214- if (!bo->rq) {
7215-out_4096:
7216- assert(bo->refcnt > 0);
7217- list_move_tail(&bo->list, &kgem->pinned_batches[0]);
7218- bo = kgem_bo_reference(bo);
7219+ bo = first_available(kgem, &kgem->pinned_batches[0]);
7220+ if (bo)
7221 goto write;
7222- }
7223-
7224- if (!__kgem_busy(kgem, bo->handle)) {
7225- assert(RQ(bo->rq)->bo == bo);
7226- __kgem_retire_rq(kgem, RQ(bo->rq));
7227- goto out_4096;
7228- }
7229 }
7230
7231 if (size <= 16384) {
7232- bo = list_first_entry(&kgem->pinned_batches[1],
7233- struct kgem_bo,
7234- list);
7235- if (!bo->rq) {
7236-out_16384:
7237- assert(bo->refcnt > 0);
7238- list_move_tail(&bo->list, &kgem->pinned_batches[1]);
7239- bo = kgem_bo_reference(bo);
7240+ bo = first_available(kgem, &kgem->pinned_batches[1]);
7241+ if (bo)
7242 goto write;
7243- }
7244-
7245- if (!__kgem_busy(kgem, bo->handle)) {
7246- __kgem_retire_rq(kgem, RQ(bo->rq));
7247- goto out_16384;
7248- }
7249 }
7250
7251 if (kgem->gen == 020) {
7252@@ -3443,16 +3924,8 @@ out_16384:
7253 list_move_tail(&bo->list, &kgem->pinned_batches[size > 4096]);
7254
7255 DBG(("%s: syncing due to busy batches\n", __FUNCTION__));
7256-
7257- VG_CLEAR(set_domain);
7258- set_domain.handle = bo->handle;
7259- set_domain.read_domains = I915_GEM_DOMAIN_GTT;
7260- set_domain.write_domain = I915_GEM_DOMAIN_GTT;
7261- if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) {
7262- DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
7263- kgem_throttle(kgem);
7264+ if (kgem_bo_wait(kgem, bo))
7265 return NULL;
7266- }
7267
7268 kgem_retire(kgem);
7269 assert(bo->rq == NULL);
7270@@ -3460,9 +3933,14 @@ out_16384:
7271 goto write;
7272 }
7273 }
7274+#else
7275+ if (kgem->surface != kgem->batch_size)
7276+ size = kgem->batch_size * sizeof(uint32_t);
7277+ else
7278+ size = kgem->nbatch * sizeof(uint32_t);
7279+#endif
7280
7281- bo = NULL;
7282- if (!kgem->has_llc) {
7283+ if (!kgem->batch_bo || !kgem->has_llc) {
7284 bo = kgem_create_linear(kgem, size, CREATE_NO_THROTTLE);
7285 if (bo) {
7286 write:
7287@@ -3471,14 +3949,11 @@ write:
7288 kgem_bo_destroy(kgem, bo);
7289 return NULL;
7290 }
7291+ return bo;
7292 }
7293 }
7294- if (bo == NULL)
7295- bo = kgem_new_batch(kgem);
7296- return bo;
7297-#else
7298+
7299 return kgem_new_batch(kgem);
7300-#endif
7301 }
7302
7303 #if !NDEBUG
7304@@ -3530,7 +4005,7 @@ static void dump_fence_regs(struct kgem *kgem)
7305
7306 static int do_execbuf(struct kgem *kgem, struct drm_i915_gem_execbuffer2 *execbuf)
7307 {
7308- int ret, err;
7309+ int ret;
7310
7311 retry:
7312 ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf);
7313@@ -3547,26 +4022,25 @@ retry:
7314
7315 /* last gasp */
7316 ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf);
7317- if (ret == 0)
7318- return 0;
7319+ if (ret != -ENOSPC)
7320+ return ret;
7321+
7322+ /* One final trick up our sleeve for when we run out of space.
7323+ * We turn everything off to free up our pinned framebuffers,
7324+ * sprites and cursors, and try just one more time.
7325+ */
7326
7327 xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING,
7328 "Failed to submit rendering commands, trying again with outputs disabled.\n");
7329
7330- /* One last trick up our sleeve for when we run out of space.
7331- * We turn everything off to free up our pinned framebuffers,
7332- * sprites and cursors, and try one last time.
7333- */
7334- err = errno;
7335- if (sna_mode_disable(container_of(kgem, struct sna, kgem))) {
7336+ if (sna_mode_disable(__to_sna(kgem))) {
7337 kgem_cleanup_cache(kgem);
7338 ret = do_ioctl(kgem->fd,
7339 DRM_IOCTL_I915_GEM_EXECBUFFER2,
7340 execbuf);
7341 DBG(("%s: last_gasp ret=%d\n", __FUNCTION__, ret));
7342- sna_mode_enable(container_of(kgem, struct sna, kgem));
7343+ sna_mode_enable(__to_sna(kgem));
7344 }
7345- errno = err;
7346
7347 return ret;
7348 }
7349@@ -3575,6 +4049,7 @@ void _kgem_submit(struct kgem *kgem)
7350 {
7351 struct kgem_request *rq;
7352 uint32_t batch_end;
7353+ int i, ret;
7354
7355 assert(!DBG_NO_HW);
7356 assert(!kgem->wedged);
7357@@ -3609,7 +4084,6 @@ void _kgem_submit(struct kgem *kgem)
7358 rq->bo = kgem_create_batch(kgem);
7359 if (rq->bo) {
7360 struct drm_i915_gem_execbuffer2 execbuf;
7361- int i, ret;
7362
7363 assert(!rq->bo->needs_flush);
7364
7365@@ -3619,7 +4093,8 @@ void _kgem_submit(struct kgem *kgem)
7366 kgem->exec[i].relocs_ptr = (uintptr_t)kgem->reloc;
7367 kgem->exec[i].alignment = 0;
7368 kgem->exec[i].offset = rq->bo->presumed_offset;
7369- kgem->exec[i].flags = 0;
7370+ /* Make sure the kernel releases any fence, ignored if gen4+ */
7371+ kgem->exec[i].flags = EXEC_OBJECT_NEEDS_FENCE;
7372 kgem->exec[i].rsvd1 = 0;
7373 kgem->exec[i].rsvd2 = 0;
7374
7375@@ -3631,7 +4106,8 @@ void _kgem_submit(struct kgem *kgem)
7376 memset(&execbuf, 0, sizeof(execbuf));
7377 execbuf.buffers_ptr = (uintptr_t)kgem->exec;
7378 execbuf.buffer_count = kgem->nexec;
7379- execbuf.batch_len = batch_end*sizeof(uint32_t);
7380+ if (kgem->gen < 030)
7381+ execbuf.batch_len = batch_end*sizeof(uint32_t);
7382 execbuf.flags = kgem->ring | kgem->batch_flags;
7383
7384 if (DBG_DUMP) {
7385@@ -3645,91 +4121,98 @@ void _kgem_submit(struct kgem *kgem)
7386 }
7387
7388 ret = do_execbuf(kgem, &execbuf);
7389- if (DEBUG_SYNC && ret == 0) {
7390- struct drm_i915_gem_set_domain set_domain;
7391-
7392- VG_CLEAR(set_domain);
7393- set_domain.handle = rq->bo->handle;
7394- set_domain.read_domains = I915_GEM_DOMAIN_GTT;
7395- set_domain.write_domain = I915_GEM_DOMAIN_GTT;
7396+ } else
7397+ ret = -ENOMEM;
7398
7399- ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
7400+ if (ret < 0) {
7401+ kgem_throttle(kgem);
7402+ if (!kgem->wedged) {
7403+ xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
7404+ "Failed to submit rendering commands (%s), disabling acceleration.\n",
7405+ strerror(-ret));
7406+ __kgem_set_wedged(kgem);
7407 }
7408- if (ret < 0) {
7409- kgem_throttle(kgem);
7410- if (!kgem->wedged) {
7411- xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
7412- "Failed to submit rendering commands, disabling acceleration.\n");
7413- __kgem_set_wedged(kgem);
7414- }
7415
7416 #if !NDEBUG
7417- ErrorF("batch[%d/%d]: %d %d %d, nreloc=%d, nexec=%d, nfence=%d, aperture=%d, fenced=%d, high=%d,%d: errno=%d\n",
7418- kgem->mode, kgem->ring, batch_end, kgem->nbatch, kgem->surface,
7419- kgem->nreloc, kgem->nexec, kgem->nfence, kgem->aperture, kgem->aperture_fenced, kgem->aperture_high, kgem->aperture_total, -ret);
7420+ ErrorF("batch[%d/%d]: %d %d %d, nreloc=%d, nexec=%d, nfence=%d, aperture=%d, fenced=%d, high=%d,%d: errno=%d\n",
7421+ kgem->mode, kgem->ring, batch_end, kgem->nbatch, kgem->surface,
7422+ kgem->nreloc, kgem->nexec, kgem->nfence, kgem->aperture, kgem->aperture_fenced, kgem->aperture_high, kgem->aperture_total, -ret);
7423
7424- for (i = 0; i < kgem->nexec; i++) {
7425- struct kgem_bo *bo, *found = NULL;
7426+ for (i = 0; i < kgem->nexec; i++) {
7427+ struct kgem_bo *bo, *found = NULL;
7428
7429- list_for_each_entry(bo, &kgem->next_request->buffers, request) {
7430- if (bo->handle == kgem->exec[i].handle) {
7431- found = bo;
7432- break;
7433- }
7434+ list_for_each_entry(bo, &kgem->next_request->buffers, request) {
7435+ if (bo->handle == kgem->exec[i].handle) {
7436+ found = bo;
7437+ break;
7438 }
7439- ErrorF("exec[%d] = handle:%d, presumed offset: %x, size: %d, tiling %d, fenced %d, snooped %d, deleted %d\n",
7440- i,
7441- kgem->exec[i].handle,
7442- (int)kgem->exec[i].offset,
7443- found ? kgem_bo_size(found) : -1,
7444- found ? found->tiling : -1,
7445- (int)(kgem->exec[i].flags & EXEC_OBJECT_NEEDS_FENCE),
7446- found ? found->snoop : -1,
7447- found ? found->purged : -1);
7448 }
7449- for (i = 0; i < kgem->nreloc; i++) {
7450- ErrorF("reloc[%d] = pos:%d, target:%d, delta:%d, read:%x, write:%x, offset:%x\n",
7451- i,
7452- (int)kgem->reloc[i].offset,
7453- kgem->reloc[i].target_handle,
7454- kgem->reloc[i].delta,
7455- kgem->reloc[i].read_domains,
7456- kgem->reloc[i].write_domain,
7457- (int)kgem->reloc[i].presumed_offset);
7458+ ErrorF("exec[%d] = handle:%d, presumed offset: %x, size: %d, tiling %d, fenced %d, snooped %d, deleted %d\n",
7459+ i,
7460+ kgem->exec[i].handle,
7461+ (int)kgem->exec[i].offset,
7462+ found ? kgem_bo_size(found) : -1,
7463+ found ? found->tiling : -1,
7464+ (int)(kgem->exec[i].flags & EXEC_OBJECT_NEEDS_FENCE),
7465+ found ? found->snoop : -1,
7466+ found ? found->purged : -1);
7467+ }
7468+ for (i = 0; i < kgem->nreloc; i++) {
7469+ ErrorF("reloc[%d] = pos:%d, target:%d, delta:%d, read:%x, write:%x, offset:%x\n",
7470+ i,
7471+ (int)kgem->reloc[i].offset,
7472+ kgem->reloc[i].target_handle,
7473+ kgem->reloc[i].delta,
7474+ kgem->reloc[i].read_domains,
7475+ kgem->reloc[i].write_domain,
7476+ (int)kgem->reloc[i].presumed_offset);
7477+ }
7478+
7479+ {
7480+ struct drm_i915_gem_get_aperture aperture;
7481+ if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture) == 0)
7482+ ErrorF("Aperture size %lld, available %lld\n",
7483+ (long long)aperture.aper_size,
7484+ (long long)aperture.aper_available_size);
7485+ }
7486+
7487+ if (ret == -ENOSPC)
7488+ dump_gtt_info(kgem);
7489+ if (ret == -EDEADLK)
7490+ dump_fence_regs(kgem);
7491+
7492+ if (DEBUG_SYNC) {
7493+ int fd = open("/tmp/batchbuffer", O_WRONLY | O_CREAT | O_APPEND, 0666);
7494+ if (fd != -1) {
7495+ int ignored = write(fd, kgem->batch, batch_end*sizeof(uint32_t));
7496+ assert(ignored == batch_end*sizeof(uint32_t));
7497+ close(fd);
7498 }
7499
7500- {
7501- struct drm_i915_gem_get_aperture aperture;
7502- if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture) == 0)
7503- ErrorF("Aperture size %lld, available %lld\n",
7504- (long long)aperture.aper_size,
7505- (long long)aperture.aper_available_size);
7506- }
7507+ FatalError("SNA: failed to submit batchbuffer, errno=%d\n", -ret);
7508+ }
7509+#endif
7510+ } else {
7511+ if (DEBUG_SYNC) {
7512+ struct drm_i915_gem_set_domain set_domain;
7513
7514- if (ret == -ENOSPC)
7515- dump_gtt_info(kgem);
7516- if (ret == -EDEADLK)
7517- dump_fence_regs(kgem);
7518-
7519- if (DEBUG_SYNC) {
7520- int fd = open("/tmp/batchbuffer", O_WRONLY | O_CREAT | O_APPEND, 0666);
7521- if (fd != -1) {
7522- int ignored = write(fd, kgem->batch, batch_end*sizeof(uint32_t));
7523- assert(ignored == batch_end*sizeof(uint32_t));
7524- close(fd);
7525- }
7526+ VG_CLEAR(set_domain);
7527+ set_domain.handle = rq->bo->handle;
7528+ set_domain.read_domains = I915_GEM_DOMAIN_GTT;
7529+ set_domain.write_domain = I915_GEM_DOMAIN_GTT;
7530
7531- FatalError("SNA: failed to submit batchbuffer, errno=%d\n", -ret);
7532- }
7533-#endif
7534+ ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
7535 }
7536- }
7537+
7538 #if SHOW_BATCH_AFTER
7539- if (gem_read(kgem->fd, rq->bo->handle, kgem->batch, 0, batch_end*sizeof(uint32_t)) == 0)
7540- __kgem_batch_debug(kgem, batch_end);
7541+ if (gem_read(kgem->fd, rq->bo->handle, kgem->batch, 0, batch_end*sizeof(uint32_t)) == 0)
7542+ __kgem_batch_debug(kgem, batch_end);
7543 #endif
7544- kgem_commit(kgem);
7545- if (kgem->wedged)
7546+
7547+ kgem_commit(kgem);
7548+ }
7549+
7550+ if (unlikely(kgem->wedged))
7551 kgem_cleanup(kgem);
7552
7553 kgem_reset(kgem);
7554@@ -3737,49 +4220,14 @@ void _kgem_submit(struct kgem *kgem)
7555 assert(kgem->next_request != NULL);
7556 }
7557
7558-static bool find_hang_state(struct kgem *kgem, char *path, int maxlen)
7559-{
7560- int minor = kgem_get_minor(kgem);
7561-
7562- /* Search for our hang state in a few canonical locations.
7563- * In the unlikely event of having multiple devices, we
7564- * will need to check which minor actually corresponds to ours.
7565- */
7566-
7567- snprintf(path, maxlen, "/sys/class/drm/card%d/error", minor);
7568- if (access(path, R_OK) == 0)
7569- return true;
7570-
7571- snprintf(path, maxlen, "/sys/kernel/debug/dri/%d/i915_error_state", minor);
7572- if (access(path, R_OK) == 0)
7573- return true;
7574-
7575- snprintf(path, maxlen, "/debug/dri/%d/i915_error_state", minor);
7576- if (access(path, R_OK) == 0)
7577- return true;
7578-
7579- path[0] = '\0';
7580- return false;
7581-}
7582-
7583 void kgem_throttle(struct kgem *kgem)
7584 {
7585- if (kgem->wedged)
7586+ if (unlikely(kgem->wedged))
7587 return;
7588
7589 if (__kgem_throttle(kgem, true)) {
7590- static int once;
7591- char path[128];
7592-
7593 xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
7594 "Detected a hung GPU, disabling acceleration.\n");
7595- if (!once && find_hang_state(kgem, path, sizeof(path))) {
7596- xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
7597- "When reporting this, please include %s and the full dmesg.\n",
7598- path);
7599- once = 1;
7600- }
7601-
7602 __kgem_set_wedged(kgem);
7603 kgem->need_throttle = false;
7604 }
7605@@ -3860,7 +4308,8 @@ bool kgem_expire_cache(struct kgem *kgem)
7606 bool idle;
7607 unsigned int i;
7608
7609- time(&now);
7610+ if (!time(&now))
7611+ return false;
7612
7613 while (__kgem_freed_bo) {
7614 bo = __kgem_freed_bo;
7615@@ -3875,7 +4324,7 @@ bool kgem_expire_cache(struct kgem *kgem)
7616 }
7617
7618 kgem_clean_large_cache(kgem);
7619- if (container_of(kgem, struct sna, kgem)->scrn->vtSema)
7620+ if (__to_sna(kgem)->scrn->vtSema)
7621 kgem_clean_scanout_cache(kgem);
7622
7623 expire = 0;
7624@@ -3885,6 +4334,7 @@ bool kgem_expire_cache(struct kgem *kgem)
7625 break;
7626 }
7627
7628+ assert(now);
7629 bo->delta = now;
7630 }
7631 if (expire) {
7632@@ -3909,7 +4359,7 @@ bool kgem_expire_cache(struct kgem *kgem)
7633 #endif
7634
7635 kgem_retire(kgem);
7636- if (kgem->wedged)
7637+ if (unlikely(kgem->wedged))
7638 kgem_cleanup(kgem);
7639
7640 kgem->expire(kgem);
7641@@ -3930,6 +4380,8 @@ bool kgem_expire_cache(struct kgem *kgem)
7642 break;
7643 }
7644
7645+ assert(now);
7646+ kgem_bo_set_purgeable(kgem, bo);
7647 bo->delta = now;
7648 }
7649 }
7650@@ -3960,16 +4412,11 @@ bool kgem_expire_cache(struct kgem *kgem)
7651 count++;
7652 size += bytes(bo);
7653 kgem_bo_free(kgem, bo);
7654- DBG(("%s: expiring %d\n",
7655+ DBG(("%s: expiring handle=%d\n",
7656 __FUNCTION__, bo->handle));
7657 }
7658 }
7659- if (!list_is_empty(&preserve)) {
7660- preserve.prev->next = kgem->inactive[i].next;
7661- kgem->inactive[i].next->prev = preserve.prev;
7662- kgem->inactive[i].next = preserve.next;
7663- preserve.next->prev = &kgem->inactive[i];
7664- }
7665+ list_splice_tail(&preserve, &kgem->inactive[i]);
7666 }
7667
7668 #ifdef DEBUG_MEMORY
7669@@ -3998,31 +4445,30 @@ bool kgem_cleanup_cache(struct kgem *kgem)
7670 unsigned int i;
7671 int n;
7672
7673+ DBG(("%s\n", __FUNCTION__));
7674+
7675 /* sync to the most recent request */
7676 for (n = 0; n < ARRAY_SIZE(kgem->requests); n++) {
7677 if (!list_is_empty(&kgem->requests[n])) {
7678 struct kgem_request *rq;
7679- struct drm_i915_gem_set_domain set_domain;
7680
7681- rq = list_first_entry(&kgem->requests[n],
7682- struct kgem_request,
7683- list);
7684+ rq = list_last_entry(&kgem->requests[n],
7685+ struct kgem_request,
7686+ list);
7687
7688 DBG(("%s: sync on cleanup\n", __FUNCTION__));
7689-
7690- VG_CLEAR(set_domain);
7691- set_domain.handle = rq->bo->handle;
7692- set_domain.read_domains = I915_GEM_DOMAIN_GTT;
7693- set_domain.write_domain = I915_GEM_DOMAIN_GTT;
7694- (void)do_ioctl(kgem->fd,
7695- DRM_IOCTL_I915_GEM_SET_DOMAIN,
7696- &set_domain);
7697+ assert(rq->ring == n);
7698+ assert(rq->bo);
7699+ assert(RQ(rq->bo->rq) == rq);
7700+ kgem_bo_wait(kgem, rq->bo);
7701 }
7702+ assert(list_is_empty(&kgem->requests[n]));
7703 }
7704
7705 kgem_retire(kgem);
7706 kgem_cleanup(kgem);
7707
7708+ DBG(("%s: need_expire?=%d\n", __FUNCTION__, kgem->need_expire));
7709 if (!kgem->need_expire)
7710 return false;
7711
7712@@ -4049,6 +4495,8 @@ bool kgem_cleanup_cache(struct kgem *kgem)
7713
7714 kgem->need_purge = false;
7715 kgem->need_expire = false;
7716+
7717+ DBG(("%s: complete\n", __FUNCTION__));
7718 return true;
7719 }
7720
7721@@ -4079,16 +4527,15 @@ retry_large:
7722 goto discard;
7723
7724 if (bo->tiling != I915_TILING_NONE) {
7725- if (use_active)
7726+ if (use_active && kgem->gen < 040)
7727 goto discard;
7728
7729- if (!gem_set_tiling(kgem->fd, bo->handle,
7730+ if (!kgem_set_tiling(kgem, bo,
7731 I915_TILING_NONE, 0))
7732 goto discard;
7733-
7734- bo->tiling = I915_TILING_NONE;
7735- bo->pitch = 0;
7736 }
7737+ assert(bo->tiling == I915_TILING_NONE);
7738+ bo->pitch = 0;
7739
7740 if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo))
7741 goto discard;
7742@@ -4169,17 +4616,17 @@ discard:
7743 break;
7744 }
7745
7746- if (I915_TILING_NONE != bo->tiling &&
7747- !gem_set_tiling(kgem->fd, bo->handle,
7748- I915_TILING_NONE, 0))
7749- continue;
7750+ if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) {
7751+ kgem_bo_free(kgem, bo);
7752+ break;
7753+ }
7754
7755 kgem_bo_remove_from_inactive(kgem, bo);
7756 assert(list_is_empty(&bo->vma));
7757 assert(list_is_empty(&bo->list));
7758
7759- bo->tiling = I915_TILING_NONE;
7760- bo->pitch = 0;
7761+ assert(bo->tiling == I915_TILING_NONE);
7762+ assert(bo->pitch == 0);
7763 bo->delta = 0;
7764 DBG((" %s: found handle=%d (num_pages=%d) in linear vma cache\n",
7765 __FUNCTION__, bo->handle, num_pages(bo)));
7766@@ -4225,13 +4672,13 @@ discard:
7767 if (first)
7768 continue;
7769
7770- if (!gem_set_tiling(kgem->fd, bo->handle,
7771- I915_TILING_NONE, 0))
7772- continue;
7773-
7774- bo->tiling = I915_TILING_NONE;
7775- bo->pitch = 0;
7776+ if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) {
7777+ kgem_bo_free(kgem, bo);
7778+ break;
7779+ }
7780 }
7781+ assert(bo->tiling == I915_TILING_NONE);
7782+ bo->pitch = 0;
7783
7784 if (bo->map__gtt || bo->map__wc || bo->map__cpu) {
7785 if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) {
7786@@ -4269,7 +4716,7 @@ discard:
7787 kgem_bo_remove_from_inactive(kgem, bo);
7788
7789 assert(bo->tiling == I915_TILING_NONE);
7790- bo->pitch = 0;
7791+ assert(bo->pitch == 0);
7792 bo->delta = 0;
7793 DBG((" %s: found handle=%d (num_pages=%d) in linear %s cache\n",
7794 __FUNCTION__, bo->handle, num_pages(bo),
7795@@ -4342,7 +4789,6 @@ struct kgem_bo *kgem_create_for_name(struct kgem *kgem, uint32_t name)
7796 bo->tiling = tiling.tiling_mode;
7797 bo->reusable = false;
7798 bo->prime = true;
7799- bo->purged = true; /* no coherency guarantees */
7800
7801 debug_alloc__bo(kgem, bo);
7802 return bo;
7803@@ -4479,6 +4925,8 @@ struct kgem_bo *kgem_create_linear(struct kgem *kgem, int size, unsigned flags)
7804 if ((flags & CREATE_UNCACHED) == 0) {
7805 bo = search_linear_cache(kgem, size, CREATE_INACTIVE | flags);
7806 if (bo) {
7807+ assert(!bo->purged);
7808+ assert(!bo->delta);
7809 assert(bo->domain != DOMAIN_GPU);
7810 ASSERT_IDLE(kgem, bo->handle);
7811 bo->refcnt = 1;
7812@@ -4760,8 +5208,7 @@ static void __kgem_bo_make_scanout(struct kgem *kgem,
7813 struct kgem_bo *bo,
7814 int width, int height)
7815 {
7816- ScrnInfoPtr scrn =
7817- container_of(kgem, struct sna, kgem)->scrn;
7818+ ScrnInfoPtr scrn = __to_sna(kgem)->scrn;
7819 struct drm_mode_fb_cmd arg;
7820
7821 assert(bo->proxy == NULL);
7822@@ -4809,6 +5256,36 @@ static void __kgem_bo_make_scanout(struct kgem *kgem,
7823 }
7824 }
7825
7826+static bool tiling_changed(struct kgem_bo *bo, int tiling, int pitch)
7827+{
7828+ if (tiling != bo->tiling)
7829+ return true;
7830+
7831+ return tiling != I915_TILING_NONE && pitch != bo->pitch;
7832+}
7833+
7834+static void set_gpu_tiling(struct kgem *kgem,
7835+ struct kgem_bo *bo,
7836+ int tiling, int pitch)
7837+{
7838+ DBG(("%s: handle=%d, tiling=%d, pitch=%d\n",
7839+ __FUNCTION__, bo->handle, tiling, pitch));
7840+
7841+ assert(!kgem->can_fence);
7842+
7843+ if (tiling_changed(bo, tiling, pitch) && bo->map__gtt) {
7844+ if (!list_is_empty(&bo->vma)) {
7845+ list_del(&bo->vma);
7846+ kgem->vma[0].count--;
7847+ }
7848+ munmap(bo->map__gtt, bytes(bo));
7849+ bo->map__gtt = NULL;
7850+ }
7851+
7852+ bo->tiling = tiling;
7853+ bo->pitch = pitch;
7854+}
7855+
7856 struct kgem_bo *kgem_create_2d(struct kgem *kgem,
7857 int width,
7858 int height,
7859@@ -4892,8 +5369,8 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
7860 return last;
7861 }
7862
7863- if (container_of(kgem, struct sna, kgem)->scrn->vtSema) {
7864- ScrnInfoPtr scrn = container_of(kgem, struct sna, kgem)->scrn;
7865+ if (__to_sna(kgem)->scrn->vtSema) {
7866+ ScrnInfoPtr scrn = __to_sna(kgem)->scrn;
7867
7868 list_for_each_entry_reverse(bo, &kgem->scanout, list) {
7869 struct drm_mode_fb_cmd arg;
7870@@ -4915,11 +5392,8 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
7871 bo->delta = 0;
7872 }
7873
7874- if (gem_set_tiling(kgem->fd, bo->handle,
7875- tiling, pitch)) {
7876- bo->tiling = tiling;
7877- bo->pitch = pitch;
7878- } else {
7879+ if (!kgem_set_tiling(kgem, bo,
7880+ tiling, pitch)) {
7881 kgem_bo_free(kgem, bo);
7882 break;
7883 }
7884@@ -4950,6 +5424,9 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
7885 }
7886 }
7887
7888+ if (flags & CREATE_CACHED)
7889+ return NULL;
7890+
7891 bo = __kgem_bo_create_as_display(kgem, size, tiling, pitch);
7892 if (bo)
7893 return bo;
7894@@ -4987,14 +5464,9 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
7895 if (num_pages(bo) < size)
7896 continue;
7897
7898- if (bo->pitch != pitch || bo->tiling != tiling) {
7899- if (!gem_set_tiling(kgem->fd, bo->handle,
7900- tiling, pitch))
7901- continue;
7902-
7903- bo->pitch = pitch;
7904- bo->tiling = tiling;
7905- }
7906+ if (!kgem_set_tiling(kgem, bo, tiling, pitch) &&
7907+ !exact)
7908+ set_gpu_tiling(kgem, bo, tiling, pitch);
7909 }
7910
7911 kgem_bo_remove_from_active(kgem, bo);
7912@@ -5020,14 +5492,11 @@ large_inactive:
7913 if (size > num_pages(bo))
7914 continue;
7915
7916- if (bo->tiling != tiling ||
7917- (tiling != I915_TILING_NONE && bo->pitch != pitch)) {
7918- if (!gem_set_tiling(kgem->fd, bo->handle,
7919- tiling, pitch))
7920+ if (!kgem_set_tiling(kgem, bo, tiling, pitch)) {
7921+ if (kgem->gen >= 040 && !exact)
7922+ set_gpu_tiling(kgem, bo, tiling, pitch);
7923+ else
7924 continue;
7925-
7926- bo->tiling = tiling;
7927- bo->pitch = pitch;
7928 }
7929
7930 if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) {
7931@@ -5039,7 +5508,6 @@ large_inactive:
7932
7933 assert(bo->domain != DOMAIN_GPU);
7934 bo->unique_id = kgem_get_unique_id(kgem);
7935- bo->pitch = pitch;
7936 bo->delta = 0;
7937 DBG((" 1:from large inactive: pitch=%d, tiling=%d, handle=%d, id=%d\n",
7938 bo->pitch, bo->tiling, bo->handle, bo->unique_id));
7939@@ -5088,14 +5556,13 @@ large_inactive:
7940 if (bo->tiling != tiling ||
7941 (tiling != I915_TILING_NONE && bo->pitch != pitch)) {
7942 if (bo->map__gtt ||
7943- !gem_set_tiling(kgem->fd, bo->handle,
7944- tiling, pitch)) {
7945+ !kgem_set_tiling(kgem, bo,
7946+ tiling, pitch)) {
7947 DBG(("inactive GTT vma with wrong tiling: %d < %d\n",
7948 bo->tiling, tiling));
7949- continue;
7950+ kgem_bo_free(kgem, bo);
7951+ break;
7952 }
7953- bo->tiling = tiling;
7954- bo->pitch = pitch;
7955 }
7956
7957 if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) {
7958@@ -5103,8 +5570,11 @@ large_inactive:
7959 break;
7960 }
7961
7962+ if (tiling == I915_TILING_NONE)
7963+ bo->pitch = pitch;
7964+
7965 assert(bo->tiling == tiling);
7966- bo->pitch = pitch;
7967+ assert(bo->pitch >= pitch);
7968 bo->delta = 0;
7969 bo->unique_id = kgem_get_unique_id(kgem);
7970
7971@@ -5170,15 +5640,12 @@ search_active:
7972 if (num_pages(bo) < size)
7973 continue;
7974
7975- if (bo->pitch != pitch) {
7976- if (!gem_set_tiling(kgem->fd,
7977- bo->handle,
7978- tiling, pitch))
7979- continue;
7980-
7981- bo->pitch = pitch;
7982- }
7983+ if (!kgem_set_tiling(kgem, bo, tiling, pitch) &&
7984+ !exact)
7985+ set_gpu_tiling(kgem, bo, tiling, pitch);
7986 }
7987+ assert(bo->tiling == tiling);
7988+ assert(bo->pitch >= pitch);
7989
7990 kgem_bo_remove_from_active(kgem, bo);
7991
7992@@ -5233,19 +5700,21 @@ search_active:
7993 if (num_pages(bo) < size)
7994 continue;
7995
7996- if (bo->tiling != tiling ||
7997- (tiling != I915_TILING_NONE && bo->pitch != pitch)) {
7998- if (!gem_set_tiling(kgem->fd,
7999- bo->handle,
8000- tiling, pitch))
8001- continue;
8002+ if (!kgem_set_tiling(kgem, bo, tiling, pitch)) {
8003+ if (kgem->gen >= 040 && !exact) {
8004+ set_gpu_tiling(kgem, bo,
8005+ tiling, pitch);
8006+ } else {
8007+ kgem_bo_free(kgem, bo);
8008+ break;
8009+ }
8010 }
8011+ assert(bo->tiling == tiling);
8012+ assert(bo->pitch >= pitch);
8013
8014 kgem_bo_remove_from_active(kgem, bo);
8015
8016 bo->unique_id = kgem_get_unique_id(kgem);
8017- bo->pitch = pitch;
8018- bo->tiling = tiling;
8019 bo->delta = 0;
8020 DBG((" 1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n",
8021 bo->pitch, bo->tiling, bo->handle, bo->unique_id));
8022@@ -5323,11 +5792,13 @@ search_inactive:
8023 continue;
8024 }
8025
8026- if (bo->tiling != tiling ||
8027- (tiling != I915_TILING_NONE && bo->pitch != pitch)) {
8028- if (!gem_set_tiling(kgem->fd, bo->handle,
8029- tiling, pitch))
8030- continue;
8031+ if (!kgem_set_tiling(kgem, bo, tiling, pitch)) {
8032+ if (kgem->gen >= 040 && !exact) {
8033+ set_gpu_tiling(kgem, bo, tiling, pitch);
8034+ } else {
8035+ kgem_bo_free(kgem, bo);
8036+ break;
8037+ }
8038 }
8039
8040 if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) {
8041@@ -5338,9 +5809,8 @@ search_inactive:
8042 kgem_bo_remove_from_inactive(kgem, bo);
8043 assert(list_is_empty(&bo->list));
8044 assert(list_is_empty(&bo->vma));
8045-
8046- bo->pitch = pitch;
8047- bo->tiling = tiling;
8048+ assert(bo->tiling == tiling);
8049+ assert(bo->pitch >= pitch);
8050
8051 bo->delta = 0;
8052 bo->unique_id = kgem_get_unique_id(kgem);
8053@@ -5388,14 +5858,17 @@ search_inactive:
8054 kgem_bo_remove_from_active(kgem, bo);
8055 __kgem_bo_clear_busy(bo);
8056
8057- if (tiling != I915_TILING_NONE && bo->pitch != pitch) {
8058- if (!gem_set_tiling(kgem->fd, bo->handle, tiling, pitch)) {
8059+ if (!kgem_set_tiling(kgem, bo, tiling, pitch)) {
8060+ if (kgem->gen >= 040 && !exact) {
8061+ set_gpu_tiling(kgem, bo, tiling, pitch);
8062+ } else {
8063 kgem_bo_free(kgem, bo);
8064 goto no_retire;
8065 }
8066 }
8067+ assert(bo->tiling == tiling);
8068+ assert(bo->pitch >= pitch);
8069
8070- bo->pitch = pitch;
8071 bo->unique_id = kgem_get_unique_id(kgem);
8072 bo->delta = 0;
8073 DBG((" 2:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n",
8074@@ -5440,18 +5913,21 @@ create:
8075 }
8076
8077 bo->unique_id = kgem_get_unique_id(kgem);
8078- if (tiling == I915_TILING_NONE ||
8079- gem_set_tiling(kgem->fd, handle, tiling, pitch)) {
8080- bo->tiling = tiling;
8081- bo->pitch = pitch;
8082+ if (kgem_set_tiling(kgem, bo, tiling, pitch)) {
8083 if (flags & CREATE_SCANOUT)
8084 __kgem_bo_make_scanout(kgem, bo, width, height);
8085 } else {
8086- if (flags & CREATE_EXACT) {
8087- DBG(("%s: failed to set exact tiling (gem_set_tiling)\n", __FUNCTION__));
8088- gem_close(kgem->fd, handle);
8089- free(bo);
8090- return NULL;
8091+ if (kgem->gen >= 040) {
8092+ assert(!kgem->can_fence);
8093+ bo->tiling = tiling;
8094+ bo->pitch = pitch;
8095+ } else {
8096+ if (flags & CREATE_EXACT) {
8097+ DBG(("%s: failed to set exact tiling (gem_set_tiling)\n", __FUNCTION__));
8098+ gem_close(kgem->fd, handle);
8099+ free(bo);
8100+ return NULL;
8101+ }
8102 }
8103 }
8104
8105@@ -5633,6 +6109,7 @@ inline static bool nearly_idle(struct kgem *kgem)
8106 {
8107 int ring = kgem->ring == KGEM_BLT;
8108
8109+ assert(ring < ARRAY_SIZE(kgem->requests));
8110 if (list_is_singular(&kgem->requests[ring]))
8111 return true;
8112
8113@@ -5720,7 +6197,7 @@ static inline bool kgem_flush(struct kgem *kgem, bool flush)
8114 if (kgem->nreloc == 0)
8115 return true;
8116
8117- if (container_of(kgem, struct sna, kgem)->flags & SNA_POWERSAVE)
8118+ if (__to_sna(kgem)->flags & SNA_POWERSAVE)
8119 return true;
8120
8121 if (kgem->flush == flush && kgem->aperture < kgem->aperture_low)
8122@@ -5982,6 +6459,55 @@ bool kgem_check_many_bo_fenced(struct kgem *kgem, ...)
8123 return kgem_flush(kgem, flush);
8124 }
8125
8126+void __kgem_bcs_set_tiling(struct kgem *kgem,
8127+ struct kgem_bo *src,
8128+ struct kgem_bo *dst)
8129+{
8130+ uint32_t state, *b;
8131+
8132+ DBG(("%s: src handle=%d:tiling=%d, dst handle=%d:tiling=%d\n",
8133+ __FUNCTION__,
8134+ src ? src->handle : 0, src ? src->tiling : 0,
8135+ dst ? dst->handle : 0, dst ? dst->tiling : 0));
8136+ assert(kgem->mode == KGEM_BLT);
8137+ assert(dst == NULL || kgem_bo_can_blt(kgem, dst));
8138+ assert(src == NULL || kgem_bo_can_blt(kgem, src));
8139+
8140+ state = 0;
8141+ if (dst && dst->tiling == I915_TILING_Y)
8142+ state |= BCS_DST_Y;
8143+ if (src && src->tiling == I915_TILING_Y)
8144+ state |= BCS_SRC_Y;
8145+
8146+ if (kgem->bcs_state == state)
8147+ return;
8148+
8149+ DBG(("%s: updating SWCTRL %x -> %x\n", __FUNCTION__,
8150+ kgem->bcs_state, state));
8151+
8152+ /* Over-estimate space in case we need to re-emit the cmd packet */
8153+ if (!kgem_check_batch(kgem, 24)) {
8154+ _kgem_submit(kgem);
8155+ _kgem_set_mode(kgem, KGEM_BLT);
8156+ if (state == 0)
8157+ return;
8158+ }
8159+
8160+ b = kgem->batch + kgem->nbatch;
8161+ if (kgem->nbatch) {
8162+ *b++ = MI_FLUSH_DW;
8163+ *b++ = 0;
8164+ *b++ = 0;
8165+ *b++ = 0;
8166+ }
8167+ *b++ = MI_LOAD_REGISTER_IMM;
8168+ *b++ = BCS_SWCTRL;
8169+ *b++ = (BCS_SRC_Y | BCS_DST_Y) << 16 | state;
8170+ kgem->nbatch = b - kgem->batch;
8171+
8172+ kgem->bcs_state = state;
8173+}
8174+
8175 uint32_t kgem_add_reloc(struct kgem *kgem,
8176 uint32_t pos,
8177 struct kgem_bo *bo,
8178@@ -6195,12 +6721,6 @@ static void kgem_trim_vma_cache(struct kgem *kgem, int type, int bucket)
8179
8180 list_del(&bo->vma);
8181 kgem->vma[type].count--;
8182-
8183- if (!bo->purged && !kgem_bo_set_purgeable(kgem, bo)) {
8184- DBG(("%s: freeing unpurgeable old mapping\n",
8185- __FUNCTION__));
8186- kgem_bo_free(kgem, bo);
8187- }
8188 }
8189 }
8190
8191@@ -6216,8 +6736,8 @@ static void *__kgem_bo_map__gtt_or_wc(struct kgem *kgem, struct kgem_bo *bo)
8192 kgem_trim_vma_cache(kgem, MAP_GTT, bucket(bo));
8193
8194 if (bo->tiling || !kgem->has_wc_mmap) {
8195- assert(num_pages(bo) <= kgem->aperture_mappable / 2);
8196 assert(kgem->gen != 021 || bo->tiling != I915_TILING_Y);
8197+ warn_unless(num_pages(bo) <= kgem->aperture_mappable / 2);
8198
8199 ptr = bo->map__gtt;
8200 if (ptr == NULL)
8201@@ -6291,6 +6811,7 @@ void *kgem_bo_map(struct kgem *kgem, struct kgem_bo *bo)
8202 DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
8203 kgem_throttle(kgem);
8204 }
8205+ bo->needs_flush = false;
8206 kgem_bo_retire(kgem, bo);
8207 bo->domain = DOMAIN_GTT;
8208 bo->gtt_dirty = true;
8209@@ -6319,14 +6840,16 @@ void *kgem_bo_map__wc(struct kgem *kgem, struct kgem_bo *bo)
8210 bo->handle, (long)bo->presumed_offset, bo->tiling, bo->map__gtt, bo->map__cpu, bo->domain));
8211
8212 assert(bo->proxy == NULL);
8213- assert(bo->exec == NULL);
8214 assert(list_is_empty(&bo->list));
8215 assert_tiling(kgem, bo);
8216 assert(!bo->purged || bo->reusable);
8217
8218 if (bo->map__wc)
8219 return bo->map__wc;
8220+ if (!kgem->has_wc_mmap)
8221+ return NULL;
8222
8223+ kgem_trim_vma_cache(kgem, MAP_GTT, bucket(bo));
8224 return __kgem_bo_map__wc(kgem, bo);
8225 }
8226
8227@@ -6411,16 +6934,34 @@ struct kgem_bo *kgem_create_map(struct kgem *kgem,
8228 first_page = (uintptr_t)ptr;
8229 last_page = first_page + size + PAGE_SIZE - 1;
8230
8231- first_page &= ~(PAGE_SIZE-1);
8232- last_page &= ~(PAGE_SIZE-1);
8233+ first_page &= ~(uintptr_t)(PAGE_SIZE-1);
8234+ last_page &= ~(uintptr_t)(PAGE_SIZE-1);
8235 assert(last_page > first_page);
8236
8237 handle = gem_userptr(kgem->fd,
8238 (void *)first_page, last_page-first_page,
8239 read_only);
8240 if (handle == 0) {
8241- DBG(("%s: import failed, errno=%d\n", __FUNCTION__, errno));
8242- return NULL;
8243+ if (read_only && kgem->has_wc_mmap) {
8244+ struct drm_i915_gem_set_domain set_domain;
8245+
8246+ handle = gem_userptr(kgem->fd,
8247+ (void *)first_page, last_page-first_page,
8248+ false);
8249+
8250+ VG_CLEAR(set_domain);
8251+ set_domain.handle = handle;
8252+ set_domain.read_domains = I915_GEM_DOMAIN_GTT;
8253+ set_domain.write_domain = 0;
8254+ if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) {
8255+ gem_close(kgem->fd, handle);
8256+ handle = 0;
8257+ }
8258+ }
8259+ if (handle == 0) {
8260+ DBG(("%s: import failed, errno=%d\n", __FUNCTION__, errno));
8261+ return NULL;
8262+ }
8263 }
8264
8265 bo = __kgem_bo_alloc(handle, (last_page - first_page) / PAGE_SIZE);
8266@@ -6483,6 +7024,7 @@ void kgem_bo_sync__cpu(struct kgem *kgem, struct kgem_bo *bo)
8267 DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
8268 kgem_throttle(kgem);
8269 }
8270+ bo->needs_flush = false;
8271 kgem_bo_retire(kgem, bo);
8272 bo->domain = DOMAIN_CPU;
8273 }
8274@@ -6523,6 +7065,7 @@ void kgem_bo_sync__cpu_full(struct kgem *kgem, struct kgem_bo *bo, bool write)
8275 kgem_throttle(kgem);
8276 }
8277 if (write) {
8278+ bo->needs_flush = false;
8279 kgem_bo_retire(kgem, bo);
8280 bo->domain = DOMAIN_CPU;
8281 } else {
8282@@ -6559,6 +7102,7 @@ void kgem_bo_sync__gtt(struct kgem *kgem, struct kgem_bo *bo)
8283 DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
8284 kgem_throttle(kgem);
8285 }
8286+ bo->needs_flush = false;
8287 kgem_bo_retire(kgem, bo);
8288 bo->domain = DOMAIN_GTT;
8289 bo->gtt_dirty = true;
8290@@ -7485,6 +8029,7 @@ kgem_replace_bo(struct kgem *kgem,
8291 }
8292 _kgem_set_mode(kgem, KGEM_BLT);
8293 }
8294+ kgem_bcs_set_tiling(kgem, src, dst);
8295
8296 br00 = XY_SRC_COPY_BLT_CMD;
8297 br13 = pitch;
8298@@ -7553,6 +8098,9 @@ bool kgem_bo_convert_to_gpu(struct kgem *kgem,
8299 __FUNCTION__, bo->handle, flags, __kgem_bo_is_busy(kgem, bo)));
8300 assert(bo->tiling == I915_TILING_NONE);
8301
8302+ if (flags & (__MOVE_PRIME | __MOVE_SCANOUT))
8303+ return false;
8304+
8305 if (kgem->has_llc)
8306 return true;
8307
8308diff --git a/src/sna/kgem.h b/src/sna/kgem.h
8309index 2267bac..6cf877c 100644
8310--- a/src/sna/kgem.h
8311+++ b/src/sna/kgem.h
8312@@ -42,6 +42,7 @@ struct kgem_bo {
8313 #define RQ(rq) ((struct kgem_request *)((uintptr_t)(rq) & ~3))
8314 #define RQ_RING(rq) ((uintptr_t)(rq) & 3)
8315 #define RQ_IS_BLT(rq) (RQ_RING(rq) == KGEM_BLT)
8316+#define RQ_IS_RENDER(rq) (RQ_RING(rq) == KGEM_RENDER)
8317 #define MAKE_REQUEST(rq, ring) ((struct kgem_request *)((uintptr_t)(rq) | (ring)))
8318
8319 struct drm_i915_gem_exec_object2 *exec;
8320@@ -103,7 +104,7 @@ struct kgem_request {
8321 struct list list;
8322 struct kgem_bo *bo;
8323 struct list buffers;
8324- int ring;
8325+ unsigned ring;
8326 };
8327
8328 enum {
8329@@ -157,6 +158,8 @@ struct kgem {
8330 int16_t count;
8331 } vma[NUM_MAP_TYPES];
8332
8333+ uint32_t bcs_state;
8334+
8335 uint32_t batch_flags;
8336 uint32_t batch_flags_base;
8337 #define I915_EXEC_SECURE (1<<9)
8338@@ -187,8 +190,11 @@ struct kgem {
8339 uint32_t has_handle_lut :1;
8340 uint32_t has_wc_mmap :1;
8341
8342+ uint32_t can_fence :1;
8343 uint32_t can_blt_cpu :1;
8344+ uint32_t can_blt_y :1;
8345 uint32_t can_render_y :1;
8346+ uint32_t can_scanout_y :1;
8347
8348 uint16_t fence_max;
8349 uint16_t half_cpu_cache_pages;
8350@@ -230,7 +236,7 @@ struct kgem {
8351
8352 #define KGEM_MAX_DEFERRED_VBO 16
8353
8354-#define KGEM_BATCH_RESERVED 1
8355+#define KGEM_BATCH_RESERVED 8 /* LRI(SWCTRL) + END */
8356 #define KGEM_RELOC_RESERVED (KGEM_MAX_DEFERRED_VBO)
8357 #define KGEM_EXEC_RESERVED (1+KGEM_MAX_DEFERRED_VBO)
8358
8359@@ -342,6 +348,11 @@ static inline bool kgem_ring_is_idle(struct kgem *kgem, int ring)
8360 {
8361 ring = ring == KGEM_BLT;
8362
8363+ if (kgem->needs_semaphore &&
8364+ !list_is_empty(&kgem->requests[!ring]) &&
8365+ !__kgem_ring_is_idle(kgem, !ring))
8366+ return false;
8367+
8368 if (list_is_empty(&kgem->requests[ring]))
8369 return true;
8370
8371@@ -400,7 +411,7 @@ static inline void kgem_set_mode(struct kgem *kgem,
8372 enum kgem_mode mode,
8373 struct kgem_bo *bo)
8374 {
8375- assert(!kgem->wedged);
8376+ warn_unless(!kgem->wedged);
8377
8378 #if DEBUG_FLUSH_BATCH
8379 kgem_submit(kgem);
8380@@ -422,7 +433,7 @@ static inline void _kgem_set_mode(struct kgem *kgem, enum kgem_mode mode)
8381 {
8382 assert(kgem->mode == KGEM_NONE);
8383 assert(kgem->nbatch == 0);
8384- assert(!kgem->wedged);
8385+ warn_unless(!kgem->wedged);
8386 kgem->context_switch(kgem, mode);
8387 kgem->mode = mode;
8388 }
8389@@ -566,7 +577,7 @@ static inline bool kgem_bo_can_blt(struct kgem *kgem,
8390 {
8391 assert(bo->refcnt);
8392
8393- if (bo->tiling == I915_TILING_Y) {
8394+ if (bo->tiling == I915_TILING_Y && !kgem->can_blt_y) {
8395 DBG(("%s: can not blt to handle=%d, tiling=Y\n",
8396 __FUNCTION__, bo->handle));
8397 return false;
8398@@ -581,6 +592,22 @@ static inline bool kgem_bo_can_blt(struct kgem *kgem,
8399 return kgem_bo_blt_pitch_is_ok(kgem, bo);
8400 }
8401
8402+void __kgem_bcs_set_tiling(struct kgem *kgem,
8403+ struct kgem_bo *src,
8404+ struct kgem_bo *dst);
8405+
8406+inline static void kgem_bcs_set_tiling(struct kgem *kgem,
8407+ struct kgem_bo *src,
8408+ struct kgem_bo *dst)
8409+{
8410+ assert(kgem->mode == KGEM_BLT);
8411+
8412+ if (!kgem->can_blt_y)
8413+ return;
8414+
8415+ __kgem_bcs_set_tiling(kgem, src, dst);
8416+}
8417+
8418 static inline bool kgem_bo_is_snoop(struct kgem_bo *bo)
8419 {
8420 assert(bo->refcnt);
8421@@ -626,7 +653,7 @@ static inline bool kgem_bo_is_busy(struct kgem_bo *bo)
8422 return bo->rq;
8423 }
8424
8425-void __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo);
8426+bool __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo);
8427 static inline bool __kgem_bo_is_busy(struct kgem *kgem, struct kgem_bo *bo)
8428 {
8429 DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__,
8430@@ -636,14 +663,13 @@ static inline bool __kgem_bo_is_busy(struct kgem *kgem, struct kgem_bo *bo)
8431 if (bo->exec)
8432 return true;
8433
8434- if (bo->rq && !__kgem_busy(kgem, bo->handle)) {
8435- __kgem_retire_requests_upto(kgem, bo);
8436- assert(list_is_empty(&bo->request));
8437- assert(bo->rq == NULL);
8438- assert(bo->domain == DOMAIN_NONE);
8439- }
8440+ if (bo->rq == NULL)
8441+ return false;
8442+
8443+ if (__kgem_busy(kgem, bo->handle))
8444+ return true;
8445
8446- return kgem_bo_is_busy(bo);
8447+ return __kgem_retire_requests_upto(kgem, bo);
8448 }
8449
8450 static inline bool kgem_bo_is_render(struct kgem_bo *bo)
8451@@ -651,7 +677,15 @@ static inline bool kgem_bo_is_render(struct kgem_bo *bo)
8452 DBG(("%s: handle=%d, rq? %d [%d]\n", __FUNCTION__,
8453 bo->handle, bo->rq != NULL, (int)RQ_RING(bo->rq)));
8454 assert(bo->refcnt);
8455- return bo->rq && RQ_RING(bo->rq) == I915_EXEC_RENDER;
8456+ return bo->rq && RQ_RING(bo->rq) != KGEM_BLT;
8457+}
8458+
8459+static inline bool kgem_bo_is_blt(struct kgem_bo *bo)
8460+{
8461+ DBG(("%s: handle=%d, rq? %d\n", __FUNCTION__,
8462+ bo->handle, bo->rq != NULL, (int)RQ_RING(bo->rq)));
8463+ assert(bo->refcnt);
8464+ return RQ_RING(bo->rq) == KGEM_BLT;
8465 }
8466
8467 static inline void kgem_bo_mark_unreusable(struct kgem_bo *bo)
8468diff --git a/src/sna/kgem_debug_gen4.c b/src/sna/kgem_debug_gen4.c
8469index 9b80dc8..8e6e47b 100644
8470--- a/src/sna/kgem_debug_gen4.c
8471+++ b/src/sna/kgem_debug_gen4.c
8472@@ -598,7 +598,7 @@ int kgem_gen4_decode_3d(struct kgem *kgem, uint32_t offset)
8473 assert(len == 7);
8474 kgem_debug_print(data, offset, 0,
8475 "3DSTATE_DEPTH_BUFFER\n");
8476- kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Seperate Stencil %d\n",
8477+ kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Separate Stencil %d\n",
8478 get_965_surfacetype(data[1] >> 29),
8479 get_965_depthformat((data[1] >> 18) & 0x7),
8480 (data[1] & 0x0001ffff) + 1,
8481diff --git a/src/sna/kgem_debug_gen5.c b/src/sna/kgem_debug_gen5.c
8482index 8b55dd9..f1b1275 100644
8483--- a/src/sna/kgem_debug_gen5.c
8484+++ b/src/sna/kgem_debug_gen5.c
8485@@ -573,7 +573,7 @@ int kgem_gen5_decode_3d(struct kgem *kgem, uint32_t offset)
8486 assert(len == 7);
8487 kgem_debug_print(data, offset, 0,
8488 "3DSTATE_DEPTH_BUFFER\n");
8489- kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Seperate Stencil %d\n",
8490+ kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Separate Stencil %d\n",
8491 get_965_surfacetype(data[1] >> 29),
8492 get_965_depthformat((data[1] >> 18) & 0x7),
8493 (data[1] & 0x0001ffff) + 1,
8494diff --git a/src/sna/kgem_debug_gen6.c b/src/sna/kgem_debug_gen6.c
8495index 7ef55d3..579c5d5 100644
8496--- a/src/sna/kgem_debug_gen6.c
8497+++ b/src/sna/kgem_debug_gen6.c
8498@@ -985,7 +985,7 @@ int kgem_gen6_decode_3d(struct kgem *kgem, uint32_t offset)
8499 assert(len == 7);
8500 kgem_debug_print(data, offset, 0,
8501 "3DSTATE_DEPTH_BUFFER\n");
8502- kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Seperate Stencil %d\n",
8503+ kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Separate Stencil %d\n",
8504 get_965_surfacetype(data[1] >> 29),
8505 get_965_depthformat((data[1] >> 18) & 0x7),
8506 (data[1] & 0x0001ffff) + 1,
8507diff --git a/src/sna/sna.h b/src/sna/sna.h
8508index 18425e3..3c19aa5 100644
8509--- a/src/sna/sna.h
8510+++ b/src/sna/sna.h
8511@@ -154,6 +154,8 @@ struct sna_pixmap {
8512 #define MAPPED_GTT 1
8513 #define MAPPED_CPU 2
8514 uint8_t flush :2;
8515+#define FLUSH_READ 1
8516+#define FLUSH_WRITE 2
8517 uint8_t shm :1;
8518 uint8_t clear :1;
8519 uint8_t header :1;
8520@@ -179,18 +181,31 @@ static inline WindowPtr get_root_window(ScreenPtr screen)
8521 #endif
8522 }
8523
8524+#if !NDEBUG
8525+static PixmapPtr check_pixmap(PixmapPtr pixmap)
8526+{
8527+ if (pixmap != NULL) {
8528+ assert(pixmap->refcnt >= 1);
8529+ assert(pixmap->devKind != 0xdeadbeef);
8530+ }
8531+ return pixmap;
8532+}
8533+#else
8534+#define check_pixmap(p) p
8535+#endif
8536+
8537 static inline PixmapPtr get_window_pixmap(WindowPtr window)
8538 {
8539 assert(window);
8540 assert(window->drawable.type != DRAWABLE_PIXMAP);
8541- return fbGetWindowPixmap(window);
8542+ return check_pixmap(fbGetWindowPixmap(window));
8543 }
8544
8545 static inline PixmapPtr get_drawable_pixmap(DrawablePtr drawable)
8546 {
8547 assert(drawable);
8548 if (drawable->type == DRAWABLE_PIXMAP)
8549- return (PixmapPtr)drawable;
8550+ return check_pixmap((PixmapPtr)drawable);
8551 else
8552 return get_window_pixmap((WindowPtr)drawable);
8553 }
8554@@ -248,7 +263,6 @@ struct sna {
8555 #define SNA_FLUSH_GTT 0x400
8556 #define SNA_PERFORMANCE 0x1000
8557 #define SNA_POWERSAVE 0x2000
8558-#define SNA_REMOVE_OUTPUTS 0x4000
8559 #define SNA_HAS_FLIP 0x10000
8560 #define SNA_HAS_ASYNC_FLIP 0x20000
8561 #define SNA_LINEAR_FB 0x40000
8562@@ -265,6 +279,8 @@ struct sna {
8563 #define AVX 0x80
8564 #define AVX2 0x100
8565
8566+ bool ignore_copy_area : 1;
8567+
8568 unsigned watch_flush;
8569
8570 struct timeval timer_tv;
8571@@ -284,7 +300,11 @@ struct sna {
8572 struct kgem_bo *shadow;
8573 unsigned front_active;
8574 unsigned shadow_active;
8575+ unsigned rr_active;
8576 unsigned flip_active;
8577+ unsigned hidden;
8578+ bool shadow_enabled;
8579+ bool shadow_wait;
8580 bool dirty;
8581
8582 int max_crtc_width, max_crtc_height;
8583@@ -318,7 +338,8 @@ struct sna {
8584 uint32_t fg, bg;
8585 int size;
8586
8587- int active;
8588+ bool disable;
8589+ bool active;
8590 int last_x;
8591 int last_y;
8592
8593@@ -353,6 +374,8 @@ struct sna {
8594 bool available;
8595 bool open;
8596 #if HAVE_PRESENT
8597+ struct list vblank_queue;
8598+ uint64_t unflip;
8599 #endif
8600 } present;
8601
8602@@ -420,7 +443,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna);
8603 bool sna_mode_fake_init(struct sna *sna, int num_fake);
8604 bool sna_mode_wants_tear_free(struct sna *sna);
8605 void sna_mode_adjust_frame(struct sna *sna, int x, int y);
8606-extern void sna_mode_discover(struct sna *sna);
8607+extern void sna_mode_discover(struct sna *sna, bool tell);
8608 extern void sna_mode_check(struct sna *sna);
8609 extern bool sna_mode_disable(struct sna *sna);
8610 extern void sna_mode_enable(struct sna *sna);
8611@@ -461,6 +484,11 @@ to_sna_from_screen(ScreenPtr screen)
8612 return to_sna(xf86ScreenToScrn(screen));
8613 }
8614
8615+pure static inline ScreenPtr to_screen_from_sna(struct sna *sna)
8616+{
8617+ return xf86ScrnToScreen(sna->scrn);
8618+}
8619+
8620 pure static inline struct sna *
8621 to_sna_from_pixmap(PixmapPtr pixmap)
8622 {
8623@@ -498,12 +526,11 @@ to_sna_from_kgem(struct kgem *kgem)
8624 extern xf86CrtcPtr sna_covering_crtc(struct sna *sna,
8625 const BoxRec *box,
8626 xf86CrtcPtr desired);
8627+extern xf86CrtcPtr sna_primary_crtc(struct sna *sna);
8628
8629 extern bool sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
8630 xf86CrtcPtr crtc, const BoxRec *clip);
8631
8632-xf86CrtcPtr sna_mode_first_crtc(struct sna *sna);
8633-
8634 const struct ust_msc {
8635 uint64_t msc;
8636 int tv_sec;
8637@@ -536,6 +563,11 @@ static inline uint64_t ust64(int tv_sec, int tv_usec)
8638 return (uint64_t)tv_sec * 1000000 + tv_usec;
8639 }
8640
8641+static inline uint64_t swap_ust(const struct ust_msc *swap)
8642+{
8643+ return ust64(swap->tv_sec, swap->tv_usec);
8644+}
8645+
8646 #if HAVE_DRI2
8647 bool sna_dri2_open(struct sna *sna, ScreenPtr pScreen);
8648 void sna_dri2_page_flip_handler(struct sna *sna, struct drm_event_vblank *event);
8649@@ -575,12 +607,51 @@ static inline void sna_present_vblank_handler(struct drm_event_vblank *event) {
8650 #endif
8651
8652 extern bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation);
8653-extern int sna_crtc_to_pipe(xf86CrtcPtr crtc);
8654 extern uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc);
8655-extern uint32_t sna_crtc_id(xf86CrtcPtr crtc);
8656-extern bool sna_crtc_is_on(xf86CrtcPtr crtc);
8657 extern bool sna_crtc_is_transformed(xf86CrtcPtr crtc);
8658
8659+#define CRTC_VBLANK 0x3
8660+#define CRTC_ON 0x80000000
8661+
8662+static inline unsigned long *sna_crtc_flags(xf86CrtcPtr crtc)
8663+{
8664+ unsigned long *flags = crtc->driver_private;
8665+ assert(flags);
8666+ return flags;
8667+}
8668+
8669+static inline unsigned sna_crtc_pipe(xf86CrtcPtr crtc)
8670+{
8671+ return *sna_crtc_flags(crtc) >> 8 & 0xff;
8672+}
8673+
8674+static inline unsigned sna_crtc_id(xf86CrtcPtr crtc)
8675+{
8676+ return *sna_crtc_flags(crtc) >> 16 & 0xff;
8677+}
8678+
8679+static inline bool sna_crtc_is_on(xf86CrtcPtr crtc)
8680+{
8681+ return *sna_crtc_flags(crtc) & CRTC_ON;
8682+}
8683+
8684+static inline void sna_crtc_set_vblank(xf86CrtcPtr crtc)
8685+{
8686+ assert((*sna_crtc_flags(crtc) & CRTC_VBLANK) < 3);
8687+ ++*sna_crtc_flags(crtc);
8688+}
8689+
8690+static inline void sna_crtc_clear_vblank(xf86CrtcPtr crtc)
8691+{
8692+ assert(*sna_crtc_flags(crtc) & CRTC_VBLANK);
8693+ --*sna_crtc_flags(crtc);
8694+}
8695+
8696+static inline bool sna_crtc_has_vblank(xf86CrtcPtr crtc)
8697+{
8698+ return *sna_crtc_flags(crtc) & CRTC_VBLANK;
8699+}
8700+
8701 CARD32 sna_format_for_depth(int depth);
8702 CARD32 sna_render_format_for_depth(int depth);
8703
8704@@ -998,8 +1069,7 @@ static inline uint32_t pixmap_size(PixmapPtr pixmap)
8705
8706 bool sna_accel_init(ScreenPtr sreen, struct sna *sna);
8707 void sna_accel_create(struct sna *sna);
8708-void sna_accel_block_handler(struct sna *sna, struct timeval **tv);
8709-void sna_accel_wakeup_handler(struct sna *sna);
8710+void sna_accel_block(struct sna *sna, struct timeval **tv);
8711 void sna_accel_watch_flush(struct sna *sna, int enable);
8712 void sna_accel_flush(struct sna *sna);
8713 void sna_accel_enter(struct sna *sna);
8714@@ -1127,6 +1197,16 @@ memcpy_blt(const void *src, void *dst, int bpp,
8715 uint16_t width, uint16_t height);
8716
8717 void
8718+affine_blt(const void *src, void *dst, int bpp,
8719+ int16_t src_x, int16_t src_y,
8720+ int16_t src_width, int16_t src_height,
8721+ int32_t src_stride,
8722+ int16_t dst_x, int16_t dst_y,
8723+ uint16_t dst_width, uint16_t dst_height,
8724+ int32_t dst_stride,
8725+ const struct pixman_f_transform *t);
8726+
8727+void
8728 memmove_box(const void *src, void *dst,
8729 int bpp, int32_t stride,
8730 const BoxRec *box,
8731@@ -1182,6 +1262,31 @@ box_intersect(BoxPtr a, const BoxRec *b)
8732 return true;
8733 }
8734
8735+const BoxRec *
8736+__find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y);
8737+inline static const BoxRec *
8738+find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
8739+{
8740+ /* Special case for incremental trapezoid clipping */
8741+ if (begin == end)
8742+ return end;
8743+
8744+ /* Quick test if scanline is within range of clip boxes */
8745+ if (begin->y2 > y) {
8746+ assert(end == begin + 1 ||
8747+ __find_clip_box_for_y(begin, end, y) == begin);
8748+ return begin;
8749+ }
8750+ if (y >= end[-1].y2) {
8751+ assert(end == begin + 1 ||
8752+ __find_clip_box_for_y(begin, end, y) == end);
8753+ return end;
8754+ }
8755+
8756+ /* Otherwise bisect to find the first box crossing y */
8757+ return __find_clip_box_for_y(begin, end, y);
8758+}
8759+
8760 unsigned sna_cpu_detect(void);
8761 char *sna_cpu_features_to_string(unsigned features, char *line);
8762
8763diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
8764index baf5f60..71a6207 100644
8765--- a/src/sna/sna_accel.c
8766+++ b/src/sna/sna_accel.c
8767@@ -52,6 +52,7 @@
8768
8769 #include <sys/time.h>
8770 #include <sys/mman.h>
8771+#include <sys/ioctl.h>
8772 #include <unistd.h>
8773
8774 #ifdef HAVE_VALGRIND
8775@@ -66,7 +67,8 @@
8776 #define FORCE_FLUSH 0
8777 #define FORCE_FULL_SYNC 0 /* https://bugs.freedesktop.org/show_bug.cgi?id=61628 */
8778
8779-#define DEFAULT_TILING I915_TILING_X
8780+#define DEFAULT_PIXMAP_TILING I915_TILING_X
8781+#define DEFAULT_SCANOUT_TILING I915_TILING_X
8782
8783 #define USE_INPLACE 1
8784 #define USE_SPANS 0 /* -1 force CPU, 1 force GPU */
8785@@ -527,10 +529,10 @@ sna_pixmap_alloc_cpu(struct sna *sna,
8786 DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__,
8787 pixmap->drawable.width, pixmap->drawable.height));
8788
8789- hint = 0;
8790- if ((flags & MOVE_ASYNC_HINT) == 0 &&
8791- ((flags & MOVE_READ) == 0 || (priv->gpu_damage && !priv->clear && !sna->kgem.has_llc)))
8792- hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE;
8793+ hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE;
8794+ if ((flags & MOVE_ASYNC_HINT) ||
8795+ (priv->gpu_damage && !priv->clear && kgem_bo_is_busy(priv->gpu_bo) && sna->kgem.can_blt_cpu))
8796+ hint = 0;
8797
8798 priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem,
8799 pixmap->drawable.width,
8800@@ -612,9 +614,9 @@ static bool sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool a
8801
8802 static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap)
8803 {
8804-#if DEFAULT_TILING == I915_TILING_NONE
8805+#if DEFAULT_PIXMAP_TILING == I915_TILING_NONE
8806 return I915_TILING_NONE;
8807-#elif DEFAULT_TILING == I915_TILING_X
8808+#elif DEFAULT_PIXMAP_TILING == I915_TILING_X
8809 return I915_TILING_X;
8810 #else
8811 /* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */
8812@@ -630,15 +632,6 @@ static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap)
8813 pixmap->drawable.height > sna->render.max_3d_size))
8814 return I915_TILING_X;
8815
8816- if (sna_damage_is_all(&sna_pixmap(pixmap)->cpu_damage,
8817- pixmap->drawable.width,
8818- pixmap->drawable.height)) {
8819- DBG(("%s: entire source is damaged, using Y-tiling\n",
8820- __FUNCTION__));
8821- sna_damage_destroy(&sna_pixmap(priv)->gpu_damage);
8822- return I915_TILING_Y;
8823- }
8824-
8825 return I915_TILING_Y;
8826 #endif
8827 }
8828@@ -666,6 +659,7 @@ struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
8829 __FUNCTION__, priv->gpu_bo->tiling, tiling,
8830 pixmap->drawable.width, pixmap->drawable.height));
8831 assert(priv->gpu_damage == NULL || priv->gpu_bo);
8832+ assert(priv->gpu_bo->tiling != tiling);
8833
8834 if (priv->pinned) {
8835 DBG(("%s: can't convert pinned bo\n", __FUNCTION__));
8836@@ -690,6 +684,12 @@ struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
8837 return NULL;
8838 }
8839
8840+ if (bo->tiling == priv->gpu_bo->tiling) {
8841+ DBG(("%s: tiling request failed\n", __FUNCTION__));
8842+ kgem_bo_destroy(&sna->kgem, bo);
8843+ return NULL;
8844+ }
8845+
8846 box.x1 = box.y1 = 0;
8847 box.x2 = pixmap->drawable.width;
8848 box.y2 = pixmap->drawable.height;
8849@@ -824,8 +824,8 @@ create_pixmap(struct sna *sna, ScreenPtr screen,
8850 datasize += adjust;
8851 }
8852
8853- DBG(("%s: allocating pixmap %dx%d, depth=%d, size=%ld\n",
8854- __FUNCTION__, width, height, depth, (long)datasize));
8855+ DBG(("%s: allocating pixmap %dx%d, depth=%d/%d, size=%ld\n",
8856+ __FUNCTION__, width, height, depth, bpp, (long)datasize));
8857 pixmap = AllocatePixmap(screen, datasize);
8858 if (!pixmap)
8859 return NullPixmap;
8860@@ -878,7 +878,11 @@ __pop_freed_pixmap(struct sna *sna)
8861 pixmap = sna->freed_pixmap;
8862 sna->freed_pixmap = pixmap->devPrivate.ptr;
8863
8864+ DBG(("%s: reusing freed pixmap=%ld header\n",
8865+ __FUNCTION__, pixmap->drawable.serialNumber));
8866+
8867 assert(pixmap->refcnt == 0);
8868+ assert(pixmap->devKind = 0xdeadbeef);
8869 assert(sna_pixmap(pixmap));
8870 assert(sna_pixmap(pixmap)->header);
8871
8872@@ -1081,6 +1085,18 @@ sna_pixmap_create_scratch(ScreenPtr screen,
8873 return pixmap;
8874 }
8875
8876+static unsigned small_copy(const RegionRec *region)
8877+{
8878+ if ((region->extents.x2 - region->extents.x1)*(region->extents.y2 - region->extents.y1) < 1024) {
8879+ DBG(("%s: region:%dx%d\n", __FUNCTION__,
8880+ (region->extents.x2 - region->extents.x1),
8881+ (region->extents.y2 - region->extents.y1)));
8882+ return COPY_SMALL;
8883+ }
8884+
8885+ return 0;
8886+}
8887+
8888 #ifdef CREATE_PIXMAP_USAGE_SHARED
8889 static Bool
8890 sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle)
8891@@ -1124,7 +1140,7 @@ sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle)
8892 pixmap->drawable.height,
8893 pixmap->drawable.bitsPerPixel,
8894 I915_TILING_NONE,
8895- CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT);
8896+ CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT);
8897 if (bo == NULL) {
8898 DBG(("%s: allocation failed\n", __FUNCTION__));
8899 return FALSE;
8900@@ -1243,7 +1259,7 @@ sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen,
8901 width, height,
8902 pixmap->drawable.bitsPerPixel,
8903 I915_TILING_NONE,
8904- CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT);
8905+ CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT);
8906 if (priv->gpu_bo == NULL) {
8907 free(priv);
8908 FreePixmap(pixmap);
8909@@ -1311,7 +1327,7 @@ static PixmapPtr sna_create_pixmap(ScreenPtr screen,
8910
8911 if (unlikely((sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0))
8912 flags &= ~KGEM_CAN_CREATE_GPU;
8913- if (wedged(sna))
8914+ if (wedged(sna) && usage != SNA_CREATE_FB)
8915 flags &= ~KGEM_CAN_CREATE_GTT;
8916
8917 DBG(("%s: usage=%d, flags=%x\n", __FUNCTION__, usage, flags));
8918@@ -1419,8 +1435,11 @@ static void __sna_free_pixmap(struct sna *sna,
8919 if (priv->flush)
8920 sna_accel_watch_flush(sna, -1);
8921
8922+#if !NDEBUG
8923+ pixmap->devKind = 0xdeadbeef;
8924+#endif
8925 if (priv->header) {
8926- assert(pixmap->drawable.pScreen == sna->scrn->pScreen);
8927+ assert(pixmap->drawable.pScreen == to_screen_from_sna(sna));
8928 assert(!priv->shm);
8929 pixmap->devPrivate.ptr = sna->freed_pixmap;
8930 sna->freed_pixmap = pixmap;
8931@@ -1529,7 +1548,7 @@ static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, un
8932 if (!priv->cpu_bo)
8933 return true;
8934
8935- assert(!priv->cpu_bo->needs_flush);
8936+ assert(!priv->cpu_bo->needs_flush || (flags & MOVE_WRITE) == 0);
8937 assert(priv->pixmap->devKind == priv->cpu_bo->pitch);
8938 return priv->pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu);
8939 }
8940@@ -1557,6 +1576,11 @@ static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, un
8941 return true;
8942 }
8943
8944+ if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__wc)) {
8945+ assert(priv->mapped == MAPPED_GTT);
8946+ return true;
8947+ }
8948+
8949 return false;
8950 }
8951
8952@@ -1577,6 +1601,16 @@ static inline bool pixmap_inplace(struct sna *sna,
8953 return false;
8954
8955 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) {
8956+ if (priv->clear) {
8957+ DBG(("%s: no, clear GPU bo is busy\n", __FUNCTION__));
8958+ return false;
8959+ }
8960+
8961+ if (flags & MOVE_ASYNC_HINT) {
8962+ DBG(("%s: no, async hint and GPU bo is busy\n", __FUNCTION__));
8963+ return false;
8964+ }
8965+
8966 if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ)) {
8967 DBG(("%s: no, GPU bo is busy\n", __FUNCTION__));
8968 return false;
8969@@ -1624,7 +1658,7 @@ static bool sna_pixmap_alloc_gpu(struct sna *sna,
8970 if (pixmap->usage_hint == SNA_CREATE_FB && (sna->flags & SNA_LINEAR_FB) == 0) {
8971 flags |= CREATE_SCANOUT;
8972 tiling = kgem_choose_tiling(&sna->kgem,
8973- -I915_TILING_X,
8974+ -DEFAULT_SCANOUT_TILING,
8975 pixmap->drawable.width,
8976 pixmap->drawable.height,
8977 pixmap->drawable.bitsPerPixel);
8978@@ -1861,7 +1895,9 @@ sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
8979 assert(priv->gpu_bo == cow->bo);
8980 assert(cow->refcnt);
8981
8982- if (flags && (flags & MOVE_WRITE) == 0 && IS_COW_OWNER(priv->cow))
8983+ if (flags && /* flags == 0 => force decouple */
8984+ (flags & MOVE_WRITE) == 0 &&
8985+ (((flags & __MOVE_FORCE) == 0) || IS_COW_OWNER(priv->cow)))
8986 return true;
8987
8988 if (!IS_COW_OWNER(priv->cow))
8989@@ -1933,7 +1969,7 @@ sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
8990 box.y2 = pixmap->drawable.height;
8991
8992 if (flags & __MOVE_PRIME) {
8993- create = CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT;
8994+ create = CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT;
8995 tiling = I915_TILING_NONE;
8996 } else {
8997 create = 0;
8998@@ -2021,6 +2057,10 @@ sna_pixmap_make_cow(struct sna *sna,
8999 cow->bo->handle));
9000
9001 src_priv->cow = MAKE_COW_OWNER(cow);
9002+ if (src_priv->flush & FLUSH_WRITE) {
9003+ assert(!src_priv->shm);
9004+ sna_add_flush_pixmap(sna, src_priv, src_priv->gpu_bo);
9005+ }
9006 }
9007
9008 if (cow == COW(dst_priv->cow)) {
9009@@ -2267,6 +2307,7 @@ skip_inplace_map:
9010 (flags & MOVE_WRITE ? (void *)priv->gpu_bo : (void *)priv->gpu_damage) && priv->cpu_damage == NULL &&
9011 priv->gpu_bo->tiling == I915_TILING_NONE &&
9012 (flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE)) &&
9013+ (!priv->clear || !kgem_bo_is_busy(priv->gpu_bo)) &&
9014 ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 ||
9015 (!priv->cow && !priv->move_to_gpu && !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)))) {
9016 void *ptr;
9017@@ -2330,7 +2371,9 @@ skip_inplace_map:
9018 pixmap->devKind, pixmap->devKind * pixmap->drawable.height));
9019
9020 if (priv->cpu_bo) {
9021+ kgem_bo_undo(&sna->kgem, priv->cpu_bo);
9022 if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) &&
9023+ sna->kgem.can_blt_cpu &&
9024 sna->render.fill_one(sna,
9025 pixmap, priv->cpu_bo, priv->clear_color,
9026 0, 0,
9027@@ -2344,21 +2387,26 @@ skip_inplace_map:
9028 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
9029 }
9030
9031- assert(pixmap->devKind);
9032- if (priv->clear_color == 0 ||
9033- pixmap->drawable.bitsPerPixel == 8 ||
9034- priv->clear_color == (1 << pixmap->drawable.depth) - 1) {
9035- memset(pixmap->devPrivate.ptr, priv->clear_color,
9036- (size_t)pixmap->devKind * pixmap->drawable.height);
9037- } else {
9038- pixman_fill(pixmap->devPrivate.ptr,
9039- pixmap->devKind/sizeof(uint32_t),
9040- pixmap->drawable.bitsPerPixel,
9041- 0, 0,
9042- pixmap->drawable.width,
9043- pixmap->drawable.height,
9044- priv->clear_color);
9045- }
9046+ if (sigtrap_get() == 0) {
9047+ assert(pixmap->devKind);
9048+ sigtrap_assert_active();
9049+ if (priv->clear_color == 0 ||
9050+ pixmap->drawable.bitsPerPixel == 8 ||
9051+ priv->clear_color == (1 << pixmap->drawable.depth) - 1) {
9052+ memset(pixmap->devPrivate.ptr, priv->clear_color,
9053+ (size_t)pixmap->devKind * pixmap->drawable.height);
9054+ } else {
9055+ pixman_fill(pixmap->devPrivate.ptr,
9056+ pixmap->devKind/sizeof(uint32_t),
9057+ pixmap->drawable.bitsPerPixel,
9058+ 0, 0,
9059+ pixmap->drawable.width,
9060+ pixmap->drawable.height,
9061+ priv->clear_color);
9062+ }
9063+ sigtrap_put();
9064+ } else
9065+ return false;
9066
9067 clear_done:
9068 sna_damage_all(&priv->cpu_damage, pixmap);
9069@@ -2531,6 +2579,9 @@ static bool cpu_clear_boxes(struct sna *sna,
9070 {
9071 struct sna_fill_op fill;
9072
9073+ if (!sna->kgem.can_blt_cpu)
9074+ return false;
9075+
9076 if (!sna_fill_init_blt(&fill, sna,
9077 pixmap, priv->cpu_bo,
9078 GXcopy, priv->clear_color,
9079@@ -2904,17 +2955,22 @@ move_to_cpu:
9080 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
9081 }
9082
9083- assert(pixmap->devKind);
9084- do {
9085- pixman_fill(pixmap->devPrivate.ptr,
9086- pixmap->devKind/sizeof(uint32_t),
9087- pixmap->drawable.bitsPerPixel,
9088- box->x1, box->y1,
9089- box->x2 - box->x1,
9090- box->y2 - box->y1,
9091- priv->clear_color);
9092- box++;
9093- } while (--n);
9094+ if (sigtrap_get() == 0) {
9095+ assert(pixmap->devKind);
9096+ sigtrap_assert_active();
9097+ do {
9098+ pixman_fill(pixmap->devPrivate.ptr,
9099+ pixmap->devKind/sizeof(uint32_t),
9100+ pixmap->drawable.bitsPerPixel,
9101+ box->x1, box->y1,
9102+ box->x2 - box->x1,
9103+ box->y2 - box->y1,
9104+ priv->clear_color);
9105+ box++;
9106+ } while (--n);
9107+ sigtrap_put();
9108+ } else
9109+ return false;
9110
9111 clear_done:
9112 if (flags & MOVE_WRITE ||
9113@@ -3209,13 +3265,14 @@ __sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags)
9114 {
9115 struct sna_pixmap *priv;
9116
9117+ assert(flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE));
9118 if ((flags & __MOVE_FORCE) == 0 && wedged(sna))
9119 return NULL;
9120
9121 priv = sna_pixmap(pixmap);
9122 if (priv == NULL) {
9123 DBG(("%s: not attached\n", __FUNCTION__));
9124- if ((flags & __MOVE_DRI) == 0)
9125+ if ((flags & (__MOVE_DRI | __MOVE_SCANOUT)) == 0)
9126 return NULL;
9127
9128 if (pixmap->usage_hint == -1) {
9129@@ -3238,6 +3295,44 @@ __sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags)
9130 return priv;
9131 }
9132
9133+inline static void sna_pixmap_unclean(struct sna *sna,
9134+ struct sna_pixmap *priv,
9135+ unsigned flags)
9136+{
9137+ struct drm_i915_gem_busy busy;
9138+
9139+ assert(DAMAGE_IS_ALL(priv->gpu_damage));
9140+ assert(priv->gpu_bo);
9141+ assert(priv->gpu_bo->proxy == NULL);
9142+ assert_pixmap_map(priv->pixmap, priv);
9143+
9144+ sna_damage_destroy(&priv->cpu_damage);
9145+ list_del(&priv->flush_list);
9146+
9147+ if (flags & (__MOVE_DRI | __MOVE_SCANOUT))
9148+ return;
9149+
9150+ if (!priv->flush || priv->gpu_bo->exec)
9151+ return;
9152+
9153+ busy.handle = priv->gpu_bo->handle;
9154+ busy.busy = 0;
9155+ ioctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
9156+
9157+ DBG(("%s(pixmap=%ld): cleaning foreign bo handle=%u, busy=%x [ring=%d]\n",
9158+ __FUNCTION__,
9159+ priv->pixmap->drawable.serialNumber,
9160+ busy.handle, busy.busy, !!(busy.busy & (0xfffe << 16))));
9161+
9162+ if (busy.busy) {
9163+ unsigned mode = KGEM_RENDER;
9164+ if (busy.busy & (0xfffe << 16))
9165+ mode = KGEM_BLT;
9166+ kgem_bo_mark_busy(&sna->kgem, priv->gpu_bo, mode);
9167+ } else
9168+ __kgem_bo_clear_busy(priv->gpu_bo);
9169+}
9170+
9171 struct sna_pixmap *
9172 sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags)
9173 {
9174@@ -3287,12 +3382,14 @@ sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int fl
9175 if (priv->cow) {
9176 unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
9177
9178+ assert(cow);
9179+
9180 if ((flags & MOVE_READ) == 0) {
9181 if (priv->gpu_damage) {
9182 r.extents = *box;
9183 r.data = NULL;
9184 if (!region_subsumes_damage(&r, priv->gpu_damage))
9185- cow |= MOVE_READ;
9186+ cow |= MOVE_READ | __MOVE_FORCE;
9187 }
9188 } else {
9189 if (priv->cpu_damage) {
9190@@ -3303,22 +3400,18 @@ sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int fl
9191 }
9192 }
9193
9194- if (cow) {
9195- if (!sna_pixmap_undo_cow(sna, priv, cow))
9196- return NULL;
9197+ if (!sna_pixmap_undo_cow(sna, priv, cow))
9198+ return NULL;
9199
9200- if (priv->gpu_bo == NULL)
9201- sna_damage_destroy(&priv->gpu_damage);
9202- }
9203+ if (priv->gpu_bo == NULL)
9204+ sna_damage_destroy(&priv->gpu_damage);
9205 }
9206
9207 if (sna_damage_is_all(&priv->gpu_damage,
9208 pixmap->drawable.width,
9209 pixmap->drawable.height)) {
9210- assert(priv->gpu_bo);
9211- assert(priv->gpu_bo->proxy == NULL);
9212- sna_damage_destroy(&priv->cpu_damage);
9213- list_del(&priv->flush_list);
9214+ DBG(("%s: already all-damaged\n", __FUNCTION__));
9215+ sna_pixmap_unclean(sna, priv, flags);
9216 goto done;
9217 }
9218
9219@@ -3527,7 +3620,8 @@ sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box,
9220 }
9221
9222 if (priv->cow) {
9223- unsigned cow = MOVE_WRITE | MOVE_READ;
9224+ unsigned cow = MOVE_WRITE | MOVE_READ | __MOVE_FORCE;
9225+ assert(cow);
9226
9227 if (flags & IGNORE_DAMAGE) {
9228 if (priv->gpu_damage) {
9229@@ -3717,8 +3811,11 @@ create_gpu_bo:
9230 else
9231 move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT;
9232
9233- if (sna_pixmap_move_to_gpu(pixmap, move))
9234+ if (sna_pixmap_move_to_gpu(pixmap, move)) {
9235+ sna_damage_all(&priv->gpu_damage,
9236+ pixmap);
9237 goto use_gpu_bo;
9238+ }
9239 }
9240
9241 if (DAMAGE_IS_ALL(priv->gpu_damage) ||
9242@@ -4019,7 +4116,7 @@ sna_pixmap_create_upload(ScreenPtr screen,
9243 assert(width);
9244 assert(height);
9245
9246- if (depth == 1)
9247+ if (depth < 8)
9248 return create_pixmap(sna, screen, width, height, depth,
9249 CREATE_PIXMAP_USAGE_SCRATCH);
9250
9251@@ -4121,27 +4218,21 @@ sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
9252
9253 if (priv->cow) {
9254 unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
9255+ assert(cow);
9256 if (flags & MOVE_READ && priv->cpu_damage)
9257 cow |= MOVE_WRITE;
9258- if (cow) {
9259- if (!sna_pixmap_undo_cow(sna, priv, cow))
9260- return NULL;
9261+ if (!sna_pixmap_undo_cow(sna, priv, cow))
9262+ return NULL;
9263
9264- if (priv->gpu_bo == NULL)
9265- sna_damage_destroy(&priv->gpu_damage);
9266- }
9267+ if (priv->gpu_bo == NULL)
9268+ sna_damage_destroy(&priv->gpu_damage);
9269 }
9270
9271 if (sna_damage_is_all(&priv->gpu_damage,
9272 pixmap->drawable.width,
9273 pixmap->drawable.height)) {
9274 DBG(("%s: already all-damaged\n", __FUNCTION__));
9275- assert(DAMAGE_IS_ALL(priv->gpu_damage));
9276- assert(priv->gpu_bo);
9277- assert(priv->gpu_bo->proxy == NULL);
9278- assert_pixmap_map(pixmap, priv);
9279- sna_damage_destroy(&priv->cpu_damage);
9280- list_del(&priv->flush_list);
9281+ sna_pixmap_unclean(sna, priv, flags);
9282 goto active;
9283 }
9284
9285@@ -4206,7 +4297,7 @@ sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
9286 if (flags & MOVE_INPLACE_HINT || (priv->cpu_damage && priv->cpu_bo == NULL))
9287 create = CREATE_GTT_MAP | CREATE_INACTIVE;
9288 if (flags & __MOVE_PRIME)
9289- create |= CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT;
9290+ create |= CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT;
9291
9292 sna_pixmap_alloc_gpu(sna, pixmap, priv, create);
9293 }
9294@@ -4534,7 +4625,7 @@ static inline bool box32_trim_and_translate(Box32Rec *box, DrawablePtr d, GCPtr
9295 return box32_clip(box, gc);
9296 }
9297
9298-static inline void box_add_pt(BoxPtr box, int16_t x, int16_t y)
9299+static inline void box_add_xy(BoxPtr box, int16_t x, int16_t y)
9300 {
9301 if (box->x1 > x)
9302 box->x1 = x;
9303@@ -4547,6 +4638,11 @@ static inline void box_add_pt(BoxPtr box, int16_t x, int16_t y)
9304 box->y2 = y;
9305 }
9306
9307+static inline void box_add_pt(BoxPtr box, const DDXPointRec *pt)
9308+{
9309+ box_add_xy(box, pt->x, pt->y);
9310+}
9311+
9312 static inline bool box32_to_box16(const Box32Rec *b32, BoxRec *b16)
9313 {
9314 b16->x1 = b32->x1;
9315@@ -4864,6 +4960,7 @@ try_upload__inplace(PixmapPtr pixmap, RegionRec *region,
9316 pixmap->devPrivate.ptr = dst;
9317 pixmap->devKind = priv->gpu_bo->pitch;
9318 priv->mapped = dst == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
9319+ priv->cpu &= priv->mapped == MAPPED_CPU;
9320 assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
9321
9322 box = region_rects(region);
9323@@ -5172,6 +5269,16 @@ static inline uint8_t blt_depth(int depth)
9324 }
9325 }
9326
9327+inline static void blt_done(struct sna *sna)
9328+{
9329+ sna->blt_state.fill_bo = 0;
9330+ if (sna->kgem.nbatch && __kgem_ring_empty(&sna->kgem)) {
9331+ DBG(("%s: flushing BLT operation on empty ring\n",
9332+ __FUNCTION__));
9333+ _kgem_submit(&sna->kgem);
9334+ }
9335+}
9336+
9337 static bool
9338 sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
9339 int x, int y, int w, int h, char *bits)
9340@@ -5217,6 +5324,7 @@ sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
9341
9342 kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
9343 assert(kgem_bo_can_blt(&sna->kgem, bo));
9344+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
9345
9346 /* Region is pre-clipped and translated into pixmap space */
9347 box = region_rects(region);
9348@@ -5238,6 +5346,7 @@ sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
9349 return false;
9350 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9351 }
9352+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
9353
9354 upload = kgem_create_buffer(&sna->kgem,
9355 bstride*bh,
9356@@ -5331,7 +5440,7 @@ sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
9357 box++;
9358 } while (--n);
9359
9360- sna->blt_state.fill_bo = 0;
9361+ blt_done(sna);
9362 return true;
9363 }
9364
9365@@ -5381,6 +5490,7 @@ sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
9366
9367 kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
9368 assert(kgem_bo_can_blt(&sna->kgem, bo));
9369+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
9370
9371 skip = h * BitmapBytePad(w + left);
9372 for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) {
9373@@ -5408,6 +5518,7 @@ sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
9374 return false;
9375 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9376 }
9377+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
9378
9379 upload = kgem_create_buffer(&sna->kgem,
9380 bstride*bh,
9381@@ -5509,7 +5620,7 @@ sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
9382 } while (--n);
9383 }
9384
9385- sna->blt_state.fill_bo = 0;
9386+ blt_done(sna);
9387 return true;
9388 }
9389
9390@@ -5837,7 +5948,7 @@ sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
9391 if (!sna->render.copy_boxes(sna, alu,
9392 &pixmap->drawable, priv->gpu_bo, sx, sy,
9393 &pixmap->drawable, priv->gpu_bo, tx, ty,
9394- box, n, 0)) {
9395+ box, n, small_copy(region))) {
9396 DBG(("%s: fallback - accelerated copy boxes failed\n",
9397 __FUNCTION__));
9398 goto fallback;
9399@@ -6098,6 +6209,9 @@ sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu,
9400
9401 kgem_bo_sync__cpu_full(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC);
9402
9403+ if (sigtrap_get())
9404+ return false;
9405+
9406 box = region_rects(region);
9407 n = region_num_rects(region);
9408 if (src_priv->gpu_bo->tiling) {
9409@@ -6137,6 +6251,8 @@ sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu,
9410 }
9411 }
9412
9413+ sigtrap_put();
9414+
9415 return true;
9416
9417 upload_inplace:
9418@@ -6234,6 +6350,9 @@ upload_inplace:
9419
9420 assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
9421
9422+ if (sigtrap_get())
9423+ return false;
9424+
9425 box = region_rects(region);
9426 n = region_num_rects(region);
9427 if (dst_priv->gpu_bo->tiling) {
9428@@ -6265,15 +6384,19 @@ upload_inplace:
9429 } while (--n);
9430
9431 if (!dst_priv->shm) {
9432- assert(ptr == MAP(dst_priv->gpu_bo->map__cpu));
9433 dst_pixmap->devPrivate.ptr = ptr;
9434 dst_pixmap->devKind = dst_priv->gpu_bo->pitch;
9435- dst_priv->mapped = MAPPED_CPU;
9436+ if (ptr == MAP(dst_priv->gpu_bo->map__cpu)) {
9437+ dst_priv->mapped = MAPPED_CPU;
9438+ dst_priv->cpu = true;
9439+ } else
9440+ dst_priv->mapped = MAPPED_GTT;
9441 assert_pixmap_map(dst_pixmap, dst_priv);
9442- dst_priv->cpu = true;
9443 }
9444 }
9445
9446+ sigtrap_put();
9447+
9448 return true;
9449 }
9450
9451@@ -6326,6 +6449,16 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
9452
9453 assert(region_num_rects(region));
9454
9455+ if (src_priv &&
9456+ src_priv->gpu_bo == NULL &&
9457+ src_priv->cpu_bo == NULL &&
9458+ src_priv->ptr == NULL) {
9459+ /* Rare but still happens, nothing to copy */
9460+ DBG(("%s: src pixmap=%ld is empty\n",
9461+ __FUNCTION__, src_pixmap->drawable.serialNumber));
9462+ return;
9463+ }
9464+
9465 if (src_pixmap == dst_pixmap)
9466 return sna_self_copy_boxes(src, dst, gc,
9467 region, dx, dy,
9468@@ -6499,7 +6632,7 @@ discard_cow:
9469 if (!sna->render.copy_boxes(sna, alu,
9470 &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
9471 &dst_pixmap->drawable, bo, 0, 0,
9472- box, n, 0)) {
9473+ box, n, small_copy(region))) {
9474 DBG(("%s: fallback - accelerated copy boxes failed\n",
9475 __FUNCTION__));
9476 goto fallback;
9477@@ -6536,7 +6669,7 @@ discard_cow:
9478 if (!sna->render.copy_boxes(sna, alu,
9479 &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
9480 &dst_pixmap->drawable, bo, 0, 0,
9481- box, n, 0)) {
9482+ box, n, small_copy(region))) {
9483 DBG(("%s: fallback - accelerated copy boxes failed\n",
9484 __FUNCTION__));
9485 goto fallback;
9486@@ -6579,7 +6712,7 @@ discard_cow:
9487 if (!sna->render.copy_boxes(sna, alu,
9488 &src_pixmap->drawable, src_priv->cpu_bo, src_dx, src_dy,
9489 &dst_pixmap->drawable, bo, 0, 0,
9490- box, n, src_priv->shm ? COPY_LAST : 0)) {
9491+ box, n, small_copy(region) | (src_priv->shm ? COPY_LAST : 0))) {
9492 DBG(("%s: fallback - accelerated copy boxes failed\n",
9493 __FUNCTION__));
9494 goto fallback;
9495@@ -6631,8 +6764,7 @@ discard_cow:
9496 ok = sna->render.copy_boxes(sna, alu,
9497 &src_pixmap->drawable, src_bo, src_dx, src_dy,
9498 &dst_pixmap->drawable, bo, 0, 0,
9499- box, n, COPY_LAST);
9500-
9501+ box, n, small_copy(region) | COPY_LAST);
9502 kgem_bo_sync__cpu(&sna->kgem, src_bo);
9503 assert(src_bo->rq == NULL);
9504 kgem_bo_destroy(&sna->kgem, src_bo);
9505@@ -6780,18 +6912,22 @@ fallback:
9506 return;
9507 }
9508
9509- assert(dst_pixmap->devPrivate.ptr);
9510- assert(dst_pixmap->devKind);
9511- do {
9512- pixman_fill(dst_pixmap->devPrivate.ptr,
9513- dst_pixmap->devKind/sizeof(uint32_t),
9514- dst_pixmap->drawable.bitsPerPixel,
9515- box->x1, box->y1,
9516- box->x2 - box->x1,
9517- box->y2 - box->y1,
9518- src_priv->clear_color);
9519- box++;
9520- } while (--n);
9521+ if (sigtrap_get() == 0) {
9522+ assert(dst_pixmap->devPrivate.ptr);
9523+ assert(dst_pixmap->devKind);
9524+ sigtrap_assert_active();
9525+ do {
9526+ pixman_fill(dst_pixmap->devPrivate.ptr,
9527+ dst_pixmap->devKind/sizeof(uint32_t),
9528+ dst_pixmap->drawable.bitsPerPixel,
9529+ box->x1, box->y1,
9530+ box->x2 - box->x1,
9531+ box->y2 - box->y1,
9532+ src_priv->clear_color);
9533+ box++;
9534+ } while (--n);
9535+ sigtrap_put();
9536+ }
9537 } else if (!sna_copy_boxes__inplace(sna, region, alu,
9538 src_pixmap, src_priv,
9539 src_dx, src_dy,
9540@@ -6848,36 +6984,39 @@ fallback:
9541 ((char *)src_pixmap->devPrivate.ptr +
9542 src_dy * src_stride + src_dx * bpp / 8);
9543
9544- do {
9545- DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n",
9546- __FUNCTION__,
9547- box->x1, box->y1,
9548- box->x2 - box->x1,
9549- box->y2 - box->y1,
9550- src_dx, src_dy,
9551- src_stride, dst_stride));
9552-
9553- assert(box->x1 >= 0);
9554- assert(box->y1 >= 0);
9555- assert(box->x2 <= dst_pixmap->drawable.width);
9556- assert(box->y2 <= dst_pixmap->drawable.height);
9557-
9558- assert(box->x1 + src_dx >= 0);
9559- assert(box->y1 + src_dy >= 0);
9560- assert(box->x2 + src_dx <= src_pixmap->drawable.width);
9561- assert(box->y2 + src_dy <= src_pixmap->drawable.height);
9562- assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
9563- assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE));
9564- assert(src_stride);
9565- assert(dst_stride);
9566- memcpy_blt(src_bits, dst_bits, bpp,
9567- src_stride, dst_stride,
9568- box->x1, box->y1,
9569- box->x1, box->y1,
9570- box->x2 - box->x1,
9571- box->y2 - box->y1);
9572- box++;
9573- } while (--n);
9574+ if (sigtrap_get() == 0) {
9575+ do {
9576+ DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n",
9577+ __FUNCTION__,
9578+ box->x1, box->y1,
9579+ box->x2 - box->x1,
9580+ box->y2 - box->y1,
9581+ src_dx, src_dy,
9582+ src_stride, dst_stride));
9583+
9584+ assert(box->x1 >= 0);
9585+ assert(box->y1 >= 0);
9586+ assert(box->x2 <= dst_pixmap->drawable.width);
9587+ assert(box->y2 <= dst_pixmap->drawable.height);
9588+
9589+ assert(box->x1 + src_dx >= 0);
9590+ assert(box->y1 + src_dy >= 0);
9591+ assert(box->x2 + src_dx <= src_pixmap->drawable.width);
9592+ assert(box->y2 + src_dy <= src_pixmap->drawable.height);
9593+ assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
9594+ assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE));
9595+ assert(src_stride);
9596+ assert(dst_stride);
9597+ memcpy_blt(src_bits, dst_bits, bpp,
9598+ src_stride, dst_stride,
9599+ box->x1, box->y1,
9600+ box->x1, box->y1,
9601+ box->x2 - box->x1,
9602+ box->y2 - box->y1);
9603+ box++;
9604+ } while (--n);
9605+ sigtrap_put();
9606+ }
9607 } else {
9608 DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__));
9609
9610@@ -6931,7 +7070,8 @@ sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc,
9611
9612 /* Short cut for unmapped windows */
9613 if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) {
9614- DBG(("%s: unmapped\n", __FUNCTION__));
9615+ DBG(("%s: unmapped/unrealized dst (pixmap=%ld)\n",
9616+ __FUNCTION__, get_window_pixmap((WindowPtr)dst)));
9617 return NULL;
9618 }
9619
9620@@ -7115,19 +7255,28 @@ sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
9621 if (gc->planemask == 0)
9622 return NULL;
9623
9624- DBG(("%s: src=(%d, %d)x(%d, %d)+(%d, %d) -> dst=(%d, %d)+(%d, %d); alu=%d, pm=%lx, depth=%d\n",
9625+ if (sna->ignore_copy_area)
9626+ return NULL;
9627+
9628+ DBG(("%s: src=pixmap=%ld:(%d, %d)x(%d, %d)+(%d, %d) -> dst=pixmap=%ld:(%d, %d)+(%d, %d); alu=%d, pm=%lx, depth=%d\n",
9629 __FUNCTION__,
9630+ get_drawable_pixmap(src)->drawable.serialNumber,
9631 src_x, src_y, width, height, src->x, src->y,
9632+ get_drawable_pixmap(dst)->drawable.serialNumber,
9633 dst_x, dst_y, dst->x, dst->y,
9634 gc->alu, gc->planemask, gc->depth));
9635
9636 if (FORCE_FALLBACK || !ACCEL_COPY_AREA || wedged(sna) ||
9637- !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8)
9638+ !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8) {
9639+ DBG(("%s: fallback copy\n", __FUNCTION__));
9640 copy = sna_fallback_copy_boxes;
9641- else if (src == dst)
9642+ } else if (src == dst) {
9643+ DBG(("%s: self copy\n", __FUNCTION__));
9644 copy = sna_self_copy_boxes;
9645- else
9646+ } else {
9647+ DBG(("%s: normal copy\n", __FUNCTION__));
9648 copy = sna_copy_boxes;
9649+ }
9650
9651 return sna_do_copy(src, dst, gc,
9652 src_x, src_y,
9653@@ -7136,30 +7285,21 @@ sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
9654 copy, 0, NULL);
9655 }
9656
9657-static const BoxRec *
9658-find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
9659+const BoxRec *
9660+__find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
9661 {
9662- const BoxRec *mid;
9663-
9664- if (end == begin)
9665- return end;
9666-
9667- if (end - begin == 1) {
9668+ assert(end - begin > 1);
9669+ do {
9670+ const BoxRec *mid = begin + (end - begin) / 2;
9671+ if (mid->y2 > y)
9672+ end = mid;
9673+ else
9674+ begin = mid;
9675+ } while (end > begin + 1);
9676 if (begin->y2 > y)
9677- return begin;
9678+ return begin;
9679 else
9680- return end;
9681- }
9682-
9683- mid = begin + (end - begin) / 2;
9684- if (mid->y2 > y)
9685- /* If no box is found in [begin, mid], the function
9686- * will return @mid, which is then known to be the
9687- * correct answer.
9688- */
9689- return find_clip_box_for_y(begin, mid, y);
9690- else
9691- return find_clip_box_for_y(mid, end, y);
9692+ return end;
9693 }
9694
9695 struct sna_fill_spans {
9696@@ -8223,6 +8363,8 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
9697 }
9698 br13 |= blt_depth(drawable->depth) << 24;
9699 br13 |= copy_ROP[gc->alu] << 16;
9700+ DBG(("%s: target-depth=%d, alu=%d, bg=%08x, fg=%08x\n",
9701+ __FUNCTION__, drawable->depth, gc->alu, gc->bgPixel, gc->fgPixel));
9702
9703 kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo);
9704 assert(kgem_bo_can_blt(&sna->kgem, arg->bo));
9705@@ -8255,6 +8397,7 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
9706 return; /* XXX fallback? */
9707 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9708 }
9709+ kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
9710
9711 assert(sna->kgem.mode == KGEM_BLT);
9712 if (sna->kgem.gen >= 0100) {
9713@@ -8270,8 +8413,8 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
9714 I915_GEM_DOMAIN_RENDER |
9715 KGEM_RELOC_FENCED,
9716 0);
9717- b[5] = gc->bgPixel;
9718- b[6] = gc->fgPixel;
9719+ b[6] = gc->bgPixel;
9720+ b[7] = gc->fgPixel;
9721
9722 dst = (uint8_t *)&b[8];
9723 sna->kgem.nbatch += 8 + src_stride;
9724@@ -8322,6 +8465,7 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
9725 return; /* XXX fallback? */
9726 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9727 }
9728+ kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
9729
9730 upload = kgem_create_buffer(&sna->kgem,
9731 bstride*bh,
9732@@ -8408,7 +8552,7 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
9733 sna_damage_add_to_pixmap(arg->damage, region, pixmap);
9734 }
9735 assert_pixmap_damage(pixmap);
9736- sna->blt_state.fill_bo = 0;
9737+ blt_done(sna);
9738 }
9739
9740 static void
9741@@ -8472,6 +8616,7 @@ sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
9742 return; /* XXX fallback? */
9743 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9744 }
9745+ kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
9746
9747 upload = kgem_create_buffer(&sna->kgem,
9748 bstride*bh,
9749@@ -8588,6 +8733,8 @@ sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
9750 }
9751 }
9752
9753+ kgem_bcs_set_tiling(&sna->kgem, upload, arg->bo);
9754+
9755 assert(sna->kgem.mode == KGEM_BLT);
9756 b = sna->kgem.batch + sna->kgem.nbatch;
9757 if (sna->kgem.gen >= 0100) {
9758@@ -8641,7 +8788,7 @@ sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
9759 sna_damage_add_to_pixmap(arg->damage, region, dst_pixmap);
9760 }
9761 assert_pixmap_damage(dst_pixmap);
9762- sna->blt_state.fill_bo = 0;
9763+ blt_done(sna);
9764 }
9765
9766 static RegionPtr
9767@@ -8895,36 +9042,11 @@ sna_poly_point_extents(DrawablePtr drawable, GCPtr gc,
9768 last.x += pt->x;
9769 last.y += pt->y;
9770 pt++;
9771- box_add_pt(&box, last.x, last.y);
9772+ box_add_xy(&box, last.x, last.y);
9773 }
9774 } else {
9775- --n; ++pt;
9776- while (n >= 8) {
9777- box_add_pt(&box, pt[0].x, pt[0].y);
9778- box_add_pt(&box, pt[1].x, pt[1].y);
9779- box_add_pt(&box, pt[2].x, pt[2].y);
9780- box_add_pt(&box, pt[3].x, pt[3].y);
9781- box_add_pt(&box, pt[4].x, pt[4].y);
9782- box_add_pt(&box, pt[5].x, pt[5].y);
9783- box_add_pt(&box, pt[6].x, pt[6].y);
9784- box_add_pt(&box, pt[7].x, pt[7].y);
9785- pt += 8;
9786- n -= 8;
9787- }
9788- if (n & 4) {
9789- box_add_pt(&box, pt[0].x, pt[0].y);
9790- box_add_pt(&box, pt[1].x, pt[1].y);
9791- box_add_pt(&box, pt[2].x, pt[2].y);
9792- box_add_pt(&box, pt[3].x, pt[3].y);
9793- pt += 4;
9794- }
9795- if (n & 2) {
9796- box_add_pt(&box, pt[0].x, pt[0].y);
9797- box_add_pt(&box, pt[1].x, pt[1].y);
9798- pt += 2;
9799- }
9800- if (n & 1)
9801- box_add_pt(&box, pt[0].x, pt[0].y);
9802+ while (--n)
9803+ box_add_pt(&box, ++pt);
9804 }
9805 box.x2++;
9806 box.y2++;
9807@@ -9636,7 +9758,7 @@ sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
9808 y += pt->y;
9809 if (blt)
9810 blt &= pt->x == 0 || pt->y == 0;
9811- box_add_pt(&box, x, y);
9812+ box_add_xy(&box, x, y);
9813 }
9814 } else {
9815 int x = box.x1;
9816@@ -9648,7 +9770,7 @@ sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
9817 x = pt->x;
9818 y = pt->y;
9819 }
9820- box_add_pt(&box, pt->x, pt->y);
9821+ box_add_pt(&box, pt);
9822 }
9823 }
9824 box.x2++;
9825@@ -11785,14 +11907,29 @@ sna_poly_fill_rect_blt(DrawablePtr drawable,
9826 if (nbox > ARRAY_SIZE(boxes))
9827 nbox = ARRAY_SIZE(boxes);
9828 n -= nbox;
9829- do {
9830+ while (nbox >= 2) {
9831+ b[0].x1 = rect[0].x + dx;
9832+ b[0].y1 = rect[0].y + dy;
9833+ b[0].x2 = b[0].x1 + rect[0].width;
9834+ b[0].y2 = b[0].y1 + rect[0].height;
9835+
9836+ b[1].x1 = rect[1].x + dx;
9837+ b[1].y1 = rect[1].y + dy;
9838+ b[1].x2 = b[1].x1 + rect[1].width;
9839+ b[1].y2 = b[1].y1 + rect[1].height;
9840+
9841+ b += 2;
9842+ rect += 2;
9843+ nbox -= 2;
9844+ }
9845+ if (nbox) {
9846 b->x1 = rect->x + dx;
9847 b->y1 = rect->y + dy;
9848 b->x2 = b->x1 + rect->width;
9849 b->y2 = b->y1 + rect->height;
9850 b++;
9851 rect++;
9852- } while (--nbox);
9853+ }
9854 fill.boxes(sna, &fill, boxes, b-boxes);
9855 b = boxes;
9856 } while (n);
9857@@ -11802,14 +11939,29 @@ sna_poly_fill_rect_blt(DrawablePtr drawable,
9858 if (nbox > ARRAY_SIZE(boxes))
9859 nbox = ARRAY_SIZE(boxes);
9860 n -= nbox;
9861- do {
9862+ while (nbox >= 2) {
9863+ b[0].x1 = rect[0].x;
9864+ b[0].y1 = rect[0].y;
9865+ b[0].x2 = b[0].x1 + rect[0].width;
9866+ b[0].y2 = b[0].y1 + rect[0].height;
9867+
9868+ b[1].x1 = rect[1].x;
9869+ b[1].y1 = rect[1].y;
9870+ b[1].x2 = b[1].x1 + rect[1].width;
9871+ b[1].y2 = b[1].y1 + rect[1].height;
9872+
9873+ b += 2;
9874+ rect += 2;
9875+ nbox -= 2;
9876+ }
9877+ if (nbox) {
9878 b->x1 = rect->x;
9879 b->y1 = rect->y;
9880 b->x2 = b->x1 + rect->width;
9881 b->y2 = b->y1 + rect->height;
9882 b++;
9883 rect++;
9884- } while (--nbox);
9885+ }
9886 fill.boxes(sna, &fill, boxes, b-boxes);
9887 b = boxes;
9888 } while (n);
9889@@ -12192,6 +12344,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
9890 return false;
9891 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9892 }
9893+ kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
9894
9895 get_drawable_deltas(drawable, pixmap, &dx, &dy);
9896 assert(extents->x1 + dx >= 0);
9897@@ -12335,6 +12488,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
9898
9899 _kgem_submit(&sna->kgem);
9900 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9901+ kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
9902 } while (1);
9903 } else {
9904 RegionRec clip;
9905@@ -12403,6 +12557,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
9906 if (!kgem_check_batch(&sna->kgem, 3)) {
9907 _kgem_submit(&sna->kgem);
9908 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9909+ kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
9910
9911 unwind_batch = sna->kgem.nbatch;
9912 unwind_reloc = sna->kgem.nreloc;
9913@@ -12499,6 +12654,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
9914 DBG(("%s: emitting split batch\n", __FUNCTION__));
9915 _kgem_submit(&sna->kgem);
9916 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9917+ kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
9918
9919 unwind_batch = sna->kgem.nbatch;
9920 unwind_reloc = sna->kgem.nreloc;
9921@@ -12572,7 +12728,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
9922 }
9923 done:
9924 assert_pixmap_damage(pixmap);
9925- sna->blt_state.fill_bo = 0;
9926+ blt_done(sna);
9927 return true;
9928 }
9929
9930@@ -13128,6 +13284,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
9931 return false;
9932 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9933 }
9934+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
9935
9936 if (!clipped) {
9937 dx += drawable->x;
9938@@ -13240,6 +13397,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
9939
9940 _kgem_submit(&sna->kgem);
9941 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9942+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
9943 } while (1);
9944 } else {
9945 RegionRec clip;
9946@@ -13297,6 +13455,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
9947 if (!kgem_check_batch(&sna->kgem, 3)) {
9948 _kgem_submit(&sna->kgem);
9949 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9950+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
9951
9952 assert(sna->kgem.mode == KGEM_BLT);
9953 b = sna->kgem.batch + sna->kgem.nbatch;
9954@@ -13369,6 +13528,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
9955 if (!kgem_check_batch(&sna->kgem, 3)) {
9956 _kgem_submit(&sna->kgem);
9957 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9958+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
9959
9960 assert(sna->kgem.mode == KGEM_BLT);
9961 b = sna->kgem.batch + sna->kgem.nbatch;
9962@@ -13419,7 +13579,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
9963 }
9964
9965 assert_pixmap_damage(pixmap);
9966- sna->blt_state.fill_bo = 0;
9967+ blt_done(sna);
9968 return true;
9969 }
9970
9971@@ -13499,6 +13659,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
9972 get_drawable_deltas(drawable, pixmap, &dx, &dy);
9973 kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
9974 assert(kgem_bo_can_blt(&sna->kgem, bo));
9975+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
9976
9977 br00 = 3 << 20;
9978 br13 = bo->pitch;
9979@@ -13543,6 +13704,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
9980 return false;
9981 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9982 }
9983+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
9984
9985 assert(sna->kgem.mode == KGEM_BLT);
9986 b = sna->kgem.batch + sna->kgem.nbatch;
9987@@ -13606,6 +13768,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
9988 return false;
9989 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9990 }
9991+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
9992
9993 upload = kgem_create_buffer(&sna->kgem,
9994 bstride*bh,
9995@@ -13736,6 +13899,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
9996 return false;
9997 _kgem_set_mode(&sna->kgem, KGEM_BLT);
9998 }
9999+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10000
10001 assert(sna->kgem.mode == KGEM_BLT);
10002 b = sna->kgem.batch + sna->kgem.nbatch;
10003@@ -13797,6 +13961,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
10004 return false;
10005 _kgem_set_mode(&sna->kgem, KGEM_BLT);
10006 }
10007+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10008
10009 upload = kgem_create_buffer(&sna->kgem,
10010 bstride*bh,
10011@@ -13927,6 +14092,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
10012 return false;
10013 _kgem_set_mode(&sna->kgem, KGEM_BLT);
10014 }
10015+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10016
10017 assert(sna->kgem.mode == KGEM_BLT);
10018 b = sna->kgem.batch + sna->kgem.nbatch;
10019@@ -13987,6 +14153,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
10020 return false;
10021 _kgem_set_mode(&sna->kgem, KGEM_BLT);
10022 }
10023+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10024
10025 upload = kgem_create_buffer(&sna->kgem,
10026 bstride*bh,
10027@@ -14064,7 +14231,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
10028 }
10029 }
10030
10031- sna->blt_state.fill_bo = 0;
10032+ blt_done(sna);
10033 return true;
10034 }
10035
10036@@ -14126,6 +14293,7 @@ sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna,
10037 return; /* XXX fallback? */
10038 _kgem_set_mode(&sna->kgem, KGEM_BLT);
10039 }
10040+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10041
10042 assert(sna->kgem.mode == KGEM_BLT);
10043 b = sna->kgem.batch + sna->kgem.nbatch;
10044@@ -14251,6 +14419,7 @@ sna_poly_fill_rect_stippled_n_box(struct sna *sna,
10045 return; /* XXX fallback? */
10046 _kgem_set_mode(&sna->kgem, KGEM_BLT);
10047 }
10048+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10049
10050 assert(sna->kgem.mode == KGEM_BLT);
10051 b = sna->kgem.batch + sna->kgem.nbatch;
10052@@ -14414,6 +14583,7 @@ sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable,
10053 get_drawable_deltas(drawable, pixmap, &dx, &dy);
10054 kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
10055 assert(kgem_bo_can_blt(&sna->kgem, bo));
10056+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10057
10058 br00 = XY_MONO_SRC_COPY_IMM | 3 << 20;
10059 br13 = bo->pitch;
10060@@ -14526,7 +14696,7 @@ sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable,
10061 }
10062
10063 assert_pixmap_damage(pixmap);
10064- sna->blt_state.fill_bo = 0;
10065+ blt_done(sna);
10066 return true;
10067 }
10068
10069@@ -14559,6 +14729,7 @@ sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable,
10070 get_drawable_deltas(drawable, pixmap, &dx, &dy);
10071 kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
10072 assert(kgem_bo_can_blt(&sna->kgem, bo));
10073+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10074
10075 br00 = XY_MONO_SRC_COPY | 3 << 20;
10076 br13 = bo->pitch;
10077@@ -14673,7 +14844,7 @@ sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable,
10078 assert_pixmap_damage(pixmap);
10079 if (tile)
10080 kgem_bo_destroy(&sna->kgem, tile);
10081- sna->blt_state.fill_bo = 0;
10082+ blt_done(sna);
10083 return true;
10084 }
10085
10086@@ -15281,6 +15452,7 @@ sna_glyph_blt(DrawablePtr drawable, GCPtr gc,
10087 }
10088 _kgem_set_mode(&sna->kgem, KGEM_BLT);
10089 }
10090+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10091
10092 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
10093 __FUNCTION__,
10094@@ -15368,6 +15540,7 @@ sna_glyph_blt(DrawablePtr drawable, GCPtr gc,
10095 if (!kgem_check_batch(&sna->kgem, 3+len)) {
10096 _kgem_submit(&sna->kgem);
10097 _kgem_set_mode(&sna->kgem, KGEM_BLT);
10098+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10099
10100 DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n",
10101 __FUNCTION__,
10102@@ -15479,7 +15652,7 @@ skip:
10103 }
10104
10105 assert_pixmap_damage(pixmap);
10106- sna->blt_state.fill_bo = 0;
10107+ blt_done(sna);
10108 return true;
10109 }
10110
10111@@ -16002,6 +16175,7 @@ sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc,
10112 }
10113 _kgem_set_mode(&sna->kgem, KGEM_BLT);
10114 }
10115+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10116
10117 unwind_batch = sna->kgem.nbatch;
10118 unwind_reloc = sna->kgem.nreloc;
10119@@ -16111,6 +16285,7 @@ sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc,
10120 if (!kgem_check_batch(&sna->kgem, 3+len)) {
10121 _kgem_submit(&sna->kgem);
10122 _kgem_set_mode(&sna->kgem, KGEM_BLT);
10123+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10124
10125 unwind_batch = sna->kgem.nbatch;
10126 unwind_reloc = sna->kgem.nreloc;
10127@@ -16229,7 +16404,7 @@ skip:
10128 }
10129
10130 assert_pixmap_damage(pixmap);
10131- sna->blt_state.fill_bo = 0;
10132+ blt_done(sna);
10133 return true;
10134 }
10135
10136@@ -16450,6 +16625,7 @@ sna_push_pixels_solid_blt(GCPtr gc,
10137
10138 kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
10139 assert(kgem_bo_can_blt(&sna->kgem, bo));
10140+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10141
10142 /* Region is pre-clipped and translated into pixmap space */
10143 box = region_rects(region);
10144@@ -16471,6 +16647,7 @@ sna_push_pixels_solid_blt(GCPtr gc,
10145 return false;
10146 _kgem_set_mode(&sna->kgem, KGEM_BLT);
10147 }
10148+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10149
10150 upload = kgem_create_buffer(&sna->kgem,
10151 bstride*bh,
10152@@ -16564,7 +16741,7 @@ sna_push_pixels_solid_blt(GCPtr gc,
10153 box++;
10154 } while (--n);
10155
10156- sna->blt_state.fill_bo = 0;
10157+ blt_done(sna);
10158 return true;
10159 }
10160
10161@@ -16789,7 +16966,8 @@ sna_get_image__inplace(PixmapPtr pixmap,
10162 break;
10163 }
10164
10165- if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
10166+ if ((flags & MOVE_INPLACE_HINT) == 0 &&
10167+ !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
10168 return false;
10169
10170 if (idle && __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
10171@@ -16801,11 +16979,19 @@ sna_get_image__inplace(PixmapPtr pixmap,
10172 assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
10173 assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
10174
10175- src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
10176- if (src == NULL)
10177- return false;
10178+ if (kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) {
10179+ src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
10180+ if (src == NULL)
10181+ return false;
10182
10183- kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
10184+ kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
10185+ } else {
10186+ src = kgem_bo_map__wc(&sna->kgem, priv->gpu_bo);
10187+ if (src == NULL)
10188+ return false;
10189+
10190+ kgem_bo_sync__gtt(&sna->kgem, priv->gpu_bo);
10191+ }
10192
10193 if (sigtrap_get())
10194 return false;
10195@@ -16833,12 +17019,11 @@ sna_get_image__inplace(PixmapPtr pixmap,
10196 region->extents.x2 - region->extents.x1,
10197 region->extents.y2 - region->extents.y1);
10198 if (!priv->shm) {
10199- assert(src == MAP(priv->gpu_bo->map__cpu));
10200 pixmap->devPrivate.ptr = src;
10201 pixmap->devKind = priv->gpu_bo->pitch;
10202- priv->mapped = MAPPED_CPU;
10203+ priv->mapped = src == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
10204 assert_pixmap_map(pixmap, priv);
10205- priv->cpu = true;
10206+ priv->cpu &= priv->mapped == MAPPED_CPU;
10207 }
10208 }
10209
10210@@ -16930,7 +17115,7 @@ sna_get_image__fast(PixmapPtr pixmap,
10211 if (priv == NULL || priv->gpu_damage == NULL)
10212 return false;
10213
10214- if (priv->clear) {
10215+ if (priv->clear && sigtrap_get() == 0) {
10216 int w = region->extents.x2 - region->extents.x1;
10217 int h = region->extents.y2 - region->extents.y1;
10218 int pitch = PixmapBytePad(w, pixmap->drawable.depth);
10219@@ -16939,6 +17124,7 @@ sna_get_image__fast(PixmapPtr pixmap,
10220 __FUNCTION__, priv->clear_color));
10221 assert(DAMAGE_IS_ALL(priv->gpu_damage));
10222 assert(priv->cpu_damage == NULL);
10223+ sigtrap_assert_active();
10224
10225 if (priv->clear_color == 0 ||
10226 pixmap->drawable.bitsPerPixel == 8 ||
10227@@ -16955,6 +17141,7 @@ sna_get_image__fast(PixmapPtr pixmap,
10228 priv->clear_color);
10229 }
10230
10231+ sigtrap_put();
10232 return true;
10233 }
10234
10235@@ -17162,17 +17349,19 @@ void sna_accel_flush(struct sna *sna)
10236 __sna_free_pixmap(sna, priv->pixmap, priv);
10237 }
10238 } else {
10239+ unsigned hints;
10240 DBG(("%s: flushing DRI pixmap=%ld\n", __FUNCTION__,
10241 priv->pixmap->drawable.serialNumber));
10242 assert(priv->flush);
10243- if (sna_pixmap_move_to_gpu(priv->pixmap,
10244- MOVE_READ | __MOVE_FORCE)) {
10245- if (priv->flush & IS_CLIPPED) {
10246+ hints = MOVE_READ | __MOVE_FORCE;
10247+ if (priv->flush & FLUSH_WRITE)
10248+ hints |= MOVE_WRITE;
10249+ if (sna_pixmap_move_to_gpu(priv->pixmap, hints)) {
10250+ if (priv->flush & FLUSH_WRITE) {
10251 kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
10252 sna_damage_all(&priv->gpu_damage, priv->pixmap);
10253 assert(priv->cpu_damage == NULL);
10254- priv->clear = false;
10255- priv->cpu = false;
10256+ assert(priv->clear == false);
10257 }
10258 }
10259 }
10260@@ -17199,6 +17388,7 @@ static struct sna_pixmap *sna_accel_scanout(struct sna *sna)
10261
10262 assert(sna->vblank_interval);
10263 assert(sna->front);
10264+ assert(!sna->mode.hidden);
10265
10266 priv = sna_pixmap(sna->front);
10267 if (priv->gpu_bo == NULL)
10268@@ -17217,7 +17407,7 @@ static void sna_accel_disarm_timer(struct sna *sna, int id)
10269 static bool has_offload_slaves(struct sna *sna)
10270 {
10271 #if HAS_PIXMAP_SHARING
10272- ScreenPtr screen = sna->scrn->pScreen;
10273+ ScreenPtr screen = to_screen_from_sna(sna);
10274 PixmapDirtyUpdatePtr dirty;
10275
10276 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
10277@@ -17231,11 +17421,14 @@ static bool has_offload_slaves(struct sna *sna)
10278
10279 static bool has_shadow(struct sna *sna)
10280 {
10281- DamagePtr damage = sna->mode.shadow_damage;
10282+ DamagePtr damage;
10283
10284- if (damage == NULL)
10285+ if (!sna->mode.shadow_enabled)
10286 return false;
10287
10288+ damage = sna->mode.shadow_damage;
10289+ assert(damage);
10290+
10291 DBG(("%s: has pending damage? %d, outstanding flips: %d\n",
10292 __FUNCTION__,
10293 RegionNotEmpty(DamageRegion(damage)),
10294@@ -17365,9 +17558,8 @@ static bool sna_accel_do_expire(struct sna *sna)
10295 static void sna_accel_post_damage(struct sna *sna)
10296 {
10297 #if HAS_PIXMAP_SHARING
10298- ScreenPtr screen = sna->scrn->pScreen;
10299+ ScreenPtr screen = to_screen_from_sna(sna);
10300 PixmapDirtyUpdatePtr dirty;
10301- bool flush = false;
10302
10303 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
10304 RegionRec region, *damage;
10305@@ -17477,7 +17669,14 @@ fallback:
10306 box, n, COPY_LAST))
10307 goto fallback;
10308
10309- flush = true;
10310+ /* Before signalling the slave via ProcessPending,
10311+ * ensure not only the batch is submitted as the
10312+ * slave may be using the Damage callback to perform
10313+ * its copy, but also that the memory must be coherent
10314+ * - we need to treat it as uncached for the PCI slave
10315+ * will bypass LLC.
10316+ */
10317+ kgem_bo_sync__gtt(&sna->kgem, __sna_pixmap_get_bo(dst));
10318 }
10319
10320 DamageRegionProcessPending(&dirty->slave_dst->drawable);
10321@@ -17485,8 +17684,6 @@ skip:
10322 RegionUninit(&region);
10323 DamageEmpty(dirty->damage);
10324 }
10325- if (flush)
10326- kgem_submit(&sna->kgem);
10327 #endif
10328 }
10329
10330@@ -17689,6 +17886,7 @@ sna_set_screen_pixmap(PixmapPtr pixmap)
10331 static Bool
10332 sna_create_window(WindowPtr win)
10333 {
10334+ DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
10335 sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate);
10336 return TRUE;
10337 }
10338@@ -17714,6 +17912,7 @@ sna_unmap_window(WindowPtr win)
10339 static Bool
10340 sna_destroy_window(WindowPtr win)
10341 {
10342+ DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
10343 sna_video_destroy_window(win);
10344 sna_dri2_destroy_window(win);
10345 return TRUE;
10346@@ -17790,20 +17989,35 @@ static bool sna_option_accel_none(struct sna *sna)
10347 if (wedged(sna))
10348 return true;
10349
10350- if (xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_DISABLE, FALSE))
10351+ if (!xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_ENABLE, TRUE))
10352 return true;
10353
10354+ if (sna->kgem.gen >= 0120)
10355+ return true;
10356+
10357+ if (!intel_option_cast_to_bool(sna->Options,
10358+ OPTION_ACCEL_METHOD,
10359+ !IS_DEFAULT_ACCEL_METHOD(NOACCEL)))
10360+ return false;
10361+
10362+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
10363 s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
10364 if (s == NULL)
10365 return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
10366
10367 return strcasecmp(s, "none") == 0;
10368+#else
10369+ return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
10370+#endif
10371 }
10372
10373 static bool sna_option_accel_blt(struct sna *sna)
10374 {
10375 const char *s;
10376
10377+ if (sna->kgem.gen >= 0110)
10378+ return true;
10379+
10380 s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
10381 if (s == NULL)
10382 return false;
10383@@ -17892,21 +18106,21 @@ bool sna_accel_init(ScreenPtr screen, struct sna *sna)
10384 backend = "disabled";
10385 sna->kgem.wedged = true;
10386 sna_render_mark_wedged(sna);
10387- } else if (sna_option_accel_blt(sna) || sna->info->gen >= 0110)
10388+ } else if (sna_option_accel_blt(sna))
10389 (void)backend;
10390- else if (sna->info->gen >= 0100)
10391+ else if (sna->kgem.gen >= 0100)
10392 backend = gen8_render_init(sna, backend);
10393- else if (sna->info->gen >= 070)
10394+ else if (sna->kgem.gen >= 070)
10395 backend = gen7_render_init(sna, backend);
10396- else if (sna->info->gen >= 060)
10397+ else if (sna->kgem.gen >= 060)
10398 backend = gen6_render_init(sna, backend);
10399- else if (sna->info->gen >= 050)
10400+ else if (sna->kgem.gen >= 050)
10401 backend = gen5_render_init(sna, backend);
10402- else if (sna->info->gen >= 040)
10403+ else if (sna->kgem.gen >= 040)
10404 backend = gen4_render_init(sna, backend);
10405- else if (sna->info->gen >= 030)
10406+ else if (sna->kgem.gen >= 030)
10407 backend = gen3_render_init(sna, backend);
10408- else if (sna->info->gen >= 020)
10409+ else if (sna->kgem.gen >= 020)
10410 backend = gen2_render_init(sna, backend);
10411
10412 DBG(("%s(backend=%s, prefer_gpu=%x)\n",
10413@@ -18003,7 +18217,7 @@ void sna_accel_close(struct sna *sna)
10414 kgem_cleanup_cache(&sna->kgem);
10415 }
10416
10417-void sna_accel_block_handler(struct sna *sna, struct timeval **tv)
10418+void sna_accel_block(struct sna *sna, struct timeval **tv)
10419 {
10420 sigtrap_assert_inactive();
10421
10422@@ -18083,22 +18297,6 @@ set_tv:
10423 }
10424 }
10425
10426-void sna_accel_wakeup_handler(struct sna *sna)
10427-{
10428- DBG(("%s: nbatch=%d, need_retire=%d, need_purge=%d\n", __FUNCTION__,
10429- sna->kgem.nbatch, sna->kgem.need_retire, sna->kgem.need_purge));
10430-
10431- if (!sna->kgem.nbatch)
10432- return;
10433-
10434- if (kgem_is_idle(&sna->kgem)) {
10435- DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
10436- _kgem_submit(&sna->kgem);
10437- }
10438-
10439- sigtrap_assert_inactive();
10440-}
10441-
10442 void sna_accel_free(struct sna *sna)
10443 {
10444 DBG(("%s\n", __FUNCTION__));
10445diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c
10446index de8f6ec..ff2bdc8 100644
10447--- a/src/sna/sna_blt.c
10448+++ b/src/sna/sna_blt.c
10449@@ -86,6 +86,11 @@ static const uint8_t fill_ROP[] = {
10450 ROP_1
10451 };
10452
10453+static void sig_done(struct sna *sna, const struct sna_composite_op *op)
10454+{
10455+ sigtrap_put();
10456+}
10457+
10458 static void nop_done(struct sna *sna, const struct sna_composite_op *op)
10459 {
10460 assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem));
10461@@ -129,7 +134,6 @@ static bool sna_blt_fill_init(struct sna *sna,
10462 struct kgem *kgem = &sna->kgem;
10463
10464 assert(kgem_bo_can_blt (kgem, bo));
10465- assert(bo->tiling != I915_TILING_Y);
10466 blt->bo[0] = bo;
10467
10468 blt->br13 = bo->pitch;
10469@@ -183,6 +187,7 @@ static bool sna_blt_fill_init(struct sna *sna,
10470 return false;
10471 _kgem_set_mode(kgem, KGEM_BLT);
10472 }
10473+ kgem_bcs_set_tiling(kgem, NULL, bo);
10474
10475 assert(sna->kgem.mode == KGEM_BLT);
10476 b = kgem->batch + kgem->nbatch;
10477@@ -237,17 +242,13 @@ static bool sna_blt_fill_init(struct sna *sna,
10478 return true;
10479 }
10480
10481-noinline static void sna_blt_fill_begin(struct sna *sna,
10482- const struct sna_blt_state *blt)
10483+noinline static void __sna_blt_fill_begin(struct sna *sna,
10484+ const struct sna_blt_state *blt)
10485 {
10486 struct kgem *kgem = &sna->kgem;
10487 uint32_t *b;
10488
10489- if (kgem->nreloc) {
10490- _kgem_submit(kgem);
10491- _kgem_set_mode(kgem, KGEM_BLT);
10492- assert(kgem->nbatch == 0);
10493- }
10494+ kgem_bcs_set_tiling(&sna->kgem, NULL, blt->bo[0]);
10495
10496 assert(kgem->mode == KGEM_BLT);
10497 b = kgem->batch + kgem->nbatch;
10498@@ -293,6 +294,21 @@ noinline static void sna_blt_fill_begin(struct sna *sna,
10499 }
10500 }
10501
10502+inline static void sna_blt_fill_begin(struct sna *sna,
10503+ const struct sna_blt_state *blt)
10504+{
10505+ struct kgem *kgem = &sna->kgem;
10506+
10507+ if (kgem->nreloc) {
10508+ _kgem_submit(kgem);
10509+ _kgem_set_mode(kgem, KGEM_BLT);
10510+ kgem_bcs_set_tiling(kgem, NULL, blt->bo[0]);
10511+ assert(kgem->nbatch == 0);
10512+ }
10513+
10514+ __sna_blt_fill_begin(sna, blt);
10515+}
10516+
10517 inline static void sna_blt_fill_one(struct sna *sna,
10518 const struct sna_blt_state *blt,
10519 int16_t x, int16_t y,
10520@@ -330,8 +346,8 @@ static bool sna_blt_copy_init(struct sna *sna,
10521 {
10522 struct kgem *kgem = &sna->kgem;
10523
10524- assert(kgem_bo_can_blt (kgem, src));
10525- assert(kgem_bo_can_blt (kgem, dst));
10526+ assert(kgem_bo_can_blt(kgem, src));
10527+ assert(kgem_bo_can_blt(kgem, dst));
10528
10529 blt->bo[0] = src;
10530 blt->bo[1] = dst;
10531@@ -370,6 +386,7 @@ static bool sna_blt_copy_init(struct sna *sna,
10532 return false;
10533 _kgem_set_mode(kgem, KGEM_BLT);
10534 }
10535+ kgem_bcs_set_tiling(&sna->kgem, src, dst);
10536
10537 sna->blt_state.fill_bo = 0;
10538 return true;
10539@@ -424,6 +441,7 @@ static bool sna_blt_alpha_fixup_init(struct sna *sna,
10540 return false;
10541 _kgem_set_mode(kgem, KGEM_BLT);
10542 }
10543+ kgem_bcs_set_tiling(&sna->kgem, src, dst);
10544
10545 sna->blt_state.fill_bo = 0;
10546 return true;
10547@@ -454,6 +472,7 @@ static void sna_blt_alpha_fixup_one(struct sna *sna,
10548 !kgem_check_reloc(kgem, 2)) {
10549 _kgem_submit(kgem);
10550 _kgem_set_mode(kgem, KGEM_BLT);
10551+ kgem_bcs_set_tiling(&sna->kgem, blt->bo[0], blt->bo[1]);
10552 }
10553
10554 assert(sna->kgem.mode == KGEM_BLT);
10555@@ -582,6 +601,7 @@ static void sna_blt_copy_one(struct sna *sna,
10556 !kgem_check_reloc(kgem, 2)) {
10557 _kgem_submit(kgem);
10558 _kgem_set_mode(kgem, KGEM_BLT);
10559+ kgem_bcs_set_tiling(&sna->kgem, blt->bo[0], blt->bo[1]);
10560 }
10561
10562 assert(sna->kgem.mode == KGEM_BLT);
10563@@ -912,8 +932,27 @@ sna_composite_mask_is_opaque(PicturePtr mask)
10564 return is_solid(mask) && is_white(mask);
10565 else if (!PICT_FORMAT_A(mask->format))
10566 return true;
10567- else
10568- return is_solid(mask) && is_opaque_solid(mask);
10569+ else if (mask->pSourcePict) {
10570+ PictSolidFill *fill = (PictSolidFill *) mask->pSourcePict;
10571+ return (fill->color >> 24) == 0xff;
10572+ } else {
10573+ struct sna_pixmap *priv;
10574+ assert(mask->pDrawable);
10575+
10576+ if (mask->pDrawable->width == 1 &&
10577+ mask->pDrawable->height == 1 &&
10578+ mask->repeat)
10579+ return pixel_is_opaque(get_pixel(mask), mask->format);
10580+
10581+ if (mask->transform)
10582+ return false;
10583+
10584+ priv = sna_pixmap_from_drawable(mask->pDrawable);
10585+ if (priv == NULL || !priv->clear)
10586+ return false;
10587+
10588+ return pixel_is_opaque(priv->clear_color, mask->format);
10589+ }
10590 }
10591
10592 fastcall
10593@@ -971,6 +1010,7 @@ static void blt_composite_fill__cpu(struct sna *sna,
10594
10595 assert(op->dst.pixmap->devPrivate.ptr);
10596 assert(op->dst.pixmap->devKind);
10597+ sigtrap_assert_active();
10598 pixman_fill(op->dst.pixmap->devPrivate.ptr,
10599 op->dst.pixmap->devKind / sizeof(uint32_t),
10600 op->dst.pixmap->drawable.bitsPerPixel,
10601@@ -990,6 +1030,7 @@ blt_composite_fill_box_no_offset__cpu(struct sna *sna,
10602
10603 assert(op->dst.pixmap->devPrivate.ptr);
10604 assert(op->dst.pixmap->devKind);
10605+ sigtrap_assert_active();
10606 pixman_fill(op->dst.pixmap->devPrivate.ptr,
10607 op->dst.pixmap->devKind / sizeof(uint32_t),
10608 op->dst.pixmap->drawable.bitsPerPixel,
10609@@ -1010,6 +1051,7 @@ blt_composite_fill_boxes_no_offset__cpu(struct sna *sna,
10610
10611 assert(op->dst.pixmap->devPrivate.ptr);
10612 assert(op->dst.pixmap->devKind);
10613+ sigtrap_assert_active();
10614 pixman_fill(op->dst.pixmap->devPrivate.ptr,
10615 op->dst.pixmap->devKind / sizeof(uint32_t),
10616 op->dst.pixmap->drawable.bitsPerPixel,
10617@@ -1031,6 +1073,7 @@ blt_composite_fill_box__cpu(struct sna *sna,
10618
10619 assert(op->dst.pixmap->devPrivate.ptr);
10620 assert(op->dst.pixmap->devKind);
10621+ sigtrap_assert_active();
10622 pixman_fill(op->dst.pixmap->devPrivate.ptr,
10623 op->dst.pixmap->devKind / sizeof(uint32_t),
10624 op->dst.pixmap->drawable.bitsPerPixel,
10625@@ -1052,6 +1095,7 @@ blt_composite_fill_boxes__cpu(struct sna *sna,
10626
10627 assert(op->dst.pixmap->devPrivate.ptr);
10628 assert(op->dst.pixmap->devKind);
10629+ sigtrap_assert_active();
10630 pixman_fill(op->dst.pixmap->devPrivate.ptr,
10631 op->dst.pixmap->devKind / sizeof(uint32_t),
10632 op->dst.pixmap->drawable.bitsPerPixel,
10633@@ -1159,6 +1203,7 @@ static inline void _sna_blt_maybe_clear(const struct sna_composite_op *op, const
10634 box->y2 - box->y1 >= op->dst.height) {
10635 struct sna_pixmap *priv = sna_pixmap(op->dst.pixmap);
10636 if (op->dst.bo == priv->gpu_bo) {
10637+ sna_damage_all(&priv->gpu_damage, op->dst.pixmap);
10638 priv->clear = true;
10639 priv->clear_color = op->u.blt.pixel;
10640 DBG(("%s: pixmap=%ld marking clear [%08x]\n",
10641@@ -1404,6 +1449,7 @@ begin_blt(struct sna *sna,
10642 return false;
10643
10644 _kgem_set_mode(&sna->kgem, KGEM_BLT);
10645+ kgem_bcs_set_tiling(&sna->kgem, NULL, op->dst.bo);
10646 }
10647
10648 return true;
10649@@ -1429,6 +1475,7 @@ prepare_blt_clear(struct sna *sna,
10650 DBG(("%s\n", __FUNCTION__));
10651
10652 if (op->dst.bo == NULL) {
10653+ op->u.blt.pixel = 0;
10654 op->blt = blt_composite_fill__cpu;
10655 if (op->dst.x|op->dst.y) {
10656 op->box = blt_composite_fill_box__cpu;
10657@@ -1439,9 +1486,8 @@ prepare_blt_clear(struct sna *sna,
10658 op->boxes = blt_composite_fill_boxes_no_offset__cpu;
10659 op->thread_boxes = blt_composite_fill_boxes_no_offset__cpu;
10660 }
10661- op->done = nop_done;
10662- op->u.blt.pixel = 0;
10663- return true;
10664+ op->done = sig_done;
10665+ return sigtrap_get() == 0;
10666 }
10667
10668 op->blt = blt_composite_fill;
10669@@ -1484,8 +1530,8 @@ prepare_blt_fill(struct sna *sna,
10670 op->boxes = blt_composite_fill_boxes_no_offset__cpu;
10671 op->thread_boxes = blt_composite_fill_boxes_no_offset__cpu;
10672 }
10673- op->done = nop_done;
10674- return true;
10675+ op->done = sig_done;
10676+ return sigtrap_get() == 0;
10677 }
10678
10679 op->blt = blt_composite_fill;
10680@@ -1668,6 +1714,7 @@ static void blt_composite_copy_boxes__thread(struct sna *sna,
10681
10682 _kgem_submit(kgem);
10683 _kgem_set_mode(kgem, KGEM_BLT);
10684+ kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
10685 } while (1);
10686 } else {
10687 do {
10688@@ -1724,6 +1771,7 @@ static void blt_composite_copy_boxes__thread(struct sna *sna,
10689
10690 _kgem_submit(kgem);
10691 _kgem_set_mode(kgem, KGEM_BLT);
10692+ kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
10693 } while (1);
10694 }
10695 sna_vertex_unlock(&sna->render);
10696@@ -1806,6 +1854,7 @@ static void blt_composite_copy_boxes__thread64(struct sna *sna,
10697
10698 _kgem_submit(kgem);
10699 _kgem_set_mode(kgem, KGEM_BLT);
10700+ kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
10701 } while (1);
10702 } else {
10703 do {
10704@@ -1864,6 +1913,7 @@ static void blt_composite_copy_boxes__thread64(struct sna *sna,
10705
10706 _kgem_submit(kgem);
10707 _kgem_set_mode(kgem, KGEM_BLT);
10708+ kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
10709 } while (1);
10710 }
10711 sna_vertex_unlock(&sna->render);
10712@@ -1973,6 +2023,7 @@ prepare_blt_copy(struct sna *sna,
10713 }
10714 _kgem_set_mode(&sna->kgem, KGEM_BLT);
10715 }
10716+ kgem_bcs_set_tiling(&sna->kgem, bo, op->dst.bo);
10717
10718 DBG(("%s\n", __FUNCTION__));
10719
10720@@ -2396,6 +2447,9 @@ prepare_blt_put(struct sna *sna,
10721 op->box = blt_put_composite_box;
10722 op->boxes = blt_put_composite_boxes;
10723 }
10724+
10725+ op->done = nop_done;
10726+ return true;
10727 } else {
10728 if (alpha_fixup) {
10729 op->u.blt.pixel = alpha_fixup;
10730@@ -2407,10 +2461,10 @@ prepare_blt_put(struct sna *sna,
10731 op->box = blt_put_composite_box__cpu;
10732 op->boxes = blt_put_composite_boxes__cpu;
10733 }
10734- }
10735- op->done = nop_done;
10736
10737- return true;
10738+ op->done = sig_done;
10739+ return sigtrap_get() == 0;
10740+ }
10741 }
10742
10743 static bool
10744@@ -2567,6 +2621,8 @@ clear:
10745 }
10746 if (hint & REPLACES)
10747 kgem_bo_undo(&sna->kgem, tmp->dst.bo);
10748+ if (flags & COMPOSITE_UPLOAD)
10749+ return false;
10750 } else {
10751 RegionRec region;
10752
10753@@ -2597,24 +2653,20 @@ clear:
10754 op = PictOpSrc;
10755 if (op == PictOpOver) {
10756 color = over(get_solid_color(src, PICT_a8r8g8b8),
10757- color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
10758- dst->format, PICT_a8r8g8b8));
10759+ solid_color(dst->format, sna_pixmap(tmp->dst.pixmap)->clear_color));
10760 op = PictOpSrc;
10761 DBG(("%s: precomputing solid OVER (%08x, %08x) -> %08x\n",
10762 __FUNCTION__, get_solid_color(src, PICT_a8r8g8b8),
10763- color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
10764- dst->format, PICT_a8r8g8b8),
10765+ solid_color(dst->format, sna_pixmap(tmp->dst.pixmap)->clear_color),
10766 color));
10767 }
10768 if (op == PictOpAdd) {
10769 color = add(get_solid_color(src, PICT_a8r8g8b8),
10770- color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
10771- dst->format, PICT_a8r8g8b8));
10772+ solid_color(dst->format, sna_pixmap(tmp->dst.pixmap)->clear_color));
10773 op = PictOpSrc;
10774 DBG(("%s: precomputing solid ADD (%08x, %08x) -> %08x\n",
10775 __FUNCTION__, get_solid_color(src, PICT_a8r8g8b8),
10776- color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
10777- dst->format, PICT_a8r8g8b8),
10778+ solid_color(dst->format, sna_pixmap(tmp->dst.pixmap)->clear_color),
10779 color));
10780 }
10781 }
10782@@ -2657,6 +2709,8 @@ fill:
10783 }
10784 if (hint & REPLACES)
10785 kgem_bo_undo(&sna->kgem, tmp->dst.bo);
10786+ if (flags & COMPOSITE_UPLOAD)
10787+ return false;
10788 } else {
10789 RegionRec region;
10790
10791@@ -2720,8 +2774,8 @@ fill:
10792 if (is_clear(src_pixmap)) {
10793 if (src->repeat ||
10794 (x >= 0 && y >= 0 &&
10795- x + width < src_pixmap->drawable.width &&
10796- y + height < src_pixmap->drawable.height)) {
10797+ x + width <= src_pixmap->drawable.width &&
10798+ y + height <= src_pixmap->drawable.height)) {
10799 color = color_convert(sna_pixmap(src_pixmap)->clear_color,
10800 src->format, tmp->dst.format);
10801 goto fill;
10802@@ -2795,7 +2849,7 @@ fill:
10803 if (src_pixmap->drawable.width <= sna->render.max_3d_size &&
10804 src_pixmap->drawable.height <= sna->render.max_3d_size &&
10805 bo->pitch <= sna->render.max_3d_pitch &&
10806- (flags & COMPOSITE_FALLBACK) == 0)
10807+ (flags & (COMPOSITE_UPLOAD | COMPOSITE_FALLBACK)) == 0)
10808 {
10809 return false;
10810 }
10811@@ -2846,7 +2900,7 @@ fallback:
10812 DBG(("%s: fallback -- unaccelerated upload\n",
10813 __FUNCTION__));
10814 goto fallback;
10815- } else {
10816+ } else if ((flags & COMPOSITE_UPLOAD) == 0) {
10817 ret = prepare_blt_copy(sna, tmp, bo, alpha_fixup);
10818 if (!ret)
10819 goto fallback;
10820@@ -3023,6 +3077,7 @@ sna_blt_composite__convert(struct sna *sna,
10821 }
10822 _kgem_set_mode(&sna->kgem, KGEM_BLT);
10823 }
10824+ kgem_bcs_set_tiling(&sna->kgem, tmp->src.bo, tmp->dst.bo);
10825
10826 if (alpha_fixup) {
10827 tmp->blt = blt_composite_copy_with_alpha;
10828@@ -3062,7 +3117,7 @@ static void sna_blt_fill_op_blt(struct sna *sna,
10829 if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) {
10830 const struct sna_blt_state *blt = &op->base.u.blt;
10831
10832- sna_blt_fill_begin(sna, blt);
10833+ __sna_blt_fill_begin(sna, blt);
10834
10835 sna->blt_state.fill_bo = blt->bo[0]->unique_id;
10836 sna->blt_state.fill_pixel = blt->pixel;
10837@@ -3079,7 +3134,7 @@ fastcall static void sna_blt_fill_op_box(struct sna *sna,
10838 if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) {
10839 const struct sna_blt_state *blt = &op->base.u.blt;
10840
10841- sna_blt_fill_begin(sna, blt);
10842+ __sna_blt_fill_begin(sna, blt);
10843
10844 sna->blt_state.fill_bo = blt->bo[0]->unique_id;
10845 sna->blt_state.fill_pixel = blt->pixel;
10846@@ -3097,7 +3152,7 @@ fastcall static void sna_blt_fill_op_boxes(struct sna *sna,
10847 if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) {
10848 const struct sna_blt_state *blt = &op->base.u.blt;
10849
10850- sna_blt_fill_begin(sna, blt);
10851+ __sna_blt_fill_begin(sna, blt);
10852
10853 sna->blt_state.fill_bo = blt->bo[0]->unique_id;
10854 sna->blt_state.fill_pixel = blt->pixel;
10855@@ -3132,7 +3187,7 @@ fastcall static void sna_blt_fill_op_points(struct sna *sna,
10856 DBG(("%s: %08x x %d\n", __FUNCTION__, blt->pixel, n));
10857
10858 if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) {
10859- sna_blt_fill_begin(sna, blt);
10860+ __sna_blt_fill_begin(sna, blt);
10861
10862 sna->blt_state.fill_bo = blt->bo[0]->unique_id;
10863 sna->blt_state.fill_pixel = blt->pixel;
10864@@ -3162,65 +3217,15 @@ fastcall static void sna_blt_fill_op_points(struct sna *sna,
10865 assert(kgem->nbatch < kgem->surface);
10866
10867 if ((dx|dy) == 0) {
10868- while (n_this_time >= 8) {
10869- *((uint64_t *)b + 0) = pt_add(cmd, p+0, 0, 0);
10870- *((uint64_t *)b + 1) = pt_add(cmd, p+1, 0, 0);
10871- *((uint64_t *)b + 2) = pt_add(cmd, p+2, 0, 0);
10872- *((uint64_t *)b + 3) = pt_add(cmd, p+3, 0, 0);
10873- *((uint64_t *)b + 4) = pt_add(cmd, p+4, 0, 0);
10874- *((uint64_t *)b + 5) = pt_add(cmd, p+5, 0, 0);
10875- *((uint64_t *)b + 6) = pt_add(cmd, p+6, 0, 0);
10876- *((uint64_t *)b + 7) = pt_add(cmd, p+7, 0, 0);
10877- b += 16;
10878- n_this_time -= 8;
10879- p += 8;
10880- }
10881- if (n_this_time & 4) {
10882- *((uint64_t *)b + 0) = pt_add(cmd, p+0, 0, 0);
10883- *((uint64_t *)b + 1) = pt_add(cmd, p+1, 0, 0);
10884- *((uint64_t *)b + 2) = pt_add(cmd, p+2, 0, 0);
10885- *((uint64_t *)b + 3) = pt_add(cmd, p+3, 0, 0);
10886- b += 8;
10887- p += 4;
10888- }
10889- if (n_this_time & 2) {
10890- *((uint64_t *)b + 0) = pt_add(cmd, p+0, 0, 0);
10891- *((uint64_t *)b + 1) = pt_add(cmd, p+1, 0, 0);
10892- b += 4;
10893- p += 2;
10894- }
10895- if (n_this_time & 1)
10896- *((uint64_t *)b + 0) = pt_add(cmd, p++, 0, 0);
10897+ do {
10898+ *(uint64_t *)b = pt_add(cmd, p++, 0, 0);
10899+ b += 2;
10900+ } while (--n_this_time);
10901 } else {
10902- while (n_this_time >= 8) {
10903- *((uint64_t *)b + 0) = pt_add(cmd, p+0, dx, dy);
10904- *((uint64_t *)b + 1) = pt_add(cmd, p+1, dx, dy);
10905- *((uint64_t *)b + 2) = pt_add(cmd, p+2, dx, dy);
10906- *((uint64_t *)b + 3) = pt_add(cmd, p+3, dx, dy);
10907- *((uint64_t *)b + 4) = pt_add(cmd, p+4, dx, dy);
10908- *((uint64_t *)b + 5) = pt_add(cmd, p+5, dx, dy);
10909- *((uint64_t *)b + 6) = pt_add(cmd, p+6, dx, dy);
10910- *((uint64_t *)b + 7) = pt_add(cmd, p+7, dx, dy);
10911- b += 16;
10912- n_this_time -= 8;
10913- p += 8;
10914- }
10915- if (n_this_time & 4) {
10916- *((uint64_t *)b + 0) = pt_add(cmd, p+0, dx, dy);
10917- *((uint64_t *)b + 1) = pt_add(cmd, p+1, dx, dy);
10918- *((uint64_t *)b + 2) = pt_add(cmd, p+2, dx, dy);
10919- *((uint64_t *)b + 3) = pt_add(cmd, p+3, dx, dy);
10920- b += 8;
10921- p += 8;
10922- }
10923- if (n_this_time & 2) {
10924- *((uint64_t *)b + 0) = pt_add(cmd, p+0, dx, dy);
10925- *((uint64_t *)b + 1) = pt_add(cmd, p+1, dx, dy);
10926- b += 4;
10927- p += 2;
10928- }
10929- if (n_this_time & 1)
10930- *((uint64_t *)b + 0) = pt_add(cmd, p++, dx, dy);
10931+ do {
10932+ *(uint64_t *)b = pt_add(cmd, p++, dx, dy);
10933+ b += 2;
10934+ } while (--n_this_time);
10935 }
10936
10937 if (!n)
10938@@ -3414,6 +3419,7 @@ static bool sna_blt_fill_box(struct sna *sna, uint8_t alu,
10939
10940 _kgem_set_mode(kgem, KGEM_BLT);
10941 }
10942+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10943
10944 assert(kgem_check_batch(kgem, 6));
10945 assert(kgem_check_reloc(kgem, 1));
10946@@ -3520,6 +3526,8 @@ bool sna_blt_fill_boxes(struct sna *sna, uint8_t alu,
10947 _kgem_set_mode(kgem, KGEM_BLT);
10948 }
10949
10950+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10951+
10952 assert(sna->kgem.mode == KGEM_BLT);
10953 b = kgem->batch + kgem->nbatch;
10954 if (kgem->gen >= 0100) {
10955@@ -3608,6 +3616,7 @@ bool sna_blt_fill_boxes(struct sna *sna, uint8_t alu,
10956
10957 _kgem_submit(kgem);
10958 _kgem_set_mode(kgem, KGEM_BLT);
10959+ kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
10960
10961 assert(sna->kgem.mode == KGEM_BLT);
10962 b = kgem->batch + kgem->nbatch;
10963@@ -3754,6 +3763,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
10964 }
10965 _kgem_set_mode(kgem, KGEM_BLT);
10966 }
10967+ kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
10968
10969 if ((dst_dx | dst_dy) == 0) {
10970 if (kgem->gen >= 0100) {
10971@@ -3814,6 +3824,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
10972
10973 _kgem_submit(kgem);
10974 _kgem_set_mode(kgem, KGEM_BLT);
10975+ kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
10976 } while (1);
10977 } else {
10978 uint64_t hdr = (uint64_t)br13 << 32 | cmd | 6;
10979@@ -3871,6 +3882,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
10980
10981 _kgem_submit(kgem);
10982 _kgem_set_mode(kgem, KGEM_BLT);
10983+ kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
10984 } while (1);
10985 }
10986 } else {
10987@@ -3932,6 +3944,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
10988
10989 _kgem_submit(kgem);
10990 _kgem_set_mode(kgem, KGEM_BLT);
10991+ kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
10992 } while (1);
10993 } else {
10994 cmd |= 6;
10995@@ -3989,6 +4002,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
10996
10997 _kgem_submit(kgem);
10998 _kgem_set_mode(kgem, KGEM_BLT);
10999+ kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
11000 } while (1);
11001 }
11002 }
11003@@ -4095,6 +4109,7 @@ bool sna_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu,
11004 !kgem_check_reloc(kgem, 2)) {
11005 _kgem_submit(kgem);
11006 _kgem_set_mode(kgem, KGEM_BLT);
11007+ kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
11008 }
11009
11010 assert(sna->kgem.mode == KGEM_BLT);
11011@@ -4190,6 +4205,7 @@ bool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu,
11012 DBG(("%s: dst == src\n", __FUNCTION__));
11013
11014 if (src_bo->tiling == I915_TILING_Y &&
11015+ !sna->kgem.can_blt_y &&
11016 kgem_bo_blt_pitch_is_ok(&sna->kgem, src_bo)) {
11017 struct kgem_bo *bo;
11018
11019@@ -4237,6 +4253,7 @@ bool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu,
11020 }
11021 } else {
11022 if (src_bo->tiling == I915_TILING_Y &&
11023+ !sna->kgem.can_blt_y &&
11024 kgem_bo_blt_pitch_is_ok(&sna->kgem, src_bo)) {
11025 DBG(("%s: src is y-tiled\n", __FUNCTION__));
11026 if (src->type != DRAWABLE_PIXMAP)
11027@@ -4251,6 +4268,7 @@ bool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu,
11028 }
11029
11030 if (dst_bo->tiling == I915_TILING_Y &&
11031+ !sna->kgem.can_blt_y &&
11032 kgem_bo_blt_pitch_is_ok(&sna->kgem, dst_bo)) {
11033 DBG(("%s: dst is y-tiled\n", __FUNCTION__));
11034 if (dst->type != DRAWABLE_PIXMAP)
11035diff --git a/src/sna/sna_composite.c b/src/sna/sna_composite.c
11036index f01f020..c6de9d5 100644
11037--- a/src/sna/sna_composite.c
11038+++ b/src/sna/sna_composite.c
11039@@ -653,8 +653,9 @@ sna_composite(CARD8 op,
11040 RegionRec region;
11041 int dx, dy;
11042
11043- DBG(("%s(%d src=%ld+(%d, %d), mask=%ld+(%d, %d), dst=%ld+(%d, %d)+(%d, %d), size=(%d, %d)\n",
11044- __FUNCTION__, op,
11045+ DBG(("%s(pixmap=%ld, op=%d, src=%ld+(%d, %d), mask=%ld+(%d, %d), dst=%ld+(%d, %d)+(%d, %d), size=(%d, %d)\n",
11046+ __FUNCTION__,
11047+ pixmap->drawable.serialNumber, op,
11048 get_picture_id(src), src_x, src_y,
11049 get_picture_id(mask), mask_x, mask_y,
11050 get_picture_id(dst), dst_x, dst_y,
11051@@ -673,13 +674,6 @@ sna_composite(CARD8 op,
11052 src = sna->clear;
11053 }
11054
11055- if (mask && sna_composite_mask_is_opaque(mask)) {
11056- DBG(("%s: removing opaque %smask\n",
11057- __FUNCTION__,
11058- mask->componentAlpha && PICT_FORMAT_RGB(mask->format) ? "CA " : ""));
11059- mask = NULL;
11060- }
11061-
11062 if (!sna_compute_composite_region(&region,
11063 src, mask, dst,
11064 src_x, src_y,
11065@@ -688,6 +682,13 @@ sna_composite(CARD8 op,
11066 width, height))
11067 return;
11068
11069+ if (mask && sna_composite_mask_is_opaque(mask)) {
11070+ DBG(("%s: removing opaque %smask\n",
11071+ __FUNCTION__,
11072+ mask->componentAlpha && PICT_FORMAT_RGB(mask->format) ? "CA " : ""));
11073+ mask = NULL;
11074+ }
11075+
11076 if (NO_COMPOSITE)
11077 goto fallback;
11078
11079@@ -797,8 +798,10 @@ sna_composite_rectangles(CARD8 op,
11080 int i, num_boxes;
11081 unsigned hint;
11082
11083- DBG(("%s(op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n",
11084- __FUNCTION__, op,
11085+ DBG(("%s(pixmap=%ld, op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n",
11086+ __FUNCTION__,
11087+ get_drawable_pixmap(dst->pDrawable)->drawable.serialNumber,
11088+ op,
11089 (color->alpha >> 8 << 24) |
11090 (color->red >> 8 << 16) |
11091 (color->green >> 8 << 8) |
11092@@ -814,38 +817,40 @@ sna_composite_rectangles(CARD8 op,
11093 return;
11094 }
11095
11096- if ((color->red|color->green|color->blue|color->alpha) <= 0x00ff) {
11097- switch (op) {
11098- case PictOpOver:
11099- case PictOpOutReverse:
11100- case PictOpAdd:
11101- return;
11102- case PictOpInReverse:
11103- case PictOpSrc:
11104- op = PictOpClear;
11105- break;
11106- case PictOpAtopReverse:
11107- op = PictOpOut;
11108- break;
11109- case PictOpXor:
11110- op = PictOpOverReverse;
11111- break;
11112- }
11113- }
11114 if (color->alpha <= 0x00ff) {
11115- switch (op) {
11116- case PictOpOver:
11117- case PictOpOutReverse:
11118- return;
11119- case PictOpInReverse:
11120- op = PictOpClear;
11121- break;
11122- case PictOpAtopReverse:
11123- op = PictOpOut;
11124- break;
11125- case PictOpXor:
11126- op = PictOpOverReverse;
11127- break;
11128+ if (PICT_FORMAT_TYPE(dst->format) == PICT_TYPE_A ||
11129+ (color->red|color->green|color->blue) <= 0x00ff) {
11130+ switch (op) {
11131+ case PictOpOver:
11132+ case PictOpOutReverse:
11133+ case PictOpAdd:
11134+ return;
11135+ case PictOpInReverse:
11136+ case PictOpSrc:
11137+ op = PictOpClear;
11138+ break;
11139+ case PictOpAtopReverse:
11140+ op = PictOpOut;
11141+ break;
11142+ case PictOpXor:
11143+ op = PictOpOverReverse;
11144+ break;
11145+ }
11146+ } else {
11147+ switch (op) {
11148+ case PictOpOver:
11149+ case PictOpOutReverse:
11150+ return;
11151+ case PictOpInReverse:
11152+ op = PictOpClear;
11153+ break;
11154+ case PictOpAtopReverse:
11155+ op = PictOpOut;
11156+ break;
11157+ case PictOpXor:
11158+ op = PictOpOverReverse;
11159+ break;
11160+ }
11161 }
11162 } else if (color->alpha >= 0xff00) {
11163 switch (op) {
11164@@ -863,11 +868,16 @@ sna_composite_rectangles(CARD8 op,
11165 case PictOpXor:
11166 op = PictOpOut;
11167 break;
11168+ case PictOpAdd:
11169+ if (PICT_FORMAT_TYPE(dst->format) == PICT_TYPE_A ||
11170+ (color->red&color->green&color->blue) >= 0xff00)
11171+ op = PictOpSrc;
11172+ break;
11173 }
11174 }
11175
11176 /* Avoid reducing overlapping translucent rectangles */
11177- if (op == PictOpOver &&
11178+ if ((op == PictOpOver || op == PictOpAdd) &&
11179 num_rects == 1 &&
11180 sna_drawable_is_clear(dst->pDrawable))
11181 op = PictOpSrc;
11182@@ -979,6 +989,9 @@ sna_composite_rectangles(CARD8 op,
11183 bool ok;
11184
11185 if (op == PictOpClear) {
11186+ if (priv->clear_color == 0)
11187+ goto done;
11188+
11189 ok = sna_get_pixel_from_rgba(&pixel,
11190 0, 0, 0, 0,
11191 dst->format);
11192@@ -990,8 +1003,11 @@ sna_composite_rectangles(CARD8 op,
11193 color->alpha,
11194 dst->format);
11195 }
11196- if (ok && priv->clear_color == pixel)
11197+ if (ok && priv->clear_color == pixel) {
11198+ DBG(("%s: matches current clear, skipping\n",
11199+ __FUNCTION__));
11200 goto done;
11201+ }
11202 }
11203
11204 if (region.data == NULL) {
11205diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
11206index 4b218b7..1b39f20 100644
11207--- a/src/sna/sna_display.c
11208+++ b/src/sna/sna_display.c
11209@@ -40,6 +40,24 @@
11210 #include <poll.h>
11211 #include <ctype.h>
11212
11213+#if HAVE_ALLOCA_H
11214+#include <alloca.h>
11215+#elif defined __GNUC__
11216+#define alloca __builtin_alloca
11217+#elif defined _AIX
11218+#define alloca __alloca
11219+#elif defined _MSC_VER
11220+#include <malloc.h>
11221+#define alloca _alloca
11222+#else
11223+void *alloca(size_t);
11224+#endif
11225+
11226+#define _PARSE_EDID_
11227+/* Jump through a few hoops in order to fixup EDIDs */
11228+#undef VERSION
11229+#undef REVISION
11230+
11231 #include "sna.h"
11232 #include "sna_reg.h"
11233 #include "fb/fbpict.h"
11234@@ -72,6 +90,8 @@
11235 #include <memcheck.h>
11236 #endif
11237
11238+#define COLDPLUG_DELAY_MS 2000
11239+
11240 /* Minor discrepancy between 32-bit/64-bit ABI in old kernels */
11241 union compat_mode_get_connector{
11242 struct drm_mode_get_connector conn;
11243@@ -88,6 +108,8 @@ union compat_mode_get_connector{
11244 #define DEFAULT_DPI 96
11245 #endif
11246
11247+#define OUTPUT_STATUS_CACHE_MS 15000
11248+
11249 #define DRM_MODE_PAGE_FLIP_ASYNC 0x02
11250
11251 #define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
11252@@ -106,30 +128,84 @@ struct local_mode_obj_get_properties {
11253 };
11254 #define LOCAL_MODE_OBJECT_PLANE 0xeeeeeeee
11255
11256+struct local_mode_set_plane {
11257+ uint32_t plane_id;
11258+ uint32_t crtc_id;
11259+ uint32_t fb_id; /* fb object contains surface format type */
11260+ uint32_t flags;
11261+
11262+ /* Signed dest location allows it to be partially off screen */
11263+ int32_t crtc_x, crtc_y;
11264+ uint32_t crtc_w, crtc_h;
11265+
11266+ /* Source values are 16.16 fixed point */
11267+ uint32_t src_x, src_y;
11268+ uint32_t src_h, src_w;
11269+};
11270+#define LOCAL_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct local_mode_set_plane)
11271+
11272+struct local_mode_get_plane {
11273+ uint32_t plane_id;
11274+
11275+ uint32_t crtc_id;
11276+ uint32_t fb_id;
11277+
11278+ uint32_t possible_crtcs;
11279+ uint32_t gamma_size;
11280+
11281+ uint32_t count_format_types;
11282+ uint64_t format_type_ptr;
11283+};
11284+#define LOCAL_IOCTL_MODE_GETPLANE DRM_IOWR(0xb6, struct local_mode_get_plane)
11285+
11286+struct local_mode_get_plane_res {
11287+ uint64_t plane_id_ptr;
11288+ uint64_t count_planes;
11289+};
11290+#define LOCAL_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xb5, struct local_mode_get_plane_res)
11291+
11292 #if 0
11293 #define __DBG DBG
11294 #else
11295 #define __DBG(x)
11296 #endif
11297
11298+#define DBG_NATIVE_ROTATION ~0 /* minimum RR_Rotate_0 */
11299+
11300 extern XF86ConfigPtr xf86configptr;
11301
11302+struct sna_cursor {
11303+ struct sna_cursor *next;
11304+ uint32_t *image;
11305+ bool transformed;
11306+ Rotation rotation;
11307+ int ref;
11308+ int size;
11309+ int last_width;
11310+ int last_height;
11311+ unsigned handle;
11312+ unsigned serial;
11313+ unsigned alloc;
11314+};
11315+
11316 struct sna_crtc {
11317+ unsigned long flags;
11318 xf86CrtcPtr base;
11319 struct drm_mode_modeinfo kmode;
11320- int dpms_mode;
11321 PixmapPtr slave_pixmap;
11322 DamagePtr slave_damage;
11323- struct kgem_bo *bo, *shadow_bo, *client_bo;
11324+ struct kgem_bo *bo, *shadow_bo, *client_bo, *cache_bo;
11325 struct sna_cursor *cursor;
11326 unsigned int last_cursor_size;
11327 uint32_t offset;
11328 bool shadow;
11329 bool fallback_shadow;
11330 bool transform;
11331+ bool cursor_transform;
11332+ bool hwcursor;
11333 bool flip_pending;
11334- uint8_t id;
11335- uint8_t pipe;
11336+
11337+ struct pict_f_transform cursor_to_fb, fb_to_cursor;
11338
11339 RegionRec client_damage; /* XXX overlap with shadow damage? */
11340
11341@@ -178,16 +254,22 @@ struct sna_output {
11342 uint32_t edid_blob_id;
11343 uint32_t edid_len;
11344 void *edid_raw;
11345+ xf86MonPtr fake_edid_mon;
11346+ void *fake_edid_raw;
11347
11348 bool has_panel_limits;
11349 int panel_hdisplay;
11350 int panel_vdisplay;
11351
11352 uint32_t dpms_id;
11353- int dpms_mode;
11354+ uint8_t dpms_mode;
11355 struct backlight backlight;
11356 int backlight_active_level;
11357
11358+ uint32_t last_detect;
11359+ uint32_t status;
11360+ bool update_properties;
11361+
11362 int num_modes;
11363 struct drm_mode_modeinfo *modes;
11364
11365@@ -218,6 +300,7 @@ enum { /* XXX copied from hw/xfree86/modes/xf86Crtc.c */
11366 OPTION_DEFAULT_MODES,
11367 };
11368
11369+static void __sna_output_dpms(xf86OutputPtr output, int dpms, int fixup);
11370 static void sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc);
11371
11372 static bool is_zaphod(ScrnInfoPtr scrn)
11373@@ -225,6 +308,81 @@ static bool is_zaphod(ScrnInfoPtr scrn)
11374 return xf86IsEntityShared(scrn->entityList[0]);
11375 }
11376
11377+static bool
11378+sna_zaphod_match(struct sna *sna, const char *output)
11379+{
11380+ const char *s, *colon;
11381+ char t[20];
11382+ unsigned int i = 0;
11383+
11384+ s = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
11385+ if (s == NULL)
11386+ return false;
11387+
11388+ colon = strchr(s, ':');
11389+ if (colon) /* Skip over the ZaphodPipes */
11390+ s = colon + 1;
11391+
11392+ do {
11393+ /* match any outputs in a comma list, stopping at whitespace */
11394+ switch (*s) {
11395+ case '\0':
11396+ t[i] = '\0';
11397+ return strcmp(t, output) == 0;
11398+
11399+ case ',':
11400+ t[i] ='\0';
11401+ if (strcmp(t, output) == 0)
11402+ return TRUE;
11403+ i = 0;
11404+ break;
11405+
11406+ case ' ':
11407+ case '\t':
11408+ case '\n':
11409+ case '\r':
11410+ break;
11411+
11412+ default:
11413+ t[i++] = *s;
11414+ break;
11415+ }
11416+
11417+ s++;
11418+ } while (i < sizeof(t));
11419+
11420+ return false;
11421+}
11422+
11423+static unsigned
11424+get_zaphod_crtcs(struct sna *sna)
11425+{
11426+ const char *str, *colon;
11427+ unsigned crtcs = 0;
11428+
11429+ str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
11430+ if (str == NULL || (colon = strchr(str, ':')) == NULL) {
11431+ DBG(("%s: no zaphod pipes, using screen number: %x\n",
11432+ __FUNCTION__,
11433+ sna->scrn->confScreen->device->screen));
11434+ return 1 << sna->scrn->confScreen->device->screen;
11435+ }
11436+
11437+ DBG(("%s: ZaphodHeads='%s'\n", __FUNCTION__, str));
11438+ while (str < colon) {
11439+ char *end;
11440+ unsigned crtc = strtoul(str, &end, 0);
11441+ if (end == str)
11442+ break;
11443+ DBG(("%s: adding CRTC %d to zaphod pipes\n",
11444+ __FUNCTION__, crtc));
11445+ crtcs |= 1 << crtc;
11446+ str = end + 1;
11447+ }
11448+ DBG(("%s: ZaphodPipes=%x\n", __FUNCTION__, crtcs));
11449+ return crtcs;
11450+}
11451+
11452 inline static unsigned count_to_mask(int x)
11453 {
11454 return (1 << x) - 1;
11455@@ -247,6 +405,16 @@ static inline struct sna_crtc *to_sna_crtc(xf86CrtcPtr crtc)
11456 return crtc->driver_private;
11457 }
11458
11459+static inline unsigned __sna_crtc_pipe(struct sna_crtc *crtc)
11460+{
11461+ return crtc->flags >> 8 & 0xff;
11462+}
11463+
11464+static inline unsigned __sna_crtc_id(struct sna_crtc *crtc)
11465+{
11466+ return crtc->flags >> 16 & 0xff;
11467+}
11468+
11469 static inline bool event_pending(int fd)
11470 {
11471 struct pollfd pfd;
11472@@ -268,65 +436,60 @@ static inline uint32_t fb_id(struct kgem_bo *bo)
11473 return bo->delta;
11474 }
11475
11476-uint32_t sna_crtc_id(xf86CrtcPtr crtc)
11477-{
11478- if (to_sna_crtc(crtc) == NULL)
11479- return 0;
11480- return to_sna_crtc(crtc)->id;
11481-}
11482-
11483-int sna_crtc_to_pipe(xf86CrtcPtr crtc)
11484-{
11485- assert(to_sna_crtc(crtc));
11486- return to_sna_crtc(crtc)->pipe;
11487-}
11488-
11489 uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc)
11490 {
11491 assert(to_sna_crtc(crtc));
11492 return to_sna_crtc(crtc)->sprite.id;
11493 }
11494
11495-bool sna_crtc_is_on(xf86CrtcPtr crtc)
11496-{
11497- assert(to_sna_crtc(crtc));
11498- return to_sna_crtc(crtc)->bo != NULL;
11499-}
11500-
11501 bool sna_crtc_is_transformed(xf86CrtcPtr crtc)
11502 {
11503 assert(to_sna_crtc(crtc));
11504 return to_sna_crtc(crtc)->transform;
11505 }
11506
11507-static inline uint64_t msc64(struct sna_crtc *sna_crtc, uint32_t seq)
11508+static inline bool msc64(struct sna_crtc *sna_crtc, uint32_t seq, uint64_t *msc)
11509 {
11510+ bool record = true;
11511 if (seq < sna_crtc->last_seq) {
11512 if (sna_crtc->last_seq - seq > 0x40000000) {
11513 sna_crtc->wrap_seq++;
11514 DBG(("%s: pipe=%d wrapped; was %u, now %u, wraps=%u\n",
11515- __FUNCTION__, sna_crtc->pipe,
11516+ __FUNCTION__, __sna_crtc_pipe(sna_crtc),
11517 sna_crtc->last_seq, seq, sna_crtc->wrap_seq));
11518- } else {
11519- ERR(("%s: pipe=%d msc went backwards; was %u, now %u\n",
11520- __FUNCTION__, sna_crtc->pipe, sna_crtc->last_seq, seq));
11521- seq = sna_crtc->last_seq;
11522+ } else {
11523+ DBG(("%s: pipe=%d msc went backwards; was %u, now %u; ignoring for last_swap\n",
11524+ __FUNCTION__, __sna_crtc_pipe(sna_crtc), sna_crtc->last_seq, seq));
11525+
11526+ record = false;
11527 }
11528 }
11529- sna_crtc->last_seq = seq;
11530- return (uint64_t)sna_crtc->wrap_seq << 32 | seq;
11531+ *msc = (uint64_t)sna_crtc->wrap_seq << 32 | seq;
11532+ return record;
11533 }
11534
11535 uint64_t sna_crtc_record_swap(xf86CrtcPtr crtc,
11536 int tv_sec, int tv_usec, unsigned seq)
11537 {
11538 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
11539+ uint64_t msc;
11540+
11541 assert(sna_crtc);
11542- DBG(("%s: recording last swap on pipe=%d, frame %d, time %d.%06d\n",
11543- __FUNCTION__, sna_crtc->pipe, seq, tv_sec, tv_usec));
11544- sna_crtc->swap.tv_sec = tv_sec;
11545- sna_crtc->swap.tv_usec = tv_usec;
11546- return sna_crtc->swap.msc = msc64(sna_crtc, seq);
11547+
11548+ if (msc64(sna_crtc, seq, &msc)) {
11549+ DBG(("%s: recording last swap on pipe=%d, frame %d [%08llx], time %d.%06d\n",
11550+ __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc,
11551+ tv_sec, tv_usec));
11552+ sna_crtc->swap.tv_sec = tv_sec;
11553+ sna_crtc->swap.tv_usec = tv_usec;
11554+ sna_crtc->swap.msc = msc;
11555+ } else {
11556+ DBG(("%s: swap event on pipe=%d, frame %d [%08llx], time %d.%06d\n",
11557+ __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc,
11558+ tv_sec, tv_usec));
11559+ }
11560+
11561+ return msc;
11562 }
11563
11564 const struct ust_msc *sna_crtc_last_swap(xf86CrtcPtr crtc)
11565@@ -342,15 +505,6 @@ const struct ust_msc *sna_crtc_last_swap(xf86CrtcPtr crtc)
11566 }
11567 }
11568
11569-xf86CrtcPtr sna_mode_first_crtc(struct sna *sna)
11570-{
11571- xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
11572- if (sna->mode.num_real_crtc)
11573- return config->crtc[0];
11574- else
11575- return NULL;
11576-}
11577-
11578 #ifndef NDEBUG
11579 static void gem_close(int fd, uint32_t handle);
11580 static void assert_scanout(struct kgem *kgem, struct kgem_bo *bo,
11581@@ -393,8 +547,9 @@ static unsigned get_fb(struct sna *sna, struct kgem_bo *bo,
11582 DBG(("%s: create fb %dx%d@%d/%d\n",
11583 __FUNCTION__, width, height, scrn->depth, scrn->bitsPerPixel));
11584
11585- assert(bo->tiling != I915_TILING_Y);
11586+ assert(bo->tiling != I915_TILING_Y || sna->kgem.can_scanout_y);
11587 assert((bo->pitch & 63) == 0);
11588+ assert(scrn->vtSema); /* must be master */
11589
11590 VG_CLEAR(arg);
11591 arg.width = width;
11592@@ -404,21 +559,83 @@ static unsigned get_fb(struct sna *sna, struct kgem_bo *bo,
11593 arg.depth = scrn->depth;
11594 arg.handle = bo->handle;
11595
11596- assert(sna->scrn->vtSema); /* must be master */
11597 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_ADDFB, &arg)) {
11598- xf86DrvMsg(scrn->scrnIndex, X_ERROR,
11599- "%s: failed to add fb: %dx%d depth=%d, bpp=%d, pitch=%d: %d\n",
11600- __FUNCTION__, width, height,
11601- scrn->depth, scrn->bitsPerPixel, bo->pitch, errno);
11602- return 0;
11603+ /* Try again with the fancy version */
11604+ struct local_mode_fb_cmd2 {
11605+ uint32_t fb_id;
11606+ uint32_t width, height;
11607+ uint32_t pixel_format;
11608+ uint32_t flags;
11609+
11610+ uint32_t handles[4];
11611+ uint32_t pitches[4]; /* pitch for each plane */
11612+ uint32_t offsets[4]; /* offset of each plane */
11613+ uint64_t modifiers[4];
11614+ } f;
11615+#define LOCAL_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct local_mode_fb_cmd2)
11616+ memset(&f, 0, sizeof(f));
11617+ f.width = width;
11618+ f.height = height;
11619+ /* XXX interlaced */
11620+ f.flags = 1 << 1; /* +modifiers */
11621+ f.handles[0] = bo->handle;
11622+ f.pitches[0] = bo->pitch;
11623+
11624+ switch (bo->tiling) {
11625+ case I915_TILING_NONE:
11626+ break;
11627+ case I915_TILING_X:
11628+ /* I915_FORMAT_MOD_X_TILED */
11629+ f.modifiers[0] = (uint64_t)1 << 56 | 1;
11630+ break;
11631+ case I915_TILING_Y:
11632+ /* I915_FORMAT_MOD_X_TILED */
11633+ f.modifiers[0] = (uint64_t)1 << 56 | 2;
11634+ break;
11635+ }
11636+
11637+#define fourcc(a,b,c,d) ((a) | (b) << 8 | (c) << 16 | (d) << 24)
11638+ switch (scrn->depth) {
11639+ default:
11640+ ERR(("%s: unhandled screen format, depth=%d\n",
11641+ __FUNCTION__, scrn->depth));
11642+ goto fail;
11643+ case 8:
11644+ f.pixel_format = fourcc('C', '8', ' ', ' ');
11645+ break;
11646+ case 15:
11647+ f.pixel_format = fourcc('X', 'R', '1', '5');
11648+ break;
11649+ case 16:
11650+ f.pixel_format = fourcc('R', 'G', '1', '6');
11651+ break;
11652+ case 24:
11653+ f.pixel_format = fourcc('X', 'R', '2', '4');
11654+ break;
11655+ case 30:
11656+ f.pixel_format = fourcc('X', 'R', '3', '0');
11657+ break;
11658+ }
11659+#undef fourcc
11660+
11661+ if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_ADDFB2, &f)) {
11662+fail:
11663+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
11664+ "%s: failed to add fb: %dx%d depth=%d, bpp=%d, pitch=%d: %d\n",
11665+ __FUNCTION__, width, height,
11666+ scrn->depth, scrn->bitsPerPixel, bo->pitch, errno);
11667+ return 0;
11668+ }
11669+
11670+ arg.fb_id = f.fb_id;
11671 }
11672 assert(arg.fb_id != 0);
11673-
11674+ bo->delta = arg.fb_id;
11675 DBG(("%s: attached fb=%d to handle=%d\n",
11676- __FUNCTION__, arg.fb_id, arg.handle));
11677+ __FUNCTION__, bo->delta, arg.handle));
11678
11679 bo->scanout = true;
11680- return bo->delta = arg.fb_id;
11681+ return bo->delta;
11682 }
11683
11684 static uint32_t gem_create(int fd, int size)
11685@@ -497,8 +714,6 @@ sna_backlight_uevent(int fd, void *closure)
11686 if (sna_output->dpms_mode != DPMSModeOn)
11687 continue;
11688
11689- assert(output->randr_output);
11690-
11691 val = backlight_get(&sna_output->backlight);
11692 if (val < 0)
11693 continue;
11694@@ -523,6 +738,7 @@ sna_backlight_uevent(int fd, void *closure)
11695 TRUE, FALSE);
11696 }
11697 }
11698+ DBG(("%s: complete\n", __FUNCTION__));
11699 }
11700
11701 static void sna_backlight_pre_init(struct sna *sna)
11702@@ -570,6 +786,7 @@ static void sna_backlight_drain_uevents(struct sna *sna)
11703 if (sna->mode.backlight_monitor == NULL)
11704 return;
11705
11706+ DBG(("%s()\n", __FUNCTION__));
11707 sna_backlight_uevent(udev_monitor_get_fd(sna->mode.backlight_monitor),
11708 sna);
11709 }
11710@@ -632,9 +849,22 @@ sna_output_backlight_set(struct sna_output *sna_output, int level)
11711 return ret;
11712 }
11713
11714+static bool
11715+has_native_backlight(struct sna_output *sna_output)
11716+{
11717+ return sna_output->backlight.type == BL_RAW;
11718+}
11719+
11720 static void
11721 sna_output_backlight_off(struct sna_output *sna_output)
11722 {
11723+ /* Trust the kernel to turn the native backlight off. However, we
11724+ * do explicitly turn the backlight back on (when we wake the output)
11725+ * just in case a third party turns it off!
11726+ */
11727+ if (has_native_backlight(sna_output))
11728+ return;
11729+
11730 DBG(("%s(%s)\n", __FUNCTION__, sna_output->base->name));
11731 backlight_off(&sna_output->backlight);
11732 sna_output_backlight_set(sna_output, 0);
11733@@ -674,7 +904,7 @@ has_user_backlight_override(xf86OutputPtr output)
11734 if (*str == '\0')
11735 return (char *)str;
11736
11737- if (backlight_exists(str) == BL_NONE) {
11738+ if (!backlight_exists(str)) {
11739 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
11740 "Unrecognised backlight control interface '%s'\n",
11741 str);
11742@@ -728,6 +958,29 @@ done:
11743 sna_output->backlight.iface, best_iface, output->name);
11744 }
11745
11746+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
11747+static inline int sigio_block(void)
11748+{
11749+ OsBlockSIGIO();
11750+ return 0;
11751+}
11752+static inline void sigio_unblock(int was_blocked)
11753+{
11754+ OsReleaseSIGIO();
11755+ (void)was_blocked;
11756+}
11757+#else
11758+#include <xf86_OSproc.h>
11759+static inline int sigio_block(void)
11760+{
11761+ return xf86BlockSIGIO();
11762+}
11763+static inline void sigio_unblock(int was_blocked)
11764+{
11765+ xf86UnblockSIGIO(was_blocked);
11766+}
11767+#endif
11768+
11769 static char *canonical_kmode_name(const struct drm_mode_modeinfo *kmode)
11770 {
11771 char tmp[32], *buf;
11772@@ -781,6 +1034,7 @@ mode_from_kmode(ScrnInfoPtr scrn,
11773 mode->VTotal = kmode->vtotal;
11774 mode->VScan = kmode->vscan;
11775
11776+ mode->VRefresh = kmode->vrefresh;
11777 mode->Flags = kmode->flags;
11778 mode->name = get_kmode_name(kmode);
11779
11780@@ -814,6 +1068,7 @@ mode_to_kmode(struct drm_mode_modeinfo *kmode, DisplayModePtr mode)
11781 kmode->vtotal = mode->VTotal;
11782 kmode->vscan = mode->VScan;
11783
11784+ kmode->vrefresh = mode->VRefresh;
11785 kmode->flags = mode->Flags;
11786 if (mode->name)
11787 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
11788@@ -824,11 +1079,12 @@ static void
11789 sna_crtc_force_outputs_on(xf86CrtcPtr crtc)
11790 {
11791 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
11792+ /* All attached outputs are valid, so update our timestamps */
11793+ unsigned now = GetTimeInMillis();
11794 int i;
11795
11796 assert(to_sna_crtc(crtc));
11797- DBG(("%s(pipe=%d), currently? %d\n", __FUNCTION__,
11798- to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->dpms_mode));
11799+ DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc)));
11800
11801 /* DPMS handling by the kernel is inconsistent, so after setting a
11802 * mode on an output presume that we intend for it to be on, or that
11803@@ -843,10 +1099,11 @@ sna_crtc_force_outputs_on(xf86CrtcPtr crtc)
11804 if (output->crtc != crtc)
11805 continue;
11806
11807- output->funcs->dpms(output, DPMSModeOn);
11808+ __sna_output_dpms(output, DPMSModeOn, false);
11809+ if (to_sna_output(output)->last_detect)
11810+ to_sna_output(output)->last_detect = now;
11811 }
11812
11813- to_sna_crtc(crtc)->dpms_mode = DPMSModeOn;
11814 #if XF86_CRTC_VERSION >= 3
11815 crtc->active = TRUE;
11816 #endif
11817@@ -859,8 +1116,7 @@ sna_crtc_force_outputs_off(xf86CrtcPtr crtc)
11818 int i;
11819
11820 assert(to_sna_crtc(crtc));
11821- DBG(("%s(pipe=%d), currently? %d\n", __FUNCTION__,
11822- to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->dpms_mode));
11823+ DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc)));
11824
11825 /* DPMS handling by the kernel is inconsistent, so after setting a
11826 * mode on an output presume that we intend for it to be on, or that
11827@@ -875,35 +1131,45 @@ sna_crtc_force_outputs_off(xf86CrtcPtr crtc)
11828 if (output->crtc != crtc)
11829 continue;
11830
11831- output->funcs->dpms(output, DPMSModeOff);
11832+ __sna_output_dpms(output, DPMSModeOff, false);
11833 }
11834-
11835- to_sna_crtc(crtc)->dpms_mode = DPMSModeOff;
11836 }
11837
11838 static unsigned
11839-rotation_reduce(struct plane *p, unsigned rotation)
11840+rotation_reflect(unsigned rotation)
11841 {
11842- unsigned unsupported_rotations = rotation & ~p->rotation.supported;
11843+ unsigned other_bits;
11844
11845- if (unsupported_rotations == 0)
11846- return rotation;
11847+ /* paranoia for future extensions */
11848+ other_bits = rotation & ~RR_Rotate_All;
11849
11850-#define RR_Reflect_XY (RR_Reflect_X | RR_Reflect_Y)
11851+ /* flip the reflection to compensate for reflecting the rotation */
11852+ other_bits ^= RR_Reflect_X | RR_Reflect_Y;
11853
11854- if ((unsupported_rotations & RR_Reflect_XY) == RR_Reflect_XY &&
11855- p->rotation.supported& RR_Rotate_180) {
11856- rotation &= ~RR_Reflect_XY;
11857- rotation ^= RR_Rotate_180;
11858- }
11859+ /* Reflect the screen by rotating the rotation bit,
11860+ * which has to have at least RR_Rotate_0 set. This allows
11861+ * us to reflect any of the rotation bits, not just 0.
11862+ */
11863+ rotation &= RR_Rotate_All;
11864+ assert(rotation);
11865+ rotation <<= 2; /* RR_Rotate_0 -> RR_Rotate_180 etc */
11866+ rotation |= rotation >> 4; /* RR_Rotate_270' to RR_Rotate_90 */
11867+
11868+ return rotation | other_bits;
11869+}
11870
11871- if ((unsupported_rotations & RR_Rotate_180) &&
11872- (p->rotation.supported& RR_Reflect_XY) == RR_Reflect_XY) {
11873- rotation ^= RR_Reflect_XY;
11874- rotation &= ~RR_Rotate_180;
11875+static unsigned
11876+rotation_reduce(struct plane *p, unsigned rotation)
11877+{
11878+ /* If unsupported try exchanging rotation for a reflection */
11879+ if (rotation & ~p->rotation.supported) {
11880+ unsigned new_rotation = rotation_reflect(rotation);
11881+ if ((new_rotation & p->rotation.supported) == new_rotation)
11882+ rotation = new_rotation;
11883 }
11884
11885-#undef RR_Reflect_XY
11886+ /* Only one rotation bit should be set */
11887+ assert(is_power_of_two(rotation & RR_Rotate_All));
11888
11889 return rotation;
11890 }
11891@@ -923,7 +1189,7 @@ rotation_set(struct sna *sna, struct plane *p, uint32_t desired)
11892 if (desired == p->rotation.current)
11893 return true;
11894
11895- if ((desired & p->rotation.supported) == 0) {
11896+ if ((desired & p->rotation.supported) != desired) {
11897 errno = EINVAL;
11898 return false;
11899 }
11900@@ -961,14 +1227,89 @@ bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation)
11901 assert(to_sna_crtc(crtc));
11902 DBG(("%s: CRTC:%d [pipe=%d], sprite=%u set-rotation=%x\n",
11903 __FUNCTION__,
11904- to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->sprite.id,
11905- rotation));
11906+ sna_crtc_id(crtc), sna_crtc_pipe(crtc),
11907+ to_sna_crtc(crtc)->sprite.id, rotation));
11908
11909 return rotation_set(to_sna(crtc->scrn),
11910 &to_sna_crtc(crtc)->sprite,
11911 rotation_reduce(&to_sna_crtc(crtc)->sprite, rotation));
11912 }
11913
11914+#if HAS_DEBUG_FULL
11915+struct kmsg {
11916+ int fd;
11917+ int saved_loglevel;
11918+};
11919+
11920+static int kmsg_get_debug(void)
11921+{
11922+ FILE *file;
11923+ int v = -1;
11924+
11925+ file = fopen("/sys/module/drm/parameters/debug", "r");
11926+ if (file) {
11927+ fscanf(file, "%d", &v);
11928+ fclose(file);
11929+ }
11930+
11931+ return v;
11932+}
11933+
11934+static void kmsg_set_debug(int v)
11935+{
11936+ FILE *file;
11937+
11938+ file = fopen("/sys/module/drm/parameters/debug", "w");
11939+ if (file) {
11940+ fprintf(file, "%d\n", v);
11941+ fclose(file);
11942+ }
11943+}
11944+
11945+static void kmsg_open(struct kmsg *k)
11946+{
11947+ k->saved_loglevel = kmsg_get_debug();
11948+ if (k->saved_loglevel != -1)
11949+ kmsg_set_debug(0xff);
11950+
11951+ k->fd = open("/dev/kmsg", O_RDONLY | O_NONBLOCK);
11952+ if (k->fd != -1)
11953+ lseek(k->fd, 0, SEEK_END);
11954+}
11955+
11956+static void kmsg_close(struct kmsg *k, int dump)
11957+{
11958+ FILE *file;
11959+
11960+ file = NULL;
11961+ if (k->fd != -1 && dump)
11962+ file = fdopen(k->fd, "r");
11963+ if (file) {
11964+ size_t len = 0;
11965+ char *line = NULL;
11966+
11967+ while (getline(&line, &len, file) != -1) {
11968+ char *start = strchr(line, ';');
11969+ if (start)
11970+ LogF("KMSG: %s", start + 1);
11971+ }
11972+
11973+ free(line);
11974+ fclose(file);
11975+ }
11976+
11977+ if (k->fd != -1)
11978+ close(k->fd);
11979+
11980+ if (k->saved_loglevel != -1)
11981+ kmsg_set_debug(k->saved_loglevel);
11982+}
11983+#else
11984+struct kmsg { int unused; };
11985+static void kmsg_open(struct kmsg *k) {}
11986+static void kmsg_close(struct kmsg *k, int dump) {}
11987+#endif
11988+
11989 static bool
11990 sna_crtc_apply(xf86CrtcPtr crtc)
11991 {
11992@@ -978,26 +1319,33 @@ sna_crtc_apply(xf86CrtcPtr crtc)
11993 struct drm_mode_crtc arg;
11994 uint32_t output_ids[32];
11995 int output_count = 0;
11996- int i;
11997+ int sigio, i;
11998+ struct kmsg kmsg;
11999+ bool ret = false;
12000
12001- DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->bo->handle));
12002+ DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__,
12003+ __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
12004+ sna_crtc->bo->handle));
12005 if (!sna_crtc->kmode.clock) {
12006 ERR(("%s(CRTC:%d [pipe=%d]): attempted to set an invalid mode\n",
12007- __FUNCTION__, sna_crtc->id, sna_crtc->pipe));
12008+ __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc)));
12009 return false;
12010 }
12011
12012+ sigio = sigio_block();
12013+ kmsg_open(&kmsg);
12014+
12015 assert(sna->mode.num_real_output < ARRAY_SIZE(output_ids));
12016 sna_crtc_disable_cursor(sna, sna_crtc);
12017
12018 if (!rotation_set(sna, &sna_crtc->primary, sna_crtc->rotation)) {
12019 ERR(("%s: set-primary-rotation failed (rotation-id=%d, rotation=%d) on CRTC:%d [pipe=%d], errno=%d\n",
12020- __FUNCTION__, sna_crtc->primary.rotation.prop, sna_crtc->rotation, sna_crtc->id, sna_crtc->pipe, errno));
12021+ __FUNCTION__, sna_crtc->primary.rotation.prop, sna_crtc->rotation, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), errno));
12022 sna_crtc->primary.rotation.supported &= ~sna_crtc->rotation;
12023- return false;
12024+ goto unblock;
12025 }
12026 DBG(("%s: CRTC:%d [pipe=%d] primary rotation set to %x\n",
12027- __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->rotation));
12028+ __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), sna_crtc->rotation));
12029
12030 for (i = 0; i < sna->mode.num_real_output; i++) {
12031 xf86OutputPtr output = config->output[i];
12032@@ -1008,7 +1356,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
12033 * and we lose track of the user settings.
12034 */
12035 if (output->crtc == NULL)
12036- output->funcs->dpms(output, DPMSModeOff);
12037+ __sna_output_dpms(output, DPMSModeOff, false);
12038
12039 if (output->crtc != crtc)
12040 continue;
12041@@ -1022,11 +1370,11 @@ sna_crtc_apply(xf86CrtcPtr crtc)
12042
12043 DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n",
12044 __FUNCTION__, output->name, i, to_connector_id(output),
12045- sna_crtc->id, sna_crtc->pipe,
12046+ __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
12047 (uint32_t)output->possible_crtcs,
12048 (uint32_t)output->possible_clones));
12049
12050- assert(output->possible_crtcs & (1 << sna_crtc->pipe) ||
12051+ assert(output->possible_crtcs & (1 << __sna_crtc_pipe(sna_crtc)) ||
12052 is_zaphod(crtc->scrn));
12053
12054 output_ids[output_count] = to_connector_id(output);
12055@@ -1034,17 +1382,17 @@ sna_crtc_apply(xf86CrtcPtr crtc)
12056 DBG(("%s: too many outputs (%d) for me!\n",
12057 __FUNCTION__, output_count));
12058 errno = EINVAL;
12059- return false;
12060+ goto unblock;
12061 }
12062 }
12063 if (output_count == 0) {
12064 DBG(("%s: no outputs\n", __FUNCTION__));
12065 errno = EINVAL;
12066- return false;
12067+ goto unblock;
12068 }
12069
12070 VG_CLEAR(arg);
12071- arg.crtc_id = sna_crtc->id;
12072+ arg.crtc_id = __sna_crtc_id(sna_crtc);
12073 arg.fb_id = fb_id(sna_crtc->bo);
12074 if (sna_crtc->transform || sna_crtc->slave_pixmap) {
12075 arg.x = 0;
12076@@ -1061,7 +1409,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
12077 arg.mode_valid = 1;
12078
12079 DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d%s%s update to %d outputs [%d...]\n",
12080- __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
12081+ __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
12082 arg.mode.hdisplay,
12083 arg.mode.vdisplay,
12084 arg.x, arg.y,
12085@@ -1071,12 +1419,15 @@ sna_crtc_apply(xf86CrtcPtr crtc)
12086 sna_crtc->transform ? " [transformed]" : "",
12087 output_count, output_count ? output_ids[0] : 0));
12088
12089- if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg))
12090- return false;
12091-
12092- sna_crtc->mode_serial++;
12093- sna_crtc_force_outputs_on(crtc);
12094- return true;
12095+ ret = drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg) == 0;
12096+ if (ret) {
12097+ sna_crtc->mode_serial++;
12098+ sna_crtc_force_outputs_on(crtc);
12099+ }
12100+unblock:
12101+ kmsg_close(&kmsg, !ret);
12102+ sigio_unblock(sigio);
12103+ return ret;
12104 }
12105
12106 static bool overlap(const BoxRec *a, const BoxRec *b)
12107@@ -1099,7 +1450,6 @@ static bool wait_for_shadow(struct sna *sna,
12108 unsigned flags)
12109 {
12110 PixmapPtr pixmap = priv->pixmap;
12111- DamagePtr damage;
12112 struct kgem_bo *bo, *tmp;
12113 int flip_active;
12114 bool ret = true;
12115@@ -1111,9 +1461,11 @@ static bool wait_for_shadow(struct sna *sna,
12116 assert(priv->move_to_gpu_data == sna);
12117 assert(sna->mode.shadow != priv->gpu_bo);
12118
12119- if (flags == 0 || pixmap != sna->front || !sna->mode.shadow_damage)
12120+ if (flags == 0 || pixmap != sna->front || !sna->mode.shadow_enabled)
12121 goto done;
12122
12123+ assert(sna->mode.shadow_damage);
12124+
12125 if ((flags & MOVE_WRITE) == 0) {
12126 if ((flags & __MOVE_SCANOUT) == 0) {
12127 struct sna_crtc *crtc;
12128@@ -1154,9 +1506,8 @@ static bool wait_for_shadow(struct sna *sna,
12129 }
12130
12131 assert(sna->mode.shadow_active);
12132-
12133- damage = sna->mode.shadow_damage;
12134- sna->mode.shadow_damage = NULL;
12135+ sna->mode.shadow_wait = true;
12136+ sna->mode.shadow_enabled = false;
12137
12138 flip_active = sna->mode.flip_active;
12139 if (flip_active) {
12140@@ -1208,6 +1559,10 @@ static bool wait_for_shadow(struct sna *sna,
12141 bo = sna->mode.shadow;
12142 }
12143 }
12144+ assert(!sna->mode.shadow_enabled);
12145+ assert(sna->mode.shadow_wait);
12146+ sna->mode.shadow_wait = false;
12147+ sna->mode.shadow_enabled = true;
12148
12149 if (bo->refcnt > 1) {
12150 bo = kgem_create_2d(&sna->kgem,
12151@@ -1230,8 +1585,6 @@ static bool wait_for_shadow(struct sna *sna,
12152 bo = sna->mode.shadow;
12153 }
12154
12155- sna->mode.shadow_damage = damage;
12156-
12157 RegionSubtract(&sna->mode.shadow_region,
12158 &sna->mode.shadow_region,
12159 &sna->mode.shadow_cancel);
12160@@ -1311,6 +1664,8 @@ done:
12161 priv->move_to_gpu_data = NULL;
12162 priv->move_to_gpu = NULL;
12163
12164+ assert(!sna->mode.shadow_wait);
12165+
12166 return ret;
12167 }
12168
12169@@ -1358,22 +1713,38 @@ bool sna_pixmap_discard_shadow_damage(struct sna_pixmap *priv,
12170 return RegionNil(&sna->mode.shadow_region);
12171 }
12172
12173+static void sna_mode_damage(DamagePtr damage, RegionPtr region, void *closure)
12174+{
12175+ /* Throw away the rectangles if the region grows too big */
12176+ region = DamageRegion(damage);
12177+ if (region->data) {
12178+ RegionRec dup;
12179+
12180+ dup = *region;
12181+ RegionUninit(&dup);
12182+
12183+ region->data = NULL;
12184+ }
12185+}
12186+
12187 static bool sna_mode_enable_shadow(struct sna *sna)
12188 {
12189- ScreenPtr screen = sna->scrn->pScreen;
12190+ ScreenPtr screen = to_screen_from_sna(sna);
12191
12192 DBG(("%s\n", __FUNCTION__));
12193 assert(sna->mode.shadow == NULL);
12194 assert(sna->mode.shadow_damage == NULL);
12195 assert(sna->mode.shadow_active == 0);
12196+ assert(!sna->mode.shadow_enabled);
12197
12198- sna->mode.shadow_damage = DamageCreate(NULL, NULL,
12199- DamageReportNone, TRUE,
12200- screen, screen);
12201+ sna->mode.shadow_damage = DamageCreate(sna_mode_damage, NULL,
12202+ DamageReportRawRegion,
12203+ TRUE, screen, sna);
12204 if (!sna->mode.shadow_damage)
12205 return false;
12206
12207 DamageRegister(&sna->front->drawable, sna->mode.shadow_damage);
12208+ sna->mode.shadow_enabled = true;
12209 return true;
12210 }
12211
12212@@ -1381,8 +1752,10 @@ static void sna_mode_disable_shadow(struct sna *sna)
12213 {
12214 struct sna_pixmap *priv;
12215
12216- if (!sna->mode.shadow_damage)
12217+ if (!sna->mode.shadow_damage) {
12218+ assert(!sna->mode.shadow_enabled);
12219 return;
12220+ }
12221
12222 DBG(("%s\n", __FUNCTION__));
12223
12224@@ -1393,6 +1766,7 @@ static void sna_mode_disable_shadow(struct sna *sna)
12225 DamageUnregister(&sna->front->drawable, sna->mode.shadow_damage);
12226 DamageDestroy(sna->mode.shadow_damage);
12227 sna->mode.shadow_damage = NULL;
12228+ sna->mode.shadow_enabled = false;
12229
12230 if (sna->mode.shadow) {
12231 kgem_bo_destroy(&sna->kgem, sna->mode.shadow);
12232@@ -1413,7 +1787,7 @@ static void sna_crtc_slave_damage(DamagePtr damage, RegionPtr region, void *clos
12233 __FUNCTION__,
12234 region->extents.x1, region->extents.y1, region->extents.x2, region->extents.y2,
12235 region_num_rects(region),
12236- crtc->pipe, crtc->base->x, crtc->base->y));
12237+ __sna_crtc_pipe(crtc), crtc->base->x, crtc->base->y));
12238
12239 assert(crtc->slave_damage == damage);
12240 assert(sna->mode.shadow_damage);
12241@@ -1431,7 +1805,7 @@ static bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc)
12242 return true;
12243 }
12244
12245- DBG(("%s: enabling for crtc %d\n", __FUNCTION__, crtc->id));
12246+ DBG(("%s: enabling for crtc %d\n", __FUNCTION__, __sna_crtc_id(crtc)));
12247
12248 if (!sna->mode.shadow_active) {
12249 if (!sna_mode_enable_shadow(sna))
12250@@ -1443,9 +1817,12 @@ static bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc)
12251 if (crtc->slave_pixmap) {
12252 assert(crtc->slave_damage == NULL);
12253
12254+ DBG(("%s: enabling PRIME slave tracking on CRTC %d [pipe=%d], pixmap=%ld\n",
12255+ __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->slave_pixmap->drawable.serialNumber));
12256 crtc->slave_damage = DamageCreate(sna_crtc_slave_damage, NULL,
12257 DamageReportRawRegion, TRUE,
12258- sna->scrn->pScreen, crtc);
12259+ to_screen_from_sna(sna),
12260+ crtc);
12261 if (crtc->slave_damage == NULL) {
12262 if (!--sna->mode.shadow_active)
12263 sna_mode_disable_shadow(sna);
12264@@ -1465,6 +1842,8 @@ static void sna_crtc_disable_override(struct sna *sna, struct sna_crtc *crtc)
12265 if (crtc->client_bo == NULL)
12266 return;
12267
12268+ assert(crtc->client_bo->refcnt > crtc->client_bo->active_scanout);
12269+
12270 if (!crtc->transform) {
12271 DrawableRec tmp;
12272
12273@@ -1489,7 +1868,7 @@ static void sna_crtc_disable_shadow(struct sna *sna, struct sna_crtc *crtc)
12274 if (!crtc->shadow)
12275 return;
12276
12277- DBG(("%s: disabling for crtc %d\n", __FUNCTION__, crtc->id));
12278+ DBG(("%s: disabling for crtc %d\n", __FUNCTION__, __sna_crtc_id(crtc)));
12279 assert(sna->mode.shadow_active > 0);
12280
12281 if (crtc->slave_damage) {
12282@@ -1517,14 +1896,24 @@ __sna_crtc_disable(struct sna *sna, struct sna_crtc *sna_crtc)
12283 sna_crtc_disable_shadow(sna, sna_crtc);
12284
12285 if (sna_crtc->bo) {
12286+ DBG(("%s: releasing handle=%d from scanout, active=%d\n",
12287+ __FUNCTION__,sna_crtc->bo->handle, sna_crtc->bo->active_scanout-1));
12288+ assert(sna_crtc->flags & CRTC_ON);
12289 assert(sna_crtc->bo->active_scanout);
12290 assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout);
12291 sna_crtc->bo->active_scanout--;
12292 kgem_bo_destroy(&sna->kgem, sna_crtc->bo);
12293 sna_crtc->bo = NULL;
12294+ sna_crtc->flags &= ~CRTC_ON;
12295
12296- assert(sna->mode.front_active);
12297- sna->mode.front_active--;
12298+ if (sna->mode.hidden) {
12299+ sna->mode.hidden--;
12300+ assert(sna->mode.hidden);
12301+ assert(sna->mode.front_active == 0);
12302+ } else {
12303+ assert(sna->mode.front_active);
12304+ sna->mode.front_active--;
12305+ }
12306 sna->mode.dirty = true;
12307 }
12308
12309@@ -1532,13 +1921,19 @@ __sna_crtc_disable(struct sna *sna, struct sna_crtc *sna_crtc)
12310 kgem_bo_destroy(&sna->kgem, sna_crtc->shadow_bo);
12311 sna_crtc->shadow_bo = NULL;
12312 }
12313- sna_crtc->transform = false;
12314+ if (sna_crtc->transform) {
12315+ assert(sna->mode.rr_active);
12316+ sna->mode.rr_active--;
12317+ sna_crtc->transform = false;
12318+ }
12319
12320+ sna_crtc->cursor_transform = false;
12321+ sna_crtc->hwcursor = true;
12322 assert(!sna_crtc->shadow);
12323 }
12324
12325 static void
12326-sna_crtc_disable(xf86CrtcPtr crtc)
12327+sna_crtc_disable(xf86CrtcPtr crtc, bool force)
12328 {
12329 struct sna *sna = to_sna(crtc->scrn);
12330 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
12331@@ -1547,14 +1942,16 @@ sna_crtc_disable(xf86CrtcPtr crtc)
12332 if (sna_crtc == NULL)
12333 return;
12334
12335- DBG(("%s: disabling crtc [%d, pipe=%d]\n", __FUNCTION__,
12336- sna_crtc->id, sna_crtc->pipe));
12337+ if (!force && sna_crtc->bo == NULL)
12338+ return;
12339+
12340+ DBG(("%s: disabling crtc [%d, pipe=%d], force?=%d\n", __FUNCTION__,
12341+ __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), force));
12342
12343 sna_crtc_force_outputs_off(crtc);
12344- assert(sna_crtc->dpms_mode == DPMSModeOff);
12345
12346 memset(&arg, 0, sizeof(arg));
12347- arg.crtc_id = sna_crtc->id;
12348+ arg.crtc_id = __sna_crtc_id(sna_crtc);
12349 (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg);
12350
12351 __sna_crtc_disable(sna, sna_crtc);
12352@@ -1574,19 +1971,19 @@ static void update_flush_interval(struct sna *sna)
12353
12354 if (!crtc->enabled) {
12355 DBG(("%s: CRTC:%d (pipe %d) disabled\n",
12356- __FUNCTION__,i, to_sna_crtc(crtc)->pipe));
12357+ __FUNCTION__,i, sna_crtc_pipe(crtc)));
12358 assert(to_sna_crtc(crtc)->bo == NULL);
12359 continue;
12360 }
12361
12362- if (to_sna_crtc(crtc)->dpms_mode != DPMSModeOn) {
12363+ if (to_sna_crtc(crtc)->bo == NULL) {
12364 DBG(("%s: CRTC:%d (pipe %d) turned off\n",
12365- __FUNCTION__,i, to_sna_crtc(crtc)->pipe));
12366+ __FUNCTION__,i, sna_crtc_pipe(crtc)));
12367 continue;
12368 }
12369
12370 DBG(("%s: CRTC:%d (pipe %d) vrefresh=%f\n",
12371- __FUNCTION__, i, to_sna_crtc(crtc)->pipe,
12372+ __FUNCTION__, i, sna_crtc_pipe(crtc),
12373 xf86ModeVRefresh(&crtc->mode)));
12374 max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(&crtc->mode));
12375 }
12376@@ -1642,7 +2039,7 @@ void sna_copy_fbcon(struct sna *sna)
12377 int dx, dy;
12378 int i;
12379
12380- if (wedged(sna))
12381+ if (wedged(sna) || isGPU(sna->scrn))
12382 return;
12383
12384 DBG(("%s\n", __FUNCTION__));
12385@@ -1662,7 +2059,7 @@ void sna_copy_fbcon(struct sna *sna)
12386 assert(crtc != NULL);
12387
12388 VG_CLEAR(mode);
12389- mode.crtc_id = crtc->id;
12390+ mode.crtc_id = __sna_crtc_id(crtc);
12391 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
12392 continue;
12393 if (!mode.fb_id)
12394@@ -1726,7 +2123,7 @@ void sna_copy_fbcon(struct sna *sna)
12395 kgem_bo_destroy(&sna->kgem, bo);
12396
12397 #if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(10, 0)
12398- sna->scrn->pScreen->canDoBGNoneRoot = ok;
12399+ to_screen_from_sna(sna)->canDoBGNoneRoot = ok;
12400 #endif
12401 }
12402
12403@@ -1736,7 +2133,6 @@ static bool use_shadow(struct sna *sna, xf86CrtcPtr crtc)
12404 PictTransform crtc_to_fb;
12405 struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc;
12406 unsigned pitch_limit;
12407- struct sna_pixmap *priv;
12408 BoxRec b;
12409
12410 assert(sna->scrn->virtualX && sna->scrn->virtualY);
12411@@ -1765,44 +2161,48 @@ static bool use_shadow(struct sna *sna, xf86CrtcPtr crtc)
12412 return true;
12413 }
12414
12415- priv = sna_pixmap_force_to_gpu(sna->front, MOVE_READ | __MOVE_SCANOUT);
12416- if (priv == NULL)
12417- return true; /* maybe we can create a bo for the scanout? */
12418-
12419- if (sna->kgem.gen == 071)
12420- pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024;
12421- else if ((sna->kgem.gen >> 3) > 4)
12422- pitch_limit = 32 * 1024;
12423- else if ((sna->kgem.gen >> 3) == 4)
12424- pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024;
12425- else if ((sna->kgem.gen >> 3) == 3)
12426- pitch_limit = priv->gpu_bo->tiling ? 8 * 1024 : 16 * 1024;
12427- else
12428- pitch_limit = 8 * 1024;
12429- DBG(("%s: gpu bo handle=%d tiling=%d pitch=%d, limit=%d\n", __FUNCTION__, priv->gpu_bo->handle, priv->gpu_bo->tiling, priv->gpu_bo->pitch, pitch_limit));
12430- if (priv->gpu_bo->pitch > pitch_limit)
12431- return true;
12432+ if (!isGPU(sna->scrn)) {
12433+ struct sna_pixmap *priv;
12434
12435- if (priv->gpu_bo->tiling && sna->flags & SNA_LINEAR_FB) {
12436- DBG(("%s: gpu bo is tiled, need linear, forcing shadow\n", __FUNCTION__));
12437- return true;
12438- }
12439+ priv = sna_pixmap_force_to_gpu(sna->front, MOVE_READ | __MOVE_SCANOUT);
12440+ if (priv == NULL)
12441+ return true; /* maybe we can create a bo for the scanout? */
12442
12443- transform = NULL;
12444- if (crtc->transformPresent)
12445- transform = &crtc->transform;
12446- if (RRTransformCompute(crtc->x, crtc->y,
12447- crtc->mode.HDisplay, crtc->mode.VDisplay,
12448- crtc->rotation, transform,
12449+ if (sna->kgem.gen == 071)
12450+ pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024;
12451+ else if ((sna->kgem.gen >> 3) > 4)
12452+ pitch_limit = 32 * 1024;
12453+ else if ((sna->kgem.gen >> 3) == 4)
12454+ pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024;
12455+ else if ((sna->kgem.gen >> 3) == 3)
12456+ pitch_limit = priv->gpu_bo->tiling ? 8 * 1024 : 16 * 1024;
12457+ else
12458+ pitch_limit = 8 * 1024;
12459+ DBG(("%s: gpu bo handle=%d tiling=%d pitch=%d, limit=%d\n", __FUNCTION__, priv->gpu_bo->handle, priv->gpu_bo->tiling, priv->gpu_bo->pitch, pitch_limit));
12460+ if (priv->gpu_bo->pitch > pitch_limit)
12461+ return true;
12462+
12463+ if (priv->gpu_bo->tiling && sna->flags & SNA_LINEAR_FB) {
12464+ DBG(("%s: gpu bo is tiled, need linear, forcing shadow\n", __FUNCTION__));
12465+ return true;
12466+ }
12467+ }
12468+
12469+ transform = NULL;
12470+ if (crtc->transformPresent)
12471+ transform = &crtc->transform;
12472+ if (RRTransformCompute(crtc->x, crtc->y,
12473+ crtc->mode.HDisplay, crtc->mode.VDisplay,
12474+ crtc->rotation, transform,
12475 &crtc_to_fb,
12476 &f_crtc_to_fb,
12477 &f_fb_to_crtc)) {
12478 bool needs_transform = true;
12479 unsigned rotation = rotation_reduce(&to_sna_crtc(crtc)->primary, crtc->rotation);
12480 DBG(("%s: natively supported rotation? rotation=%x & supported=%x == %d\n",
12481- __FUNCTION__, crtc->rotation, to_sna_crtc(crtc)->primary.rotation.supported,
12482- !!(crtc->rotation & to_sna_crtc(crtc)->primary.rotation.supported)));
12483- if (to_sna_crtc(crtc)->primary.rotation.supported & rotation)
12484+ __FUNCTION__, rotation, to_sna_crtc(crtc)->primary.rotation.supported,
12485+ rotation == (rotation & to_sna_crtc(crtc)->primary.rotation.supported)));
12486+ if ((to_sna_crtc(crtc)->primary.rotation.supported & rotation) == rotation)
12487 needs_transform = RRTransformCompute(crtc->x, crtc->y,
12488 crtc->mode.HDisplay, crtc->mode.VDisplay,
12489 RR_Rotate_0, transform,
12490@@ -1912,6 +2312,28 @@ get_scanout_bo(struct sna *sna, PixmapPtr pixmap)
12491 return priv->gpu_bo;
12492 }
12493
12494+static void shadow_clear(struct sna *sna,
12495+ PixmapPtr front, struct kgem_bo *bo,
12496+ xf86CrtcPtr crtc)
12497+{
12498+ bool ok = false;
12499+ if (!wedged(sna))
12500+ ok = sna->render.fill_one(sna, front, bo, 0,
12501+ 0, 0, crtc->mode.HDisplay, crtc->mode.VDisplay,
12502+ GXclear);
12503+ if (!ok) {
12504+ void *ptr = kgem_bo_map__gtt(&sna->kgem, bo);
12505+ if (ptr)
12506+ memset(ptr, 0, bo->pitch * crtc->mode.HDisplay);
12507+ }
12508+ sna->mode.shadow_dirty = true;
12509+}
12510+
12511+static bool rr_active(xf86CrtcPtr crtc)
12512+{
12513+ return crtc->transformPresent || crtc->rotation != RR_Rotate_0;
12514+}
12515+
12516 static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
12517 {
12518 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
12519@@ -1919,10 +2341,15 @@ static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
12520 struct sna *sna = to_sna(scrn);
12521 struct kgem_bo *bo;
12522
12523- sna_crtc->transform = false;
12524+ if (sna_crtc->transform) {
12525+ assert(sna->mode.rr_active);
12526+ sna_crtc->transform = false;
12527+ sna->mode.rr_active--;
12528+ }
12529 sna_crtc->rotation = RR_Rotate_0;
12530
12531 if (use_shadow(sna, crtc)) {
12532+ PixmapPtr front;
12533 unsigned long tiled_limit;
12534 int tiling;
12535
12536@@ -1977,8 +2404,8 @@ force_shadow:
12537 return NULL;
12538 }
12539
12540- if (__sna_pixmap_get_bo(sna->front) && !crtc->transformPresent) {
12541- DrawableRec tmp;
12542+ front = sna_crtc->slave_pixmap ?: sna->front;
12543+ if (__sna_pixmap_get_bo(front) && !rr_active(crtc)) {
12544 BoxRec b;
12545
12546 b.x1 = crtc->x;
12547@@ -1986,28 +2413,48 @@ force_shadow:
12548 b.x2 = crtc->x + crtc->mode.HDisplay;
12549 b.y2 = crtc->y + crtc->mode.VDisplay;
12550
12551- DBG(("%s: copying onto shadow CRTC: (%d, %d)x(%d, %d), handle=%d\n",
12552- __FUNCTION__,
12553- b.x1, b.y1,
12554- b.x2, b.y2,
12555- bo->handle));
12556-
12557- tmp.width = crtc->mode.HDisplay;
12558- tmp.height = crtc->mode.VDisplay;
12559- tmp.depth = sna->front->drawable.depth;
12560- tmp.bitsPerPixel = sna->front->drawable.bitsPerPixel;
12561-
12562- (void)sna->render.copy_boxes(sna, GXcopy,
12563- &sna->front->drawable, __sna_pixmap_get_bo(sna->front), 0, 0,
12564- &tmp, bo, -b.x1, -b.y1,
12565- &b, 1, 0);
12566- }
12567+ if (b.x1 < 0)
12568+ b.x1 = 0;
12569+ if (b.y1 < 0)
12570+ b.y1 = 0;
12571+ if (b.x2 > scrn->virtualX)
12572+ b.x2 = scrn->virtualX;
12573+ if (b.y2 > scrn->virtualY)
12574+ b.y2 = scrn->virtualY;
12575+ if (b.x2 - b.x1 < crtc->mode.HDisplay ||
12576+ b.y2 - b.y1 < crtc->mode.VDisplay)
12577+ shadow_clear(sna, front, bo, crtc);
12578+
12579+ if (b.y2 > b.y1 && b.x2 > b.x1) {
12580+ DrawableRec tmp;
12581+
12582+ DBG(("%s: copying onto shadow CRTC: (%d, %d)x(%d, %d) [fb=%dx%d], handle=%d\n",
12583+ __FUNCTION__,
12584+ b.x1, b.y1,
12585+ b.x2-b.x1, b.y2-b.y1,
12586+ scrn->virtualX, scrn->virtualY,
12587+ bo->handle));
12588+
12589+ tmp.width = crtc->mode.HDisplay;
12590+ tmp.height = crtc->mode.VDisplay;
12591+ tmp.depth = front->drawable.depth;
12592+ tmp.bitsPerPixel = front->drawable.bitsPerPixel;
12593+
12594+ if (!sna->render.copy_boxes(sna, GXcopy,
12595+ &front->drawable, __sna_pixmap_get_bo(front), 0, 0,
12596+ &tmp, bo, -crtc->x, -crtc->y,
12597+ &b, 1, COPY_LAST))
12598+ shadow_clear(sna, front, bo, crtc);
12599+ }
12600+ } else
12601+ shadow_clear(sna, front, bo, crtc);
12602
12603 sna_crtc->shadow_bo_width = crtc->mode.HDisplay;
12604 sna_crtc->shadow_bo_height = crtc->mode.VDisplay;
12605 sna_crtc->shadow_bo = bo;
12606 out_shadow:
12607 sna_crtc->transform = true;
12608+ sna->mode.rr_active++;
12609 return kgem_bo_reference(bo);
12610 } else {
12611 if (sna_crtc->shadow_bo) {
12612@@ -2048,26 +2495,26 @@ out_shadow:
12613 }
12614
12615 if (sna->flags & SNA_TEAR_FREE) {
12616+ RegionRec region;
12617+
12618 assert(sna_crtc->slave_pixmap == NULL);
12619
12620 DBG(("%s: enabling TearFree shadow\n", __FUNCTION__));
12621+ region.extents.x1 = 0;
12622+ region.extents.y1 = 0;
12623+ region.extents.x2 = sna->scrn->virtualX;
12624+ region.extents.y2 = sna->scrn->virtualY;
12625+ region.data = NULL;
12626+
12627 if (!sna_crtc_enable_shadow(sna, sna_crtc)) {
12628 DBG(("%s: failed to enable crtc shadow\n", __FUNCTION__));
12629 return NULL;
12630 }
12631
12632 if (sna->mode.shadow == NULL && !wedged(sna)) {
12633- RegionRec region;
12634 struct kgem_bo *shadow;
12635
12636 DBG(("%s: creating TearFree shadow bo\n", __FUNCTION__));
12637-
12638- region.extents.x1 = 0;
12639- region.extents.y1 = 0;
12640- region.extents.x2 = sna->scrn->virtualX;
12641- region.extents.y2 = sna->scrn->virtualY;
12642- region.data = NULL;
12643-
12644 shadow = kgem_create_2d(&sna->kgem,
12645 region.extents.x2,
12646 region.extents.y2,
12647@@ -2093,9 +2540,11 @@ out_shadow:
12648 goto force_shadow;
12649 }
12650
12651+ assert(__sna_pixmap_get_bo(sna->front) == NULL ||
12652+ __sna_pixmap_get_bo(sna->front)->pitch == shadow->pitch);
12653 sna->mode.shadow = shadow;
12654- set_shadow(sna, &region);
12655 }
12656+ set_shadow(sna, &region);
12657
12658 sna_crtc_disable_override(sna, sna_crtc);
12659 } else
12660@@ -2107,6 +2556,37 @@ out_shadow:
12661 }
12662 }
12663
12664+#define SCALING_EPSILON (1./256)
12665+
12666+static bool
12667+is_affine(const struct pixman_f_transform *t)
12668+{
12669+ return (fabs(t->m[2][0]) < SCALING_EPSILON &&
12670+ fabs(t->m[2][1]) < SCALING_EPSILON);
12671+}
12672+
12673+static double determinant(const struct pixman_f_transform *t)
12674+{
12675+ return t->m[0][0]*t->m[1][1] - t->m[1][0]*t->m[0][1];
12676+}
12677+
12678+static bool
12679+affine_is_pixel_exact(const struct pixman_f_transform *t)
12680+{
12681+ double det = t->m[2][2] * determinant(t);
12682+ if (fabs (det * det - 1.0) < SCALING_EPSILON) {
12683+ if (fabs(t->m[0][1]) < SCALING_EPSILON &&
12684+ fabs(t->m[1][0]) < SCALING_EPSILON)
12685+ return true;
12686+
12687+ if (fabs(t->m[0][0]) < SCALING_EPSILON &&
12688+ fabs(t->m[1][1]) < SCALING_EPSILON)
12689+ return true;
12690+ }
12691+
12692+ return false;
12693+}
12694+
12695 static void sna_crtc_randr(xf86CrtcPtr crtc)
12696 {
12697 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
12698@@ -2152,6 +2632,18 @@ static void sna_crtc_randr(xf86CrtcPtr crtc)
12699 } else
12700 crtc->transform_in_use = sna_crtc->rotation != RR_Rotate_0;
12701
12702+ if (needs_transform) {
12703+ sna_crtc->hwcursor = is_affine(&f_fb_to_crtc);
12704+ sna_crtc->cursor_transform =
12705+ sna_crtc->hwcursor &&
12706+ !affine_is_pixel_exact(&f_fb_to_crtc);
12707+ } else {
12708+ sna_crtc->hwcursor = true;
12709+ sna_crtc->cursor_transform = false;
12710+ }
12711+ DBG(("%s: hwcursor?=%d, cursor_transform?=%d\n",
12712+ __FUNCTION__, sna_crtc->hwcursor, sna_crtc->cursor_transform));
12713+
12714 crtc->crtc_to_framebuffer = crtc_to_fb;
12715 crtc->f_crtc_to_framebuffer = f_crtc_to_fb;
12716 crtc->f_framebuffer_to_crtc = f_fb_to_crtc;
12717@@ -2184,7 +2676,7 @@ static void sna_crtc_randr(xf86CrtcPtr crtc)
12718 static void
12719 sna_crtc_damage(xf86CrtcPtr crtc)
12720 {
12721- ScreenPtr screen = crtc->scrn->pScreen;
12722+ ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
12723 struct sna *sna = to_sna(crtc->scrn);
12724 RegionRec region, *damage;
12725
12726@@ -2200,8 +2692,14 @@ sna_crtc_damage(xf86CrtcPtr crtc)
12727 if (region.extents.y2 > screen->height)
12728 region.extents.y2 = screen->height;
12729
12730+ if (region.extents.x2 <= region.extents.x1 ||
12731+ region.extents.y2 <= region.extents.y1) {
12732+ DBG(("%s: crtc not damaged, all-clipped\n", __FUNCTION__));
12733+ return;
12734+ }
12735+
12736 DBG(("%s: marking crtc %d as completely damaged (%d, %d), (%d, %d)\n",
12737- __FUNCTION__, to_sna_crtc(crtc)->id,
12738+ __FUNCTION__, sna_crtc_id(crtc),
12739 region.extents.x1, region.extents.y1,
12740 region.extents.x2, region.extents.y2));
12741 to_sna_crtc(crtc)->client_damage = region;
12742@@ -2268,11 +2766,18 @@ __sna_crtc_set_mode(xf86CrtcPtr crtc)
12743 struct kgem_bo *saved_bo, *bo;
12744 uint32_t saved_offset;
12745 bool saved_transform;
12746+ bool saved_hwcursor;
12747+ bool saved_cursor_transform;
12748
12749- DBG(("%s\n", __FUNCTION__));
12750+ DBG(("%s: CRTC=%d, pipe=%d, hidden?=%d\n", __FUNCTION__,
12751+ __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), sna->mode.hidden));
12752+ if (sna->mode.hidden)
12753+ return TRUE;
12754
12755 saved_bo = sna_crtc->bo;
12756 saved_transform = sna_crtc->transform;
12757+ saved_cursor_transform = sna_crtc->cursor_transform;
12758+ saved_hwcursor = sna_crtc->hwcursor;
12759 saved_offset = sna_crtc->offset;
12760
12761 sna_crtc->fallback_shadow = false;
12762@@ -2304,7 +2809,11 @@ retry: /* Attach per-crtc pixmap or direct */
12763 goto error;
12764 }
12765
12766+ sna_crtc->flags |= CRTC_ON;
12767 bo->active_scanout++;
12768+ DBG(("%s: marking handle=%d as active=%d (removing %d from scanout, active=%d)\n",
12769+ __FUNCTION__, bo->handle, bo->active_scanout,
12770+ saved_bo ? saved_bo->handle : 0, saved_bo ? saved_bo->active_scanout - 1: -1));
12771 if (saved_bo) {
12772 assert(saved_bo->active_scanout);
12773 assert(saved_bo->refcnt >= saved_bo->active_scanout);
12774@@ -2315,17 +2824,33 @@ retry: /* Attach per-crtc pixmap or direct */
12775 sna_crtc_randr(crtc);
12776 if (sna_crtc->transform)
12777 sna_crtc_damage(crtc);
12778+ if (sna_crtc->cursor && /* Reload cursor if RandR maybe changed */
12779+ (!sna_crtc->hwcursor ||
12780+ saved_cursor_transform || sna_crtc->cursor_transform ||
12781+ sna_crtc->cursor->rotation != crtc->rotation))
12782+ sna_crtc_disable_cursor(sna, sna_crtc);
12783+
12784+ assert(!sna->mode.hidden);
12785 sna->mode.front_active += saved_bo == NULL;
12786 sna->mode.dirty = true;
12787- DBG(("%s: front_active=%d\n", __FUNCTION__, sna->mode.front_active));
12788+ DBG(("%s: handle=%d, scanout_active=%d, front_active=%d\n",
12789+ __FUNCTION__, bo->handle, bo->active_scanout, sna->mode.front_active));
12790
12791 return TRUE;
12792
12793 error:
12794 sna_crtc->offset = saved_offset;
12795+ if (sna_crtc->transform) {
12796+ assert(sna->mode.rr_active);
12797+ sna->mode.rr_active--;
12798+ }
12799+ if (saved_transform)
12800+ sna->mode.rr_active++;
12801 sna_crtc->transform = saved_transform;
12802+ sna_crtc->cursor_transform = saved_cursor_transform;
12803+ sna_crtc->hwcursor = saved_hwcursor;
12804 sna_crtc->bo = saved_bo;
12805- sna_mode_discover(sna);
12806+ sna_mode_discover(sna, true);
12807 return FALSE;
12808 }
12809
12810@@ -2346,14 +2871,14 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
12811 xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO,
12812 "switch to mode %dx%d@%.1f on %s using pipe %d, position (%d, %d), rotation %s, reflection %s\n",
12813 mode->HDisplay, mode->VDisplay, xf86ModeVRefresh(mode),
12814- outputs_for_crtc(crtc, outputs, sizeof(outputs)), sna_crtc->pipe,
12815+ outputs_for_crtc(crtc, outputs, sizeof(outputs)), __sna_crtc_pipe(sna_crtc),
12816 x, y, rotation_to_str(rotation), reflection_to_str(rotation));
12817
12818 assert(mode->HDisplay <= sna->mode.max_crtc_width &&
12819 mode->VDisplay <= sna->mode.max_crtc_height);
12820
12821 #if HAS_GAMMA
12822- drmModeCrtcSetGamma(sna->kgem.fd, sna_crtc->id,
12823+ drmModeCrtcSetGamma(sna->kgem.fd, __sna_crtc_id(sna_crtc),
12824 crtc->gamma_size,
12825 crtc->gamma_red,
12826 crtc->gamma_green,
12827@@ -2372,17 +2897,10 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
12828 static void
12829 sna_crtc_dpms(xf86CrtcPtr crtc, int mode)
12830 {
12831- struct sna_crtc *priv = to_sna_crtc(crtc);
12832-
12833 DBG(("%s(pipe %d, dpms mode -> %d):= active=%d\n",
12834- __FUNCTION__, priv->pipe, mode, mode == DPMSModeOn));
12835- if (priv->dpms_mode == mode)
12836- return;
12837+ __FUNCTION__, sna_crtc_pipe(crtc), mode, mode == DPMSModeOn));
12838
12839- assert(priv);
12840- priv->dpms_mode = mode;
12841-
12842- if (mode == DPMSModeOn && crtc->enabled && priv->bo == NULL) {
12843+ if (mode == DPMSModeOn && crtc->enabled) {
12844 if (__sna_crtc_set_mode(crtc))
12845 update_flush_interval(to_sna(crtc->scrn));
12846 else
12847@@ -2390,7 +2908,7 @@ sna_crtc_dpms(xf86CrtcPtr crtc, int mode)
12848 }
12849
12850 if (mode != DPMSModeOn)
12851- sna_crtc_disable(crtc);
12852+ sna_crtc_disable(crtc, false);
12853 }
12854
12855 void sna_mode_adjust_frame(struct sna *sna, int x, int y)
12856@@ -2426,7 +2944,7 @@ sna_crtc_gamma_set(xf86CrtcPtr crtc,
12857 {
12858 assert(to_sna_crtc(crtc));
12859 drmModeCrtcSetGamma(to_sna(crtc->scrn)->kgem.fd,
12860- to_sna_crtc(crtc)->id,
12861+ sna_crtc_id(crtc),
12862 size, red, green, blue);
12863 }
12864
12865@@ -2455,7 +2973,7 @@ sna_crtc_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr pixmap)
12866 return TRUE;
12867
12868 DBG(("%s: CRTC:%d, pipe=%d setting scanout pixmap=%ld\n",
12869- __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
12870+ __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
12871 pixmap ? pixmap->drawable.serialNumber : 0));
12872
12873 /* Disable first so that we can unregister the damage tracking */
12874@@ -2576,6 +3094,10 @@ static int plane_details(struct sna *sna, struct plane *p)
12875 }
12876 }
12877
12878+ p->rotation.supported &= DBG_NATIVE_ROTATION;
12879+ if (!xf86ReturnOptValBool(sna->Options, OPTION_ROTATION, TRUE))
12880+ p->rotation.supported = RR_Rotate_0;
12881+
12882 if (props != (uint32_t *)stack_props)
12883 free(props);
12884
12885@@ -2587,16 +3109,11 @@ static void
12886 sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
12887 {
12888 #define LOCAL_IOCTL_SET_CAP DRM_IOWR(0x0d, struct local_set_cap)
12889-#define LOCAL_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xb5, struct local_mode_get_plane_res)
12890-#define LOCAL_IOCTL_MODE_GETPLANE DRM_IOWR(0xb6, struct local_mode_get_plane)
12891 struct local_set_cap {
12892 uint64_t name;
12893 uint64_t value;
12894 } cap;
12895- struct local_mode_get_plane_res {
12896- uint64_t plane_id_ptr;
12897- uint64_t count_planes;
12898- } r;
12899+ struct local_mode_get_plane_res r;
12900 uint32_t stack_planes[32];
12901 uint32_t *planes = stack_planes;
12902 int i;
12903@@ -2629,18 +3146,7 @@ sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
12904 VG(VALGRIND_MAKE_MEM_DEFINED(planes, sizeof(uint32_t)*r.count_planes));
12905
12906 for (i = 0; i < r.count_planes; i++) {
12907- struct local_mode_get_plane {
12908- uint32_t plane_id;
12909-
12910- uint32_t crtc_id;
12911- uint32_t fb_id;
12912-
12913- uint32_t possible_crtcs;
12914- uint32_t gamma_size;
12915-
12916- uint32_t count_format_types;
12917- uint64_t format_type_ptr;
12918- } p;
12919+ struct local_mode_get_plane p;
12920 struct plane details;
12921
12922 VG_CLEAR(p);
12923@@ -2649,11 +3155,11 @@ sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
12924 if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_GETPLANE, &p))
12925 continue;
12926
12927- if ((p.possible_crtcs & (1 << crtc->pipe)) == 0)
12928+ if ((p.possible_crtcs & (1 << __sna_crtc_pipe(crtc))) == 0)
12929 continue;
12930
12931 DBG(("%s: plane %d is attached to our pipe=%d\n",
12932- __FUNCTION__, planes[i], crtc->pipe));
12933+ __FUNCTION__, planes[i], __sna_crtc_pipe(crtc)));
12934
12935 details.id = p.plane_id;
12936 details.rotation.prop = 0;
12937@@ -2698,43 +3204,45 @@ sna_crtc_init__cursor(struct sna *sna, struct sna_crtc *crtc)
12938
12939 VG_CLEAR(arg);
12940 arg.flags = DRM_MODE_CURSOR_BO;
12941- arg.crtc_id = crtc->id;
12942+ arg.crtc_id = __sna_crtc_id(crtc);
12943 arg.width = arg.height = 0;
12944 arg.handle = 0;
12945
12946 (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg);
12947+ crtc->hwcursor = true;
12948 }
12949
12950 static bool
12951-sna_crtc_add(ScrnInfoPtr scrn, int id)
12952+sna_crtc_add(ScrnInfoPtr scrn, unsigned id)
12953 {
12954 struct sna *sna = to_sna(scrn);
12955 xf86CrtcPtr crtc;
12956 struct sna_crtc *sna_crtc;
12957 struct drm_i915_get_pipe_from_crtc_id get_pipe;
12958
12959- DBG(("%s(%d)\n", __FUNCTION__, id));
12960+ DBG(("%s(%d): is-zaphod? %d\n", __FUNCTION__, id, is_zaphod(scrn)));
12961
12962 sna_crtc = calloc(sizeof(struct sna_crtc), 1);
12963 if (sna_crtc == NULL)
12964 return false;
12965
12966- sna_crtc->id = id;
12967- sna_crtc->dpms_mode = -1;
12968+ assert(id < 256);
12969+ sna_crtc->flags = id << 16;
12970
12971 VG_CLEAR(get_pipe);
12972 get_pipe.pipe = 0;
12973- get_pipe.crtc_id = sna_crtc->id;
12974+ get_pipe.crtc_id = id;
12975 if (drmIoctl(sna->kgem.fd,
12976 DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID,
12977 &get_pipe)) {
12978 free(sna_crtc);
12979 return false;
12980 }
12981- sna_crtc->pipe = get_pipe.pipe;
12982+ assert((unsigned)get_pipe.pipe < 256);
12983+ sna_crtc->flags |= get_pipe.pipe << 8;
12984
12985 if (is_zaphod(scrn) &&
12986- scrn->confScreen->device->screen != sna_crtc->pipe) {
12987+ (get_zaphod_crtcs(sna) & (1 << get_pipe.pipe)) == 0) {
12988 free(sna_crtc);
12989 return true;
12990 }
12991@@ -2744,7 +3252,7 @@ sna_crtc_add(ScrnInfoPtr scrn, int id)
12992 sna_crtc_find_planes(sna, sna_crtc);
12993
12994 DBG(("%s: CRTC:%d [pipe=%d], primary id=%x: supported-rotations=%x, current-rotation=%x, sprite id=%x: supported-rotations=%x, current-rotation=%x\n",
12995- __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
12996+ __FUNCTION__, id, get_pipe.pipe,
12997 sna_crtc->primary.id, sna_crtc->primary.rotation.supported, sna_crtc->primary.rotation.current,
12998 sna_crtc->sprite.id, sna_crtc->sprite.rotation.supported, sna_crtc->sprite.rotation.current));
12999
13000@@ -2761,7 +3269,7 @@ sna_crtc_add(ScrnInfoPtr scrn, int id)
13001 crtc->driver_private = sna_crtc;
13002 sna_crtc->base = crtc;
13003 DBG(("%s: attached crtc[%d] pipe=%d\n",
13004- __FUNCTION__, id, sna_crtc->pipe));
13005+ __FUNCTION__, id, __sna_crtc_pipe(sna_crtc)));
13006
13007 return true;
13008 }
13009@@ -2798,20 +3306,56 @@ find_property(struct sna *sna, struct sna_output *output, const char *name)
13010 return -1;
13011 }
13012
13013+static void update_properties(struct sna *sna, struct sna_output *output)
13014+{
13015+ union compat_mode_get_connector compat_conn;
13016+ struct drm_mode_modeinfo dummy;
13017+
13018+ VG_CLEAR(compat_conn);
13019+
13020+ compat_conn.conn.connector_id = output->id;
13021+ compat_conn.conn.count_props = output->num_props;
13022+ compat_conn.conn.props_ptr = (uintptr_t)output->prop_ids;
13023+ compat_conn.conn.prop_values_ptr = (uintptr_t)output->prop_values;
13024+ compat_conn.conn.count_modes = 1; /* skip detect */
13025+ compat_conn.conn.modes_ptr = (uintptr_t)&dummy;
13026+ compat_conn.conn.count_encoders = 0;
13027+
13028+ (void)drmIoctl(sna->kgem.fd,
13029+ DRM_IOCTL_MODE_GETCONNECTOR,
13030+ &compat_conn.conn);
13031+
13032+ assert(compat_conn.conn.count_props == output->num_props);
13033+ output->update_properties = false;
13034+}
13035+
13036 static xf86OutputStatus
13037 sna_output_detect(xf86OutputPtr output)
13038 {
13039 struct sna *sna = to_sna(output->scrn);
13040 struct sna_output *sna_output = output->driver_private;
13041 union compat_mode_get_connector compat_conn;
13042+ uint32_t now;
13043
13044 DBG(("%s(%s:%d)\n", __FUNCTION__, output->name, sna_output->id));
13045+ sna_output->update_properties = false;
13046
13047 if (!sna_output->id) {
13048 DBG(("%s(%s) hiding due to lost connection\n", __FUNCTION__, output->name));
13049 return XF86OutputStatusDisconnected;
13050 }
13051
13052+ /* Cache detections for 15s or hotplug event */
13053+ now = GetTimeInMillis();
13054+ if (sna_output->last_detect != 0 &&
13055+ (int32_t)(now - sna_output->last_detect) <= OUTPUT_STATUS_CACHE_MS) {
13056+ DBG(("%s(%s) reporting cached status (since %dms): %d\n",
13057+ __FUNCTION__, output->name, now - sna_output->last_detect,
13058+ sna_output->status));
13059+ sna_output->update_properties = true;
13060+ return sna_output->status;
13061+ }
13062+
13063 VG_CLEAR(compat_conn);
13064 compat_conn.conn.connector_id = sna_output->id;
13065 sna_output->num_modes = compat_conn.conn.count_modes = 0; /* reprobe */
13066@@ -2854,15 +3398,20 @@ sna_output_detect(xf86OutputPtr output)
13067 DBG(("%s(%s): found %d modes, connection status=%d\n",
13068 __FUNCTION__, output->name, sna_output->num_modes, compat_conn.conn.connection));
13069
13070+ sna_output->last_detect = now;
13071 switch (compat_conn.conn.connection) {
13072 case DRM_MODE_CONNECTED:
13073- return XF86OutputStatusConnected;
13074+ sna_output->status = XF86OutputStatusConnected;
13075+ break;
13076 case DRM_MODE_DISCONNECTED:
13077- return XF86OutputStatusDisconnected;
13078+ sna_output->status = XF86OutputStatusDisconnected;
13079+ break;
13080 default:
13081 case DRM_MODE_UNKNOWNCONNECTION:
13082- return XF86OutputStatusUnknown;
13083+ sna_output->status = XF86OutputStatusUnknown;
13084+ break;
13085 }
13086+ return sna_output->status;
13087 }
13088
13089 static Bool
13090@@ -2907,6 +3456,13 @@ sna_output_attach_edid(xf86OutputPtr output)
13091 if (sna_output->edid_idx == -1)
13092 return;
13093
13094+ /* Always refresh the blob as the kernel may randomly update the
13095+ * id even if the contents of the blob doesn't change, and a
13096+ * request for the stale id will return nothing.
13097+ */
13098+ if (sna_output->update_properties)
13099+ update_properties(sna, sna_output);
13100+
13101 raw = sna_output->edid_raw;
13102 blob.length = sna_output->edid_len;
13103
13104@@ -2917,8 +3473,12 @@ sna_output_attach_edid(xf86OutputPtr output)
13105 old = NULL;
13106
13107 blob.blob_id = sna_output->prop_values[sna_output->edid_idx];
13108- DBG(("%s: attaching EDID id=%d, current=%d\n",
13109- __FUNCTION__, blob.blob_id, sna_output->edid_blob_id));
13110+ if (!blob.blob_id)
13111+ goto done;
13112+
13113+ DBG(("%s(%s): attaching EDID id=%d, current=%d\n",
13114+ __FUNCTION__, output->name,
13115+ blob.blob_id, sna_output->edid_blob_id));
13116 if (blob.blob_id == sna_output->edid_blob_id && 0) { /* sigh */
13117 if (output->MonInfo) {
13118 /* XXX the property keeps on disappearing... */
13119@@ -2936,11 +3496,14 @@ sna_output_attach_edid(xf86OutputPtr output)
13120 }
13121
13122 blob.data = (uintptr_t)raw;
13123- if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
13124- goto done;
13125+ if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) {
13126+ DBG(("%s(%s): failed to read blob, reusing previous\n",
13127+ __FUNCTION__, output->name));
13128+ goto skip_read;
13129+ }
13130
13131- DBG(("%s: retrieving blob id=%d, length=%d\n",
13132- __FUNCTION__, blob.blob_id, blob.length));
13133+ DBG(("%s(%s): retrieving blob id=%d, length=%d\n",
13134+ __FUNCTION__, output->name, blob.blob_id, blob.length));
13135
13136 if (blob.length > sna_output->edid_len) {
13137 raw = realloc(raw, blob.length);
13138@@ -2949,13 +3512,26 @@ sna_output_attach_edid(xf86OutputPtr output)
13139
13140 VG(memset(raw, 0, blob.length));
13141 blob.data = (uintptr_t)raw;
13142- if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
13143- goto done;
13144+ }
13145+
13146+ if (blob.length != sna_output->edid_len &&
13147+ drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
13148+ goto done;
13149+
13150+ if (blob.length < 128)
13151+ goto done;
13152+
13153+ if (blob.length & 127) {
13154+ /* Truncated EDID! Make sure no one reads too far */
13155+ *SECTION(NO_EDID, (uint8_t*)raw) = blob.length/128 - 1;
13156+ blob.length &= -128;
13157 }
13158
13159 if (old &&
13160 blob.length == sna_output->edid_len &&
13161 memcmp(old, raw, blob.length) == 0) {
13162+ DBG(("%s(%s): EDID + MonInfo is unchanged\n",
13163+ __FUNCTION__, output->name));
13164 assert(sna_output->edid_raw == raw);
13165 sna_output->edid_blob_id = blob.blob_id;
13166 RRChangeOutputProperty(output->randr_output,
13167@@ -2983,18 +3559,173 @@ done:
13168 }
13169 }
13170
13171+static void
13172+sna_output_attach_tile(xf86OutputPtr output)
13173+{
13174+#if XF86_OUTPUT_VERSION >= 3
13175+ struct sna *sna = to_sna(output->scrn);
13176+ struct sna_output *sna_output = output->driver_private;
13177+ struct drm_mode_get_blob blob;
13178+ struct xf86CrtcTileInfo tile_info, *set = NULL;
13179+ char *tile;
13180+ int id;
13181+
13182+ id = find_property(sna, sna_output, "TILE");
13183+ DBG(("%s: found? TILE=%d\n", __FUNCTION__, id));
13184+ if (id == -1)
13185+ goto out;
13186+
13187+ if (sna_output->update_properties)
13188+ update_properties(sna, sna_output);
13189+
13190+ VG_CLEAR(blob);
13191+ blob.blob_id = sna_output->prop_values[id];
13192+ blob.length = 0;
13193+ if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
13194+ goto out;
13195+
13196+ do {
13197+ id = blob.length;
13198+ tile = alloca(id + 1);
13199+ blob.data = (uintptr_t)tile;
13200+ VG(memset(tile, 0, id));
13201+ DBG(("%s: reading %d bytes for TILE blob\n", __FUNCTION__, id));
13202+ if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
13203+ goto out;
13204+ } while (id != blob.length);
13205+
13206+ tile[blob.length] = '\0'; /* paranoia */
13207+ DBG(("%s: TILE='%s'\n", __FUNCTION__, tile));
13208+ if (xf86OutputParseKMSTile(tile, blob.length, &tile_info))
13209+ set = &tile_info;
13210+out:
13211+ xf86OutputSetTile(output, set);
13212+#endif
13213+}
13214+
13215+static bool duplicate_mode(DisplayModePtr modes, DisplayModePtr m)
13216+{
13217+ if (m == NULL)
13218+ return false;
13219+
13220+ while (modes) {
13221+ if (xf86ModesEqual(modes, m))
13222+ return true;
13223+
13224+ modes = modes->next;
13225+ }
13226+
13227+ return false;
13228+}
13229+
13230+static struct pixel_count {
13231+ int16_t width, height;
13232+} common_16_9[] = {
13233+ { 640, 360 },
13234+ { 720, 405 },
13235+ { 864, 486 },
13236+ { 960, 540 },
13237+ { 1024, 576 },
13238+ { 1280, 720 },
13239+ { 1366, 768 },
13240+ { 1600, 900 },
13241+ { 1920, 1080 },
13242+ { 2048, 1152 },
13243+ { 2560, 1440 },
13244+ { 2880, 1620 },
13245+ { 3200, 1800 },
13246+ { 3840, 2160 },
13247+ { 4096, 2304 },
13248+ { 5120, 2880 },
13249+ { 7680, 4320 },
13250+ { 15360, 8640 },
13251+}, common_16_10[] = {
13252+ { 1280, 800 },
13253+ { 1400, 900 },
13254+ { 1680, 1050 },
13255+ { 1920, 1200 },
13256+ { 2560, 1600 },
13257+};
13258+
13259 static DisplayModePtr
13260-default_modes(void)
13261+default_modes(DisplayModePtr preferred)
13262 {
13263+ DisplayModePtr modes;
13264+ int n;
13265+
13266 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0)
13267- return xf86GetDefaultModes();
13268+ modes = xf86GetDefaultModes();
13269 #else
13270- return xf86GetDefaultModes(0, 0);
13271+ modes = xf86GetDefaultModes(0, 0);
13272+#endif
13273+
13274+ /* XXX O(n^2) mode list generation :( */
13275+
13276+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,4,99,901,0)
13277+ if (preferred) {
13278+ DisplayModePtr m;
13279+
13280+ /* Add a half-resolution mode useful for large panels */
13281+ m = xf86GTFMode(preferred->HDisplay/2,
13282+ preferred->VDisplay/2,
13283+ xf86ModeVRefresh(preferred),
13284+ FALSE, FALSE);
13285+ if (!duplicate_mode(modes, m))
13286+ modes = xf86ModesAdd(modes, m);
13287+ else
13288+ free(m);
13289+
13290+ if (preferred->VDisplay * 16 > preferred->HDisplay*9 - preferred->HDisplay/32 &&
13291+ preferred->VDisplay * 16 < preferred->HDisplay*9 + preferred->HDisplay/32) {
13292+ DBG(("Adding 16:9 modes -- %d < %d > %d\n",
13293+ preferred->HDisplay*9 - preferred->HDisplay/32,
13294+ preferred->VDisplay * 16,
13295+ preferred->HDisplay*9 + preferred->HDisplay/32));
13296+ for (n = 0; n < ARRAY_SIZE(common_16_9); n++) {
13297+ if (preferred->HDisplay <= common_16_9[n].width ||
13298+ preferred->VDisplay <= common_16_9[n].height)
13299+ break;
13300+
13301+ m = xf86GTFMode(common_16_9[n].width,
13302+ common_16_9[n].height,
13303+ xf86ModeVRefresh(preferred),
13304+ FALSE, FALSE);
13305+ if (!duplicate_mode(modes, m))
13306+ modes = xf86ModesAdd(modes, m);
13307+ else
13308+ free(m);
13309+ }
13310+ }
13311+
13312+ if (preferred->VDisplay * 16 > preferred->HDisplay*10 - preferred->HDisplay/32 &&
13313+ preferred->VDisplay * 16 < preferred->HDisplay*10 + preferred->HDisplay/32) {
13314+ DBG(("Adding 16:10 modes -- %d < %d > %d\n",
13315+ preferred->HDisplay*10 - preferred->HDisplay/32,
13316+ preferred->VDisplay * 16,
13317+ preferred->HDisplay*10 + preferred->HDisplay/32));
13318+ for (n = 0; n < ARRAY_SIZE(common_16_10); n++) {
13319+ if (preferred->HDisplay <= common_16_10[n].width ||
13320+ preferred->VDisplay <= common_16_10[n].height)
13321+ break;
13322+
13323+ m = xf86GTFMode(common_16_10[n].width,
13324+ common_16_10[n].height,
13325+ xf86ModeVRefresh(preferred),
13326+ FALSE, FALSE);
13327+ if (!duplicate_mode(modes, m))
13328+ modes = xf86ModesAdd(modes, m);
13329+ else
13330+ free(m);
13331+ }
13332+ }
13333+ }
13334 #endif
13335+
13336+ return modes;
13337 }
13338
13339 static DisplayModePtr
13340-sna_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
13341+sna_output_add_default_modes(xf86OutputPtr output, DisplayModePtr modes)
13342 {
13343 xf86MonPtr mon = output->MonInfo;
13344 DisplayModePtr i, m, preferred = NULL;
13345@@ -3015,7 +3746,7 @@ sna_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
13346 max_vrefresh = max(max_vrefresh, 60.0);
13347 max_vrefresh *= (1 + SYNC_TOLERANCE);
13348
13349- m = default_modes();
13350+ m = default_modes(preferred);
13351 xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
13352
13353 for (i = m; i; i = i->next) {
13354@@ -3034,28 +3765,47 @@ sna_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
13355 }
13356
13357 static DisplayModePtr
13358+sna_output_override_edid(xf86OutputPtr output)
13359+{
13360+ struct sna_output *sna_output = output->driver_private;
13361+
13362+ if (sna_output->fake_edid_mon == NULL)
13363+ return NULL;
13364+
13365+ xf86OutputSetEDID(output, sna_output->fake_edid_mon);
13366+ return xf86DDCGetModes(output->scrn->scrnIndex,
13367+ sna_output->fake_edid_mon);
13368+}
13369+
13370+static DisplayModePtr
13371 sna_output_get_modes(xf86OutputPtr output)
13372 {
13373 struct sna_output *sna_output = output->driver_private;
13374- DisplayModePtr Modes = NULL, current = NULL;
13375+ DisplayModePtr Modes, current;
13376 int i;
13377
13378 DBG(("%s(%s:%d)\n", __FUNCTION__, output->name, sna_output->id));
13379 assert(sna_output->id);
13380
13381+ Modes = sna_output_override_edid(output);
13382+ if (Modes)
13383+ return Modes;
13384+
13385 sna_output_attach_edid(output);
13386+ sna_output_attach_tile(output);
13387
13388+ current = NULL;
13389 if (output->crtc) {
13390 struct drm_mode_crtc mode;
13391
13392 VG_CLEAR(mode);
13393 assert(to_sna_crtc(output->crtc));
13394- mode.crtc_id = to_sna_crtc(output->crtc)->id;
13395+ mode.crtc_id = sna_crtc_id(output->crtc);
13396
13397 if (drmIoctl(to_sna(output->scrn)->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode) == 0) {
13398 DBG(("%s: CRTC:%d, pipe=%d: has mode?=%d\n", __FUNCTION__,
13399- to_sna_crtc(output->crtc)->id,
13400- to_sna_crtc(output->crtc)->pipe,
13401+ sna_crtc_id(output->crtc),
13402+ sna_crtc_pipe(output->crtc),
13403 mode.mode_valid && mode.mode.clock));
13404
13405 if (mode.mode_valid && mode.mode.clock) {
13406@@ -3117,7 +3867,7 @@ sna_output_get_modes(xf86OutputPtr output)
13407 }
13408
13409 if (sna_output->add_default_modes)
13410- Modes = sna_output_panel_edid(output, Modes);
13411+ Modes = sna_output_add_default_modes(output, Modes);
13412
13413 return Modes;
13414 }
13415@@ -3132,6 +3882,8 @@ sna_output_destroy(xf86OutputPtr output)
13416 return;
13417
13418 free(sna_output->edid_raw);
13419+ free(sna_output->fake_edid_raw);
13420+
13421 for (i = 0; i < sna_output->num_props; i++) {
13422 if (sna_output->props[i].kprop == NULL)
13423 continue;
13424@@ -3155,7 +3907,7 @@ sna_output_destroy(xf86OutputPtr output)
13425 }
13426
13427 static void
13428-sna_output_dpms(xf86OutputPtr output, int dpms)
13429+__sna_output_dpms(xf86OutputPtr output, int dpms, int fixup)
13430 {
13431 struct sna *sna = to_sna(output->scrn);
13432 struct sna_output *sna_output = output->driver_private;
13433@@ -3182,8 +3934,9 @@ sna_output_dpms(xf86OutputPtr output, int dpms)
13434 if (sna_output->backlight.iface && dpms != DPMSModeOn) {
13435 if (old_dpms == DPMSModeOn) {
13436 sna_output->backlight_active_level = sna_output_backlight_get(output);
13437- DBG(("%s: saving current backlight %d\n",
13438- __FUNCTION__, sna_output->backlight_active_level));
13439+ DBG(("%s(%s:%d): saving current backlight %d\n",
13440+ __FUNCTION__, output->name, sna_output->id,
13441+ sna_output->backlight_active_level));
13442 }
13443 sna_output->dpms_mode = dpms;
13444 sna_output_backlight_off(sna_output);
13445@@ -3193,18 +3946,31 @@ sna_output_dpms(xf86OutputPtr output, int dpms)
13446 drmModeConnectorSetProperty(sna->kgem.fd,
13447 sna_output->id,
13448 sna_output->dpms_id,
13449- dpms))
13450- dpms = old_dpms;
13451+ dpms)) {
13452+ DBG(("%s(%s:%d): failed to set DPMS to %d (fixup? %d)\n",
13453+ __FUNCTION__, output->name, sna_output->id, dpms, fixup));
13454+ if (fixup) {
13455+ sna_crtc_disable(output->crtc, false);
13456+ return;
13457+ }
13458+ }
13459
13460 if (sna_output->backlight.iface && dpms == DPMSModeOn) {
13461- DBG(("%s: restoring previous backlight %d\n",
13462- __FUNCTION__, sna_output->backlight_active_level));
13463+ DBG(("%s(%d:%d: restoring previous backlight %d\n",
13464+ __FUNCTION__, output->name, sna_output->id,
13465+ sna_output->backlight_active_level));
13466 sna_output_backlight_on(sna_output);
13467 }
13468
13469 sna_output->dpms_mode = dpms;
13470 }
13471
13472+static void
13473+sna_output_dpms(xf86OutputPtr output, int dpms)
13474+{
13475+ __sna_output_dpms(output, dpms, true);
13476+}
13477+
13478 static bool
13479 sna_property_ignore(drmModePropertyPtr prop)
13480 {
13481@@ -3239,14 +4005,14 @@ sna_output_create_ranged_atom(xf86OutputPtr output, Atom *atom,
13482 err = RRConfigureOutputProperty(output->randr_output, *atom, FALSE,
13483 TRUE, immutable, 2, atom_range);
13484 if (err != 0)
13485- xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
13486+ xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
13487 "RRConfigureOutputProperty error, %d\n", err);
13488
13489 err = RRChangeOutputProperty(output->randr_output, *atom, XA_INTEGER,
13490 32, PropModeReplace, 1, &value,
13491 FALSE, FALSE);
13492 if (err != 0)
13493- xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
13494+ xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
13495 "RRChangeOutputProperty error, %d\n", err);
13496 }
13497
13498@@ -3303,7 +4069,7 @@ sna_output_create_resources(xf86OutputPtr output)
13499 p->kprop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
13500 p->num_atoms - 1, (INT32 *)&p->atoms[1]);
13501 if (err != 0) {
13502- xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
13503+ xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
13504 "RRConfigureOutputProperty error, %d\n", err);
13505 }
13506
13507@@ -3315,7 +4081,7 @@ sna_output_create_resources(xf86OutputPtr output)
13508 XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1],
13509 FALSE, FALSE);
13510 if (err != 0) {
13511- xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
13512+ xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
13513 "RRChangeOutputProperty error, %d\n", err);
13514 }
13515 }
13516@@ -3385,18 +4151,19 @@ sna_output_set_property(xf86OutputPtr output, Atom property,
13517 if (value->type != XA_INTEGER || value->format != 32 ||
13518 value->size != 1)
13519 return FALSE;
13520- val = *(uint32_t *)value->data;
13521
13522+ val = *(uint32_t *)value->data;
13523 drmModeConnectorSetProperty(sna->kgem.fd, sna_output->id,
13524 p->kprop->prop_id, (uint64_t)val);
13525 return TRUE;
13526 } else if (p->kprop->flags & DRM_MODE_PROP_ENUM) {
13527- Atom atom;
13528- const char *name;
13529- int j;
13530+ Atom atom;
13531+ const char *name;
13532+ int j;
13533
13534 if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
13535 return FALSE;
13536+
13537 memcpy(&atom, value->data, 4);
13538 name = NameForAtom(atom);
13539 if (name == NULL)
13540@@ -3425,7 +4192,7 @@ static Bool
13541 sna_output_get_property(xf86OutputPtr output, Atom property)
13542 {
13543 struct sna_output *sna_output = output->driver_private;
13544- int err;
13545+ int err, i, j;
13546
13547 if (property == backlight_atom || property == backlight_deprecated_atom) {
13548 INT32 val;
13549@@ -3449,7 +4216,7 @@ sna_output_get_property(xf86OutputPtr output, Atom property)
13550 XA_INTEGER, 32, PropModeReplace, 1, &val,
13551 FALSE, FALSE);
13552 if (err != 0) {
13553- xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
13554+ xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
13555 "RRChangeOutputProperty error, %d\n", err);
13556 return FALSE;
13557 }
13558@@ -3457,6 +4224,40 @@ sna_output_get_property(xf86OutputPtr output, Atom property)
13559 return TRUE;
13560 }
13561
13562+ for (i = 0; i < sna_output->num_props; i++) {
13563+ struct sna_property *p = &sna_output->props[i];
13564+
13565+ if (p->atoms == NULL || p->atoms[0] != property)
13566+ continue;
13567+
13568+ if (sna_output->update_properties && output->scrn->vtSema)
13569+ update_properties(to_sna(output->scrn), sna_output);
13570+
13571+ err = 0;
13572+ if (p->kprop->flags & DRM_MODE_PROP_RANGE) {
13573+ err = RRChangeOutputProperty(output->randr_output,
13574+ property, XA_INTEGER, 32,
13575+ PropModeReplace, 1,
13576+ &sna_output->prop_values[i],
13577+ FALSE, FALSE);
13578+ } else if (p->kprop->flags & DRM_MODE_PROP_ENUM) {
13579+ for (j = 0; j < p->kprop->count_enums; j++) {
13580+ if (p->kprop->enums[j].value == sna_output->prop_values[i])
13581+ break;
13582+ }
13583+ err = RRChangeOutputProperty(output->randr_output,
13584+ property, XA_ATOM, 32,
13585+ PropModeReplace, 1,
13586+ &p->atoms[j+1],
13587+ FALSE, FALSE);
13588+ }
13589+
13590+ if (err != 0)
13591+ xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
13592+ "RRChangeOutputProperty error, %d\n", err);
13593+ return TRUE;
13594+ }
13595+
13596 return FALSE;
13597 }
13598
13599@@ -3504,43 +4305,6 @@ static const char * const output_names[] = {
13600 };
13601
13602 static bool
13603-sna_zaphod_match(const char *s, const char *output)
13604-{
13605- char t[20];
13606- unsigned int i = 0;
13607-
13608- do {
13609- /* match any outputs in a comma list, stopping at whitespace */
13610- switch (*s) {
13611- case '\0':
13612- t[i] = '\0';
13613- return strcmp(t, output) == 0;
13614-
13615- case ',':
13616- t[i] ='\0';
13617- if (strcmp(t, output) == 0)
13618- return TRUE;
13619- i = 0;
13620- break;
13621-
13622- case ' ':
13623- case '\t':
13624- case '\n':
13625- case '\r':
13626- break;
13627-
13628- default:
13629- t[i++] = *s;
13630- break;
13631- }
13632-
13633- s++;
13634- } while (i < sizeof(t));
13635-
13636- return false;
13637-}
13638-
13639-static bool
13640 output_ignored(ScrnInfoPtr scrn, const char *name)
13641 {
13642 char monitor_name[64];
13643@@ -3572,14 +4336,20 @@ gather_encoders(struct sna *sna, uint32_t id, int count,
13644 struct drm_mode_get_encoder enc;
13645 uint32_t *ids = NULL;
13646
13647+ DBG(("%s(%d): expected count=%d\n", __FUNCTION__, id, count));
13648+
13649 VG_CLEAR(compat_conn);
13650 memset(out, 0, sizeof(*out));
13651
13652 do {
13653- free(ids);
13654- ids = malloc(sizeof(*ids) * count);
13655- if (ids == 0)
13656+ uint32_t *nids;
13657+
13658+ nids = realloc(ids, sizeof(*ids) * count);
13659+ if (nids == NULL) {
13660+ free(ids);
13661 return false;
13662+ }
13663+ ids = nids;
13664
13665 compat_conn.conn.connector_id = id;
13666 compat_conn.conn.count_props = 0;
13667@@ -3599,6 +4369,7 @@ gather_encoders(struct sna *sna, uint32_t id, int count,
13668 count = compat_conn.conn.count_encoders;
13669 } while (1);
13670
13671+ DBG(("%s(%d): gathering %d encoders\n", __FUNCTION__, id, count));
13672 for (count = 0; count < compat_conn.conn.count_encoders; count++) {
13673 enc.encoder_id = ids[count];
13674 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETENCODER, &enc)) {
13675@@ -3606,6 +4377,8 @@ gather_encoders(struct sna *sna, uint32_t id, int count,
13676 count = 0;
13677 break;
13678 }
13679+ DBG(("%s(%d): encoder=%d, possible_crtcs=%x, possible_clones=%x\n",
13680+ __FUNCTION__, id, enc.encoder_id, enc.possible_crtcs, enc.possible_clones));
13681 out->possible_crtcs |= enc.possible_crtcs;
13682 out->possible_clones |= enc.possible_clones;
13683
13684@@ -3731,6 +4504,116 @@ static int name_from_path(struct sna *sna,
13685 return 0;
13686 }
13687
13688+static char *fake_edid_name(xf86OutputPtr output)
13689+{
13690+ struct sna *sna = to_sna(output->scrn);
13691+ const char *str, *colon;
13692+
13693+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
13694+ str = xf86GetOptValString(sna->Options, OPTION_EDID);
13695+#else
13696+ str = NULL;
13697+#endif
13698+ if (str == NULL)
13699+ return NULL;
13700+
13701+ do {
13702+ colon = strchr(str, ':');
13703+ if (colon == NULL)
13704+ return NULL;
13705+
13706+ if (strncmp(str, output->name, colon-str) == 0 &&
13707+ output->name[colon-str] == '\0') {
13708+ char *path;
13709+ int len;
13710+
13711+ str = colon + 1;
13712+ colon = strchr(str, ',');
13713+ if (colon)
13714+ len = colon - str;
13715+ else
13716+ len = strlen(str);
13717+
13718+ path = malloc(len + 1);
13719+ if (path == NULL)
13720+ return NULL;
13721+
13722+ memcpy(path, str, len);
13723+ path[len] = '\0';
13724+ return path;
13725+ }
13726+
13727+ str = strchr(colon + 1, ',');
13728+ if (str == NULL)
13729+ return NULL;
13730+
13731+ str++;
13732+ } while (1);
13733+}
13734+
13735+static void
13736+sna_output_load_fake_edid(xf86OutputPtr output)
13737+{
13738+ struct sna_output *sna_output = output->driver_private;
13739+ const char *filename;
13740+ FILE *file;
13741+ void *raw;
13742+ int size;
13743+ xf86MonPtr mon;
13744+
13745+ filename = fake_edid_name(output);
13746+ if (filename == NULL)
13747+ return;
13748+
13749+ file = fopen(filename, "rb");
13750+ if (file == NULL)
13751+ goto err;
13752+
13753+ fseek(file, 0, SEEK_END);
13754+ size = ftell(file);
13755+ if (size % 128) {
13756+ fclose(file);
13757+ goto err;
13758+ }
13759+
13760+ raw = malloc(size);
13761+ if (raw == NULL) {
13762+ fclose(file);
13763+ free(raw);
13764+ goto err;
13765+ }
13766+
13767+ fseek(file, 0, SEEK_SET);
13768+ if (fread(raw, size, 1, file) != 1) {
13769+ fclose(file);
13770+ free(raw);
13771+ goto err;
13772+ }
13773+ fclose(file);
13774+
13775+ mon = xf86InterpretEDID(output->scrn->scrnIndex, raw);
13776+ if (mon == NULL) {
13777+ free(raw);
13778+ goto err;
13779+ }
13780+
13781+ if (mon && size > 128)
13782+ mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
13783+
13784+ sna_output->fake_edid_mon = mon;
13785+ sna_output->fake_edid_raw = raw;
13786+
13787+ xf86DrvMsg(output->scrn->scrnIndex, X_CONFIG,
13788+ "Loading EDID from \"%s\" for output %s\n",
13789+ filename, output->name);
13790+ return;
13791+
13792+err:
13793+ xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
13794+ "Could not read EDID file \"%s\" for output %s\n",
13795+ filename, output->name);
13796+}
13797+
13798 static int
13799 sna_output_add(struct sna *sna, unsigned id, unsigned serial)
13800 {
13801@@ -3765,6 +4648,7 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
13802 return -1;
13803 }
13804 assert(compat_conn.conn.connector_id == id);
13805+ DBG(("%s(%d): has %d associated encoders\n", __FUNCTION__, id, compat_conn.conn.count_encoders));
13806
13807 if (compat_conn.conn.connector_type < ARRAY_SIZE(output_names))
13808 output_name = output_names[compat_conn.conn.connector_type];
13809@@ -3813,25 +4697,26 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
13810 }
13811
13812 if (is_zaphod(scrn)) {
13813- const char *str;
13814+ unsigned zaphod_crtcs;
13815
13816- str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
13817- if (str && !sna_zaphod_match(str, name)) {
13818- DBG(("%s: zaphod mismatch, want %s, have %s\n", __FUNCTION__, str, name));
13819+ if (!sna_zaphod_match(sna, name)) {
13820+ DBG(("%s: zaphod mismatch, want %s, have %s\n",
13821+ __FUNCTION__,
13822+ xf86GetOptValString(sna->Options, OPTION_ZAPHOD) ?: "???",
13823+ name));
13824 return 0;
13825 }
13826
13827- if ((possible_crtcs & (1 << scrn->confScreen->device->screen)) == 0) {
13828- if (str) {
13829- xf86DrvMsg(scrn->scrnIndex, X_ERROR,
13830- "%s is an invalid output for screen (pipe) %d\n",
13831- name, scrn->confScreen->device->screen);
13832- return -1;
13833- } else
13834- return 0;
13835+ zaphod_crtcs = get_zaphod_crtcs(sna);
13836+ possible_crtcs &= zaphod_crtcs;
13837+ if (possible_crtcs == 0) {
13838+ xf86DrvMsg(scrn->scrnIndex, X_ERROR,
13839+ "%s is an invalid output for screen %d\n",
13840+ name, scrn->confScreen->device->screen);
13841+ return -1;
13842 }
13843
13844- possible_crtcs = 1;
13845+ possible_crtcs >>= ffs(zaphod_crtcs) - 1;
13846 }
13847
13848 sna_output = calloc(sizeof(struct sna_output), 1);
13849@@ -3841,6 +4726,12 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
13850 sna_output->num_props = compat_conn.conn.count_props;
13851 sna_output->prop_ids = malloc(sizeof(uint32_t)*compat_conn.conn.count_props);
13852 sna_output->prop_values = malloc(sizeof(uint64_t)*compat_conn.conn.count_props);
13853+ if (sna_output->prop_ids == NULL || sna_output->prop_values == NULL) {
13854+ free(sna_output->prop_ids);
13855+ free(sna_output->prop_values);
13856+ free(sna_output);
13857+ return -1;
13858+ }
13859
13860 compat_conn.conn.count_encoders = 0;
13861
13862@@ -3865,16 +4756,16 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
13863 /* Construct name from topology, and recheck if output is acceptable */
13864 path = name_from_path(sna, sna_output, name);
13865 if (path) {
13866- const char *str;
13867-
13868 if (output_ignored(scrn, name)) {
13869 len = 0;
13870 goto skip;
13871 }
13872
13873- str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
13874- if (str && !sna_zaphod_match(str, name)) {
13875- DBG(("%s: zaphod mismatch, want %s, have %s\n", __FUNCTION__, str, name));
13876+ if (is_zaphod(scrn) && !sna_zaphod_match(sna, name)) {
13877+ DBG(("%s: zaphod mismatch, want %s, have %s\n",
13878+ __FUNCTION__,
13879+ xf86GetOptValString(sna->Options, OPTION_ZAPHOD) ?: "???",
13880+ name));
13881 len = 0;
13882 goto skip;
13883 }
13884@@ -3945,10 +4836,8 @@ reset:
13885 sna_output->dpms_mode = sna_output->prop_values[i];
13886 DBG(("%s: found 'DPMS' (idx=%d, id=%d), initial value=%d\n",
13887 __FUNCTION__, i, sna_output->dpms_id, sna_output->dpms_mode));
13888- } else {
13889- sna_output->dpms_id = -1;
13890+ } else
13891 sna_output->dpms_mode = DPMSModeOff;
13892- }
13893
13894 sna_output->possible_encoders = possible_encoders;
13895 sna_output->attached_encoders = attached_encoders;
13896@@ -3969,6 +4858,8 @@ reset:
13897 output->possible_crtcs = possible_crtcs & count_to_mask(sna->mode.num_real_crtc);
13898 output->interlaceAllowed = TRUE;
13899
13900+ sna_output_load_fake_edid(output);
13901+
13902 if (serial) {
13903 if (output->randr_output == NULL) {
13904 output->randr_output = RROutputCreate(xf86ScrnToScreen(scrn), name, len, output);
13905@@ -3976,6 +4867,7 @@ reset:
13906 goto cleanup;
13907 }
13908
13909+ RROutputChanged(output->randr_output, TRUE);
13910 sna_output_create_resources(output);
13911 RRPostPendingProperties(output->randr_output);
13912
13913@@ -4009,38 +4901,6 @@ skip:
13914 return len;
13915 }
13916
13917-static void sna_output_del(xf86OutputPtr output)
13918-{
13919- ScrnInfoPtr scrn = output->scrn;
13920- xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
13921- int i;
13922-
13923- DBG(("%s(%s)\n", __FUNCTION__, output->name));
13924- assert(to_sna_output(output));
13925-
13926- RROutputDestroy(output->randr_output);
13927- sna_output_destroy(output);
13928-
13929- while (output->probed_modes)
13930- xf86DeleteMode(&output->probed_modes, output->probed_modes);
13931-
13932- free(output);
13933-
13934- for (i = 0; i < config->num_output; i++)
13935- if (config->output[i] == output)
13936- break;
13937- assert(i < to_sna(scrn)->mode.num_real_output);
13938- DBG(("%s: removing output #%d of %d\n",
13939- __FUNCTION__, i, to_sna(scrn)->mode.num_real_output));
13940-
13941- for (; i < config->num_output; i++) {
13942- config->output[i] = config->output[i+1];
13943- config->output[i]->possible_clones >>= 1;
13944- }
13945- config->num_output--;
13946- to_sna(scrn)->mode.num_real_output--;
13947-}
13948-
13949 static int output_rank(const void *A, const void *B)
13950 {
13951 const xf86OutputPtr *a = A;
13952@@ -4058,6 +4918,7 @@ static void sort_config_outputs(struct sna *sna)
13953 {
13954 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
13955 qsort(config->output, sna->mode.num_real_output, sizeof(*config->output), output_rank);
13956+ config->compat_output = 0; /* make sure it is a sane value */
13957 sna_mode_compute_possible_outputs(sna);
13958 }
13959
13960@@ -4080,6 +4941,8 @@ static bool disable_unused_crtc(struct sna *sna)
13961 bool update = false;
13962 int o, c;
13963
13964+ DBG(("%s\n", __FUNCTION__));
13965+
13966 for (c = 0; c < sna->mode.num_real_crtc; c++) {
13967 xf86CrtcPtr crtc = config->crtc[c];
13968
13969@@ -4094,7 +4957,7 @@ static bool disable_unused_crtc(struct sna *sna)
13970
13971 if (o == sna->mode.num_real_output) {
13972 DBG(("%s: CRTC:%d was enabled with no outputs\n",
13973- __FUNCTION__, to_sna_crtc(crtc)->id));
13974+ __FUNCTION__, sna_crtc_id(crtc)));
13975 crtc->enabled = false;
13976 update = true;
13977 }
13978@@ -4108,17 +4971,53 @@ static bool disable_unused_crtc(struct sna *sna)
13979 return update;
13980 }
13981
13982-void sna_mode_discover(struct sna *sna)
13983+static bool
13984+output_check_status(struct sna *sna, struct sna_output *output)
13985+{
13986+ union compat_mode_get_connector compat_conn;
13987+ struct drm_mode_modeinfo dummy;
13988+ xf86OutputStatus status;
13989+
13990+ VG_CLEAR(compat_conn);
13991+
13992+ compat_conn.conn.connector_id = output->id;
13993+ compat_conn.conn.count_modes = 1; /* skip detect */
13994+ compat_conn.conn.modes_ptr = (uintptr_t)&dummy;
13995+ compat_conn.conn.count_encoders = 0;
13996+ compat_conn.conn.count_props = 0;
13997+
13998+ (void)drmIoctl(sna->kgem.fd,
13999+ DRM_IOCTL_MODE_GETCONNECTOR,
14000+ &compat_conn.conn);
14001+
14002+ switch (compat_conn.conn.connection) {
14003+ case DRM_MODE_CONNECTED:
14004+ status = XF86OutputStatusConnected;
14005+ break;
14006+ case DRM_MODE_DISCONNECTED:
14007+ status = XF86OutputStatusDisconnected;
14008+ break;
14009+ default:
14010+ case DRM_MODE_UNKNOWNCONNECTION:
14011+ status = XF86OutputStatusUnknown;
14012+ break;
14013+ }
14014+ return output->status == status;
14015+}
14016+
14017+void sna_mode_discover(struct sna *sna, bool tell)
14018 {
14019 ScreenPtr screen = xf86ScrnToScreen(sna->scrn);
14020 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
14021 struct drm_mode_card_res res;
14022- uint32_t connectors[32];
14023+ uint32_t connectors[32], now;
14024 unsigned changed = 0;
14025 unsigned serial;
14026 int i, j;
14027
14028 DBG(("%s()\n", __FUNCTION__));
14029+ sna->flags &= ~SNA_REPROBE;
14030+
14031 VG_CLEAR(connectors);
14032
14033 memset(&res, 0, sizeof(res));
14034@@ -4128,8 +5027,9 @@ void sna_mode_discover(struct sna *sna)
14035 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
14036 return;
14037
14038- DBG(("%s: now %d (was %d) connectors\n", __FUNCTION__,
14039- res.count_connectors, sna->mode.num_real_output));
14040+ DBG(("%s: now %d (was %d) connectors, %d encoders, %d crtc\n", __FUNCTION__,
14041+ res.count_connectors, sna->mode.num_real_output,
14042+ res.count_encoders, res.count_crtcs));
14043 if (res.count_connectors > 32)
14044 return;
14045
14046@@ -4142,6 +5042,7 @@ void sna_mode_discover(struct sna *sna)
14047 if (serial == 0)
14048 serial = ++sna->mode.serial;
14049
14050+ now = GetTimeInMillis();
14051 for (i = 0; i < res.count_connectors; i++) {
14052 DBG(("%s: connector[%d] = %d\n", __FUNCTION__, i, connectors[i]));
14053 for (j = 0; j < sna->mode.num_real_output; j++) {
14054@@ -4161,32 +5062,41 @@ void sna_mode_discover(struct sna *sna)
14055
14056 for (i = 0; i < sna->mode.num_real_output; i++) {
14057 xf86OutputPtr output = config->output[i];
14058+ struct sna_output *sna_output = to_sna_output(output);
14059
14060- if (to_sna_output(output)->id == 0)
14061+ if (sna_output->id == 0)
14062 continue;
14063
14064- if (to_sna_output(output)->serial == serial)
14065+ if (sna_output->serial == serial) {
14066+ if (output_check_status(sna, sna_output)) {
14067+ DBG(("%s: output %s (id=%d), retained state\n",
14068+ __FUNCTION__, output->name, sna_output->id));
14069+ sna_output->last_detect = now;
14070+ } else {
14071+ DBG(("%s: output %s (id=%d), changed state, reprobing\n",
14072+ __FUNCTION__, output->name, sna_output->id));
14073+ sna_output->last_detect = 0;
14074+ changed |= 4;
14075+ }
14076 continue;
14077+ }
14078
14079 DBG(("%s: removing output %s (id=%d), serial=%u [now %u]\n",
14080- __FUNCTION__, output->name, to_sna_output(output)->id,
14081- to_sna_output(output)->serial, serial));
14082+ __FUNCTION__, output->name, sna_output->id,
14083+ sna_output->serial, serial));
14084
14085 xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
14086- "%s output %s\n",
14087- sna->flags & SNA_REMOVE_OUTPUTS ? "Removed" : "Disabled",
14088+ "Disabled output %s\n",
14089 output->name);
14090- if (sna->flags & SNA_REMOVE_OUTPUTS) {
14091- sna_output_del(output);
14092- i--;
14093- } else {
14094- to_sna_output(output)->id = 0;
14095- output->crtc = NULL;
14096- }
14097+ sna_output->id = 0;
14098+ sna_output->last_detect = 0;
14099+ output->crtc = NULL;
14100+ RROutputChanged(output->randr_output, TRUE);
14101 changed |= 2;
14102 }
14103
14104- if (changed) {
14105+ /* Have the list of available outputs been updated? */
14106+ if (changed & 3) {
14107 DBG(("%s: outputs changed, broadcasting\n", __FUNCTION__));
14108
14109 sna_mode_set_primary(sna);
14110@@ -4200,6 +5110,51 @@ void sna_mode_discover(struct sna *sna)
14111
14112 xf86RandR12TellChanged(screen);
14113 }
14114+
14115+ /* If anything has changed, refresh the RandR information.
14116+ * Note this could recurse once from udevless RRGetInfo() probes,
14117+ * but only once.
14118+ */
14119+ if (changed && tell)
14120+ RRGetInfo(screen, TRUE);
14121+}
14122+
14123+/* Since we only probe the current mode on startup, we may not have the full
14124+ * list of modes available until the user explicitly requests them. Fake a
14125+ * hotplug event after a second after starting to fill in any missing modes.
14126+ */
14127+static CARD32 sna_mode_coldplug(OsTimerPtr timer, CARD32 now, void *data)
14128+{
14129+ struct sna *sna = data;
14130+ ScreenPtr screen = xf86ScrnToScreen(sna->scrn);
14131+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
14132+ bool reprobe = false;
14133+ int i;
14134+
14135+ DBG(("%s()\n", __FUNCTION__));
14136+
14137+ for (i = 0; i < sna->mode.num_real_output; i++) {
14138+ xf86OutputPtr output = config->output[i];
14139+ struct sna_output *sna_output = to_sna_output(output);
14140+
14141+ if (sna_output->id == 0)
14142+ continue;
14143+ if (sna_output->last_detect)
14144+ continue;
14145+ if (output->status == XF86OutputStatusDisconnected)
14146+ continue;
14147+
14148+ DBG(("%s: output %s connected, needs reprobe\n",
14149+ __FUNCTION__, output->name));
14150+ reprobe = true;
14151+ }
14152+
14153+ if (reprobe) {
14154+ RRGetInfo(screen, TRUE);
14155+ RRTellChanged(screen);
14156+ }
14157+ free(timer);
14158+ return 0;
14159 }
14160
14161 static void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new)
14162@@ -4208,7 +5163,7 @@ static void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new)
14163
14164 DBG(("%s\n", __FUNCTION__));
14165
14166- if (wedged(sna))
14167+ if (wedged(sna) || isGPU(sna->scrn))
14168 return;
14169
14170 old_priv = sna_pixmap_force_to_gpu(old, MOVE_READ);
14171@@ -4220,12 +5175,19 @@ static void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new)
14172 return;
14173
14174 if (old_priv->clear) {
14175- (void)sna->render.fill_one(sna, new, new_priv->gpu_bo,
14176- old_priv->clear_color,
14177- 0, 0,
14178- new->drawable.width,
14179- new->drawable.height,
14180- GXcopy);
14181+ bool ok = false;
14182+ if (!wedged(sna))
14183+ ok = sna->render.fill_one(sna, new, new_priv->gpu_bo,
14184+ old_priv->clear_color,
14185+ 0, 0,
14186+ new->drawable.width,
14187+ new->drawable.height,
14188+ GXcopy);
14189+ if (!ok) {
14190+ void *ptr = kgem_bo_map__gtt(&sna->kgem, new_priv->gpu_bo);
14191+ if (ptr)
14192+ memset(ptr, 0, new_priv->gpu_bo->pitch*new->drawable.height);
14193+ }
14194 new_priv->clear = true;
14195 new_priv->clear_color = old_priv->clear_color;
14196 } else {
14197@@ -4281,11 +5243,18 @@ static void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new)
14198 __FUNCTION__, box.x2, box.y2, sx, sy, dx, dy));
14199
14200 if (box.x2 != new->drawable.width || box.y2 != new->drawable.height) {
14201- (void)sna->render.fill_one(sna, new, new_priv->gpu_bo, 0,
14202- 0, 0,
14203- new->drawable.width,
14204- new->drawable.height,
14205- GXclear);
14206+ bool ok = false;
14207+ if (!wedged(sna))
14208+ ok = sna->render.fill_one(sna, new, new_priv->gpu_bo, 0,
14209+ 0, 0,
14210+ new->drawable.width,
14211+ new->drawable.height,
14212+ GXclear);
14213+ if (!ok) {
14214+ void *ptr = kgem_bo_map__gtt(&sna->kgem, new_priv->gpu_bo);
14215+ if (ptr)
14216+ memset(ptr, 0, new_priv->gpu_bo->pitch*new->drawable.height);
14217+ }
14218 }
14219 (void)sna->render.copy_boxes(sna, GXcopy,
14220 &old->drawable, old_priv->gpu_bo, sx, sy,
14221@@ -4302,7 +5271,7 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
14222 {
14223 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
14224 struct sna *sna = to_sna(scrn);
14225- ScreenPtr screen = scrn->pScreen;
14226+ ScreenPtr screen = xf86ScrnToScreen(scrn);
14227 PixmapPtr new_front;
14228 int i;
14229
14230@@ -4337,6 +5306,7 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
14231 for (i = 0; i < sna->mode.num_real_crtc; i++)
14232 sna_crtc_disable_shadow(sna, to_sna_crtc(config->crtc[i]));
14233 assert(sna->mode.shadow_active == 0);
14234+ assert(!sna->mode.shadow_enabled);
14235 assert(sna->mode.shadow_damage == NULL);
14236 assert(sna->mode.shadow == NULL);
14237
14238@@ -4371,7 +5341,7 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
14239 continue;
14240
14241 if (!__sna_crtc_set_mode(crtc))
14242- sna_crtc_disable(crtc);
14243+ sna_crtc_disable(crtc, false);
14244 }
14245
14246 sna_mode_wakeup(sna);
14247@@ -4381,19 +5351,6 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
14248 }
14249
14250 /* cursor handling */
14251-struct sna_cursor {
14252- struct sna_cursor *next;
14253- uint32_t *image;
14254- Rotation rotation;
14255- int ref;
14256- int size;
14257- int last_width;
14258- int last_height;
14259- unsigned handle;
14260- unsigned serial;
14261- unsigned alloc;
14262-};
14263-
14264 static void
14265 rotate_coord(Rotation rotation, int size,
14266 int x_dst, int y_dst,
14267@@ -4429,36 +5386,6 @@ rotate_coord(Rotation rotation, int size,
14268 *y_src = y_dst;
14269 }
14270
14271-static void
14272-rotate_coord_back(Rotation rotation, int size, int *x, int *y)
14273-{
14274- int t;
14275-
14276- if (rotation & RR_Reflect_X)
14277- *x = size - *x - 1;
14278- if (rotation & RR_Reflect_Y)
14279- *y = size - *y - 1;
14280-
14281- switch (rotation & 0xf) {
14282- case RR_Rotate_0:
14283- break;
14284- case RR_Rotate_90:
14285- t = *x;
14286- *x = *y;
14287- *y = size - t - 1;
14288- break;
14289- case RR_Rotate_180:
14290- *x = size - *x - 1;
14291- *y = size - *y - 1;
14292- break;
14293- case RR_Rotate_270:
14294- t = *x;
14295- *x = size - *y - 1;
14296- *y = t;
14297- break;
14298- }
14299-}
14300-
14301 static struct sna_cursor *__sna_create_cursor(struct sna *sna, int size)
14302 {
14303 struct sna_cursor *c;
14304@@ -4519,6 +5446,17 @@ static uint32_t *get_cursor_argb(CursorPtr c)
14305 #endif
14306 }
14307
14308+static int __cursor_size(int width, int height)
14309+{
14310+ int i, size;
14311+
14312+ i = MAX(width, height);
14313+ for (size = 64; size < i; size <<= 1)
14314+ ;
14315+
14316+ return size;
14317+}
14318+
14319 static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
14320 {
14321 struct sna_cursor *cursor;
14322@@ -4526,6 +5464,8 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
14323 const uint32_t *argb;
14324 uint32_t *image;
14325 int width, height, pitch, size, x, y;
14326+ PictTransform cursor_to_fb;
14327+ bool transformed;
14328 Rotation rotation;
14329
14330 assert(sna->cursor.ref);
14331@@ -4537,8 +5477,8 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
14332 cursor ? cursor->serial : 0,
14333 sna->cursor.serial));
14334 if (cursor && cursor->serial == sna->cursor.serial) {
14335- assert(cursor->size == sna->cursor.size);
14336- assert(cursor->rotation == crtc->transform_in_use ? crtc->rotation : RR_Rotate_0);
14337+ assert(cursor->size == sna->cursor.size || cursor->transformed);
14338+ assert(cursor->rotation == (!to_sna_crtc(crtc)->cursor_transform && crtc->transform_in_use) ? crtc->rotation : RR_Rotate_0);
14339 assert(cursor->ref);
14340 return cursor;
14341 }
14342@@ -4550,22 +5490,44 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
14343 sna->cursor.serial,
14344 get_cursor_argb(sna->cursor.ref) != NULL));
14345
14346- rotation = crtc->transform_in_use ? crtc->rotation : RR_Rotate_0;
14347+ transformed = to_sna_crtc(crtc)->cursor_transform;
14348+ rotation = (!transformed && crtc->transform_in_use) ? crtc->rotation : RR_Rotate_0;
14349
14350- if (sna->cursor.use_gtt) { /* Don't allow phys cursor sharing */
14351+ /* Don't allow phys cursor sharing */
14352+ if (sna->cursor.use_gtt && !transformed) {
14353 for (cursor = sna->cursor.cursors; cursor; cursor = cursor->next) {
14354- if (cursor->serial == sna->cursor.serial && cursor->rotation == rotation) {
14355+ if (cursor->serial == sna->cursor.serial &&
14356+ cursor->rotation == rotation &&
14357+ !cursor->transformed) {
14358 __DBG(("%s: reusing handle=%d, serial=%d, rotation=%d, size=%d\n",
14359 __FUNCTION__, cursor->handle, cursor->serial, cursor->rotation, cursor->size));
14360 assert(cursor->size == sna->cursor.size);
14361 return cursor;
14362 }
14363 }
14364-
14365- cursor = to_sna_crtc(crtc)->cursor;
14366 }
14367
14368- size = sna->cursor.size;
14369+ if (transformed) {
14370+ struct pixman_box16 box;
14371+
14372+ box.x1 = box.y1 = 0;
14373+ box.x2 = sna->cursor.ref->bits->width;
14374+ box.y2 = sna->cursor.ref->bits->height;
14375+
14376+ pixman_f_transform_bounds(&crtc->f_crtc_to_framebuffer, &box);
14377+ size = __cursor_size(box.x2 - box.x1, box.y2 - box.y1);
14378+ } else
14379+ size = sna->cursor.size;
14380+
14381+ if (crtc->transform_in_use)
14382+ RRTransformCompute(0, 0, size, size,
14383+ crtc->rotation,
14384+ crtc->transformPresent ? &crtc->transform : NULL,
14385+ &cursor_to_fb,
14386+ &to_sna_crtc(crtc)->cursor_to_fb,
14387+ &to_sna_crtc(crtc)->fb_to_cursor);
14388+
14389+ cursor = to_sna_crtc(crtc)->cursor;
14390 if (cursor && cursor->alloc < 4*size*size)
14391 cursor = NULL;
14392
14393@@ -4577,7 +5539,7 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
14394 }
14395 }
14396
14397- width = sna->cursor.ref->bits->width;
14398+ width = sna->cursor.ref->bits->width;
14399 height = sna->cursor.ref->bits->height;
14400 source = sna->cursor.ref->bits->source;
14401 mask = sna->cursor.ref->bits->mask;
14402@@ -4585,7 +5547,7 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
14403 pitch = BitmapBytePad(width);
14404
14405 image = cursor->image;
14406- if (image == NULL) {
14407+ if (image == NULL || transformed) {
14408 image = sna->cursor.scratch;
14409 cursor->last_width = cursor->last_height = size;
14410 }
14411@@ -4616,6 +5578,19 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
14412 mask += pitch;
14413 source += pitch;
14414 }
14415+ if (transformed) {
14416+ affine_blt(image, cursor->image, 32,
14417+ 0, 0, width, height, size * 4,
14418+ 0, 0, size, size, size * 4,
14419+ &to_sna_crtc(crtc)->cursor_to_fb);
14420+ image = cursor->image;
14421+ }
14422+ } else if (transformed) {
14423+ affine_blt(argb, cursor->image, 32,
14424+ 0, 0, width, height, width * 4,
14425+ 0, 0, size, size, size * 4,
14426+ &to_sna_crtc(crtc)->cursor_to_fb);
14427+ image = cursor->image;
14428 } else
14429 memcpy_blt(argb, image, 32,
14430 width * 4, size * 4,
14431@@ -4662,6 +5637,7 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
14432
14433 cursor->size = size;
14434 cursor->rotation = rotation;
14435+ cursor->transformed = transformed;
14436 cursor->serial = sna->cursor.serial;
14437 cursor->last_width = width;
14438 cursor->last_height = height;
14439@@ -4674,28 +5650,39 @@ sna_realize_cursor(xf86CursorInfoPtr info, CursorPtr cursor)
14440 return NULL;
14441 }
14442
14443-#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
14444-static inline int sigio_block(void)
14445+static void enable_fb_access(ScrnInfoPtr scrn, int state)
14446 {
14447- OsBlockSIGIO();
14448- return 0;
14449-}
14450-static inline void sigio_unblock(int was_blocked)
14451-{
14452- OsReleaseSIGIO();
14453- (void)was_blocked;
14454-}
14455+ scrn->EnableDisableFBAccess(
14456+#ifdef XF86_HAS_SCRN_CONV
14457+ scrn,
14458 #else
14459-#include <xf86_OSproc.h>
14460-static inline int sigio_block(void)
14461+ scrn->scrnIndex,
14462+#endif
14463+ state);
14464+}
14465+
14466+
14467+static void __restore_swcursor(ScrnInfoPtr scrn)
14468 {
14469- return xf86BlockSIGIO();
14470+ DBG(("%s: attempting to restore SW cursor\n", __FUNCTION__));
14471+ enable_fb_access(scrn, FALSE);
14472+ enable_fb_access(scrn, TRUE);
14473+
14474+ RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)__restore_swcursor,
14475+ (WakeupHandlerProcPtr)NoopDDA,
14476+ scrn);
14477 }
14478-static inline void sigio_unblock(int was_blocked)
14479+
14480+static void restore_swcursor(struct sna *sna)
14481 {
14482- xf86UnblockSIGIO(was_blocked);
14483+ /* XXX Force the cursor to be restored (avoiding recursion) */
14484+ FreeCursor(sna->cursor.ref, None);
14485+ sna->cursor.ref = NULL;
14486+
14487+ RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)__restore_swcursor,
14488+ (WakeupHandlerProcPtr)NoopDDA,
14489+ sna->scrn);
14490 }
14491-#endif
14492
14493 static void
14494 sna_show_cursors(ScrnInfoPtr scrn)
14495@@ -4721,7 +5708,7 @@ sna_show_cursors(ScrnInfoPtr scrn)
14496
14497 if (!crtc->cursor_in_range) {
14498 DBG(("%s: skipping cursor outside CRTC (pipe=%d)\n",
14499- __FUNCTION__, sna_crtc->pipe));
14500+ __FUNCTION__, sna_crtc_pipe(crtc)));
14501 continue;
14502 }
14503
14504@@ -4729,16 +5716,16 @@ sna_show_cursors(ScrnInfoPtr scrn)
14505 if (cursor == NULL ||
14506 (sna_crtc->cursor == cursor && sna_crtc->last_cursor_size == cursor->size)) {
14507 DBG(("%s: skipping cursor already show on CRTC (pipe=%d)\n",
14508- __FUNCTION__, sna_crtc->pipe));
14509+ __FUNCTION__, sna_crtc_pipe(crtc)));
14510 continue;
14511 }
14512
14513 DBG(("%s: CRTC pipe=%d, handle->%d\n", __FUNCTION__,
14514- sna_crtc->pipe, cursor->handle));
14515+ sna_crtc_pipe(crtc), cursor->handle));
14516
14517 VG_CLEAR(arg);
14518 arg.flags = DRM_MODE_CURSOR_BO;
14519- arg.crtc_id = sna_crtc->id;
14520+ arg.crtc_id = __sna_crtc_id(sna_crtc);
14521 arg.width = arg.height = cursor->size;
14522 arg.handle = cursor->handle;
14523
14524@@ -4750,10 +5737,17 @@ sna_show_cursors(ScrnInfoPtr scrn)
14525 cursor->ref++;
14526 sna_crtc->cursor = cursor;
14527 sna_crtc->last_cursor_size = cursor->size;
14528+ } else {
14529+ ERR(("%s: failed to show cursor on CRTC:%d [pipe=%d], disabling hwcursor\n",
14530+ __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc)));
14531+ sna->cursor.disable = true;
14532 }
14533 }
14534 sigio_unblock(sigio);
14535 sna->cursor.active = true;
14536+
14537+ if (unlikely(sna->cursor.disable))
14538+ restore_swcursor(sna);
14539 }
14540
14541 static void
14542@@ -4789,24 +5783,45 @@ static void
14543 sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc)
14544 {
14545 struct drm_mode_cursor arg;
14546+ int sigio;
14547
14548 if (!crtc->cursor)
14549 return;
14550
14551- DBG(("%s: CRTC:%d, handle=%d\n", __FUNCTION__, crtc->id, crtc->cursor->handle));
14552- assert(crtc->cursor->ref);
14553+ sigio = sigio_block();
14554+ if (crtc->cursor) {
14555+ DBG(("%s: CRTC:%d, handle=%d\n", __FUNCTION__, __sna_crtc_id(crtc), crtc->cursor->handle));
14556+ assert(crtc->cursor->ref > 0);
14557+ crtc->cursor->ref--;
14558+ crtc->cursor = NULL;
14559+ crtc->last_cursor_size = 0;
14560
14561- VG_CLEAR(arg);
14562- arg.flags = DRM_MODE_CURSOR_BO;
14563- arg.crtc_id = crtc->id;
14564- arg.width = arg.height = 0;
14565- arg.handle = 0;
14566+ VG_CLEAR(arg);
14567+ arg.flags = DRM_MODE_CURSOR_BO;
14568+ arg.crtc_id = __sna_crtc_id(crtc);
14569+ arg.width = arg.height = 0;
14570+ arg.handle = 0;
14571
14572- (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg);
14573- assert(crtc->cursor->ref > 0);
14574- crtc->cursor->ref--;
14575- crtc->cursor = NULL;
14576- crtc->last_cursor_size = 0;
14577+ (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg);
14578+ }
14579+ sigio_unblock(sigio);
14580+}
14581+
14582+static void
14583+sna_disable_cursors(ScrnInfoPtr scrn)
14584+{
14585+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
14586+ struct sna *sna = to_sna(scrn);
14587+ int sigio, c;
14588+
14589+ DBG(("%s\n", __FUNCTION__));
14590+
14591+ sigio = sigio_block();
14592+ for (c = 0; c < sna->mode.num_real_crtc; c++) {
14593+ assert(to_sna_crtc(xf86_config->crtc[c]));
14594+ sna_crtc_disable_cursor(sna, to_sna_crtc(xf86_config->crtc[c]));
14595+ }
14596+ sigio_unblock(sigio);
14597 }
14598
14599 static void
14600@@ -4876,7 +5891,7 @@ sna_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
14601
14602 VG_CLEAR(arg);
14603 arg.flags = 0;
14604- arg.crtc_id = sna_crtc->id;
14605+ arg.crtc_id = __sna_crtc_id(sna_crtc);
14606 arg.handle = 0;
14607
14608 if (sna_crtc->bo == NULL)
14609@@ -4885,18 +5900,20 @@ sna_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
14610 if (crtc->transform_in_use) {
14611 int xhot = sna->cursor.ref->bits->xhot;
14612 int yhot = sna->cursor.ref->bits->yhot;
14613- struct pict_f_vector v;
14614+ struct pict_f_vector v, hot;
14615
14616- v.v[0] = (x + xhot) + 0.5;
14617- v.v[1] = (y + yhot) + 0.5;
14618- v.v[2] = 1;
14619+ v.v[0] = x + xhot + .5;
14620+ v.v[1] = y + yhot + .5;
14621+ v.v[2] = 1.;
14622 pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &v);
14623
14624- rotate_coord_back(crtc->rotation, sna->cursor.size, &xhot, &yhot);
14625+ hot.v[0] = xhot;
14626+ hot.v[1] = yhot;
14627+ hot.v[2] = 1.;
14628+ pixman_f_transform_point(&sna_crtc->fb_to_cursor, &hot);
14629
14630- /* cursor will have 0.5 added to it already so floor is sufficent */
14631- arg.x = floor(v.v[0]) - xhot;
14632- arg.y = floor(v.v[1]) - yhot;
14633+ arg.x = floor(v.v[0] - hot.v[0]);
14634+ arg.y = floor(v.v[1] - hot.v[1]);
14635 } else {
14636 arg.x = x - crtc->x;
14637 arg.y = y - crtc->y;
14638@@ -4932,11 +5949,13 @@ disable:
14639 }
14640
14641 __DBG(("%s: CRTC:%d (%d, %d), handle=%d, flags=%x (old cursor handle=%d), move? %d, update handle? %d\n",
14642- __FUNCTION__, sna_crtc->id, arg.x, arg.y, arg.handle, arg.flags, sna_crtc->cursor ? sna_crtc->cursor->handle : 0,
14643+ __FUNCTION__, __sna_crtc_id(sna_crtc), arg.x, arg.y, arg.handle, arg.flags, sna_crtc->cursor ? sna_crtc->cursor->handle : 0,
14644 arg.flags & DRM_MODE_CURSOR_MOVE, arg.flags & DRM_MODE_CURSOR_BO));
14645
14646- if (arg.flags &&
14647- drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg) == 0) {
14648+ if (arg.flags == 0)
14649+ continue;
14650+
14651+ if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg) == 0) {
14652 if (arg.flags & DRM_MODE_CURSOR_BO) {
14653 if (sna_crtc->cursor) {
14654 assert(sna_crtc->cursor->ref > 0);
14655@@ -4949,9 +5968,20 @@ disable:
14656 } else
14657 sna_crtc->last_cursor_size = 0;
14658 }
14659+ } else {
14660+ ERR(("%s: failed to update cursor on CRTC:%d [pipe=%d], disabling hwcursor\n",
14661+ __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc)));
14662+ /* XXX How to force switch back to SW cursor?
14663+ * Right now we just want until the next cursor image
14664+ * change, which is fairly frequent.
14665+ */
14666+ sna->cursor.disable = true;
14667 }
14668 }
14669 sigio_unblock(sigio);
14670+
14671+ if (unlikely(sna->cursor.disable))
14672+ restore_swcursor(sna);
14673 }
14674
14675 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,2)
14676@@ -4978,17 +6008,6 @@ sna_load_cursor_image(ScrnInfoPtr scrn, unsigned char *src)
14677 {
14678 }
14679
14680-static int __cursor_size(CursorPtr cursor)
14681-{
14682- int i, size;
14683-
14684- i = MAX(cursor->bits->width, cursor->bits->height);
14685- for (size = 64; size < i; size <<= 1)
14686- ;
14687-
14688- return size;
14689-}
14690-
14691 static bool
14692 sna_cursor_preallocate(struct sna *sna)
14693 {
14694@@ -5006,6 +6025,50 @@ sna_cursor_preallocate(struct sna *sna)
14695 return true;
14696 }
14697
14698+static bool
14699+transformable_cursor(struct sna *sna, CursorPtr cursor)
14700+{
14701+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
14702+ int i;
14703+
14704+ for (i = 0; i < sna->mode.num_real_crtc; i++) {
14705+ xf86CrtcPtr crtc = config->crtc[i];
14706+ struct pixman_box16 box;
14707+ int size;
14708+
14709+ if (!to_sna_crtc(crtc)->hwcursor) {
14710+ DBG(("%s: hwcursor disabled on CRTC:%d [pipe=%d]\n",
14711+ __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc)));
14712+ return false;
14713+ }
14714+
14715+ if (!sna->cursor.use_gtt || !sna->cursor.scratch) {
14716+ DBG(("%s: unable to use GTT curosor access [%d] or no scratch [%d]\n",
14717+ __FUNCTION__, sna->cursor.use_gtt, sna->cursor.scratch));
14718+ return false;
14719+ }
14720+
14721+ box.x1 = box.y1 = 0;
14722+ box.x2 = cursor->bits->width;
14723+ box.y2 = cursor->bits->height;
14724+
14725+ if (!pixman_f_transform_bounds(&crtc->f_crtc_to_framebuffer,
14726+ &box)) {
14727+ DBG(("%s: unable to transform bounds\n", __FUNCTION__));
14728+ return false;
14729+ }
14730+
14731+ size = __cursor_size(box.x2 - box.x1, box.y2 - box.y1);
14732+ if (size > sna->cursor.max_size) {
14733+ DBG(("%s: transformed cursor size=%d too large, max=%d\n",
14734+ __FUNCTION__, size, sna->cursor.max_size));
14735+ return false;
14736+ }
14737+ }
14738+
14739+ return true;
14740+}
14741+
14742 static Bool
14743 sna_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
14744 {
14745@@ -5014,6 +6077,9 @@ sna_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
14746 DBG(("%s (%dx%d)?\n", __FUNCTION__,
14747 cursor->bits->width, cursor->bits->height));
14748
14749+ if (sna->cursor.disable)
14750+ return FALSE;
14751+
14752 /* cursors are invariant */
14753 if (cursor == sna->cursor.ref)
14754 return TRUE;
14755@@ -5023,12 +6089,24 @@ sna_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
14756 sna->cursor.ref = NULL;
14757 }
14758
14759- sna->cursor.size = __cursor_size(cursor);
14760- if (sna->cursor.size > sna->cursor.max_size)
14761+ sna->cursor.size =
14762+ __cursor_size(cursor->bits->width, cursor->bits->height);
14763+ if (sna->cursor.size > sna->cursor.max_size) {
14764+ DBG(("%s: cursor size=%d too large, max %d: using sw cursor\n",
14765+ __FUNCTION__, sna->cursor.size, sna->cursor.max_size));
14766+ return FALSE;
14767+ }
14768+
14769+ if (sna->mode.rr_active && !transformable_cursor(sna, cursor)) {
14770+ DBG(("%s: RandR active [%d] and non-transformable cursor: using sw cursor\n",
14771+ __FUNCTION__, sna->mode.rr_active));
14772 return FALSE;
14773+ }
14774
14775- if (!sna_cursor_preallocate(sna))
14776+ if (!sna_cursor_preallocate(sna)) {
14777+ DBG(("%s: cursor preallocation failed: using sw cursor\n", __FUNCTION__));
14778 return FALSE;
14779+ }
14780
14781 sna->cursor.ref = cursor;
14782 cursor->refcnt++;
14783@@ -5087,11 +6165,9 @@ sna_cursor_pre_init(struct sna *sna)
14784 DBG(("%s: cursor updates use_gtt?=%d\n",
14785 __FUNCTION__, sna->cursor.use_gtt));
14786
14787- if (!sna->cursor.use_gtt) {
14788- sna->cursor.scratch = malloc(sna->cursor.max_size * sna->cursor.max_size * 4);
14789- if (!sna->cursor.scratch)
14790- sna->cursor.max_size = 0;
14791- }
14792+ sna->cursor.scratch = malloc(sna->cursor.max_size * sna->cursor.max_size * 4);
14793+ if (!sna->cursor.scratch && !sna->cursor.use_gtt)
14794+ sna->cursor.max_size = 0;
14795
14796 sna->cursor.num_stash = -sna->mode.num_real_crtc;
14797
14798@@ -5193,7 +6269,7 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
14799 int output_count = 0;
14800 int i;
14801
14802- DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, crtc->id, crtc->pipe, bo->handle));
14803+ DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), bo->handle));
14804
14805 assert(sna->mode.num_real_output < ARRAY_SIZE(output_ids));
14806 assert(crtc->bo);
14807@@ -5207,11 +6283,11 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
14808
14809 DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n",
14810 __FUNCTION__, output->name, i, to_connector_id(output),
14811- crtc->id, crtc->pipe,
14812+ __sna_crtc_id(crtc), __sna_crtc_pipe(crtc),
14813 (uint32_t)output->possible_crtcs,
14814 (uint32_t)output->possible_clones));
14815
14816- assert(output->possible_crtcs & (1 << crtc->pipe) ||
14817+ assert(output->possible_crtcs & (1 << __sna_crtc_pipe(crtc)) ||
14818 is_zaphod(sna->scrn));
14819
14820 output_ids[output_count] = to_connector_id(output);
14821@@ -5221,7 +6297,7 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
14822 assert(output_count);
14823
14824 VG_CLEAR(arg);
14825- arg.crtc_id = crtc->id;
14826+ arg.crtc_id = __sna_crtc_id(crtc);
14827 arg.fb_id = fb_id(bo);
14828 assert(arg.fb_id);
14829 arg.x = x;
14830@@ -5232,7 +6308,7 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
14831 arg.mode_valid = 1;
14832
14833 DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d across %d outputs [%d...]\n",
14834- __FUNCTION__, crtc->id, crtc->pipe,
14835+ __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc),
14836 arg.mode.hdisplay,
14837 arg.mode.vdisplay,
14838 arg.x, arg.y,
14839@@ -5247,6 +6323,37 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
14840 return true;
14841 }
14842
14843+static void sna_mode_restore(struct sna *sna)
14844+{
14845+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
14846+ int error = 0;
14847+ int i;
14848+
14849+ assert(!sna->mode.hidden);
14850+
14851+ for (i = 0; i < sna->mode.num_real_crtc; i++) {
14852+ xf86CrtcPtr crtc = config->crtc[i];
14853+
14854+ assert(to_sna_crtc(crtc) != NULL);
14855+ if (to_sna_crtc(crtc)->bo == NULL)
14856+ continue;
14857+
14858+ assert(crtc->enabled);
14859+ if (!__sna_crtc_set_mode(crtc)) {
14860+ sna_crtc_disable(crtc, false);
14861+ error++;
14862+ }
14863+ }
14864+ sna_mode_wakeup(sna);
14865+ update_flush_interval(sna);
14866+ sna_cursors_reload(sna);
14867+ sna->mode.dirty = false;
14868+
14869+ if (error)
14870+ xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
14871+ "Failed to restore display configuration\n");
14872+}
14873+
14874 int
14875 sna_page_flip(struct sna *sna,
14876 struct kgem_bo *bo,
14877@@ -5263,9 +6370,9 @@ sna_page_flip(struct sna *sna,
14878 assert(bo->refcnt);
14879
14880 assert((sna->flags & SNA_IS_HOSTED) == 0);
14881- assert((sna->flags & SNA_TEAR_FREE) == 0);
14882 assert(sna->mode.flip_active == 0);
14883 assert(sna->mode.front_active);
14884+ assert(!sna->mode.hidden);
14885 assert(sna->scrn->vtSema);
14886
14887 if ((sna->flags & (data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP)) == 0)
14888@@ -5277,9 +6384,10 @@ sna_page_flip(struct sna *sna,
14889 struct sna_crtc *crtc = config->crtc[i]->driver_private;
14890 struct drm_mode_crtc_page_flip arg;
14891 uint32_t crtc_offset;
14892+ int fixup;
14893
14894 DBG(("%s: crtc %d id=%d, pipe=%d active? %d\n",
14895- __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo != NULL));
14896+ __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->bo != NULL));
14897 if (crtc->bo == NULL)
14898 continue;
14899 assert(!crtc->transform);
14900@@ -5288,13 +6396,17 @@ sna_page_flip(struct sna *sna,
14901 assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
14902 assert(crtc->flip_bo == NULL);
14903
14904- arg.crtc_id = crtc->id;
14905+ if (data == NULL && crtc->bo == bo)
14906+ goto next_crtc;
14907+
14908+ arg.crtc_id = __sna_crtc_id(crtc);
14909 arg.fb_id = get_fb(sna, bo, width, height);
14910 if (arg.fb_id == 0) {
14911 assert(count == 0);
14912 return 0;
14913 }
14914
14915+ fixup = 0;
14916 crtc_offset = crtc->base->y << 16 | crtc->base->x;
14917
14918 if (bo->pitch != crtc->bo->pitch || crtc_offset != crtc->offset) {
14919@@ -5303,7 +6415,12 @@ sna_page_flip(struct sna *sna,
14920 bo->pitch, crtc->bo->pitch,
14921 crtc_offset, crtc->offset));
14922 fixup_flip:
14923+ fixup = 1;
14924 if (crtc->bo != bo && sna_crtc_flip(sna, crtc, bo, crtc->base->x, crtc->base->y)) {
14925+update_scanout:
14926+ DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n",
14927+ __FUNCTION__, crtc->bo->handle, crtc->bo->active_scanout,
14928+ bo->handle, bo->active_scanout));
14929 assert(crtc->bo->active_scanout);
14930 assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
14931 crtc->bo->active_scanout--;
14932@@ -5319,17 +6436,10 @@ fixup_flip:
14933
14934 if (data == NULL)
14935 goto next_crtc;
14936-
14937- /* queue a flip in order to send the event */
14938- } else {
14939- if (count && !xf86SetDesiredModes(sna->scrn)) {
14940- xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
14941- "failed to restore display configuration\n");
14942- for (; i < sna->mode.num_real_crtc; i++)
14943- sna_crtc_disable(config->crtc[i]);
14944- }
14945- return 0;
14946- }
14947+
14948+ /* queue a flip in order to send the event */
14949+ } else
14950+ goto error;
14951 }
14952
14953 /* Only the reference crtc will finally deliver its page flip
14954@@ -5346,7 +6456,7 @@ fixup_flip:
14955
14956 retry_flip:
14957 DBG(("%s: crtc %d id=%d, pipe=%d --> fb %d\n",
14958- __FUNCTION__, i, crtc->id, crtc->pipe, arg.fb_id));
14959+ __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), arg.fb_id));
14960 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
14961 ERR(("%s: pageflip failed with err=%d\n", __FUNCTION__, errno));
14962
14963@@ -5354,7 +6464,7 @@ retry_flip:
14964 struct drm_mode_crtc mode;
14965
14966 memset(&mode, 0, sizeof(mode));
14967- mode.crtc_id = crtc->id;
14968+ mode.crtc_id = __sna_crtc_id(crtc);
14969 drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode);
14970
14971 DBG(("%s: crtc=%d, valid?=%d, fb attached?=%d, expected=%d\n",
14972@@ -5375,15 +6485,24 @@ retry_flip:
14973 goto retry_flip;
14974 }
14975
14976+ if (!fixup)
14977+ goto fixup_flip;
14978+
14979+error:
14980 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
14981- "page flipping failed, on CRTC:%d (pipe=%d), disabling %s page flips\n",
14982- crtc->id, crtc->pipe, data ? "synchronous": "asynchronous");
14983+ "page flipping failed, on CRTC:%d (pipe=%d), disabling %s page flips\n",
14984+ __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), data ? "synchronous": "asynchronous");
14985+
14986+ if (count || crtc->bo == bo)
14987+ sna_mode_restore(sna);
14988+
14989 sna->flags &= ~(data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP);
14990- goto fixup_flip;
14991+ return 0;
14992 }
14993
14994 if (data) {
14995 assert(crtc->flip_bo == NULL);
14996+ assert(handler);
14997 crtc->flip_handler = handler;
14998 crtc->flip_data = data;
14999 crtc->flip_bo = kgem_bo_reference(bo);
15000@@ -5391,8 +6510,11 @@ retry_flip:
15001 crtc->flip_serial = crtc->mode_serial;
15002 crtc->flip_pending = true;
15003 sna->mode.flip_active++;
15004- }
15005
15006+ DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
15007+ __FUNCTION__, __sna_crtc_id(crtc), crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial));
15008+ } else
15009+ goto update_scanout;
15010 next_crtc:
15011 count++;
15012 }
15013@@ -5471,7 +6593,7 @@ static void crtc_init_gamma(xf86CrtcPtr crtc)
15014
15015 assert(sna_crtc);
15016
15017- lut.crtc_id = sna_crtc->id;
15018+ lut.crtc_id = __sna_crtc_id(sna_crtc);
15019 lut.gamma_size = 256;
15020 lut.red = (uintptr_t)(gamma);
15021 lut.green = (uintptr_t)(gamma + 256);
15022@@ -5485,7 +6607,7 @@ static void crtc_init_gamma(xf86CrtcPtr crtc)
15023 }
15024
15025 DBG(("%s: CRTC:%d, pipe=%d: gamma set?=%d\n",
15026- __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
15027+ __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
15028 gamma_set));
15029 if (!gamma_set) {
15030 int i;
15031@@ -5528,6 +6650,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
15032 {
15033 ScrnInfoPtr scrn = sna->scrn;
15034 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
15035+ int crtc_active, crtc_enabled;
15036 int width, height;
15037 int i, j;
15038
15039@@ -5565,6 +6688,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
15040 }
15041
15042 /* Copy the existing modes on each CRTCs */
15043+ crtc_active = crtc_enabled = 0;
15044 for (i = 0; i < sna->mode.num_real_crtc; i++) {
15045 xf86CrtcPtr crtc = config->crtc[i];
15046 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
15047@@ -5577,12 +6701,12 @@ static bool sna_probe_initial_configuration(struct sna *sna)
15048
15049 /* Retrieve the current mode */
15050 VG_CLEAR(mode);
15051- mode.crtc_id = sna_crtc->id;
15052+ mode.crtc_id = __sna_crtc_id(sna_crtc);
15053 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
15054 continue;
15055
15056 DBG(("%s: CRTC:%d, pipe=%d: has mode?=%d\n", __FUNCTION__,
15057- sna_crtc->id, sna_crtc->pipe,
15058+ __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
15059 mode.mode_valid && mode.mode.clock));
15060
15061 if (!mode.mode_valid || mode.mode.clock == 0)
15062@@ -5593,6 +6717,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
15063 crtc->desiredX = mode.x;
15064 crtc->desiredY = mode.y;
15065 crtc->desiredTransformPresent = FALSE;
15066+ crtc_active++;
15067 }
15068
15069 /* Reconstruct outputs pointing to active CRTC */
15070@@ -5604,6 +6729,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
15071
15072 crtc_id = (uintptr_t)output->crtc;
15073 output->crtc = NULL;
15074+ output->status = XF86OutputStatusUnknown;
15075 if (sna->flags & SNA_IS_SLAVED)
15076 continue;
15077
15078@@ -5623,7 +6749,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
15079 xf86CrtcPtr crtc = config->crtc[j];
15080
15081 assert(to_sna_crtc(crtc));
15082- if (to_sna_crtc(crtc)->id != crtc_id)
15083+ if (sna_crtc_id(crtc) != crtc_id)
15084 continue;
15085
15086 if (crtc->desiredMode.status == MODE_OK) {
15087@@ -5641,18 +6767,30 @@ static bool sna_probe_initial_configuration(struct sna *sna)
15088 "Output %s using initial mode %s on pipe %d\n",
15089 output->name,
15090 crtc->desiredMode.name,
15091- to_sna_crtc(crtc)->pipe);
15092+ sna_crtc_pipe(crtc));
15093
15094 output->crtc = crtc;
15095+ output->status = XF86OutputStatusConnected;
15096 crtc->enabled = TRUE;
15097+ crtc_enabled++;
15098+
15099+ output_set_gamma(output, crtc);
15100+
15101+ if (output->conf_monitor) {
15102+ output->mm_width = output->conf_monitor->mon_width;
15103+ output->mm_height = output->conf_monitor->mon_height;
15104+ }
15105+
15106+#if 0
15107+ sna_output_attach_edid(output);
15108+ sna_output_attach_tile(output);
15109+#endif
15110
15111 if (output->mm_width == 0 || output->mm_height == 0) {
15112 output->mm_height = (crtc->desiredMode.VDisplay * 254) / (10*DEFAULT_DPI);
15113 output->mm_width = (crtc->desiredMode.HDisplay * 254) / (10*DEFAULT_DPI);
15114 }
15115
15116- output_set_gamma(output, crtc);
15117-
15118 M = calloc(1, sizeof(DisplayModeRec));
15119 if (M) {
15120 *M = crtc->desiredMode;
15121@@ -5673,6 +6811,12 @@ static bool sna_probe_initial_configuration(struct sna *sna)
15122 }
15123 }
15124
15125+ if (crtc_active != crtc_enabled) {
15126+ DBG(("%s: only enabled %d out of %d active CRTC, forcing a reconfigure\n",
15127+ __FUNCTION__, crtc_enabled, crtc_active));
15128+ return false;
15129+ }
15130+
15131 width = height = 0;
15132 for (i = 0; i < sna->mode.num_real_crtc; i++) {
15133 xf86CrtcPtr crtc = config->crtc[i];
15134@@ -5707,8 +6851,8 @@ static bool sna_probe_initial_configuration(struct sna *sna)
15135 if (sna_output->num_modes == 0)
15136 continue;
15137
15138- width = sna_output->modes[0].hdisplay;
15139- height= sna_output->modes[0].vdisplay;
15140+ width = sna_output->modes[0].hdisplay;
15141+ height = sna_output->modes[0].vdisplay;
15142
15143 DBG(("%s: panel '%s' is %dx%d\n",
15144 __FUNCTION__, output->name, width, height));
15145@@ -5788,7 +6932,7 @@ probe_capabilities(struct sna *sna)
15146 sna->flags &= ~(SNA_HAS_FLIP | SNA_HAS_ASYNC_FLIP);
15147 if (has_flip(sna))
15148 sna->flags |= SNA_HAS_FLIP;
15149- if (has_flip__async(sna))
15150+ if (has_flip__async(sna) && (sna->flags & SNA_TEAR_FREE) == 0)
15151 sna->flags |= SNA_HAS_ASYNC_FLIP;
15152 DBG(("%s: page flips? %s, async? %s\n", __FUNCTION__,
15153 sna->flags & SNA_HAS_FLIP ? "enabled" : "disabled",
15154@@ -5814,6 +6958,7 @@ sna_crtc_config_notify(ScreenPtr screen)
15155 }
15156
15157 update_flush_interval(sna);
15158+ sna->cursor.disable = false; /* Reset HW cursor until the next fail */
15159 sna_cursors_reload(sna);
15160
15161 probe_capabilities(sna);
15162@@ -5840,6 +6985,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
15163 }
15164
15165 probe_capabilities(sna);
15166+ sna->mode.hidden = 1;
15167
15168 if (!xf86GetOptValInteger(sna->Options, OPTION_VIRTUAL, &num_fake))
15169 num_fake = 1;
15170@@ -5855,6 +7001,9 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
15171 if (res) {
15172 xf86CrtcConfigPtr xf86_config;
15173
15174+ DBG(("%s: found %d CRTC, %d encoders, %d connectors\n",
15175+ __FUNCTION__, res->count_crtcs, res->count_encoders, res->count_connectors));
15176+
15177 assert(res->count_crtcs);
15178 assert(res->count_connectors);
15179
15180@@ -5862,6 +7011,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
15181
15182 xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
15183 xf86_config->xf86_crtc_notify = sna_crtc_config_notify;
15184+ xf86_config->compat_output = 0;
15185
15186 for (i = 0; i < res->count_crtcs; i++)
15187 if (!sna_crtc_add(scrn, res->crtcs[i]))
15188@@ -5912,6 +7062,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
15189 }
15190 }
15191 sort_config_outputs(sna);
15192+ TimerSet(NULL, 0, COLDPLUG_DELAY_MS, sna_mode_coldplug, sna);
15193
15194 sna_setup_provider(scrn);
15195 return scrn->modes != NULL;
15196@@ -5955,7 +7106,7 @@ sna_mode_set_primary(struct sna *sna)
15197
15198 DBG(("%s: setting PrimaryOutput %s\n", __FUNCTION__, output->name));
15199 rr->primaryOutput = output->randr_output;
15200- RROutputChanged(rr->primaryOutput, 0);
15201+ RROutputChanged(rr->primaryOutput, FALSE);
15202 rr->layoutChanged = TRUE;
15203 break;
15204 }
15205@@ -5974,12 +7125,9 @@ sna_mode_disable(struct sna *sna)
15206 if (!sna->scrn->vtSema)
15207 return false;
15208
15209- /* XXX we will cause previously hidden cursors to be reshown, but
15210- * this should be a rare fixup case for severe fragmentation.
15211- */
15212- sna_hide_cursors(sna->scrn);
15213+ sna_disable_cursors(sna->scrn);
15214 for (i = 0; i < sna->mode.num_real_crtc; i++)
15215- sna_crtc_disable(config->crtc[i]);
15216+ sna_crtc_disable(config->crtc[i], false);
15217 assert(sna->mode.front_active == 0);
15218
15219 sna_mode_wakeup(sna);
15220@@ -6001,6 +7149,11 @@ sna_mode_enable(struct sna *sna)
15221 if (!sna->scrn->vtSema)
15222 return;
15223
15224+ if (sna->mode.hidden) {
15225+ DBG(("%s: hidden outputs\n", __FUNCTION__));
15226+ return;
15227+ }
15228+
15229 for (i = 0; i < sna->mode.num_real_crtc; i++) {
15230 xf86CrtcPtr crtc = config->crtc[i];
15231
15232@@ -6016,13 +7169,30 @@ sna_mode_enable(struct sna *sna)
15233 }
15234
15235 update_flush_interval(sna);
15236- sna_show_cursors(sna->scrn);
15237+ sna_cursors_reload(sna);
15238 sna->mode.dirty = false;
15239 }
15240
15241+static void sna_randr_close(struct sna *sna)
15242+{
15243+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
15244+ int n;
15245+
15246+ /* The RR structs are freed early during CloseScreen as they
15247+ * are tracked as Resources. However, we may be tempted to
15248+ * access them during shutdown so decouple them now.
15249+ */
15250+ for (n = 0; n < config->num_output; n++)
15251+ config->output[n]->randr_output = NULL;
15252+
15253+ for (n = 0; n < config->num_crtc; n++)
15254+ config->crtc[n]->randr_crtc = NULL;
15255+}
15256+
15257 void
15258 sna_mode_close(struct sna *sna)
15259 {
15260+ sna_randr_close(sna);
15261 sna_mode_wakeup(sna);
15262
15263 if (sna->flags & SNA_IS_HOSTED)
15264@@ -6077,15 +7247,22 @@ xf86CrtcPtr
15265 sna_covering_crtc(struct sna *sna, const BoxRec *box, xf86CrtcPtr desired)
15266 {
15267 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
15268- xf86CrtcPtr best_crtc;
15269- int best_coverage, c;
15270+ xf86CrtcPtr best_crtc = NULL;
15271+ int best_coverage = -1, c;
15272
15273 if (sna->flags & SNA_IS_HOSTED)
15274 return NULL;
15275
15276 /* If we do not own the VT, we do not own the CRTC either */
15277- if (!sna->scrn->vtSema)
15278+ if (!sna->scrn->vtSema) {
15279+ DBG(("%s: none, VT switched\n", __FUNCTION__));
15280+ return NULL;
15281+ }
15282+
15283+ if (sna->mode.hidden) {
15284+ DBG(("%s: none, hidden outputs\n", __FUNCTION__));
15285 return NULL;
15286+ }
15287
15288 DBG(("%s for box=(%d, %d), (%d, %d)\n",
15289 __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
15290@@ -6107,10 +7284,10 @@ sna_covering_crtc(struct sna *sna, const BoxRec *box, xf86CrtcPtr desired)
15291 cover_box.x2, cover_box.y2));
15292 return desired;
15293 }
15294+ best_crtc = desired;
15295+ best_coverage = 0;
15296 }
15297
15298- best_crtc = NULL;
15299- best_coverage = 0;
15300 for (c = 0; c < sna->mode.num_real_crtc; c++) {
15301 xf86CrtcPtr crtc = config->crtc[c];
15302 BoxRec cover_box;
15303@@ -6156,6 +7333,21 @@ sna_covering_crtc(struct sna *sna, const BoxRec *box, xf86CrtcPtr desired)
15304 return best_crtc;
15305 }
15306
15307+xf86CrtcPtr sna_primary_crtc(struct sna *sna)
15308+{
15309+ rrScrPrivPtr rr = rrGetScrPriv(xf86ScrnToScreen(sna->scrn));
15310+ if (rr && rr->primaryOutput) {
15311+ xf86OutputPtr output = rr->primaryOutput->devPrivate;
15312+ if (output->crtc && to_sna_crtc(output->crtc))
15313+ return output->crtc;
15314+ }
15315+
15316+ if (sna->mode.num_real_crtc)
15317+ return XF86_CRTC_CONFIG_PTR(sna->scrn)->crtc[0];
15318+
15319+ return NULL;
15320+}
15321+
15322 #define MI_LOAD_REGISTER_IMM (0x22<<23)
15323
15324 static bool sna_emit_wait_for_scanline_hsw(struct sna *sna,
15325@@ -6433,7 +7625,7 @@ sna_wait_for_scanline(struct sna *sna,
15326 y2 /= 2;
15327 }
15328
15329- pipe = sna_crtc_to_pipe(crtc);
15330+ pipe = sna_crtc_pipe(crtc);
15331 DBG(("%s: pipe=%d, y1=%d, y2=%d, full_height?=%d\n",
15332 __FUNCTION__, pipe, y1, y2, full_height));
15333
15334@@ -6457,19 +7649,198 @@ sna_wait_for_scanline(struct sna *sna,
15335 return ret;
15336 }
15337
15338-void sna_mode_check(struct sna *sna)
15339+static bool sna_mode_shutdown_crtc(xf86CrtcPtr crtc)
15340+{
15341+ struct sna *sna = to_sna(crtc->scrn);
15342+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
15343+ bool disabled = false;
15344+ int o;
15345+
15346+ xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
15347+ "%s: invalid state found on pipe %d, disabling CRTC:%d\n",
15348+ __FUNCTION__,
15349+ __sna_crtc_pipe(to_sna_crtc(crtc)),
15350+ __sna_crtc_id(to_sna_crtc(crtc)));
15351+ sna_crtc_disable(crtc, true);
15352+#if XF86_CRTC_VERSION >= 3
15353+ crtc->active = FALSE;
15354+#endif
15355+ if (crtc->enabled) {
15356+ crtc->enabled = FALSE;
15357+ disabled = true;
15358+ }
15359+
15360+ for (o = 0; o < sna->mode.num_real_output; o++) {
15361+ xf86OutputPtr output = config->output[o];
15362+
15363+ if (output->crtc != crtc)
15364+ continue;
15365+
15366+ output->funcs->dpms(output, DPMSModeOff);
15367+ output->crtc = NULL;
15368+ }
15369+
15370+ return disabled;
15371+}
15372+
15373+static xf86CrtcPtr
15374+lookup_crtc_by_id(struct sna *sna, int id)
15375 {
15376 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
15377+ int c;
15378+
15379+ for (c = 0; c < sna->mode.num_real_crtc; c++) {
15380+ xf86CrtcPtr crtc = config->crtc[c];
15381+ if (__sna_crtc_id(to_sna_crtc(crtc)) == id)
15382+ return crtc;
15383+ }
15384+
15385+ return NULL;
15386+}
15387+
15388+static int plane_type(struct sna *sna, int id)
15389+{
15390+ struct local_mode_obj_get_properties arg;
15391+ uint64_t stack_props[24];
15392+ uint32_t *props = (uint32_t *)stack_props;
15393+ uint64_t *values = stack_props + 8;
15394+ int i, type = -1;
15395+
15396+ memset(&arg, 0, sizeof(struct local_mode_obj_get_properties));
15397+ arg.obj_id = id;
15398+ arg.obj_type = LOCAL_MODE_OBJECT_PLANE;
15399+
15400+ arg.props_ptr = (uintptr_t)props;
15401+ arg.prop_values_ptr = (uintptr_t)values;
15402+ arg.count_props = 16;
15403+
15404+ if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_OBJ_GETPROPERTIES, &arg))
15405+ return -1;
15406+
15407+ DBG(("%s: object %d (type %x) has %d props\n", __FUNCTION__,
15408+ id, LOCAL_MODE_OBJECT_PLANE, arg.count_props));
15409+
15410+ if (arg.count_props > 16) {
15411+ props = malloc(2*sizeof(uint64_t)*arg.count_props);
15412+ if (props == NULL)
15413+ return -1;
15414+
15415+ values = (uint64_t *)props + arg.count_props;
15416+
15417+ arg.props_ptr = (uintptr_t)props;
15418+ arg.prop_values_ptr = (uintptr_t)values;
15419+
15420+ if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_OBJ_GETPROPERTIES, &arg))
15421+ arg.count_props = 0;
15422+ }
15423+ VG(VALGRIND_MAKE_MEM_DEFINED(arg.props_ptr, sizeof(uint32_t)*arg.count_props));
15424+ VG(VALGRIND_MAKE_MEM_DEFINED(arg.prop_values_ptr, sizeof(uint64_t)*arg.count_props));
15425+
15426+ for (i = 0; i < arg.count_props; i++) {
15427+ struct drm_mode_get_property prop;
15428+
15429+ memset(&prop, 0, sizeof(prop));
15430+ prop.prop_id = props[i];
15431+ if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) {
15432+ ERR(("%s: prop[%d].id=%d GETPROPERTY failed with errno=%d\n",
15433+ __FUNCTION__, i, props[i], errno));
15434+ continue;
15435+ }
15436+
15437+ DBG(("%s: prop[%d] .id=%ld, .name=%s, .flags=%x, .value=%ld\n", __FUNCTION__, i,
15438+ (long)props[i], prop.name, (unsigned)prop.flags, (long)values[i]));
15439+
15440+ if (strcmp(prop.name, "type") == 0) {
15441+ type = values[i];
15442+ break;
15443+ }
15444+ }
15445+
15446+ if (props != (uint32_t *)stack_props)
15447+ free(props);
15448+
15449+ return type;
15450+}
15451+
15452+static bool
15453+sna_mode_disable_secondary_planes(struct sna *sna)
15454+{
15455+ struct local_mode_get_plane_res r;
15456+ uint32_t stack_planes[64];
15457+ uint32_t *planes = stack_planes;
15458+ bool disabled = false;
15459 int i;
15460
15461+ VG_CLEAR(r);
15462+ r.plane_id_ptr = (uintptr_t)planes;
15463+ r.count_planes = ARRAY_SIZE(stack_planes);
15464+ if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_GETPLANERESOURCES, &r))
15465+ return false;
15466+
15467+ DBG(("%s: %d planes\n", __FUNCTION__, (int)r.count_planes));
15468+
15469+ if (r.count_planes > ARRAY_SIZE(stack_planes)) {
15470+ planes = malloc(sizeof(uint32_t)*r.count_planes);
15471+ if (planes == NULL)
15472+ return false;
15473+
15474+ r.plane_id_ptr = (uintptr_t)planes;
15475+ if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_GETPLANERESOURCES, &r))
15476+ r.count_planes = 0;
15477+ }
15478+
15479+ VG(VALGRIND_MAKE_MEM_DEFINED(planes, sizeof(uint32_t)*r.count_planes));
15480+
15481+ for (i = 0; i < r.count_planes; i++) {
15482+ struct local_mode_get_plane p;
15483+ struct local_mode_set_plane s;
15484+
15485+ VG_CLEAR(p);
15486+ p.plane_id = planes[i];
15487+ p.count_format_types = 0;
15488+ if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_GETPLANE, &p))
15489+ continue;
15490+
15491+ if (p.fb_id == 0 || p.crtc_id == 0)
15492+ continue;
15493+
15494+ if (plane_type(sna, p.plane_id) == DRM_PLANE_TYPE_PRIMARY)
15495+ continue;
15496+
15497+ memset(&s, 0, sizeof(s));
15498+ s.plane_id = p.plane_id;
15499+ s.crtc_id = p.crtc_id;
15500+ if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s)) {
15501+ xf86CrtcPtr crtc = lookup_crtc_by_id(sna, p.crtc_id);
15502+ if (crtc)
15503+ disabled |= sna_mode_shutdown_crtc(crtc);
15504+ }
15505+ }
15506+
15507+ if (planes != stack_planes)
15508+ free(planes);
15509+
15510+ return disabled;
15511+}
15512+
15513+void sna_mode_check(struct sna *sna)
15514+{
15515+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
15516+ bool disabled;
15517+ int c, o;
15518+
15519 if (sna->flags & SNA_IS_HOSTED)
15520 return;
15521
15522- DBG(("%s\n", __FUNCTION__));
15523+ DBG(("%s: hidden?=%d\n", __FUNCTION__, sna->mode.hidden));
15524+ if (sna->mode.hidden)
15525+ return;
15526+
15527+ disabled = sna_mode_disable_secondary_planes(sna);
15528
15529 /* Validate CRTC attachments and force consistency upon the kernel */
15530- for (i = 0; i < sna->mode.num_real_crtc; i++) {
15531- xf86CrtcPtr crtc = config->crtc[i];
15532+ for (c = 0; c < sna->mode.num_real_crtc; c++) {
15533+ xf86CrtcPtr crtc = config->crtc[c];
15534 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
15535 struct drm_mode_crtc mode;
15536 uint32_t expected[2];
15537@@ -6483,7 +7854,7 @@ void sna_mode_check(struct sna *sna)
15538 expected[1] = sna_crtc->flip_bo ? fb_id(sna_crtc->flip_bo) : -1;
15539
15540 VG_CLEAR(mode);
15541- mode.crtc_id = sna_crtc->id;
15542+ mode.crtc_id = __sna_crtc_id(sna_crtc);
15543 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
15544 continue;
15545
15546@@ -6492,16 +7863,12 @@ void sna_mode_check(struct sna *sna)
15547 mode.crtc_id, mode.mode_valid,
15548 mode.fb_id, expected[0], expected[1]));
15549
15550- if (mode.fb_id != expected[0] && mode.fb_id != expected[1]) {
15551- xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
15552- "%s: invalid state found on pipe %d, disabling CRTC:%d\n",
15553- __FUNCTION__, sna_crtc->pipe, sna_crtc->id);
15554- sna_crtc_disable(crtc);
15555- }
15556+ if (mode.fb_id != expected[0] && mode.fb_id != expected[1])
15557+ disabled |= sna_mode_shutdown_crtc(crtc);
15558 }
15559
15560- for (i = 0; i < config->num_output; i++) {
15561- xf86OutputPtr output = config->output[i];
15562+ for (o = 0; o < config->num_output; o++) {
15563+ xf86OutputPtr output = config->output[o];
15564 struct sna_output *sna_output;
15565
15566 if (output->crtc)
15567@@ -6515,26 +7882,15 @@ void sna_mode_check(struct sna *sna)
15568 }
15569
15570 update_flush_interval(sna);
15571+
15572+ if (disabled)
15573+ xf86RandR12TellChanged(xf86ScrnToScreen(sna->scrn));
15574 }
15575
15576 static bool
15577 sna_crtc_hide_planes(struct sna *sna, struct sna_crtc *crtc)
15578 {
15579-#define LOCAL_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct local_mode_set_plane)
15580- struct local_mode_set_plane {
15581- uint32_t plane_id;
15582- uint32_t crtc_id;
15583- uint32_t fb_id; /* fb object contains surface format type */
15584- uint32_t flags;
15585-
15586- /* Signed dest location allows it to be partially off screen */
15587- int32_t crtc_x, crtc_y;
15588- uint32_t crtc_w, crtc_h;
15589-
15590- /* Source values are 16.16 fixed point */
15591- uint32_t src_x, src_y;
15592- uint32_t src_h, src_w;
15593- } s;
15594+ struct local_mode_set_plane s;
15595
15596 if (crtc->primary.id == 0)
15597 return false;
15598@@ -6561,17 +7917,16 @@ void sna_mode_reset(struct sna *sna)
15599
15600 DBG(("%s\n", __FUNCTION__));
15601
15602- sna_hide_cursors(sna->scrn);
15603+ sna_disable_cursors(sna->scrn);
15604 for (i = 0; i < sna->mode.num_real_crtc; i++)
15605 if (!sna_crtc_hide_planes(sna, to_sna_crtc(config->crtc[i])))
15606- sna_crtc_disable(config->crtc[i]);
15607+ sna_crtc_disable(config->crtc[i], true);
15608 assert(sna->mode.front_active == 0);
15609
15610 for (i = 0; i < sna->mode.num_real_crtc; i++) {
15611 struct sna_crtc *sna_crtc = to_sna_crtc(config->crtc[i]);
15612
15613 assert(sna_crtc != NULL);
15614- sna_crtc->dpms_mode = -1;
15615
15616 /* Force the rotation property to be reset on next use */
15617 rotation_reset(&sna_crtc->primary);
15618@@ -6641,9 +7996,10 @@ sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
15619 {
15620 int16_t sx, sy;
15621 struct sna *sna = to_sna(crtc->scrn);
15622- ScreenPtr screen = sna->scrn->pScreen;
15623+ ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
15624 DrawablePtr draw = crtc_source(crtc, &sx, &sy);
15625 PictFormatPtr format;
15626+ PictTransform T;
15627 PicturePtr src, dst;
15628 PixmapPtr pixmap;
15629 int depth, error;
15630@@ -6664,6 +8020,14 @@ sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
15631 __FUNCTION__, format->format, depth, draw->bitsPerPixel,
15632 bo->pitch, crtc->mode.HDisplay, crtc->mode.VDisplay));
15633
15634+ if (sx | sy)
15635+ RegionTranslate(region, sx, sy);
15636+ error = !sna_drawable_move_region_to_cpu(draw, region, MOVE_READ);
15637+ if (sx | sy)
15638+ RegionTranslate(region, -sx, -sy);
15639+ if (error)
15640+ return;
15641+
15642 ptr = kgem_bo_map__gtt(&sna->kgem, bo);
15643 if (ptr == NULL)
15644 return;
15645@@ -6683,9 +8047,37 @@ sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
15646 if (!src)
15647 goto free_pixmap;
15648
15649- error = SetPictureTransform(src, &crtc->crtc_to_framebuffer);
15650- if (error)
15651- goto free_src;
15652+ pixman_transform_init_translate(&T, sx << 16, sy << 16);
15653+ pixman_transform_multiply(&T, &T, &crtc->crtc_to_framebuffer);
15654+ if (!sna_transform_is_integer_translation(&T, &sx, &sy)) {
15655+#define f2d(x) (((double)(x))/65536.)
15656+ DBG(("%s: transform=[[%f %f %f], [%f %f %f], [%f %f %f]] (raw [[%x %x %x], [%x %x %x], [%x %x %x]])\n",
15657+ __FUNCTION__,
15658+ f2d(T.matrix[0][0]),
15659+ f2d(T.matrix[0][1]),
15660+ f2d(T.matrix[0][2]),
15661+ f2d(T.matrix[1][0]),
15662+ f2d(T.matrix[1][1]),
15663+ f2d(T.matrix[1][2]),
15664+ f2d(T.matrix[2][0]),
15665+ f2d(T.matrix[2][1]),
15666+ f2d(T.matrix[2][2]),
15667+ T.matrix[0][0],
15668+ T.matrix[0][1],
15669+ T.matrix[0][2],
15670+ T.matrix[1][0],
15671+ T.matrix[1][1],
15672+ T.matrix[1][2],
15673+ T.matrix[2][0],
15674+ T.matrix[2][1],
15675+ T.matrix[2][2]));
15676+#undef f2d
15677+
15678+ error = SetPictureTransform(src, &T);
15679+ if (error)
15680+ goto free_src;
15681+ sx = sy = 0;
15682+ }
15683
15684 if (crtc->filter && crtc->transform_in_use)
15685 SetPicturePictFilter(src, crtc->filter,
15686@@ -6733,10 +8125,11 @@ sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
15687 {
15688 int16_t sx, sy;
15689 struct sna *sna = to_sna(crtc->scrn);
15690- ScreenPtr screen = crtc->scrn->pScreen;
15691+ ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
15692 DrawablePtr draw = crtc_source(crtc, &sx, &sy);
15693 struct sna_composite_op tmp;
15694 PictFormatPtr format;
15695+ PictTransform T;
15696 PicturePtr src, dst;
15697 PixmapPtr pixmap;
15698 const BoxRec *b;
15699@@ -6777,9 +8170,14 @@ sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
15700 if (!src)
15701 goto free_pixmap;
15702
15703- error = SetPictureTransform(src, &crtc->crtc_to_framebuffer);
15704- if (error)
15705- goto free_src;
15706+ pixman_transform_init_translate(&T, sx << 16, sy << 16);
15707+ pixman_transform_multiply(&T, &T, &crtc->crtc_to_framebuffer);
15708+ if (!sna_transform_is_integer_translation(&T, &sx, &sy)) {
15709+ error = SetPictureTransform(src, &T);
15710+ if (error)
15711+ goto free_src;
15712+ sx = sy = 0;
15713+ }
15714
15715 if (crtc->filter && crtc->transform_in_use)
15716 SetPicturePictFilter(src, crtc->filter,
15717@@ -6839,7 +8237,7 @@ sna_crtc_redisplay(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo *bo)
15718 struct sna_pixmap *priv = sna_pixmap((PixmapPtr)draw);
15719
15720 DBG(("%s: crtc %d [pipe=%d], damage (%d, %d), (%d, %d) x %d\n",
15721- __FUNCTION__, to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe,
15722+ __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc),
15723 region->extents.x1, region->extents.y1,
15724 region->extents.x2, region->extents.y2,
15725 region_num_rects(region)));
15726@@ -6908,18 +8306,21 @@ void sna_shadow_set_crtc(struct sna *sna,
15727 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
15728 struct sna_pixmap *priv;
15729
15730+ assert(sna_crtc);
15731 DBG(("%s: setting shadow override for CRTC:%d to handle=%d\n",
15732- __FUNCTION__, sna_crtc->id, bo->handle));
15733+ __FUNCTION__, __sna_crtc_id(sna_crtc), bo->handle));
15734
15735 assert(sna->flags & SNA_TEAR_FREE);
15736- assert(sna_crtc);
15737 assert(!sna_crtc->transform);
15738
15739 if (sna_crtc->client_bo != bo) {
15740- if (sna_crtc->client_bo)
15741+ if (sna_crtc->client_bo) {
15742+ assert(sna_crtc->client_bo->refcnt > sna_crtc->client_bo->active_scanout);
15743 kgem_bo_destroy(&sna->kgem, sna_crtc->client_bo);
15744+ }
15745
15746 sna_crtc->client_bo = kgem_bo_reference(bo);
15747+ assert(sna_crtc->client_bo->refcnt > sna_crtc->client_bo->active_scanout);
15748 sna_crtc_damage(crtc);
15749 }
15750
15751@@ -6969,11 +8370,12 @@ void sna_shadow_unset_crtc(struct sna *sna,
15752 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
15753
15754 DBG(("%s: clearin shadow override for CRTC:%d\n",
15755- __FUNCTION__, sna_crtc->id));
15756+ __FUNCTION__, __sna_crtc_id(sna_crtc)));
15757
15758 if (sna_crtc->client_bo == NULL)
15759 return;
15760
15761+ assert(sna_crtc->client_bo->refcnt > sna_crtc->client_bo->active_scanout);
15762 kgem_bo_destroy(&sna->kgem, sna_crtc->client_bo);
15763 sna_crtc->client_bo = NULL;
15764 list_del(&sna_crtc->shadow_link);
15765@@ -6982,15 +8384,50 @@ void sna_shadow_unset_crtc(struct sna *sna,
15766 sna_crtc_damage(crtc);
15767 }
15768
15769+static bool move_crtc_to_gpu(struct sna *sna)
15770+{
15771+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
15772+ int i;
15773+
15774+ for (i = 0; i < sna->mode.num_real_crtc; i++) {
15775+ struct sna_crtc *crtc = to_sna_crtc(config->crtc[i]);
15776+
15777+ assert(crtc);
15778+
15779+ if (crtc->bo == NULL)
15780+ continue;
15781+
15782+ if (crtc->slave_pixmap)
15783+ continue;
15784+
15785+ if (crtc->client_bo)
15786+ continue;
15787+
15788+ DBG(("%s: CRTC %d [pipe=%d] requires frontbuffer\n",
15789+ __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc)));
15790+ return sna_pixmap_move_to_gpu(sna->front,
15791+ MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT);
15792+ }
15793+
15794+ return true;
15795+}
15796+
15797 void sna_mode_redisplay(struct sna *sna)
15798 {
15799 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
15800 RegionPtr region;
15801 int i;
15802
15803- if (!sna->mode.shadow_damage)
15804+ if (sna->mode.hidden) {
15805+ DBG(("%s: hidden outputs, skipping\n", __FUNCTION__));
15806+ return;
15807+ }
15808+
15809+ if (!sna->mode.shadow_enabled)
15810 return;
15811
15812+ assert(sna->mode.shadow_damage);
15813+
15814 DBG(("%s: posting shadow damage? %d (flips pending? %d, mode reconfiguration pending? %d)\n",
15815 __FUNCTION__,
15816 !RegionNil(DamageRegion(sna->mode.shadow_damage)),
15817@@ -7012,21 +8449,23 @@ void sna_mode_redisplay(struct sna *sna)
15818 region->extents.x2, region->extents.y2));
15819
15820 if (sna->mode.flip_active) {
15821- DamagePtr damage;
15822-
15823- damage = sna->mode.shadow_damage;
15824- sna->mode.shadow_damage = NULL;
15825+ DBG(("%s: checking for %d outstanding flip completions\n",
15826+ __FUNCTION__, sna->mode.flip_active));
15827
15828+ sna->mode.dirty = true;
15829 while (sna->mode.flip_active && sna_mode_wakeup(sna))
15830 ;
15831+ sna->mode.dirty = false;
15832
15833- sna->mode.shadow_damage = damage;
15834+ DBG(("%s: now %d outstanding flip completions (enabled? %d)\n",
15835+ __FUNCTION__,
15836+ sna->mode.flip_active,
15837+ sna->mode.shadow_enabled));
15838+ if (sna->mode.flip_active || !sna->mode.shadow_enabled)
15839+ return;
15840 }
15841
15842- if (sna->mode.flip_active)
15843- return;
15844-
15845- if (wedged(sna) || !sna_pixmap_move_to_gpu(sna->front, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT)) {
15846+ if (wedged(sna) || !move_crtc_to_gpu(sna)) {
15847 DBG(("%s: forcing scanout update using the CPU\n", __FUNCTION__));
15848 if (!sna_pixmap_move_to_cpu(sna->front, MOVE_READ))
15849 return;
15850@@ -7050,7 +8489,7 @@ void sna_mode_redisplay(struct sna *sna)
15851 struct kgem_bo *bo = NULL;
15852
15853 DBG(("%s: fallback intersects pipe=%d [(%d, %d), (%d, %d)]\n",
15854- __FUNCTION__, sna_crtc->pipe,
15855+ __FUNCTION__, __sna_crtc_pipe(sna_crtc),
15856 damage.extents.x1, damage.extents.y1,
15857 damage.extents.x2, damage.extents.y2));
15858
15859@@ -7060,7 +8499,7 @@ void sna_mode_redisplay(struct sna *sna)
15860 RegionNull(&new_damage);
15861 RegionCopy(&new_damage, &damage);
15862
15863- bo = sna_crtc->client_bo;
15864+ bo = sna_crtc->cache_bo;
15865 if (bo == NULL) {
15866 damage.extents = crtc->bounds;
15867 damage.data = NULL;
15868@@ -7085,7 +8524,7 @@ void sna_mode_redisplay(struct sna *sna)
15869 if (bo != sna_crtc->bo) {
15870 struct drm_mode_crtc_page_flip arg;
15871
15872- arg.crtc_id = sna_crtc->id;
15873+ arg.crtc_id = __sna_crtc_id(sna_crtc);
15874 arg.fb_id = get_fb(sna, bo,
15875 crtc->mode.HDisplay,
15876 crtc->mode.VDisplay);
15877@@ -7096,6 +8535,9 @@ void sna_mode_redisplay(struct sna *sna)
15878
15879 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
15880 if (sna_crtc_flip(sna, sna_crtc, bo, 0, 0)) {
15881+ DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n",
15882+ __FUNCTION__, sna_crtc->bo->handle, sna_crtc->bo->active_scanout,
15883+ bo->handle, bo->active_scanout));
15884 assert(sna_crtc->bo->active_scanout);
15885 assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout);
15886 sna_crtc->bo->active_scanout--;
15887@@ -7103,10 +8545,10 @@ void sna_mode_redisplay(struct sna *sna)
15888
15889 sna_crtc->bo = bo;
15890 sna_crtc->bo->active_scanout++;
15891- sna_crtc->client_bo = NULL;
15892+ sna_crtc->cache_bo = NULL;
15893 } else {
15894 DBG(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
15895- __FUNCTION__, arg.fb_id, i, sna_crtc->id, sna_crtc->pipe, errno));
15896+ __FUNCTION__, arg.fb_id, i, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), errno));
15897 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
15898 "Page flipping failed, disabling TearFree\n");
15899 sna->flags &= ~SNA_TEAR_FREE;
15900@@ -7116,7 +8558,7 @@ void sna_mode_redisplay(struct sna *sna)
15901 sna_crtc_redisplay__fallback(crtc, &damage, sna_crtc->bo);
15902
15903 kgem_bo_destroy(&sna->kgem, bo);
15904- sna_crtc->client_bo = NULL;
15905+ sna_crtc->cache_bo = NULL;
15906 }
15907 } else {
15908 sna->mode.flip_active++;
15909@@ -7127,8 +8569,12 @@ void sna_mode_redisplay(struct sna *sna)
15910 sna_crtc->flip_bo = bo;
15911 sna_crtc->flip_bo->active_scanout++;
15912 sna_crtc->flip_serial = sna_crtc->mode_serial;
15913+ sna_crtc->flip_pending = true;
15914
15915- sna_crtc->client_bo = kgem_bo_reference(sna_crtc->bo);
15916+ sna_crtc->cache_bo = kgem_bo_reference(sna_crtc->bo);
15917+
15918+ DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
15919+ __FUNCTION__, __sna_crtc_id(sna_crtc), sna_crtc->flip_bo->handle, sna_crtc->flip_bo->active_scanout, sna_crtc->flip_serial));
15920 }
15921 }
15922 }
15923@@ -7201,7 +8647,7 @@ void sna_mode_redisplay(struct sna *sna)
15924 damage.extents = crtc->bounds;
15925 damage.data = NULL;
15926
15927- bo = sna_crtc->client_bo;
15928+ bo = sna_crtc->cache_bo;
15929 if (bo == NULL)
15930 bo = kgem_create_2d(&sna->kgem,
15931 crtc->mode.HDisplay,
15932@@ -7210,12 +8656,12 @@ void sna_mode_redisplay(struct sna *sna)
15933 sna_crtc->bo->tiling,
15934 CREATE_SCANOUT);
15935 if (bo == NULL)
15936- goto disable1;
15937+ continue;
15938
15939 sna_crtc_redisplay(crtc, &damage, bo);
15940 kgem_bo_submit(&sna->kgem, bo);
15941
15942- arg.crtc_id = sna_crtc->id;
15943+ arg.crtc_id = __sna_crtc_id(sna_crtc);
15944 arg.fb_id = get_fb(sna, bo,
15945 crtc->mode.HDisplay,
15946 crtc->mode.VDisplay);
15947@@ -7228,6 +8674,9 @@ void sna_mode_redisplay(struct sna *sna)
15948
15949 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
15950 if (sna_crtc_flip(sna, sna_crtc, bo, 0, 0)) {
15951+ DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n",
15952+ __FUNCTION__, sna_crtc->bo->handle, sna_crtc->bo->active_scanout - 1,
15953+ bo->handle, bo->active_scanout));
15954 assert(sna_crtc->bo->active_scanout);
15955 assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout);
15956 sna_crtc->bo->active_scanout--;
15957@@ -7235,13 +8684,13 @@ void sna_mode_redisplay(struct sna *sna)
15958
15959 sna_crtc->bo = kgem_bo_reference(bo);
15960 sna_crtc->bo->active_scanout++;
15961- sna_crtc->client_bo = kgem_bo_reference(bo);
15962+ sna_crtc->cache_bo = kgem_bo_reference(bo);
15963 } else {
15964 BoxRec box;
15965 DrawableRec tmp;
15966
15967 DBG(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
15968- __FUNCTION__, arg.fb_id, i, sna_crtc->id, sna_crtc->pipe, errno));
15969+ __FUNCTION__, arg.fb_id, i, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), errno));
15970 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
15971 "Page flipping failed, disabling TearFree\n");
15972 sna->flags &= ~SNA_TEAR_FREE;
15973@@ -7260,12 +8709,12 @@ disable1:
15974 &box, 1, COPY_LAST)) {
15975 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
15976 "%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n",
15977- __FUNCTION__, sna_crtc->id, sna_crtc->pipe);
15978- sna_crtc_disable(crtc);
15979+ __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc));
15980+ sna_crtc_disable(crtc, false);
15981 }
15982
15983 kgem_bo_destroy(&sna->kgem, bo);
15984- sna_crtc->client_bo = NULL;
15985+ sna_crtc->cache_bo = NULL;
15986 }
15987 continue;
15988 }
15989@@ -7279,7 +8728,9 @@ disable1:
15990 sna_crtc->flip_serial = sna_crtc->mode_serial;
15991 sna_crtc->flip_pending = true;
15992
15993- sna_crtc->client_bo = kgem_bo_reference(sna_crtc->bo);
15994+ sna_crtc->cache_bo = kgem_bo_reference(sna_crtc->bo);
15995+ DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
15996+ __FUNCTION__, __sna_crtc_id(sna_crtc), sna_crtc->flip_bo->handle, sna_crtc->flip_bo->active_scanout, sna_crtc->flip_serial));
15997 } else {
15998 sna_crtc_redisplay(crtc, &damage, sna_crtc->bo);
15999 kgem_scanout_flush(&sna->kgem, sna_crtc->bo);
16000@@ -7315,20 +8766,19 @@ disable1:
16001
16002 assert(crtc != NULL);
16003 DBG(("%s: crtc %d [%d, pipe=%d] active? %d, transformed? %d\n",
16004- __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo ? crtc->bo->handle : 0, crtc->transform));
16005+ __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->bo ? crtc->bo->handle : 0, crtc->transform));
16006 if (crtc->bo == NULL || crtc->transform)
16007 continue;
16008
16009 assert(config->crtc[i]->enabled);
16010- assert(crtc->dpms_mode <= DPMSModeOn);
16011 assert(crtc->flip_bo == NULL);
16012
16013- arg.crtc_id = crtc->id;
16014+ arg.crtc_id = __sna_crtc_id(crtc);
16015 arg.user_data = (uintptr_t)crtc;
16016
16017 if (crtc->client_bo) {
16018 DBG(("%s: apply shadow override bo for CRTC:%d on pipe=%d, handle=%d\n",
16019- __FUNCTION__, crtc->id, crtc->pipe, crtc->client_bo->handle));
16020+ __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->client_bo->handle));
16021 arg.fb_id = get_fb(sna, crtc->client_bo,
16022 crtc->base->mode.HDisplay,
16023 crtc->base->mode.VDisplay);
16024@@ -7365,8 +8815,12 @@ fixup_shadow:
16025 y = crtc->base->y;
16026 }
16027
16028- if (crtc->bo == flip_bo)
16029+ if (crtc->bo == flip_bo) {
16030+ assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
16031+ DBG(("%s: flip handle=%d is already on the CRTC\n",
16032+ __FUNCTION__, flip_bo->handle));
16033 continue;
16034+ }
16035
16036 if (flip_bo->pitch != crtc->bo->pitch || (y << 16 | x) != crtc->offset) {
16037 DBG(("%s: changing pitch (new %d =?= old %d) or offset (new %x =?= old %x)\n",
16038@@ -7375,6 +8829,9 @@ fixup_shadow:
16039 y << 16 | x, crtc->offset));
16040 fixup_flip:
16041 if (sna_crtc_flip(sna, crtc, flip_bo, x, y)) {
16042+ DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n",
16043+ __FUNCTION__, crtc->bo->handle, crtc->bo->active_scanout-1,
16044+ flip_bo->handle, flip_bo->active_scanout));
16045 assert(flip_bo != crtc->bo);
16046 assert(crtc->bo->active_scanout);
16047 assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
16048@@ -7400,15 +8857,15 @@ fixup_flip:
16049
16050 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
16051 "%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n",
16052- __FUNCTION__, crtc->id, crtc->pipe);
16053- sna_crtc_disable(crtc->base);
16054+ __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc));
16055+ sna_crtc_disable(crtc->base, false);
16056 }
16057 continue;
16058 }
16059
16060 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
16061 ERR(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
16062- __FUNCTION__, arg.fb_id, i, crtc->id, crtc->pipe, errno));
16063+ __FUNCTION__, arg.fb_id, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), errno));
16064 goto fixup_flip;
16065 }
16066 sna->mode.flip_active++;
16067@@ -7421,6 +8878,9 @@ fixup_flip:
16068 crtc->flip_serial = crtc->mode_serial;
16069 crtc->flip_pending = true;
16070
16071+ DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
16072+ __FUNCTION__, __sna_crtc_id(crtc), crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial));
16073+
16074 {
16075 struct drm_i915_gem_busy busy = { flip_bo->handle };
16076 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy) == 0) {
16077@@ -7495,13 +8955,19 @@ again:
16078 {
16079 struct drm_event_vblank *vbl = (struct drm_event_vblank *)e;
16080 struct sna_crtc *crtc = (void *)(uintptr_t)vbl->user_data;
16081+ uint64_t msc;
16082
16083 /* Beware Zaphod! */
16084 sna = to_sna(crtc->base->scrn);
16085
16086- crtc->swap.tv_sec = vbl->tv_sec;
16087- crtc->swap.tv_usec = vbl->tv_usec;
16088- crtc->swap.msc = msc64(crtc, vbl->sequence);
16089+ if (msc64(crtc, vbl->sequence, &msc)) {
16090+ DBG(("%s: recording last swap on pipe=%d, frame %d [%08llx], time %d.%06d\n",
16091+ __FUNCTION__, __sna_crtc_pipe(crtc), vbl->sequence, (long long)msc, vbl->tv_sec, vbl->tv_usec));
16092+ crtc->swap.tv_sec = vbl->tv_sec;
16093+ crtc->swap.tv_usec = vbl->tv_usec;
16094+ crtc->swap.msc = msc;
16095+ }
16096+ assert(crtc->flip_pending);
16097 crtc->flip_pending = false;
16098
16099 assert(crtc->flip_bo);
16100@@ -7509,8 +8975,9 @@ again:
16101 assert(crtc->flip_bo->refcnt >= crtc->flip_bo->active_scanout);
16102
16103 if (crtc->flip_serial == crtc->mode_serial) {
16104- DBG(("%s: removing handle=%d from scanout, installing handle=%d\n",
16105- __FUNCTION__, crtc->bo->handle, crtc->flip_bo->handle));
16106+ DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n",
16107+ __FUNCTION__, crtc->bo->handle, crtc->bo->active_scanout - 1,
16108+ crtc->flip_bo->handle, crtc->flip_bo->active_scanout));
16109 assert(crtc->bo->active_scanout);
16110 assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
16111 crtc->bo->active_scanout--;
16112@@ -7531,8 +8998,10 @@ again:
16113
16114 DBG(("%s: flip complete, pending? %d\n", __FUNCTION__, sna->mode.flip_active));
16115 assert(sna->mode.flip_active);
16116- if (--sna->mode.flip_active == 0)
16117+ if (--sna->mode.flip_active == 0) {
16118+ assert(crtc->flip_handler);
16119 crtc->flip_handler(vbl, crtc->flip_data);
16120+ }
16121 }
16122 break;
16123 default:
16124diff --git a/src/sna/sna_display_fake.c b/src/sna/sna_display_fake.c
16125index 4d74c38..a07fe0f 100644
16126--- a/src/sna/sna_display_fake.c
16127+++ b/src/sna/sna_display_fake.c
16128@@ -192,7 +192,7 @@ static const xf86OutputFuncsRec sna_output_funcs = {
16129 static Bool
16130 sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
16131 {
16132- ScreenPtr screen = scrn->pScreen;
16133+ ScreenPtr screen = xf86ScrnToScreen(scrn);
16134 PixmapPtr new_front;
16135
16136 DBG(("%s (%d, %d) -> (%d, %d)\n", __FUNCTION__,
16137@@ -262,6 +262,7 @@ static bool add_fake_output(struct sna *sna, bool late)
16138 output->mm_height = 0;
16139 output->interlaceAllowed = FALSE;
16140 output->subpixel_order = SubPixelNone;
16141+ output->status = XF86OutputStatusDisconnected;
16142
16143 output->possible_crtcs = ~((1 << sna->mode.num_real_crtc) - 1);
16144 output->possible_clones = ~((1 << sna->mode.num_real_output) - 1);
16145diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
16146index e5c4d53..33cf3d9 100644
16147--- a/src/sna/sna_dri2.c
16148+++ b/src/sna/sna_dri2.c
16149@@ -82,12 +82,23 @@ get_private(void *buffer)
16150 return (struct sna_dri2_private *)((DRI2Buffer2Ptr)buffer+1);
16151 }
16152
16153+pure static inline DRI2BufferPtr sna_pixmap_get_buffer(PixmapPtr pixmap)
16154+{
16155+ assert(pixmap->refcnt);
16156+ return ((void **)__get_private(pixmap, sna_pixmap_key))[2];
16157+}
16158+
16159+static inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr)
16160+{
16161+ assert(pixmap->refcnt);
16162+ ((void **)__get_private(pixmap, sna_pixmap_key))[2] = ptr;
16163+}
16164+
16165 #if DRI2INFOREC_VERSION >= 4
16166 enum event_type {
16167 WAITMSC = 0,
16168 SWAP,
16169- SWAP_WAIT,
16170- SWAP_THROTTLE,
16171+ SWAP_COMPLETE,
16172 FLIP,
16173 FLIP_THROTTLE,
16174 FLIP_COMPLETE,
16175@@ -98,6 +109,7 @@ struct dri_bo {
16176 struct list link;
16177 struct kgem_bo *bo;
16178 uint32_t name;
16179+ unsigned flags;
16180 };
16181
16182 struct sna_dri2_event {
16183@@ -108,6 +120,8 @@ struct sna_dri2_event {
16184 xf86CrtcPtr crtc;
16185 int pipe;
16186 bool queued;
16187+ bool sync;
16188+ bool chained;
16189
16190 /* for swaps & flips only */
16191 DRI2SwapEventPtr event_complete;
16192@@ -116,35 +130,145 @@ struct sna_dri2_event {
16193 DRI2BufferPtr back;
16194 struct kgem_bo *bo;
16195
16196+ struct copy {
16197+ struct kgem_bo *bo;
16198+ unsigned flags;
16199+ uint32_t name;
16200+ uint32_t size;
16201+ } pending;
16202+
16203 struct sna_dri2_event *chain;
16204
16205- struct list cache;
16206 struct list link;
16207
16208- int mode;
16209+ int flip_continue;
16210+ int keepalive;
16211+ int signal;
16212 };
16213
16214+#if DRI2INFOREC_VERSION < 10
16215+#undef USE_ASYNC_SWAP
16216+#endif
16217+
16218+#if USE_ASYNC_SWAP
16219+#define KEEPALIVE 8 /* wait ~100ms before discarding swap caches */
16220+#define APPLY_DAMAGE 0
16221+#else
16222+#define USE_ASYNC_SWAP 0
16223+#define KEEPALIVE 1
16224+#define APPLY_DAMAGE 1
16225+#endif
16226+
16227 static void sna_dri2_flip_event(struct sna_dri2_event *flip);
16228+inline static DRI2BufferPtr dri2_window_get_front(WindowPtr win);
16229+
16230+static struct kgem_bo *
16231+__sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
16232+ DRI2BufferPtr src, DRI2BufferPtr dst,
16233+ unsigned flags);
16234+
16235+inline static void
16236+__sna_dri2_copy_event(struct sna_dri2_event *info, unsigned flags)
16237+{
16238+ DBG(("%s: flags = %x\n", __FUNCTION__, flags));
16239+ info->bo = __sna_dri2_copy_region(info->sna, info->draw, NULL,
16240+ info->back, info->front,
16241+ flags);
16242+ info->front->flags = info->back->flags;
16243+}
16244+
16245+static int front_pitch(DrawablePtr draw)
16246+{
16247+ DRI2BufferPtr buffer;
16248+
16249+ buffer = NULL;
16250+ if (draw->type != DRAWABLE_PIXMAP)
16251+ buffer = dri2_window_get_front((WindowPtr)draw);
16252+ if (buffer == NULL)
16253+ buffer = sna_pixmap_get_buffer(get_drawable_pixmap(draw));
16254+
16255+ return buffer ? buffer->pitch : 0;
16256+}
16257+
16258+struct dri2_window {
16259+ DRI2BufferPtr front;
16260+ struct sna_dri2_event *chain;
16261+ xf86CrtcPtr crtc;
16262+ int64_t msc_delta;
16263+ struct list cache;
16264+ uint32_t cache_size;
16265+ int scanout;
16266+};
16267+
16268+static struct dri2_window *dri2_window(WindowPtr win)
16269+{
16270+ assert(win->drawable.type != DRAWABLE_PIXMAP);
16271+ return ((void **)__get_private(win, sna_window_key))[1];
16272+}
16273+
16274+static bool use_scanout(struct sna *sna,
16275+ DrawablePtr draw,
16276+ struct dri2_window *priv)
16277+{
16278+ if (priv->front)
16279+ return true;
16280+
16281+ if (priv->scanout < 0)
16282+ priv->scanout =
16283+ (sna->flags & (SNA_LINEAR_FB | SNA_NO_WAIT | SNA_NO_FLIP)) == 0 &&
16284+ draw->width == sna->front->drawable.width &&
16285+ draw->height == sna->front->drawable.height &&
16286+ draw->bitsPerPixel == sna->front->drawable.bitsPerPixel;
16287+
16288+ return priv->scanout;
16289+}
16290
16291 static void
16292 sna_dri2_get_back(struct sna *sna,
16293 DrawablePtr draw,
16294- DRI2BufferPtr back,
16295- struct sna_dri2_event *info)
16296+ DRI2BufferPtr back)
16297 {
16298+ struct dri2_window *priv = dri2_window((WindowPtr)draw);
16299+ uint32_t size;
16300 struct kgem_bo *bo;
16301+ struct dri_bo *c;
16302 uint32_t name;
16303+ int flags;
16304 bool reuse;
16305
16306- DBG(("%s: draw size=%dx%d, buffer size=%dx%d\n",
16307+ DBG(("%s: draw size=%dx%d, back buffer handle=%d size=%dx%d, is-scanout? %d, active?=%d, pitch=%d, front pitch=%d\n",
16308 __FUNCTION__, draw->width, draw->height,
16309- get_private(back)->size & 0xffff, get_private(back)->size >> 16));
16310- reuse = (draw->height << 16 | draw->width) == get_private(back)->size;
16311+ get_private(back)->bo->handle,
16312+ get_private(back)->size & 0xffff, get_private(back)->size >> 16,
16313+ get_private(back)->bo->scanout,
16314+ get_private(back)->bo->active_scanout,
16315+ back->pitch, front_pitch(draw)));
16316+ assert(priv);
16317+
16318+ size = draw->height << 16 | draw->width;
16319+ if (size != priv->cache_size) {
16320+ while (!list_is_empty(&priv->cache)) {
16321+ c = list_first_entry(&priv->cache, struct dri_bo, link);
16322+ list_del(&c->link);
16323+
16324+ DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
16325+ assert(c->bo);
16326+ kgem_bo_destroy(&sna->kgem, c->bo);
16327+
16328+ free(c);
16329+ }
16330+ priv->cache_size = size;
16331+ }
16332+
16333+ reuse = size == get_private(back)->size;
16334+ if (reuse)
16335+ reuse = get_private(back)->bo->scanout == use_scanout(sna, draw, priv);
16336+ DBG(("%s: reuse backbuffer? %d\n", __FUNCTION__, reuse));
16337 if (reuse) {
16338 bo = get_private(back)->bo;
16339 assert(bo->refcnt);
16340- DBG(("%s: back buffer handle=%d, scanout?=%d, refcnt=%d\n",
16341- __FUNCTION__, bo->handle, bo->active_scanout, get_private(back)->refcnt));
16342+ DBG(("%s: back buffer handle=%d, active?=%d, refcnt=%d\n",
16343+ __FUNCTION__, bo->handle, bo->active_scanout, get_private(back)->refcnt));
16344 if (bo->active_scanout == 0) {
16345 DBG(("%s: reuse unattached back\n", __FUNCTION__));
16346 get_private(back)->stale = false;
16347@@ -153,24 +277,33 @@ sna_dri2_get_back(struct sna *sna,
16348 }
16349
16350 bo = NULL;
16351- if (info) {
16352- struct dri_bo *c;
16353- list_for_each_entry(c, &info->cache, link) {
16354- if (c->bo && c->bo->scanout == 0) {
16355- bo = c->bo;
16356- name = c->name;
16357- DBG(("%s: reuse cache handle=%d\n", __FUNCTION__, bo->handle));
16358- list_move_tail(&c->link, &info->cache);
16359- c->bo = NULL;
16360- }
16361+ list_for_each_entry(c, &priv->cache, link) {
16362+ DBG(("%s: cache: handle=%d, active=%d\n",
16363+ __FUNCTION__, c->bo ? c->bo->handle : 0, c->bo ? c->bo->active_scanout : -1));
16364+ assert(c->bo);
16365+ if (c->bo->active_scanout == 0) {
16366+ bo = c->bo;
16367+ name = c->name;
16368+ flags = c->flags;
16369+ DBG(("%s: reuse cache handle=%d, name=%d, flags=%d\n", __FUNCTION__, bo->handle, name, flags));
16370+ c->bo = NULL;
16371+ _list_del(&c->link);
16372+ break;
16373 }
16374 }
16375 if (bo == NULL) {
16376 DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
16377+ flags = CREATE_EXACT;
16378+
16379+ if (use_scanout(sna, draw, priv)) {
16380+ DBG(("%s: requesting scanout compatible back\n", __FUNCTION__));
16381+ flags |= CREATE_SCANOUT;
16382+ }
16383+
16384 bo = kgem_create_2d(&sna->kgem,
16385 draw->width, draw->height, draw->bitsPerPixel,
16386 get_private(back)->bo->tiling,
16387- get_private(back)->bo->scanout ? CREATE_SCANOUT : 0);
16388+ flags);
16389 if (bo == NULL)
16390 return;
16391
16392@@ -179,30 +312,42 @@ sna_dri2_get_back(struct sna *sna,
16393 kgem_bo_destroy(&sna->kgem, bo);
16394 return;
16395 }
16396+
16397+ flags = 0;
16398+ if (USE_ASYNC_SWAP && back->flags) {
16399+ BoxRec box;
16400+
16401+ box.x1 = 0;
16402+ box.y1 = 0;
16403+ box.x2 = draw->width;
16404+ box.y2 = draw->height;
16405+
16406+ DBG(("%s: filling new buffer with old back\n", __FUNCTION__));
16407+ if (sna->render.copy_boxes(sna, GXcopy,
16408+ draw, get_private(back)->bo, 0, 0,
16409+ draw, bo, 0, 0,
16410+ &box, 1, COPY_LAST | COPY_DRI))
16411+ flags = back->flags;
16412+ }
16413 }
16414 assert(bo->active_scanout == 0);
16415
16416- if (info && reuse) {
16417- bool found = false;
16418- struct dri_bo *c;
16419-
16420- list_for_each_entry_reverse(c, &info->cache, link) {
16421- if (c->bo == NULL) {
16422- found = true;
16423- _list_del(&c->link);
16424- break;
16425- }
16426- }
16427- if (!found)
16428+ if (reuse && get_private(back)->bo->refcnt == 1 + get_private(back)->bo->active_scanout) {
16429+ if (&c->link == &priv->cache)
16430 c = malloc(sizeof(*c));
16431 if (c != NULL) {
16432 c->bo = ref(get_private(back)->bo);
16433 c->name = back->name;
16434- list_add(&c->link, &info->cache);
16435- DBG(("%s: cacheing handle=%d (name=%d)\n", __FUNCTION__, c->bo->handle, c->name));
16436+ c->flags = back->flags;
16437+ list_add(&c->link, &priv->cache);
16438+ DBG(("%s: caching handle=%d (name=%d, flags=%d, active_scanout=%d)\n", __FUNCTION__, c->bo->handle, c->name, c->flags, c->bo->active_scanout));
16439 }
16440+ } else {
16441+ if (&c->link != &priv->cache)
16442+ free(c);
16443 }
16444
16445+ assert(bo->active_scanout == 0);
16446 assert(bo != get_private(back)->bo);
16447 kgem_bo_destroy(&sna->kgem, get_private(back)->bo);
16448
16449@@ -210,21 +355,12 @@ sna_dri2_get_back(struct sna *sna,
16450 get_private(back)->size = draw->height << 16 | draw->width;
16451 back->pitch = bo->pitch;
16452 back->name = name;
16453+ back->flags = flags;
16454
16455- get_private(back)->stale = false;
16456-}
16457-
16458-struct dri2_window {
16459- DRI2BufferPtr front;
16460- struct sna_dri2_event *chain;
16461- xf86CrtcPtr crtc;
16462- int64_t msc_delta;
16463-};
16464+ assert(back->pitch);
16465+ assert(back->name);
16466
16467-static struct dri2_window *dri2_window(WindowPtr win)
16468-{
16469- assert(win->drawable.type != DRAWABLE_PIXMAP);
16470- return ((void **)__get_private(win, sna_window_key))[1];
16471+ get_private(back)->stale = false;
16472 }
16473
16474 static struct sna_dri2_event *
16475@@ -241,12 +377,14 @@ inline static DRI2BufferPtr dri2_window_get_front(WindowPtr win)
16476 }
16477 #else
16478 inline static void *dri2_window_get_front(WindowPtr win) { return NULL; }
16479+#define APPLY_DAMAGE 1
16480 #endif
16481
16482 #if DRI2INFOREC_VERSION < 6
16483
16484 #define xorg_can_triple_buffer() 0
16485 #define swap_limit(d, l) false
16486+#define mark_stale(b)
16487
16488 #else
16489
16490@@ -273,6 +411,8 @@ mark_stale(DRI2BufferPtr back)
16491 * stale frame. (This is mostly useful for tracking down
16492 * driver bugs!)
16493 */
16494+ DBG(("%s(handle=%d) => %d\n", __FUNCTION__,
16495+ get_private(back)->bo->handle, xorg_can_triple_buffer()));
16496 get_private(back)->stale = xorg_can_triple_buffer();
16497 }
16498
16499@@ -290,16 +430,20 @@ sna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
16500 __FUNCTION__, get_drawable_pixmap(draw)->drawable.serialNumber,
16501 buffer->attachment, get_private(buffer)->bo->handle, buffer->name));
16502 assert(get_private(buffer)->refcnt);
16503- assert(get_private(buffer)->bo->refcnt > get_private(buffer)->bo->active_scanout);
16504+ assert(get_private(buffer)->bo->refcnt >= get_private(buffer)->bo->active_scanout);
16505+ assert(kgem_bo_flink(&to_sna_from_drawable(draw)->kgem, get_private(buffer)->bo) == buffer->name);
16506
16507 if (buffer->attachment == DRI2BufferBackLeft &&
16508 draw->type != DRAWABLE_PIXMAP) {
16509- DBG(("%s: replacing back buffer\n", __FUNCTION__));
16510- sna_dri2_get_back(to_sna_from_drawable(draw), draw, buffer, dri2_chain(draw));
16511+ DBG(("%s: replacing back buffer on window %ld\n", __FUNCTION__, draw->id));
16512+ sna_dri2_get_back(to_sna_from_drawable(draw), draw, buffer);
16513
16514- assert(kgem_bo_flink(&to_sna_from_drawable(draw)->kgem, get_private(buffer)->bo) == buffer->name);
16515 assert(get_private(buffer)->bo->refcnt);
16516 assert(get_private(buffer)->bo->active_scanout == 0);
16517+ assert(kgem_bo_flink(&to_sna_from_drawable(draw)->kgem, get_private(buffer)->bo) == buffer->name);
16518+ DBG(("%s: reusing back buffer handle=%d, name=%d, pitch=%d, age=%d\n",
16519+ __FUNCTION__, get_private(buffer)->bo->handle,
16520+ buffer->name, buffer->pitch, buffer->flags));
16521 }
16522 }
16523
16524@@ -314,11 +458,6 @@ static bool swap_limit(DrawablePtr draw, int limit)
16525 }
16526 #endif
16527
16528-#if DRI2INFOREC_VERSION < 10
16529-#undef USE_ASYNC_SWAP
16530-#define USE_ASYNC_SWAP 0
16531-#endif
16532-
16533 #define COLOR_PREFER_TILING_Y 0
16534
16535 /* Prefer to enable TILING_Y if this buffer will never be a
16536@@ -328,6 +467,9 @@ static uint32_t color_tiling(struct sna *sna, DrawablePtr draw)
16537 {
16538 uint32_t tiling;
16539
16540+ if (!sna->kgem.can_fence)
16541+ return I915_TILING_NONE;
16542+
16543 if (COLOR_PREFER_TILING_Y &&
16544 (draw->width != sna->front->drawable.width ||
16545 draw->height != sna->front->drawable.height))
16546@@ -355,7 +497,6 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
16547 PixmapPtr pixmap)
16548 {
16549 struct sna_pixmap *priv;
16550- int tiling;
16551
16552 DBG(("%s: attaching DRI client to pixmap=%ld\n",
16553 __FUNCTION__, pixmap->drawable.serialNumber));
16554@@ -373,31 +514,29 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
16555 return NULL;
16556 }
16557
16558- assert(priv->flush == false);
16559+ assert(priv->flush == false || priv->pinned & PIN_DRI3);
16560+ assert(priv->gpu_bo->flush == false || priv->pinned & PIN_DRI3);
16561 assert(priv->cpu_damage == NULL);
16562 assert(priv->gpu_bo);
16563 assert(priv->gpu_bo->proxy == NULL);
16564- assert(priv->gpu_bo->flush == false);
16565-
16566- tiling = color_tiling(sna, &pixmap->drawable);
16567- if (tiling < 0)
16568- tiling = -tiling;
16569- if (priv->gpu_bo->tiling != tiling)
16570- sna_pixmap_change_tiling(pixmap, tiling);
16571
16572- return priv->gpu_bo;
16573-}
16574+ if (!sna->kgem.can_fence) {
16575+ if (priv->gpu_bo->tiling &&
16576+ !sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) {
16577+ DBG(("%s: failed to discard tiling (%d) for DRI2 protocol\n", __FUNCTION__, priv->gpu_bo->tiling));
16578+ return NULL;
16579+ }
16580+ } else {
16581+ int tiling = color_tiling(sna, &pixmap->drawable);
16582+ if (tiling < 0)
16583+ tiling = -tiling;
16584+ if (priv->gpu_bo->tiling < tiling && !priv->gpu_bo->scanout)
16585+ sna_pixmap_change_tiling(pixmap, tiling);
16586+ }
16587
16588-pure static inline void *sna_pixmap_get_buffer(PixmapPtr pixmap)
16589-{
16590- assert(pixmap->refcnt);
16591- return ((void **)__get_private(pixmap, sna_pixmap_key))[2];
16592-}
16593+ priv->gpu_bo->active_scanout++;
16594
16595-static inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr)
16596-{
16597- assert(pixmap->refcnt);
16598- ((void **)__get_private(pixmap, sna_pixmap_key))[2] = ptr;
16599+ return priv->gpu_bo;
16600 }
16601
16602 void
16603@@ -422,13 +561,18 @@ sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap, struct kgem_bo *bo)
16604 if (private->bo == bo)
16605 return;
16606
16607+ assert(private->bo->active_scanout > 0);
16608+ private->bo->active_scanout--;
16609+
16610 DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle));
16611 private->bo->flush = false;
16612 kgem_bo_destroy(&sna->kgem, private->bo);
16613
16614+
16615 buffer->name = kgem_bo_flink(&sna->kgem, bo);
16616 buffer->pitch = bo->pitch;
16617 private->bo = ref(bo);
16618+ bo->active_scanout++;
16619
16620 DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, bo->handle));
16621 bo->flush = true;
16622@@ -449,9 +593,9 @@ sna_dri2_create_buffer(DrawablePtr draw,
16623 struct sna_dri2_private *private;
16624 PixmapPtr pixmap;
16625 struct kgem_bo *bo;
16626- unsigned flags = 0;
16627+ unsigned bpp = format ?: draw->bitsPerPixel;
16628+ unsigned flags = CREATE_EXACT;
16629 uint32_t size;
16630- int bpp;
16631
16632 DBG(("%s pixmap=%ld, (attachment=%d, format=%d, drawable=%dx%d), window?=%d\n",
16633 __FUNCTION__,
16634@@ -468,11 +612,11 @@ sna_dri2_create_buffer(DrawablePtr draw,
16635 if (draw->type != DRAWABLE_PIXMAP)
16636 buffer = dri2_window_get_front((WindowPtr)draw);
16637 if (buffer == NULL)
16638- buffer = sna_pixmap_get_buffer(pixmap);
16639+ buffer = (DRI2Buffer2Ptr)sna_pixmap_get_buffer(pixmap);
16640 if (buffer) {
16641 private = get_private(buffer);
16642
16643- DBG(("%s: reusing front buffer attachment, win=%lu %dx%d, pixmap=%ld [%ld] %dx%d, handle=%d, name=%d\n",
16644+ DBG(("%s: reusing front buffer attachment, win=%lu %dx%d, pixmap=%ld [%ld] %dx%d, handle=%d, name=%d, active_scanout=%d\n",
16645 __FUNCTION__,
16646 draw->type != DRAWABLE_PIXMAP ? (long)draw->id : (long)0,
16647 draw->width, draw->height,
16648@@ -480,12 +624,14 @@ sna_dri2_create_buffer(DrawablePtr draw,
16649 private->pixmap->drawable.serialNumber,
16650 pixmap->drawable.width,
16651 pixmap->drawable.height,
16652- private->bo->handle, buffer->name));
16653+ private->bo->handle, buffer->name,
16654+ private->bo->active_scanout));
16655
16656 assert(private->pixmap == pixmap);
16657 assert(sna_pixmap(pixmap)->flush);
16658 assert(sna_pixmap(pixmap)->pinned & PIN_DRI2);
16659 assert(kgem_bo_flink(&sna->kgem, private->bo) == buffer->name);
16660+ assert(private->bo->pitch == buffer->pitch);
16661
16662 private->refcnt++;
16663 return buffer;
16664@@ -498,7 +644,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
16665 assert(sna_pixmap(pixmap) != NULL);
16666
16667 bo = ref(bo);
16668- bpp = pixmap->drawable.bitsPerPixel;
16669 if (pixmap == sna->front && !(sna->flags & SNA_LINEAR_FB))
16670 flags |= CREATE_SCANOUT;
16671 DBG(("%s: attaching to front buffer %dx%d [%p:%d], scanout? %d\n",
16672@@ -506,6 +651,7 @@ sna_dri2_create_buffer(DrawablePtr draw,
16673 pixmap->drawable.width, pixmap->drawable.height,
16674 pixmap, pixmap->refcnt, flags & CREATE_SCANOUT));
16675 size = (uint32_t)pixmap->drawable.height << 16 | pixmap->drawable.width;
16676+ bpp = pixmap->drawable.bitsPerPixel;
16677 break;
16678
16679 case DRI2BufferBackLeft:
16680@@ -514,6 +660,7 @@ sna_dri2_create_buffer(DrawablePtr draw,
16681 flags |= CREATE_SCANOUT;
16682 if (draw->width == sna->front->drawable.width &&
16683 draw->height == sna->front->drawable.height &&
16684+ draw->bitsPerPixel == bpp &&
16685 (sna->flags & (SNA_LINEAR_FB | SNA_NO_WAIT | SNA_NO_FLIP)) == 0)
16686 flags |= CREATE_SCANOUT;
16687 }
16688@@ -521,7 +668,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
16689 case DRI2BufferFrontRight:
16690 case DRI2BufferFakeFrontLeft:
16691 case DRI2BufferFakeFrontRight:
16692- bpp = draw->bitsPerPixel;
16693 DBG(("%s: creating back buffer %dx%d, suitable for scanout? %d\n",
16694 __FUNCTION__,
16695 draw->width, draw->height,
16696@@ -530,7 +676,7 @@ sna_dri2_create_buffer(DrawablePtr draw,
16697 bo = kgem_create_2d(&sna->kgem,
16698 draw->width,
16699 draw->height,
16700- draw->bitsPerPixel,
16701+ bpp,
16702 color_tiling(sna, draw),
16703 flags);
16704 break;
16705@@ -558,7 +704,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
16706 * not understand W tiling and the GTT is incapable of
16707 * W fencing.
16708 */
16709- bpp = format ? format : draw->bitsPerPixel;
16710 bpp *= 2;
16711 bo = kgem_create_2d(&sna->kgem,
16712 ALIGN(draw->width, 64),
16713@@ -570,7 +715,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
16714 case DRI2BufferDepthStencil:
16715 case DRI2BufferHiz:
16716 case DRI2BufferAccum:
16717- bpp = format ? format : draw->bitsPerPixel,
16718 bo = kgem_create_2d(&sna->kgem,
16719 draw->width, draw->height, bpp,
16720 other_tiling(sna, draw),
16721@@ -614,7 +758,7 @@ sna_dri2_create_buffer(DrawablePtr draw,
16722 pixmap->refcnt++;
16723
16724 priv = sna_pixmap(pixmap);
16725- assert(priv->flush == false);
16726+ assert(priv->flush == false || priv->pinned & PIN_DRI3);
16727 assert((priv->pinned & PIN_DRI2) == 0);
16728
16729 /* Don't allow this named buffer to be replaced */
16730@@ -630,14 +774,14 @@ sna_dri2_create_buffer(DrawablePtr draw,
16731 if (priv->gpu_bo->exec)
16732 sna->kgem.flush = 1;
16733
16734- priv->flush |= 1;
16735+ priv->flush |= FLUSH_READ;
16736 if (draw->type == DRAWABLE_PIXMAP) {
16737 /* DRI2 renders directly into GLXPixmaps, treat as hostile */
16738 kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
16739 sna_damage_all(&priv->gpu_damage, pixmap);
16740 priv->clear = false;
16741 priv->cpu = false;
16742- priv->flush |= 2;
16743+ priv->flush |= FLUSH_WRITE;
16744 }
16745
16746 sna_accel_watch_flush(sna, 1);
16747@@ -651,7 +795,69 @@ err:
16748 return NULL;
16749 }
16750
16751-static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
16752+static void
16753+sna_dri2_cache_bo(struct sna *sna,
16754+ DrawablePtr draw,
16755+ struct kgem_bo *bo,
16756+ uint32_t name,
16757+ uint32_t size,
16758+ uint32_t flags)
16759+{
16760+ struct dri_bo *c;
16761+
16762+ DBG(("%s(handle=%d, name=%d)\n", __FUNCTION__, bo->handle, name));
16763+
16764+ if (draw == NULL) {
16765+ DBG(("%s: no draw, releasing handle=%d\n",
16766+ __FUNCTION__, bo->handle));
16767+ goto err;
16768+ }
16769+
16770+ if (draw->type == DRAWABLE_PIXMAP) {
16771+ DBG(("%s: not a window, releasing handle=%d\n",
16772+ __FUNCTION__, bo->handle));
16773+ goto err;
16774+ }
16775+
16776+ if (bo->refcnt > 1 + bo->active_scanout) {
16777+ DBG(("%s: multiple references [%d], releasing handle\n",
16778+ __FUNCTION__, bo->refcnt, bo->handle));
16779+ goto err;
16780+ }
16781+
16782+ if ((draw->height << 16 | draw->width) != size) {
16783+ DBG(("%s: wrong size [%dx%d], releasing handle\n",
16784+ __FUNCTION__,
16785+ size & 0xffff, size >> 16,
16786+ bo->handle));
16787+ goto err;
16788+ }
16789+
16790+ if (bo->scanout && front_pitch(draw) != bo->pitch) {
16791+ DBG(("%s: scanout with pitch change [%d != %d], releasing handle\n",
16792+ __FUNCTION__, bo->pitch, front_pitch(draw), bo->handle));
16793+ goto err;
16794+ }
16795+
16796+ c = malloc(sizeof(*c));
16797+ if (!c)
16798+ goto err;
16799+
16800+ DBG(("%s: caching handle=%d (name=%d, flags=%d, active_scanout=%d)\n", __FUNCTION__, bo->handle, name, flags, bo->active_scanout));
16801+
16802+ c->bo = bo;
16803+ c->name = name;
16804+ c->flags = flags;
16805+ list_add(&c->link, &dri2_window((WindowPtr)draw)->cache);
16806+ return;
16807+
16808+err:
16809+ kgem_bo_destroy(&sna->kgem, bo);
16810+}
16811+
16812+static void _sna_dri2_destroy_buffer(struct sna *sna,
16813+ DrawablePtr draw,
16814+ DRI2Buffer2Ptr buffer)
16815 {
16816 struct sna_dri2_private *private = get_private(buffer);
16817
16818@@ -669,7 +875,7 @@ static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
16819
16820 if (private->proxy) {
16821 DBG(("%s: destroying proxy\n", __FUNCTION__));
16822- _sna_dri2_destroy_buffer(sna, private->proxy);
16823+ _sna_dri2_destroy_buffer(sna, draw, private->proxy);
16824 private->pixmap = NULL;
16825 }
16826
16827@@ -683,6 +889,9 @@ static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
16828 assert(priv->pinned & PIN_DRI2);
16829 assert(priv->flush);
16830
16831+ assert(priv->gpu_bo->active_scanout > 0);
16832+ priv->gpu_bo->active_scanout--;
16833+
16834 /* Undo the DRI markings on this pixmap */
16835 DBG(("%s: releasing last DRI pixmap=%ld, scanout?=%d\n",
16836 __FUNCTION__,
16837@@ -692,24 +901,29 @@ static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
16838 list_del(&priv->flush_list);
16839
16840 DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle));
16841- priv->gpu_bo->flush = false;
16842 priv->pinned &= ~PIN_DRI2;
16843
16844- priv->flush = false;
16845+ if ((priv->pinned & PIN_DRI3) == 0) {
16846+ priv->gpu_bo->flush = false;
16847+ priv->flush = false;
16848+ }
16849 sna_accel_watch_flush(sna, -1);
16850
16851 sna_pixmap_set_buffer(pixmap, NULL);
16852 pixmap->drawable.pScreen->DestroyPixmap(pixmap);
16853 }
16854- assert(private->bo->flush == false);
16855
16856- kgem_bo_destroy(&sna->kgem, private->bo);
16857+ sna_dri2_cache_bo(sna, draw,
16858+ private->bo,
16859+ buffer->name,
16860+ private->size,
16861+ buffer->flags);
16862 free(buffer);
16863 }
16864
16865 static void sna_dri2_destroy_buffer(DrawablePtr draw, DRI2Buffer2Ptr buffer)
16866 {
16867- _sna_dri2_destroy_buffer(to_sna_from_drawable(draw), buffer);
16868+ _sna_dri2_destroy_buffer(to_sna_from_drawable(draw), draw, buffer);
16869 }
16870
16871 static DRI2BufferPtr sna_dri2_reference_buffer(DRI2BufferPtr buffer)
16872@@ -746,10 +960,9 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
16873 {
16874 struct sna *sna = to_sna_from_pixmap(pixmap);
16875 struct sna_pixmap *priv = sna_pixmap(pixmap);
16876- RegionRec region;
16877
16878- DBG(("%s: pixmap=%ld, handle=%d\n",
16879- __FUNCTION__, pixmap->drawable.serialNumber, bo->handle));
16880+ DBG(("%s: pixmap=%ld, handle=%d (old handle=%d)\n",
16881+ __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, priv->gpu_bo->handle));
16882
16883 assert(pixmap->drawable.width * pixmap->drawable.bitsPerPixel <= 8*bo->pitch);
16884 assert(pixmap->drawable.height * bo->pitch <= kgem_bo_size(bo));
16885@@ -758,21 +971,34 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
16886 assert((priv->pinned & (PIN_PRIME | PIN_DRI3)) == 0);
16887 assert(priv->flush);
16888
16889- /* Post damage on the new front buffer so that listeners, such
16890- * as DisplayLink know take a copy and shove it over the USB,
16891- * also for software cursors and the like.
16892- */
16893- region.extents.x1 = region.extents.y1 = 0;
16894- region.extents.x2 = pixmap->drawable.width;
16895- region.extents.y2 = pixmap->drawable.height;
16896- region.data = NULL;
16897- DamageRegionAppend(&pixmap->drawable, &region);
16898+ if (APPLY_DAMAGE) {
16899+ RegionRec region;
16900+
16901+ /* Post damage on the new front buffer so that listeners, such
16902+ * as DisplayLink know take a copy and shove it over the USB,
16903+ * also for software cursors and the like.
16904+ */
16905+ region.extents.x1 = region.extents.y1 = 0;
16906+ region.extents.x2 = pixmap->drawable.width;
16907+ region.extents.y2 = pixmap->drawable.height;
16908+ region.data = NULL;
16909+
16910+ /*
16911+ * Eeek, beware the sw cursor copying to the old bo
16912+ * causing recursion and mayhem.
16913+ */
16914+ DBG(("%s: marking whole pixmap as damaged\n", __FUNCTION__));
16915+ sna->ignore_copy_area = true;
16916+ DamageRegionAppend(&pixmap->drawable, &region);
16917+ }
16918
16919 damage(pixmap, priv, NULL);
16920
16921 assert(bo->refcnt);
16922- if (priv->move_to_gpu)
16923+ if (priv->move_to_gpu) {
16924+ DBG(("%s: applying final/discard move-to-gpu\n", __FUNCTION__));
16925 priv->move_to_gpu(sna, priv, 0);
16926+ }
16927 if (priv->gpu_bo != bo) {
16928 DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, priv->gpu_bo->handle));
16929 priv->gpu_bo->flush = false;
16930@@ -792,8 +1018,27 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
16931 bo->domain = DOMAIN_NONE;
16932 assert(bo->flush);
16933
16934- DamageRegionProcessPending(&pixmap->drawable);
16935+ if (APPLY_DAMAGE) {
16936+ DamageRegionProcessPending(&pixmap->drawable);
16937+ sna->ignore_copy_area = false;
16938+ }
16939+}
16940+
16941+#if defined(__GNUC__)
16942+#define popcount(x) __builtin_popcount(x)
16943+#else
16944+static int popcount(unsigned int x)
16945+{
16946+ int count = 0;
16947+
16948+ while (x) {
16949+ count += x&1;
16950+ x >>= 1;
16951+ }
16952+
16953+ return count;
16954 }
16955+#endif
16956
16957 static void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kgem_bo *src, bool sync)
16958 {
16959@@ -823,6 +1068,12 @@ static void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kg
16960 return;
16961 }
16962
16963+ if (sna->render_state.gt < 2 && sna->kgem.has_semaphores) {
16964+ DBG(("%s: small GT [%d], not forcing selection\n",
16965+ __FUNCTION__, sna->render_state.gt));
16966+ return;
16967+ }
16968+
16969 VG_CLEAR(busy);
16970 busy.handle = src->handle;
16971 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy))
16972@@ -859,9 +1110,12 @@ static void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kg
16973 * The ultimate question is whether preserving the ring outweighs
16974 * the cost of the query.
16975 */
16976- mode = KGEM_RENDER;
16977- if (busy.busy & (0xfffe << 16))
16978+ if (popcount(busy.busy >> 16) > 1)
16979+ mode = busy.busy & 0xffff ? KGEM_BLT : KGEM_RENDER;
16980+ else if (busy.busy & (0xfffe << 16))
16981 mode = KGEM_BLT;
16982+ else
16983+ mode = KGEM_RENDER;
16984 kgem_bo_mark_busy(&sna->kgem, busy.handle == src->handle ? src : dst, mode);
16985 _kgem_set_mode(&sna->kgem, mode);
16986 }
16987@@ -871,10 +1125,13 @@ static bool is_front(int attachment)
16988 return attachment == DRI2BufferFrontLeft;
16989 }
16990
16991+#define DRI2_SYNC 0x1
16992+#define DRI2_DAMAGE 0x2
16993+#define DRI2_BO 0x4
16994 static struct kgem_bo *
16995 __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
16996 DRI2BufferPtr src, DRI2BufferPtr dst,
16997- bool sync)
16998+ unsigned flags)
16999 {
17000 PixmapPtr pixmap = get_drawable_pixmap(draw);
17001 DrawableRec scratch, *src_draw = &pixmap->drawable, *dst_draw = &pixmap->drawable;
17002@@ -886,7 +1143,7 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
17003 struct kgem_bo *dst_bo;
17004 const BoxRec *boxes;
17005 int16_t dx, dy, sx, sy;
17006- unsigned flags;
17007+ unsigned hint;
17008 int n;
17009
17010 /* To hide a stale DRI2Buffer, one may choose to substitute
17011@@ -962,8 +1219,9 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
17012 }
17013 }
17014 } else
17015- sync = false;
17016+ flags &= ~DRI2_SYNC;
17017
17018+ scratch.pScreen = draw->pScreen;
17019 scratch.x = scratch.y = 0;
17020 scratch.width = scratch.height = 0;
17021 scratch.depth = draw->depth;
17022@@ -987,11 +1245,12 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
17023 scratch.height = src_priv->size >> 16;
17024 src_draw = &scratch;
17025
17026- DBG(("%s: source size %dx%d, region size %dx%d\n",
17027+ DBG(("%s: source size %dx%d, region size %dx%d, src offset %dx%d\n",
17028 __FUNCTION__,
17029 scratch.width, scratch.height,
17030 clip.extents.x2 - clip.extents.x1,
17031- clip.extents.y2 - clip.extents.y1));
17032+ clip.extents.y2 - clip.extents.y1,
17033+ -sx, -sy));
17034
17035 source.extents.x1 = -sx;
17036 source.extents.y1 = -sy;
17037@@ -1002,6 +1261,10 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
17038 assert(region == NULL || region == &clip);
17039 pixman_region_intersect(&clip, &clip, &source);
17040
17041+ if (!pixman_region_not_empty(&clip)) {
17042+ DBG(("%s: region doesn't overlap pixmap\n", __FUNCTION__));
17043+ return NULL;
17044+ }
17045 }
17046
17047 dst_bo = dst_priv->bo;
17048@@ -1013,12 +1276,12 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
17049 /* Preserve the CRTC shadow overrides */
17050 sna_shadow_steal_crtcs(sna, &shadow);
17051
17052- flags = MOVE_WRITE | __MOVE_FORCE;
17053+ hint = MOVE_WRITE | __MOVE_FORCE;
17054 if (clip.data)
17055- flags |= MOVE_READ;
17056+ hint |= MOVE_READ;
17057
17058 assert(region == NULL || region == &clip);
17059- priv = sna_pixmap_move_area_to_gpu(pixmap, &clip.extents, flags);
17060+ priv = sna_pixmap_move_area_to_gpu(pixmap, &clip.extents, hint);
17061 if (priv) {
17062 damage(pixmap, priv, region);
17063 dst_bo = priv->gpu_bo;
17064@@ -1050,20 +1313,20 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
17065 assert(region == NULL || region == &clip);
17066 pixman_region_intersect(&clip, &clip, &target);
17067
17068- sync = false;
17069+ flags &= ~DRI2_SYNC;
17070 }
17071
17072 if (!wedged(sna)) {
17073 xf86CrtcPtr crtc;
17074
17075 crtc = NULL;
17076- if (sync && sna_pixmap_is_scanout(sna, pixmap))
17077+ if (flags & DRI2_SYNC && sna_pixmap_is_scanout(sna, pixmap))
17078 crtc = sna_covering_crtc(sna, &clip.extents, NULL);
17079 sna_dri2_select_mode(sna, dst_bo, src_bo, crtc != NULL);
17080
17081- sync = (crtc != NULL&&
17082- sna_wait_for_scanline(sna, pixmap, crtc,
17083- &clip.extents));
17084+ if (crtc == NULL ||
17085+ !sna_wait_for_scanline(sna, pixmap, crtc, &clip.extents))
17086+ flags &= ~DRI2_SYNC;
17087 }
17088
17089 if (region) {
17090@@ -1075,8 +1338,11 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
17091 boxes = &clip.extents;
17092 n = 1;
17093 }
17094- DamageRegionAppend(&pixmap->drawable, region);
17095-
17096+ if (APPLY_DAMAGE || flags & DRI2_DAMAGE) {
17097+ DBG(("%s: marking region as damaged\n", __FUNCTION__));
17098+ sna->ignore_copy_area = true;
17099+ DamageRegionAppend(&pixmap->drawable, region);
17100+ }
17101
17102 DBG(("%s: copying [(%d, %d), (%d, %d)]x%d src=(%d, %d), dst=(%d, %d)\n",
17103 __FUNCTION__,
17104@@ -1084,29 +1350,35 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
17105 boxes[0].x2, boxes[0].y2,
17106 n, sx, sy, dx, dy));
17107
17108- flags = COPY_LAST;
17109- if (sync)
17110- flags |= COPY_SYNC;
17111+ hint = COPY_LAST | COPY_DRI;
17112+ if (flags & DRI2_SYNC)
17113+ hint |= COPY_SYNC;
17114 if (!sna->render.copy_boxes(sna, GXcopy,
17115 src_draw, src_bo, sx, sy,
17116 dst_draw, dst_bo, dx, dy,
17117- boxes, n, flags))
17118+ boxes, n, hint))
17119 memcpy_copy_boxes(sna, GXcopy,
17120 src_draw, src_bo, sx, sy,
17121 dst_draw, dst_bo, dx, dy,
17122- boxes, n, flags);
17123-
17124- DBG(("%s: flushing? %d\n", __FUNCTION__, sync));
17125- if (sync) { /* STAT! */
17126- struct kgem_request *rq = sna->kgem.next_request;
17127- kgem_submit(&sna->kgem);
17128- if (rq->bo) {
17129- bo = ref(rq->bo);
17130- DBG(("%s: recording sync fence handle=%d\n", __FUNCTION__, bo->handle));
17131+ boxes, n, hint);
17132+
17133+ if (flags & (DRI2_SYNC | DRI2_BO)) { /* STAT! */
17134+ struct kgem_request *rq = RQ(dst_bo->rq);
17135+ if (rq && rq != (void *)&sna->kgem) {
17136+ if (rq->bo == NULL)
17137+ kgem_submit(&sna->kgem);
17138+ if (rq->bo) { /* Becareful in case the gpu is wedged */
17139+ bo = ref(rq->bo);
17140+ DBG(("%s: recording sync fence handle=%d\n",
17141+ __FUNCTION__, bo->handle));
17142+ }
17143 }
17144 }
17145
17146- DamageRegionProcessPending(&pixmap->drawable);
17147+ if (APPLY_DAMAGE || flags & DRI2_DAMAGE) {
17148+ DamageRegionProcessPending(&pixmap->drawable);
17149+ sna->ignore_copy_area = false;
17150+ }
17151
17152 if (clip.data)
17153 pixman_region_fini(&clip);
17154@@ -1142,6 +1414,8 @@ sna_dri2_copy_region(DrawablePtr draw,
17155 assert(get_private(src)->refcnt);
17156 assert(get_private(dst)->refcnt);
17157
17158+ assert(get_private(src)->bo != get_private(dst)->bo);
17159+
17160 assert(get_private(src)->bo->refcnt);
17161 assert(get_private(dst)->bo->refcnt);
17162
17163@@ -1151,7 +1425,7 @@ sna_dri2_copy_region(DrawablePtr draw,
17164 region->extents.x2, region->extents.y2,
17165 region_num_rects(region)));
17166
17167- __sna_dri2_copy_region(sna, draw, region, src, dst, false);
17168+ __sna_dri2_copy_region(sna, draw, region, src, dst, DRI2_DAMAGE);
17169 }
17170
17171 inline static uint32_t pipe_select(int pipe)
17172@@ -1169,15 +1443,53 @@ inline static uint32_t pipe_select(int pipe)
17173 return 0;
17174 }
17175
17176-static inline int sna_wait_vblank(struct sna *sna, union drm_wait_vblank *vbl, int pipe)
17177+static inline bool sna_next_vblank(struct sna_dri2_event *info)
17178+{
17179+ union drm_wait_vblank vbl;
17180+
17181+ DBG(("%s(pipe=%d, waiting until next vblank)\n",
17182+ __FUNCTION__, info->pipe));
17183+ assert(info->pipe != -1);
17184+
17185+ VG_CLEAR(vbl);
17186+ vbl.request.type =
17187+ DRM_VBLANK_RELATIVE |
17188+ DRM_VBLANK_EVENT |
17189+ pipe_select(info->pipe);
17190+ vbl.request.sequence = 1;
17191+ vbl.request.signal = (uintptr_t)info;
17192+
17193+ assert(!info->queued);
17194+ if (drmIoctl(info->sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, &vbl))
17195+ return false;
17196+
17197+ info->queued = true;
17198+ return true;
17199+}
17200+
17201+static inline bool sna_wait_vblank(struct sna_dri2_event *info,
17202+ unsigned seq)
17203 {
17204- DBG(("%s(pipe=%d, waiting until seq=%u%s)\n",
17205- __FUNCTION__, pipe, vbl->request.sequence,
17206- vbl->request.type & DRM_VBLANK_RELATIVE ? " [relative]" : ""));
17207- assert(pipe != -1);
17208+ union drm_wait_vblank vbl;
17209
17210- vbl->request.type |= pipe_select(pipe);
17211- return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl);
17212+ DBG(("%s(pipe=%d, waiting until vblank %u)\n",
17213+ __FUNCTION__, info->pipe, seq));
17214+ assert(info->pipe != -1);
17215+
17216+ VG_CLEAR(vbl);
17217+ vbl.request.type =
17218+ DRM_VBLANK_ABSOLUTE |
17219+ DRM_VBLANK_EVENT |
17220+ pipe_select(info->pipe);
17221+ vbl.request.sequence = seq;
17222+ vbl.request.signal = (uintptr_t)info;
17223+
17224+ assert(!info->queued);
17225+ if (drmIoctl(info->sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, &vbl))
17226+ return false;
17227+
17228+ info->queued = true;
17229+ return true;
17230 }
17231
17232 #if DRI2INFOREC_VERSION >= 4
17233@@ -1206,6 +1518,8 @@ draw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc)
17234 priv->crtc = crtc;
17235 priv->msc_delta = 0;
17236 priv->chain = NULL;
17237+ priv->scanout = -1;
17238+ list_init(&priv->cache);
17239 dri2_window_attach((WindowPtr)draw, priv);
17240 }
17241 } else {
17242@@ -1214,8 +1528,8 @@ draw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc)
17243 const struct ust_msc *this = sna_crtc_last_swap(crtc);
17244 DBG(("%s: Window transferring from pipe=%d [msc=%llu] to pipe=%d [msc=%llu], delta now %lld\n",
17245 __FUNCTION__,
17246- sna_crtc_to_pipe(priv->crtc), (long long)last->msc,
17247- sna_crtc_to_pipe(crtc), (long long)this->msc,
17248+ sna_crtc_pipe(priv->crtc), (long long)last->msc,
17249+ sna_crtc_pipe(crtc), (long long)this->msc,
17250 (long long)(priv->msc_delta + this->msc - last->msc)));
17251 priv->msc_delta += this->msc - last->msc;
17252 priv->crtc = crtc;
17253@@ -1248,57 +1562,112 @@ sna_dri2_get_crtc(DrawablePtr draw)
17254 NULL);
17255 }
17256
17257-static void
17258-sna_dri2_remove_event(WindowPtr win, struct sna_dri2_event *info)
17259+static void frame_swap_complete(struct sna_dri2_event *frame, int type)
17260 {
17261- struct dri2_window *priv;
17262- struct sna_dri2_event *chain;
17263-
17264- assert(win->drawable.type == DRAWABLE_WINDOW);
17265- DBG(("%s: remove[%p] from window %ld, active? %d\n",
17266- __FUNCTION__, info, (long)win->drawable.id, info->draw != NULL));
17267+ const struct ust_msc *swap;
17268
17269- priv = dri2_window(win);
17270- assert(priv);
17271- assert(priv->chain != NULL);
17272+ assert(frame->signal);
17273+ frame->signal = false;
17274
17275- if (priv->chain == info) {
17276- priv->chain = info->chain;
17277+ if (frame->client == NULL) {
17278+ DBG(("%s: client already gone\n", __FUNCTION__));
17279 return;
17280 }
17281
17282- chain = priv->chain;
17283- while (chain->chain != info)
17284- chain = chain->chain;
17285- assert(chain != info);
17286- assert(info->chain != chain);
17287- chain->chain = info->chain;
17288-}
17289-
17290-static void
17291-sna_dri2_event_free(struct sna_dri2_event *info)
17292-{
17293- DrawablePtr draw = info->draw;
17294+ assert(frame->draw);
17295
17296- DBG(("%s(draw?=%d)\n", __FUNCTION__, draw != NULL));
17297- if (draw && draw->type == DRAWABLE_WINDOW)
17298- sna_dri2_remove_event((WindowPtr)draw, info);
17299+ swap = sna_crtc_last_swap(frame->crtc);
17300+ DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc=%lld], tv=%d.%06d\n",
17301+ __FUNCTION__, type, (long)frame->draw->id, frame->pipe,
17302+ (long long)swap->msc,
17303+ (long long)draw_current_msc(frame->draw, frame->crtc, swap->msc),
17304+ swap->tv_sec, swap->tv_usec));
17305
17306- _sna_dri2_destroy_buffer(info->sna, info->front);
17307- _sna_dri2_destroy_buffer(info->sna, info->back);
17308+ DRI2SwapComplete(frame->client, frame->draw,
17309+ draw_current_msc(frame->draw, frame->crtc, swap->msc),
17310+ swap->tv_sec, swap->tv_usec,
17311+ type, frame->event_complete, frame->event_data);
17312+}
17313
17314- while (!list_is_empty(&info->cache)) {
17315- struct dri_bo *c;
17316+static void fake_swap_complete(struct sna *sna, ClientPtr client,
17317+ DrawablePtr draw, xf86CrtcPtr crtc,
17318+ int type, DRI2SwapEventPtr func, void *data)
17319+{
17320+ const struct ust_msc *swap;
17321
17322- c = list_first_entry(&info->cache, struct dri_bo, link);
17323- list_del(&c->link);
17324+ swap = sna_crtc_last_swap(crtc);
17325+ DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n",
17326+ __FUNCTION__, type, (long)draw->id, crtc ? sna_crtc_pipe(crtc) : -1,
17327+ (long long)swap->msc,
17328+ (long long)draw_current_msc(draw, crtc, swap->msc),
17329+ swap->tv_sec, swap->tv_usec));
17330
17331- DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
17332- if (c->bo)
17333- kgem_bo_destroy(&info->sna->kgem, c->bo);
17334+ DRI2SwapComplete(client, draw,
17335+ draw_current_msc(draw, crtc, swap->msc),
17336+ swap->tv_sec, swap->tv_usec,
17337+ type, func, data);
17338+}
17339
17340- free(c);
17341+static void
17342+sna_dri2_remove_event(struct sna_dri2_event *info)
17343+{
17344+ WindowPtr win = (WindowPtr)info->draw;
17345+ struct dri2_window *priv;
17346+ struct sna_dri2_event *chain;
17347+
17348+ assert(win->drawable.type == DRAWABLE_WINDOW);
17349+ DBG(("%s: remove[%p] from window %ld, active? %d\n",
17350+ __FUNCTION__, info, (long)win->drawable.id, info->draw != NULL));
17351+ assert(!info->signal);
17352+
17353+ priv = dri2_window(win);
17354+ assert(priv);
17355+ assert(priv->chain != NULL);
17356+ assert(info->chained);
17357+ info->chained = false;
17358+
17359+ if (priv->chain != info) {
17360+ chain = priv->chain;
17361+ while (chain->chain != info)
17362+ chain = chain->chain;
17363+ assert(chain != info);
17364+ assert(info->chain != chain);
17365+ chain->chain = info->chain;
17366+ return;
17367+ }
17368+
17369+ priv->chain = info->chain;
17370+ if (priv->chain == NULL) {
17371+ struct dri_bo *c, *tmp;
17372+
17373+ c = list_entry(priv->cache.next->next, struct dri_bo, link);
17374+ list_for_each_entry_safe_from(c, tmp, &priv->cache, link) {
17375+ list_del(&c->link);
17376+
17377+ DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
17378+ assert(c->bo);
17379+ kgem_bo_destroy(&info->sna->kgem, c->bo);
17380+ free(c);
17381+ }
17382 }
17383+}
17384+
17385+static void
17386+sna_dri2_event_free(struct sna_dri2_event *info)
17387+{
17388+ DBG(("%s(draw?=%d)\n", __FUNCTION__, info->draw != NULL));
17389+ assert(!info->queued);
17390+ assert(!info->signal);
17391+ assert(info->pending.bo == NULL);
17392+
17393+ if (info->sna->dri2.flip_pending == info)
17394+ info->sna->dri2.flip_pending = NULL;
17395+ assert(info->sna->dri2.flip_pending != info);
17396+ if (info->chained)
17397+ sna_dri2_remove_event(info);
17398+
17399+ _sna_dri2_destroy_buffer(info->sna, info->draw, info->front);
17400+ _sna_dri2_destroy_buffer(info->sna, info->draw, info->back);
17401
17402 if (info->bo) {
17403 DBG(("%s: releasing batch handle=%d\n", __FUNCTION__, info->bo->handle));
17404@@ -1331,15 +1700,24 @@ sna_dri2_client_gone(CallbackListPtr *list, void *closure, void *data)
17405
17406 event = list_first_entry(&priv->events, struct sna_dri2_event, link);
17407 assert(event->client == client);
17408+ list_del(&event->link);
17409+ event->signal = false;
17410
17411- if (event->queued) {
17412- if (event->draw)
17413- sna_dri2_remove_event((WindowPtr)event->draw,
17414- event);
17415- event->client = NULL;
17416- event->draw = NULL;
17417- list_del(&event->link);
17418- } else
17419+ if (event->pending.bo) {
17420+ assert(event->pending.bo->active_scanout > 0);
17421+ event->pending.bo->active_scanout--;
17422+
17423+ kgem_bo_destroy(&sna->kgem, event->pending.bo);
17424+ event->pending.bo = NULL;
17425+ }
17426+
17427+ if (event->chained)
17428+ sna_dri2_remove_event(event);
17429+
17430+ event->client = NULL;
17431+ event->draw = NULL;
17432+
17433+ if (!event->queued)
17434 sna_dri2_event_free(event);
17435 }
17436
17437@@ -1365,7 +1743,10 @@ static bool add_event_to_client(struct sna_dri2_event *info, struct sna *sna, Cl
17438 }
17439
17440 static struct sna_dri2_event *
17441-sna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client)
17442+sna_dri2_add_event(struct sna *sna,
17443+ DrawablePtr draw,
17444+ ClientPtr client,
17445+ xf86CrtcPtr crtc)
17446 {
17447 struct dri2_window *priv;
17448 struct sna_dri2_event *info, *chain;
17449@@ -1382,11 +1763,11 @@ sna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client)
17450 if (info == NULL)
17451 return NULL;
17452
17453- list_init(&info->cache);
17454 info->sna = sna;
17455 info->draw = draw;
17456- info->crtc = priv->crtc;
17457- info->pipe = sna_crtc_to_pipe(priv->crtc);
17458+ info->crtc = crtc;
17459+ info->pipe = sna_crtc_pipe(crtc);
17460+ info->keepalive = 1;
17461
17462 if (!add_event_to_client(info, sna, client)) {
17463 free(info);
17464@@ -1394,6 +1775,7 @@ sna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client)
17465 }
17466
17467 assert(priv->chain != info);
17468+ info->chained = true;
17469
17470 if (priv->chain == NULL) {
17471 priv->chain = info;
17472@@ -1423,26 +1805,29 @@ void sna_dri2_decouple_window(WindowPtr win)
17473 struct sna *sna = to_sna_from_drawable(&win->drawable);
17474 assert(priv->crtc);
17475 sna_shadow_unset_crtc(sna, priv->crtc);
17476- _sna_dri2_destroy_buffer(sna, priv->front);
17477+ _sna_dri2_destroy_buffer(sna, NULL, priv->front);
17478 priv->front = NULL;
17479 }
17480+
17481+ priv->scanout = -1;
17482 }
17483
17484 void sna_dri2_destroy_window(WindowPtr win)
17485 {
17486 struct dri2_window *priv;
17487+ struct sna *sna;
17488
17489 priv = dri2_window(win);
17490 if (priv == NULL)
17491 return;
17492
17493 DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
17494+ sna = to_sna_from_drawable(&win->drawable);
17495
17496 if (priv->front) {
17497- struct sna *sna = to_sna_from_drawable(&win->drawable);
17498 assert(priv->crtc);
17499 sna_shadow_unset_crtc(sna, priv->crtc);
17500- _sna_dri2_destroy_buffer(sna, priv->front);
17501+ _sna_dri2_destroy_buffer(sna, NULL, priv->front);
17502 }
17503
17504 if (priv->chain) {
17505@@ -1452,18 +1837,44 @@ void sna_dri2_destroy_window(WindowPtr win)
17506
17507 chain = priv->chain;
17508 while ((info = chain)) {
17509+ assert(info->draw == &win->drawable);
17510+ if (info->signal)
17511+ frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE);
17512+ if (info->pending.bo) {
17513+ assert(info->pending.bo->active_scanout > 0);
17514+ info->pending.bo->active_scanout--;
17515+
17516+ info->signal = true;
17517+ frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE);
17518+
17519+ kgem_bo_destroy(&sna->kgem, info->pending.bo);
17520+ info->pending.bo = NULL;
17521+ }
17522+
17523 info->draw = NULL;
17524- info->client = NULL;
17525 list_del(&info->link);
17526
17527 chain = info->chain;
17528 info->chain = NULL;
17529+ info->chained = false;
17530
17531 if (!info->queued)
17532 sna_dri2_event_free(info);
17533 }
17534 }
17535
17536+ while (!list_is_empty(&priv->cache)) {
17537+ struct dri_bo *c;
17538+
17539+ c = list_first_entry(&priv->cache, struct dri_bo, link);
17540+ list_del(&c->link);
17541+
17542+ DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
17543+ assert(c->bo);
17544+ kgem_bo_destroy(&sna->kgem, c->bo);
17545+ free(c);
17546+ }
17547+
17548 free(priv);
17549 }
17550
17551@@ -1479,19 +1890,29 @@ sna_dri2_flip(struct sna_dri2_event *info)
17552 {
17553 struct kgem_bo *bo = get_private(info->back)->bo;
17554 struct kgem_bo *tmp_bo;
17555- uint32_t tmp_name;
17556+ uint32_t tmp_name, tmp_flags;
17557 int tmp_pitch;
17558
17559 DBG(("%s(type=%d)\n", __FUNCTION__, info->type));
17560
17561 assert(sna_pixmap_get_buffer(info->sna->front) == info->front);
17562 assert(get_drawable_pixmap(info->draw)->drawable.height * bo->pitch <= kgem_bo_size(bo));
17563+ assert(get_private(info->front)->size == get_private(info->back)->size);
17564 assert(bo->refcnt);
17565
17566+ if (info->sna->mode.flip_active) {
17567+ DBG(("%s: %d flips still active, aborting\n",
17568+ __FUNCTION__, info->sna->mode.flip_active));
17569+ return false;
17570+ }
17571+
17572 if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler,
17573 info->type == FLIP_ASYNC ? NULL : info))
17574 return false;
17575
17576+ DBG(("%s: queued flip=%p\n", __FUNCTION__, info->type == FLIP_ASYNC ? NULL : info));
17577+ assert(info->signal || info->type != FLIP_THROTTLE);
17578+
17579 assert(info->sna->dri2.flip_pending == NULL ||
17580 info->sna->dri2.flip_pending == info);
17581 if (info->type != FLIP_ASYNC)
17582@@ -1505,13 +1926,20 @@ sna_dri2_flip(struct sna_dri2_event *info)
17583 tmp_bo = get_private(info->front)->bo;
17584 tmp_name = info->front->name;
17585 tmp_pitch = info->front->pitch;
17586+ tmp_flags = info->front->flags;
17587+
17588+ assert(tmp_bo->active_scanout > 0);
17589+ tmp_bo->active_scanout--;
17590
17591 set_bo(info->sna->front, bo);
17592
17593+ info->front->flags = info->back->flags;
17594 info->front->name = info->back->name;
17595 info->front->pitch = info->back->pitch;
17596 get_private(info->front)->bo = bo;
17597+ bo->active_scanout++;
17598
17599+ info->back->flags = tmp_flags;
17600 info->back->name = tmp_name;
17601 info->back->pitch = tmp_pitch;
17602 get_private(info->back)->bo = tmp_bo;
17603@@ -1521,6 +1949,7 @@ sna_dri2_flip(struct sna_dri2_event *info)
17604 assert(get_private(info->back)->bo->refcnt);
17605 assert(get_private(info->front)->bo != get_private(info->back)->bo);
17606
17607+ info->keepalive = KEEPALIVE;
17608 info->queued = true;
17609 return true;
17610 }
17611@@ -1549,15 +1978,16 @@ can_flip(struct sna * sna,
17612 }
17613
17614 assert(sna->scrn->vtSema);
17615+ assert(!sna->mode.hidden);
17616
17617 if ((sna->flags & (SNA_HAS_FLIP | SNA_HAS_ASYNC_FLIP)) == 0) {
17618 DBG(("%s: no, pageflips disabled\n", __FUNCTION__));
17619 return false;
17620 }
17621
17622- if (front->format != back->format) {
17623+ if (front->cpp != back->cpp) {
17624 DBG(("%s: no, format mismatch, front = %d, back = %d\n",
17625- __FUNCTION__, front->format, back->format));
17626+ __FUNCTION__, front->cpp, back->cpp));
17627 return false;
17628 }
17629
17630@@ -1567,7 +1997,7 @@ can_flip(struct sna * sna,
17631 }
17632
17633 if (!sna_crtc_is_on(crtc)) {
17634- DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_to_pipe(crtc)));
17635+ DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_pipe(crtc)));
17636 return false;
17637 }
17638
17639@@ -1581,7 +2011,7 @@ can_flip(struct sna * sna,
17640 if (sna_pixmap_get_buffer(pixmap) != front) {
17641 DBG(("%s: no, DRI2 drawable is no longer attached (old name=%d, new name=%d) to pixmap=%ld\n",
17642 __FUNCTION__, front->name,
17643- sna_pixmap_get_buffer(pixmap) ? ((DRI2BufferPtr)sna_pixmap_get_buffer(pixmap))->name : 0,
17644+ sna_pixmap_get_buffer(pixmap) ? sna_pixmap_get_buffer(pixmap)->name : 0,
17645 pixmap->drawable.serialNumber));
17646 return false;
17647 }
17648@@ -1661,7 +2091,6 @@ can_flip(struct sna * sna,
17649 }
17650
17651 DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
17652- assert(dri2_window(win)->front == NULL);
17653 return true;
17654 }
17655
17656@@ -1680,9 +2109,9 @@ can_xchg(struct sna *sna,
17657 if (draw->type == DRAWABLE_PIXMAP)
17658 return false;
17659
17660- if (front->format != back->format) {
17661+ if (front->cpp != back->cpp) {
17662 DBG(("%s: no, format mismatch, front = %d, back = %d\n",
17663- __FUNCTION__, front->format, back->format));
17664+ __FUNCTION__, front->cpp, back->cpp));
17665 return false;
17666 }
17667
17668@@ -1714,6 +2143,8 @@ can_xchg(struct sna *sna,
17669 return false;
17670 }
17671
17672+ DBG(("%s: back size=%x, front size=%x\n",
17673+ __FUNCTION__, get_private(back)->size, get_private(front)->size));
17674 if (get_private(back)->size != get_private(front)->size) {
17675 DBG(("%s: no, back buffer %dx%d does not match front buffer %dx%d\n",
17676 __FUNCTION__,
17677@@ -1766,9 +2197,9 @@ overlaps_other_crtc(struct sna *sna, xf86CrtcPtr desired)
17678 static bool
17679 can_xchg_crtc(struct sna *sna,
17680 DrawablePtr draw,
17681+ xf86CrtcPtr crtc,
17682 DRI2BufferPtr front,
17683- DRI2BufferPtr back,
17684- xf86CrtcPtr crtc)
17685+ DRI2BufferPtr back)
17686 {
17687 WindowPtr win = (WindowPtr)draw;
17688 PixmapPtr pixmap;
17689@@ -1785,9 +2216,9 @@ can_xchg_crtc(struct sna *sna,
17690 if (draw->type == DRAWABLE_PIXMAP)
17691 return false;
17692
17693- if (front->format != back->format) {
17694+ if (front->cpp != back->cpp) {
17695 DBG(("%s: no, format mismatch, front = %d, back = %d\n",
17696- __FUNCTION__, front->format, back->format));
17697+ __FUNCTION__, front->cpp, back->cpp));
17698 return false;
17699 }
17700
17701@@ -1866,7 +2297,6 @@ sna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
17702
17703 back_bo = get_private(back)->bo;
17704 front_bo = get_private(front)->bo;
17705- assert(front_bo != back_bo);
17706
17707 DBG(("%s: win=%ld, exchange front=%d/%d and back=%d/%d, pixmap=%ld %dx%d\n",
17708 __FUNCTION__, win->drawable.id,
17709@@ -1876,10 +2306,12 @@ sna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
17710 pixmap->drawable.width,
17711 pixmap->drawable.height));
17712
17713- DBG(("%s: back_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
17714- __FUNCTION__, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt, back_bo->active_scanout));
17715- DBG(("%s: front_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
17716- __FUNCTION__, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt, front_bo->active_scanout));
17717+ DBG(("%s: back_bo handle=%d, pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
17718+ __FUNCTION__, back_bo->handle, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt, back_bo->active_scanout));
17719+ DBG(("%s: front_bo handle=%d, pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
17720+ __FUNCTION__, front_bo->handle, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt, front_bo->active_scanout));
17721+
17722+ assert(front_bo != back_bo);
17723 assert(front_bo->refcnt);
17724 assert(back_bo->refcnt);
17725
17726@@ -1894,6 +2326,10 @@ sna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
17727 get_private(back)->bo = front_bo;
17728 mark_stale(back);
17729
17730+ assert(front_bo->active_scanout > 0);
17731+ front_bo->active_scanout--;
17732+ back_bo->active_scanout++;
17733+
17734 tmp = front->name;
17735 front->name = back->name;
17736 back->name = tmp;
17737@@ -1902,15 +2338,23 @@ sna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
17738 front->pitch = back->pitch;
17739 back->pitch = tmp;
17740
17741+ tmp = front->flags;
17742+ front->flags = back->flags;
17743+ back->flags = tmp;
17744+
17745 assert(front_bo->refcnt);
17746 assert(back_bo->refcnt);
17747
17748+ assert(front_bo->pitch == get_private(front)->bo->pitch);
17749+ assert(back_bo->pitch == get_private(back)->bo->pitch);
17750+
17751 assert(get_private(front)->bo == sna_pixmap(pixmap)->gpu_bo);
17752 }
17753
17754 static void sna_dri2_xchg_crtc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc, DRI2BufferPtr front, DRI2BufferPtr back)
17755 {
17756 WindowPtr win = (WindowPtr)draw;
17757+ struct dri2_window *priv = dri2_window(win);
17758 DRI2Buffer2Ptr tmp;
17759 struct kgem_bo *bo;
17760
17761@@ -1922,21 +2366,33 @@ static void sna_dri2_xchg_crtc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr cr
17762 get_window_pixmap(win)->drawable.serialNumber,
17763 get_window_pixmap(win)->drawable.width,
17764 get_window_pixmap(win)->drawable.height));
17765+ assert(can_xchg_crtc(to_sna_from_drawable(draw), draw, crtc, front, back));
17766
17767- DamageRegionAppend(&win->drawable, &win->clipList);
17768+ if (APPLY_DAMAGE) {
17769+ DBG(("%s: marking drawable as damaged\n", __FUNCTION__));
17770+ sna->ignore_copy_area = true;
17771+ DamageRegionAppend(&win->drawable, &win->clipList);
17772+ }
17773 sna_shadow_set_crtc(sna, crtc, get_private(back)->bo);
17774- DamageRegionProcessPending(&win->drawable);
17775-
17776- assert(dri2_window(win)->front == NULL);
17777+ if (APPLY_DAMAGE) {
17778+ DamageRegionProcessPending(&win->drawable);
17779+ sna->ignore_copy_area = false;
17780+ }
17781
17782 tmp = calloc(1, sizeof(*tmp) + sizeof(struct sna_dri2_private));
17783 if (tmp == NULL) {
17784 back->attachment = -1;
17785 if (get_private(back)->proxy == NULL) {
17786- get_private(back)->pixmap = get_window_pixmap(win);
17787- get_private(back)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(get_private(back)->pixmap));
17788+ get_private(back)->pixmap = get_private(front)->pixmap;
17789+ get_private(back)->proxy = sna_dri2_reference_buffer(get_private(front)->proxy ?: front);
17790 }
17791- dri2_window(win)->front = sna_dri2_reference_buffer(back);
17792+
17793+ if (priv->front) {
17794+ assert(front == priv->front);
17795+ assert(get_private(priv->front)->refcnt > 1);
17796+ get_private(priv->front)->refcnt--;
17797+ }
17798+ priv->front = sna_dri2_reference_buffer(back);
17799 return;
17800 }
17801
17802@@ -1946,73 +2402,53 @@ static void sna_dri2_xchg_crtc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr cr
17803 get_private(tmp)->refcnt = 1;
17804 get_private(tmp)->bo = get_private(back)->bo;
17805 get_private(tmp)->size = get_private(back)->size;
17806- get_private(tmp)->pixmap = get_window_pixmap(win);
17807- get_private(tmp)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(get_private(tmp)->pixmap));
17808- dri2_window(win)->front = tmp;
17809-
17810- DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
17811- back->name = 0;
17812- bo = kgem_create_2d(&sna->kgem,
17813- draw->width, draw->height, draw->bitsPerPixel,
17814- get_private(back)->bo->tiling,
17815- CREATE_SCANOUT);
17816- if (bo != NULL) {
17817- get_private(back)->bo = bo;
17818- back->pitch = bo->pitch;
17819- back->name = kgem_bo_flink(&sna->kgem, bo);
17820- }
17821- if (back->name == 0) {
17822- if (bo != NULL)
17823- kgem_bo_destroy(&sna->kgem, bo);
17824- get_private(back)->bo = NULL;
17825- back->attachment = -1;
17826- }
17827-}
17828-
17829-static void frame_swap_complete(struct sna_dri2_event *frame, int type)
17830-{
17831- const struct ust_msc *swap;
17832-
17833- if (frame->draw == NULL)
17834- return;
17835-
17836- assert(frame->client);
17837-
17838- swap = sna_crtc_last_swap(frame->crtc);
17839- DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc=%lld], tv=%d.%06d\n",
17840- __FUNCTION__, type, (long)frame->draw, frame->pipe,
17841- (long long)swap->msc,
17842- (long long)draw_current_msc(frame->draw, frame->crtc, swap->msc),
17843- swap->tv_sec, swap->tv_usec));
17844-
17845- DRI2SwapComplete(frame->client, frame->draw,
17846- draw_current_msc(frame->draw, frame->crtc, swap->msc),
17847- swap->tv_sec, swap->tv_usec,
17848- type, frame->event_complete, frame->event_data);
17849-}
17850-
17851-static void fake_swap_complete(struct sna *sna, ClientPtr client,
17852- DrawablePtr draw, xf86CrtcPtr crtc,
17853- int type, DRI2SwapEventPtr func, void *data)
17854-{
17855- const struct ust_msc *swap;
17856-
17857- swap = sna_crtc_last_swap(crtc);
17858- DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n",
17859- __FUNCTION__, type, (long)draw->id, crtc ? sna_crtc_to_pipe(crtc) : -1,
17860- (long long)swap->msc,
17861- (long long)draw_current_msc(draw, crtc, swap->msc),
17862- swap->tv_sec, swap->tv_usec));
17863+ get_private(tmp)->pixmap = get_private(front)->pixmap;
17864+ get_private(tmp)->proxy = sna_dri2_reference_buffer(get_private(front)->proxy ?: front);
17865+ mark_stale(back);
17866
17867- DRI2SwapComplete(client, draw,
17868- draw_current_msc(draw, crtc, swap->msc),
17869- swap->tv_sec, swap->tv_usec,
17870- type, func, data);
17871+ if (priv->front) {
17872+ DBG(("%s: replacing Window frontbuffer (was handle=%d) now handle=%d\n",
17873+ __FUNCTION__,
17874+ get_private(priv->front)->bo->handle,
17875+ get_private(tmp)->bo->handle));
17876+ assert(front == priv->front);
17877+ assert(get_private(priv->front)->refcnt > 1);
17878+ get_private(priv->front)->refcnt--;
17879+ }
17880+ priv->front = tmp;
17881+
17882+ if (get_private(front)->proxy) {
17883+ DBG(("%s: reusing current proxy frontbuffer\n", __FUNCTION__));
17884+ front->attachment = DRI2BufferBackLeft;
17885+ ref(get_private(tmp)->bo);
17886+ back->attachment = DRI2BufferFrontLeft;
17887+ } else {
17888+ DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
17889+ back->name = 0;
17890+ back->flags = 0;
17891+ bo = kgem_create_2d(&sna->kgem,
17892+ draw->width, draw->height, draw->bitsPerPixel,
17893+ get_private(back)->bo->tiling,
17894+ CREATE_SCANOUT | CREATE_EXACT);
17895+ if (bo != NULL) {
17896+ get_private(back)->bo = bo;
17897+ back->pitch = bo->pitch;
17898+ get_private(back)->size = draw->height << 16 | draw->width;
17899+ back->name = kgem_bo_flink(&sna->kgem, bo);
17900+ }
17901+ if (back->name == 0) {
17902+ if (bo != NULL)
17903+ kgem_bo_destroy(&sna->kgem, bo);
17904+ get_private(back)->bo = NULL;
17905+ back->attachment = DRI2BufferFrontLeft;
17906+ }
17907+ }
17908 }
17909
17910 static void chain_swap(struct sna_dri2_event *chain)
17911 {
17912- union drm_wait_vblank vbl;
17913+ DBG(("%s: draw=%ld, queued?=%d, type=%d\n",
17914+ __FUNCTION__, (long)chain->draw->id, chain->queued, chain->type));
17915
17916 if (chain->draw == NULL) {
17917 sna_dri2_event_free(chain);
17918@@ -2023,25 +2459,15 @@ static void chain_swap(struct sna_dri2_event *chain)
17919 return;
17920
17921 assert(chain == dri2_chain(chain->draw));
17922- DBG(("%s: chaining draw=%ld, type=%d\n",
17923- __FUNCTION__, (long)chain->draw->id, chain->type));
17924- chain->queued = true;
17925+ assert(chain->signal);
17926
17927 switch (chain->type) {
17928- case SWAP_THROTTLE:
17929+ case SWAP_COMPLETE:
17930 DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
17931- if (chain->sna->mode.shadow &&
17932- !chain->sna->mode.shadow_damage) {
17933+ if (chain->sna->mode.shadow && chain->sna->mode.shadow_wait) {
17934 /* recursed from wait_for_shadow(), simply requeue */
17935 DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__));
17936- VG_CLEAR(vbl);
17937- vbl.request.type =
17938- DRM_VBLANK_RELATIVE |
17939- DRM_VBLANK_EVENT;
17940- vbl.request.sequence = 1;
17941- vbl.request.signal = (uintptr_t)chain;
17942-
17943- if (!sna_wait_vblank(chain->sna, &vbl, chain->pipe))
17944+ if (sna_next_vblank(chain))
17945 return;
17946
17947 DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno));
17948@@ -2049,35 +2475,27 @@ static void chain_swap(struct sna_dri2_event *chain)
17949
17950 if (can_xchg(chain->sna, chain->draw, chain->front, chain->back)) {
17951 sna_dri2_xchg(chain->draw, chain->front, chain->back);
17952- } else if (can_xchg_crtc(chain->sna, chain->draw, chain->front, chain->back, chain->crtc)) {
17953- sna_dri2_xchg_crtc(chain->sna, chain->draw, chain->crtc, chain->front, chain->back);
17954+ } else if (can_xchg_crtc(chain->sna, chain->draw, chain->crtc,
17955+ chain->front, chain->back)) {
17956+ sna_dri2_xchg_crtc(chain->sna, chain->draw, chain->crtc,
17957+ chain->front, chain->back);
17958 } else {
17959- assert(chain->queued);
17960- chain->bo = __sna_dri2_copy_region(chain->sna, chain->draw, NULL,
17961- chain->back, chain->front,
17962- true);
17963+ __sna_dri2_copy_event(chain, chain->sync | DRI2_BO);
17964 }
17965+ assert(get_private(chain->back)->bo != get_private(chain->front)->bo);
17966 case SWAP:
17967 break;
17968 default:
17969 return;
17970 }
17971
17972- VG_CLEAR(vbl);
17973- vbl.request.type =
17974- DRM_VBLANK_RELATIVE |
17975- DRM_VBLANK_EVENT;
17976- vbl.request.sequence = 1;
17977- vbl.request.signal = (uintptr_t)chain;
17978- if (sna_wait_vblank(chain->sna, &vbl, chain->pipe)) {
17979+ if ((chain->type == SWAP_COMPLETE &&
17980+ !swap_limit(chain->draw, 2 + !chain->sync) &&
17981+ !chain->sync) ||
17982+ !sna_next_vblank(chain)) {
17983 DBG(("%s: vblank wait failed, unblocking client\n", __FUNCTION__));
17984 frame_swap_complete(chain, DRI2_BLIT_COMPLETE);
17985 sna_dri2_event_free(chain);
17986- } else {
17987- if (chain->type == SWAP_THROTTLE && !swap_limit(chain->draw, 2)) {
17988- DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
17989- frame_swap_complete(chain, DRI2_BLIT_COMPLETE);
17990- }
17991 }
17992 }
17993
17994@@ -2099,27 +2517,20 @@ static inline bool rq_is_busy(struct kgem *kgem, struct kgem_bo *bo)
17995 return __kgem_busy(kgem, bo->handle);
17996 }
17997
17998-static bool sna_dri2_blit_complete(struct sna *sna,
17999- struct sna_dri2_event *info)
18000+static bool sna_dri2_blit_complete(struct sna_dri2_event *info)
18001 {
18002- if (rq_is_busy(&sna->kgem, info->bo)) {
18003- union drm_wait_vblank vbl;
18004-
18005+ if (rq_is_busy(&info->sna->kgem, info->bo)) {
18006 DBG(("%s: vsync'ed blit is still busy, postponing\n",
18007 __FUNCTION__));
18008-
18009- VG_CLEAR(vbl);
18010- vbl.request.type =
18011- DRM_VBLANK_RELATIVE |
18012- DRM_VBLANK_EVENT;
18013- vbl.request.sequence = 1;
18014- vbl.request.signal = (uintptr_t)info;
18015- assert(info->queued);
18016- if (!sna_wait_vblank(sna, &vbl, info->pipe))
18017+ if (sna_next_vblank(info))
18018 return false;
18019 }
18020
18021 DBG(("%s: blit finished\n", __FUNCTION__));
18022+ if (info->bo) {
18023+ kgem_bo_destroy(&info->sna->kgem, info->bo);
18024+ info->bo = NULL;
18025+ }
18026 return true;
18027 }
18028
18029@@ -2128,11 +2539,12 @@ void sna_dri2_vblank_handler(struct drm_event_vblank *event)
18030 struct sna_dri2_event *info = (void *)(uintptr_t)event->user_data;
18031 struct sna *sna = info->sna;
18032 DrawablePtr draw;
18033- union drm_wait_vblank vbl;
18034 uint64_t msc;
18035
18036- DBG(("%s(type=%d, sequence=%d)\n", __FUNCTION__, info->type, event->sequence));
18037+ DBG(("%s(type=%d, sequence=%d, draw=%ld)\n", __FUNCTION__, info->type, event->sequence, info->draw ? info->draw->serialNumber : 0));
18038 assert(info->queued);
18039+ info->queued = false;
18040+
18041 msc = sna_crtc_record_event(info->crtc, event);
18042
18043 draw = info->draw;
18044@@ -2144,65 +2556,100 @@ void sna_dri2_vblank_handler(struct drm_event_vblank *event)
18045 switch (info->type) {
18046 case FLIP:
18047 /* If we can still flip... */
18048+ assert(info->signal);
18049 if (can_flip(sna, draw, info->front, info->back, info->crtc) &&
18050 sna_dri2_flip(info))
18051 return;
18052
18053 /* else fall through to blit */
18054 case SWAP:
18055- assert(info->queued);
18056- if (sna->mode.shadow && !sna->mode.shadow_damage) {
18057+ assert(info->signal);
18058+ if (sna->mode.shadow && sna->mode.shadow_wait) {
18059 /* recursed from wait_for_shadow(), simply requeue */
18060 DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__));
18061-
18062 } else if (can_xchg(info->sna, draw, info->front, info->back)) {
18063 sna_dri2_xchg(draw, info->front, info->back);
18064- info->type = SWAP_WAIT;
18065- } else if (can_xchg_crtc(sna, draw, info->front, info->back, info->crtc)) {
18066- sna_dri2_xchg_crtc(sna, draw, info->crtc, info->front, info->back);
18067- info->type = SWAP_WAIT;
18068+ info->type = SWAP_COMPLETE;
18069+ } else if (can_xchg_crtc(sna, draw, info->crtc,
18070+ info->front, info->back)) {
18071+ sna_dri2_xchg_crtc(sna, draw, info->crtc,
18072+ info->front, info->back);
18073+ info->type = SWAP_COMPLETE;
18074 } else {
18075- assert(info->queued);
18076- info->bo = __sna_dri2_copy_region(sna, draw, NULL,
18077- info->back, info->front, true);
18078- info->type = SWAP_WAIT;
18079+ __sna_dri2_copy_event(info, DRI2_BO | DRI2_SYNC);
18080+ info->type = SWAP_COMPLETE;
18081 }
18082
18083- VG_CLEAR(vbl);
18084- vbl.request.type =
18085- DRM_VBLANK_RELATIVE |
18086- DRM_VBLANK_EVENT;
18087- vbl.request.sequence = 1;
18088- vbl.request.signal = (uintptr_t)info;
18089-
18090- assert(info->queued);
18091- if (!sna_wait_vblank(sna, &vbl, info->pipe))
18092+ if (sna_next_vblank(info))
18093 return;
18094
18095 DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno));
18096+ assert(info->pending.bo == NULL);
18097+ assert(info->keepalive == 1);
18098 /* fall through to SwapComplete */
18099- case SWAP_WAIT:
18100- if (!sna_dri2_blit_complete(sna, info))
18101- return;
18102-
18103- DBG(("%s: swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
18104- event->sequence, event->tv_sec, event->tv_usec));
18105- frame_swap_complete(info, DRI2_BLIT_COMPLETE);
18106- break;
18107-
18108- case SWAP_THROTTLE:
18109+ case SWAP_COMPLETE:
18110 DBG(("%s: %d complete, frame=%d tv=%d.%06d\n",
18111 __FUNCTION__, info->type,
18112 event->sequence, event->tv_sec, event->tv_usec));
18113
18114- if (xorg_can_triple_buffer()) {
18115- if (!sna_dri2_blit_complete(sna, info))
18116+ if (info->signal) {
18117+ if (!sna_dri2_blit_complete(info))
18118 return;
18119
18120 DBG(("%s: triple buffer swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
18121 event->sequence, event->tv_sec, event->tv_usec));
18122 frame_swap_complete(info, DRI2_BLIT_COMPLETE);
18123 }
18124+
18125+ if (info->pending.bo) {
18126+ if (sna->mode.shadow && sna->mode.shadow_wait) {
18127+ /* recursed from wait_for_shadow(), simply requeue */
18128+ DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__));
18129+ if (sna_next_vblank(info))
18130+ return;
18131+ }
18132+
18133+ assert(info->pending.bo->active_scanout > 0);
18134+ info->pending.bo->active_scanout--;
18135+
18136+ sna_dri2_cache_bo(info->sna, info->draw,
18137+ get_private(info->back)->bo,
18138+ info->back->name,
18139+ get_private(info->back)->size,
18140+ info->back->flags);
18141+
18142+ get_private(info->back)->bo = info->pending.bo;
18143+ get_private(info->back)->size = info->pending.size;
18144+ info->back->name = info->pending.name;
18145+ info->back->pitch = info->pending.bo->pitch;
18146+ info->back->flags = info->pending.flags;
18147+ info->pending.bo = NULL;
18148+
18149+ assert(get_private(info->back)->bo != get_private(info->front)->bo);
18150+
18151+ if (can_xchg(info->sna, info->draw, info->front, info->back))
18152+ sna_dri2_xchg(info->draw, info->front, info->back);
18153+ else if (can_xchg_crtc(info->sna, info->draw, info->crtc,
18154+ info->front, info->back))
18155+ sna_dri2_xchg_crtc(info->sna, info->draw, info->crtc,
18156+ info->front, info->back);
18157+ else
18158+ __sna_dri2_copy_event(info, info->sync | DRI2_BO);
18159+
18160+ info->keepalive++;
18161+ info->signal = true;
18162+ }
18163+
18164+ if (--info->keepalive) {
18165+ if (sna_next_vblank(info))
18166+ return;
18167+
18168+ if (info->signal) {
18169+ DBG(("%s: triple buffer swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
18170+ event->sequence, event->tv_sec, event->tv_usec));
18171+ frame_swap_complete(info, DRI2_BLIT_COMPLETE);
18172+ }
18173+ }
18174 break;
18175
18176 case WAITMSC:
18177@@ -2218,11 +2665,11 @@ void sna_dri2_vblank_handler(struct drm_event_vblank *event)
18178 }
18179
18180 if (info->chain) {
18181+ DBG(("%s: continuing chain\n", __FUNCTION__));
18182 assert(info->chain != info);
18183 assert(info->draw == draw);
18184- sna_dri2_remove_event((WindowPtr)draw, info);
18185+ sna_dri2_remove_event(info);
18186 chain_swap(info->chain);
18187- info->draw = NULL;
18188 }
18189
18190 done:
18191@@ -2230,101 +2677,139 @@ done:
18192 DBG(("%s complete\n", __FUNCTION__));
18193 }
18194
18195-static bool
18196+static void
18197 sna_dri2_immediate_blit(struct sna *sna,
18198 struct sna_dri2_event *info,
18199- bool sync, bool event)
18200+ bool sync)
18201 {
18202 DrawablePtr draw = info->draw;
18203- bool ret = false;
18204+ struct sna_dri2_event *chain = dri2_chain(draw);
18205
18206 if (sna->flags & SNA_NO_WAIT)
18207 sync = false;
18208
18209- DBG(("%s: emitting immediate blit, throttling client, synced? %d, chained? %d, send-event? %d\n",
18210- __FUNCTION__, sync, dri2_chain(draw) != info,
18211- event));
18212+ DBG(("%s: emitting immediate blit, throttling client, synced? %d, chained? %d, pipe %d\n",
18213+ __FUNCTION__, sync, chain != info, info->pipe));
18214
18215- info->type = SWAP_THROTTLE;
18216- if (!sync || dri2_chain(draw) == info) {
18217- DBG(("%s: no pending blit, starting chain\n",
18218- __FUNCTION__));
18219+ info->type = SWAP_COMPLETE;
18220+ info->sync = sync;
18221+ info->keepalive = KEEPALIVE;
18222
18223- info->queued = true;
18224- info->bo = __sna_dri2_copy_region(sna, draw, NULL,
18225- info->back,
18226- info->front,
18227- sync);
18228- if (event) {
18229- if (sync) {
18230- union drm_wait_vblank vbl;
18231-
18232- VG_CLEAR(vbl);
18233- vbl.request.type =
18234- DRM_VBLANK_RELATIVE |
18235- DRM_VBLANK_EVENT;
18236- vbl.request.sequence = 1;
18237- vbl.request.signal = (uintptr_t)info;
18238- ret = !sna_wait_vblank(sna, &vbl, info->pipe);
18239- if (ret)
18240- event = !swap_limit(draw, 2);
18241- }
18242- if (event) {
18243- DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
18244- frame_swap_complete(info, DRI2_BLIT_COMPLETE);
18245- }
18246+ if (chain == info) {
18247+ DBG(("%s: no pending blit, starting chain\n", __FUNCTION__));
18248+
18249+ if (can_xchg(info->sna, info->draw, info->front, info->back)) {
18250+ sna_dri2_xchg(info->draw, info->front, info->back);
18251+ } else if (can_xchg_crtc(info->sna, info->draw, info->crtc,
18252+ info->front, info->back)) {
18253+ sna_dri2_xchg_crtc(info->sna, info->draw, info->crtc,
18254+ info->front, info->back);
18255+ } else
18256+ __sna_dri2_copy_event(info, sync | DRI2_BO);
18257+
18258+ assert(info->signal);
18259+
18260+ if ((!swap_limit(draw, 2 + !sync) && !sync) ||
18261+ !sna_next_vblank(info)) {
18262+ DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
18263+ frame_swap_complete(info, DRI2_BLIT_COMPLETE);
18264+ sna_dri2_event_free(info);
18265+ }
18266+ return;
18267+ }
18268+
18269+ if (chain->type == SWAP_COMPLETE) {
18270+ assert(chain->draw == info->draw);
18271+ assert(chain->client == info->client);
18272+ assert(chain->event_complete == info->event_complete);
18273+ assert(chain->event_data == info->event_data);
18274+ assert(chain->queued);
18275+
18276+ if ((!sync || !chain->sync) && chain->pending.bo) {
18277+ bool signal = chain->signal;
18278+
18279+ DBG(("%s: swap elision, unblocking client\n", __FUNCTION__));
18280+ chain->signal = true;
18281+ frame_swap_complete(chain, DRI2_EXCHANGE_COMPLETE);
18282+ chain->signal = signal;
18283+
18284+ assert(chain->pending.bo->active_scanout > 0);
18285+ chain->pending.bo->active_scanout--;
18286+
18287+ sna_dri2_cache_bo(chain->sna, chain->draw,
18288+ chain->pending.bo,
18289+ chain->pending.name,
18290+ chain->pending.size,
18291+ chain->pending.flags);
18292+ chain->pending.bo = NULL;
18293+ }
18294+
18295+ if (chain->pending.bo == NULL && swap_limit(draw, 2 + !sync)) {
18296+ DBG(("%s: setting handle=%d as pending blit (current event front=%d, back=%d)\n", __FUNCTION__,
18297+ get_private(info->back)->bo->handle,
18298+ get_private(chain->front)->bo->handle,
18299+ get_private(chain->back)->bo->handle));
18300+ chain->pending.bo = ref(get_private(info->back)->bo);
18301+ chain->pending.size = get_private(info->back)->size;
18302+ chain->pending.name = info->back->name;
18303+ chain->pending.flags = info->back->flags;
18304+ chain->sync = sync;
18305+ info->signal = false; /* transfer signal to pending */
18306+
18307+ /* Prevent us from handing it back on next GetBuffers */
18308+ chain->pending.bo->active_scanout++;
18309+
18310+ sna_dri2_event_free(info);
18311+ return;
18312 }
18313- } else {
18314- DBG(("%s: pending blit, chained\n", __FUNCTION__));
18315- ret = true;
18316 }
18317
18318- DBG(("%s: continue? %d\n", __FUNCTION__, ret));
18319- return ret;
18320+ DBG(("%s: pending blit, chained\n", __FUNCTION__));
18321 }
18322
18323 static bool
18324 sna_dri2_flip_continue(struct sna_dri2_event *info)
18325 {
18326- DBG(("%s(mode=%d)\n", __FUNCTION__, info->mode));
18327-
18328- if (info->mode > 0){
18329- struct kgem_bo *bo = get_private(info->front)->bo;
18330+ struct kgem_bo *bo = get_private(info->front)->bo;
18331
18332- info->type = info->mode;
18333+ DBG(("%s(mode=%d)\n", __FUNCTION__, info->flip_continue));
18334+ assert(info->flip_continue > 0);
18335+ info->type = info->flip_continue;
18336+ info->flip_continue = 0;
18337
18338- if (bo != sna_pixmap(info->sna->front)->gpu_bo)
18339- return false;
18340+ if (info->sna->mode.front_active == 0)
18341+ return false;
18342
18343- if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler, info))
18344- return false;
18345+ if (bo != sna_pixmap(info->sna->front)->gpu_bo)
18346+ return false;
18347
18348- assert(info->sna->dri2.flip_pending == NULL ||
18349- info->sna->dri2.flip_pending == info);
18350- info->sna->dri2.flip_pending = info;
18351- assert(info->queued);
18352- } else {
18353- info->type = -info->mode;
18354+ if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler, info))
18355+ return false;
18356
18357- if (!info->draw)
18358- return false;
18359+ DBG(("%s: queued flip=%p\n", __FUNCTION__, info));
18360+ assert(info->sna->dri2.flip_pending == NULL ||
18361+ info->sna->dri2.flip_pending == info);
18362+ info->sna->dri2.flip_pending = info;
18363+ info->queued = true;
18364+ info->signal = info->type == FLIP_THROTTLE;
18365
18366- if (!can_flip(info->sna, info->draw, info->front, info->back, info->crtc))
18367- return false;
18368+ return true;
18369+}
18370
18371- assert(sna_pixmap_get_buffer(get_drawable_pixmap(info->draw)) == info->front);
18372- if (!sna_dri2_flip(info))
18373- return false;
18374+static bool
18375+sna_dri2_flip_keepalive(struct sna_dri2_event *info)
18376+{
18377+ DBG(("%s(keepalive?=%d)\n", __FUNCTION__, info->keepalive-1));
18378+ assert(info->keepalive > 0);
18379+ if (!--info->keepalive)
18380+ return false;
18381
18382- if (!xorg_can_triple_buffer()) {
18383- sna_dri2_get_back(info->sna, info->draw, info->back, info);
18384- DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
18385- frame_swap_complete(info, DRI2_FLIP_COMPLETE);
18386- }
18387- }
18388+ if (info->draw == NULL)
18389+ return false;
18390
18391- info->mode = 0;
18392- return true;
18393+ DBG(("%s: marking next flip as complete\n", __FUNCTION__));
18394+ info->flip_continue = FLIP_COMPLETE;
18395+ return sna_dri2_flip_continue(info);
18396 }
18397
18398 static void chain_flip(struct sna *sna)
18399@@ -2332,8 +2817,8 @@ static void chain_flip(struct sna *sna)
18400 struct sna_dri2_event *chain = sna->dri2.flip_pending;
18401
18402 assert(chain->type == FLIP);
18403- DBG(("%s: chaining type=%d, cancelled?=%d\n",
18404- __FUNCTION__, chain->type, chain->draw == NULL));
18405+ DBG(("%s: chaining type=%d, cancelled?=%d window=%ld\n",
18406+ __FUNCTION__, chain->type, chain->draw == NULL, chain->draw ? chain->draw->id : 0));
18407
18408 sna->dri2.flip_pending = NULL;
18409 if (chain->draw == NULL) {
18410@@ -2343,31 +2828,18 @@ static void chain_flip(struct sna *sna)
18411
18412 assert(chain == dri2_chain(chain->draw));
18413 assert(!chain->queued);
18414- chain->queued = true;
18415
18416 if (can_flip(sna, chain->draw, chain->front, chain->back, chain->crtc) &&
18417 sna_dri2_flip(chain)) {
18418 DBG(("%s: performing chained flip\n", __FUNCTION__));
18419 } else {
18420 DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
18421- chain->bo = __sna_dri2_copy_region(sna, chain->draw, NULL,
18422- chain->back, chain->front,
18423- true);
18424+ __sna_dri2_copy_event(chain, DRI2_SYNC);
18425
18426 if (xorg_can_triple_buffer()) {
18427- union drm_wait_vblank vbl;
18428-
18429- VG_CLEAR(vbl);
18430-
18431- chain->type = SWAP_WAIT;
18432- vbl.request.type =
18433- DRM_VBLANK_RELATIVE |
18434- DRM_VBLANK_EVENT;
18435- vbl.request.sequence = 1;
18436- vbl.request.signal = (uintptr_t)chain;
18437-
18438- assert(chain->queued);
18439- if (!sna_wait_vblank(sna, &vbl, chain->pipe))
18440+ chain->type = SWAP_COMPLETE;
18441+ assert(chain->signal);
18442+ if (sna_next_vblank(chain))
18443 return;
18444 }
18445
18446@@ -2381,8 +2853,9 @@ static void sna_dri2_flip_event(struct sna_dri2_event *flip)
18447 {
18448 struct sna *sna = flip->sna;
18449
18450- DBG(("%s(pipe=%d, event=%d)\n", __FUNCTION__, flip->pipe, flip->type));
18451+ DBG(("%s flip=%p (pipe=%d, event=%d)\n", __FUNCTION__, flip, flip->pipe, flip->type));
18452 assert(flip->queued);
18453+ flip->queued = false;
18454
18455 if (sna->dri2.flip_pending == flip)
18456 sna->dri2.flip_pending = NULL;
18457@@ -2399,27 +2872,35 @@ static void sna_dri2_flip_event(struct sna_dri2_event *flip)
18458 break;
18459
18460 case FLIP_THROTTLE:
18461- DBG(("%s: triple buffer swap complete, unblocking client\n", __FUNCTION__));
18462- frame_swap_complete(flip, DRI2_FLIP_COMPLETE);
18463+ if (flip->signal) {
18464+ DBG(("%s: triple buffer swap complete, unblocking client\n", __FUNCTION__));
18465+ frame_swap_complete(flip, DRI2_FLIP_COMPLETE);
18466+ }
18467 case FLIP_COMPLETE:
18468+ assert(!flip->signal);
18469 if (sna->dri2.flip_pending) {
18470+ DBG(("%s: pending flip\n", __FUNCTION__));
18471 sna_dri2_event_free(flip);
18472 chain_flip(sna);
18473- } else if (!flip->mode) {
18474+ } else if (!flip->flip_continue) {
18475 DBG(("%s: flip chain complete\n", __FUNCTION__));
18476+ if (!sna_dri2_flip_keepalive(flip)) {
18477+ if (flip->chain) {
18478+ sna_dri2_remove_event(flip);
18479+ chain_swap(flip->chain);
18480+ }
18481
18482- if (flip->chain) {
18483- sna_dri2_remove_event((WindowPtr)flip->draw,
18484- flip);
18485- chain_swap(flip->chain);
18486- flip->draw = NULL;
18487+ sna_dri2_event_free(flip);
18488 }
18489-
18490- sna_dri2_event_free(flip);
18491 } else if (!sna_dri2_flip_continue(flip)) {
18492 DBG(("%s: no longer able to flip\n", __FUNCTION__));
18493- if (flip->draw == NULL || !sna_dri2_immediate_blit(sna, flip, false, flip->mode < 0))
18494- sna_dri2_event_free(flip);
18495+ if (flip->draw != NULL)
18496+ __sna_dri2_copy_event(flip, 0);
18497+ if (flip->signal) {
18498+ DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
18499+ frame_swap_complete(flip, DRI2_BLIT_COMPLETE);
18500+ }
18501+ sna_dri2_event_free(flip);
18502 }
18503 break;
18504
18505@@ -2433,17 +2914,27 @@ static void sna_dri2_flip_event(struct sna_dri2_event *flip)
18506 }
18507 }
18508
18509+static int
18510+sna_query_vblank(struct sna *sna, xf86CrtcPtr crtc, union drm_wait_vblank *vbl)
18511+{
18512+ VG_CLEAR(*vbl);
18513+ vbl->request.type =
18514+ _DRM_VBLANK_RELATIVE | pipe_select(sna_crtc_pipe(crtc));
18515+ vbl->request.sequence = 0;
18516+
18517+ return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl);
18518+}
18519+
18520 static uint64_t
18521 get_current_msc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc)
18522 {
18523 union drm_wait_vblank vbl;
18524- uint64_t ret = -1;
18525+ uint64_t ret;
18526
18527- VG_CLEAR(vbl);
18528- vbl.request.type = _DRM_VBLANK_RELATIVE;
18529- vbl.request.sequence = 0;
18530- if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0)
18531+ if (sna_query_vblank(sna, crtc, &vbl) == 0)
18532 ret = sna_crtc_record_vblank(crtc, &vbl);
18533+ else
18534+ ret = sna_crtc_last_swap(crtc)->msc;
18535
18536 return draw_current_msc(draw, crtc, ret);
18537 }
18538@@ -2494,12 +2985,18 @@ static int use_triple_buffer(struct sna *sna, ClientPtr client, bool async)
18539 }
18540
18541 static bool immediate_swap(struct sna *sna,
18542- uint64_t target_msc,
18543- uint64_t divisor,
18544 DrawablePtr draw,
18545 xf86CrtcPtr crtc,
18546+ uint64_t *target_msc,
18547+ uint64_t divisor,
18548+ uint64_t remainder,
18549 uint64_t *current_msc)
18550 {
18551+ /*
18552+ * If divisor is zero, or current_msc is smaller than target_msc
18553+ * we just need to make sure target_msc passes before initiating
18554+ * the swap.
18555+ */
18556 if (divisor == 0) {
18557 *current_msc = -1;
18558
18559@@ -2508,71 +3005,86 @@ static bool immediate_swap(struct sna *sna,
18560 return true;
18561 }
18562
18563- if (target_msc)
18564+ if (*target_msc)
18565 *current_msc = get_current_msc(sna, draw, crtc);
18566
18567 DBG(("%s: current_msc=%ld, target_msc=%ld -- %s\n",
18568- __FUNCTION__, (long)*current_msc, (long)target_msc,
18569- (*current_msc >= target_msc - 1) ? "yes" : "no"));
18570- return *current_msc >= target_msc - 1;
18571+ __FUNCTION__, (long)*current_msc, (long)*target_msc,
18572+ (*current_msc >= *target_msc - 1) ? "yes" : "no"));
18573+ return *current_msc >= *target_msc - 1;
18574 }
18575
18576 DBG(("%s: explicit waits requests, divisor=%ld\n",
18577 __FUNCTION__, (long)divisor));
18578 *current_msc = get_current_msc(sna, draw, crtc);
18579- return false;
18580+ if (*current_msc >= *target_msc) {
18581+ DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
18582+ __FUNCTION__,
18583+ (long long)*current_msc,
18584+ (long long)*target_msc,
18585+ (long long)divisor,
18586+ (long long)remainder));
18587+
18588+ *target_msc = *current_msc + remainder - *current_msc % divisor;
18589+ if (*target_msc <= *current_msc)
18590+ *target_msc += divisor;
18591+ }
18592+
18593+ DBG(("%s: target_msc=%lld, current_msc=%lld, immediate?=%d\n",
18594+ __FUNCTION__, (long long)*target_msc, (long long)*current_msc,
18595+ *current_msc >= *target_msc - 1));
18596+ return *current_msc >= *target_msc - 1;
18597 }
18598
18599 static bool
18600 sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
18601 DRI2BufferPtr front, DRI2BufferPtr back,
18602- CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
18603+ bool immediate, CARD64 *target_msc, CARD64 current_msc,
18604 DRI2SwapEventPtr func, void *data)
18605 {
18606 struct sna *sna = to_sna_from_drawable(draw);
18607 struct sna_dri2_event *info;
18608- uint64_t current_msc;
18609-
18610- if (immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc)) {
18611- int type;
18612
18613+ if (immediate) {
18614+ bool signal = false;
18615 info = sna->dri2.flip_pending;
18616 DBG(("%s: performing immediate swap on pipe %d, pending? %d, mode: %d, continuation? %d\n",
18617- __FUNCTION__, sna_crtc_to_pipe(crtc),
18618- info != NULL, info ? info->mode : 0,
18619+ __FUNCTION__, sna_crtc_pipe(crtc),
18620+ info != NULL, info ? info->flip_continue : 0,
18621 info && info->draw == draw));
18622
18623 if (info && info->draw == draw) {
18624 assert(info->type != FLIP);
18625 assert(info->front == front);
18626+ assert(info->queued);
18627 if (info->back != back) {
18628- _sna_dri2_destroy_buffer(sna, info->back);
18629+ _sna_dri2_destroy_buffer(sna, draw, info->back);
18630 info->back = sna_dri2_reference_buffer(back);
18631 }
18632- if (info->mode || current_msc >= *target_msc) {
18633- DBG(("%s: executing xchg of pending flip\n",
18634- __FUNCTION__));
18635- sna_dri2_xchg(draw, front, back);
18636- info->mode = type = FLIP_COMPLETE;
18637- goto new_back;
18638- } else {
18639+ DBG(("%s: executing xchg of pending flip: flip_continue=%d, keepalive=%d, chain?=%d\n", __FUNCTION__, info->flip_continue, info->keepalive, current_msc < *target_msc));
18640+ sna_dri2_xchg(draw, front, back);
18641+ info->keepalive = KEEPALIVE;
18642+ if (xorg_can_triple_buffer() &&
18643+ current_msc < *target_msc) {
18644 DBG(("%s: chaining flip\n", __FUNCTION__));
18645- type = FLIP_THROTTLE;
18646- if (xorg_can_triple_buffer())
18647- info->mode = -type;
18648- else
18649- info->mode = -FLIP_COMPLETE;
18650+ info->flip_continue = FLIP_THROTTLE;
18651 goto out;
18652+ } else {
18653+ info->flip_continue = FLIP_COMPLETE;
18654+ signal = info->signal;
18655+ info->signal = true;
18656+ goto new_back;
18657 }
18658 }
18659
18660- info = sna_dri2_add_event(sna, draw, client);
18661+ info = sna_dri2_add_event(sna, draw, client, crtc);
18662 if (info == NULL)
18663 return false;
18664
18665 assert(info->crtc == crtc);
18666 info->event_complete = func;
18667 info->event_data = data;
18668+ info->signal = true;
18669
18670 info->front = sna_dri2_reference_buffer(front);
18671 info->back = sna_dri2_reference_buffer(back);
18672@@ -2584,26 +3096,31 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
18673 */
18674 DBG(("%s: queueing flip after pending completion\n",
18675 __FUNCTION__));
18676- info->type = type = FLIP;
18677+ info->type = FLIP;
18678 sna->dri2.flip_pending = info;
18679- assert(info->queued);
18680 current_msc++;
18681+ } else if (sna->mode.flip_active) {
18682+ DBG(("%s: %d outstanding flips from old client, queueing\n",
18683+ __FUNCTION__, sna->mode.flip_active));
18684+ goto queue;
18685 } else {
18686- info->type = type = use_triple_buffer(sna, client, *target_msc == 0);
18687+ info->type = use_triple_buffer(sna, client, *target_msc == 0);
18688 if (!sna_dri2_flip(info)) {
18689 DBG(("%s: flip failed, falling back\n", __FUNCTION__));
18690 sna_dri2_event_free(info);
18691 return false;
18692 }
18693+ assert(get_private(info->front)->bo->active_scanout);
18694 }
18695
18696- swap_limit(draw, 1 + (type == FLIP_THROTTLE));
18697- if (type >= FLIP_COMPLETE) {
18698+ swap_limit(draw, 1 + (info->type == FLIP_THROTTLE));
18699+ if (info->type >= FLIP_COMPLETE) {
18700 new_back:
18701 if (!xorg_can_triple_buffer())
18702- sna_dri2_get_back(sna, draw, back, info);
18703+ sna_dri2_get_back(sna, draw, back);
18704 DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
18705 frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE);
18706+ info->signal = signal;
18707 if (info->type == FLIP_ASYNC)
18708 sna_dri2_event_free(info);
18709 }
18710@@ -2613,57 +3130,31 @@ out:
18711 return true;
18712 }
18713
18714- info = sna_dri2_add_event(sna, draw, client);
18715+queue:
18716+ if (KEEPALIVE > 1 && sna->dri2.flip_pending) {
18717+ info = sna->dri2.flip_pending;
18718+ info->keepalive = 1;
18719+ }
18720+
18721+ info = sna_dri2_add_event(sna, draw, client, crtc);
18722 if (info == NULL)
18723 return false;
18724
18725 assert(info->crtc == crtc);
18726 info->event_complete = func;
18727 info->event_data = data;
18728+ info->signal = true;
18729 info->type = FLIP;
18730
18731 info->front = sna_dri2_reference_buffer(front);
18732 info->back = sna_dri2_reference_buffer(back);
18733
18734- /*
18735- * If divisor is zero, or current_msc is smaller than target_msc
18736- * we just need to make sure target_msc passes before initiating
18737- * the swap.
18738- */
18739- if (divisor && current_msc >= *target_msc) {
18740- DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
18741- __FUNCTION__,
18742- (long long)current_msc,
18743- (long long)*target_msc,
18744- (long long)divisor,
18745- (long long)remainder));
18746-
18747- *target_msc = current_msc + remainder - current_msc % divisor;
18748- if (*target_msc <= current_msc)
18749- *target_msc += divisor;
18750- }
18751-
18752- if (*target_msc <= current_msc + 1) {
18753- if (!sna_dri2_flip(info)) {
18754- sna_dri2_event_free(info);
18755- return false;
18756- }
18757+ if (*target_msc <= current_msc + 1 && sna_dri2_flip(info)) {
18758 *target_msc = current_msc + 1;
18759 } else {
18760- union drm_wait_vblank vbl;
18761-
18762- VG_CLEAR(vbl);
18763-
18764- vbl.request.type =
18765- DRM_VBLANK_ABSOLUTE |
18766- DRM_VBLANK_EVENT;
18767-
18768 /* Account for 1 frame extra pageflip delay */
18769- vbl.reply.sequence = draw_target_seq(draw, *target_msc - 1);
18770- vbl.request.signal = (uintptr_t)info;
18771-
18772- info->queued = true;
18773- if (sna_wait_vblank(sna, &vbl, info->pipe)) {
18774+ if (!sna_wait_vblank(info,
18775+ draw_target_seq(draw, *target_msc - 1))) {
18776 sna_dri2_event_free(info);
18777 return false;
18778 }
18779@@ -2674,128 +3165,6 @@ out:
18780 return true;
18781 }
18782
18783-static bool
18784-sna_dri2_schedule_xchg(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
18785- DRI2BufferPtr front, DRI2BufferPtr back,
18786- CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
18787- DRI2SwapEventPtr func, void *data)
18788-{
18789- struct sna *sna = to_sna_from_drawable(draw);
18790- uint64_t current_msc;
18791- bool sync, event;
18792-
18793- if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc))
18794- return false;
18795-
18796- sync = current_msc < *target_msc;
18797- event = dri2_chain(draw) == NULL;
18798- if (!sync || event) {
18799- DBG(("%s: performing immediate xchg on pipe %d\n",
18800- __FUNCTION__, sna_crtc_to_pipe(crtc)));
18801- sna_dri2_xchg(draw, front, back);
18802- }
18803- if (sync) {
18804- struct sna_dri2_event *info;
18805-
18806- info = sna_dri2_add_event(sna, draw, client);
18807- if (!info)
18808- goto complete;
18809-
18810- info->event_complete = func;
18811- info->event_data = data;
18812-
18813- info->front = sna_dri2_reference_buffer(front);
18814- info->back = sna_dri2_reference_buffer(back);
18815- info->type = SWAP_THROTTLE;
18816-
18817- if (event) {
18818- union drm_wait_vblank vbl;
18819-
18820- VG_CLEAR(vbl);
18821- vbl.request.type =
18822- DRM_VBLANK_RELATIVE |
18823- DRM_VBLANK_EVENT;
18824- vbl.request.sequence = 1;
18825- vbl.request.signal = (uintptr_t)info;
18826-
18827- info->queued = true;
18828- if (sna_wait_vblank(sna, &vbl, info->pipe)) {
18829- sna_dri2_event_free(info);
18830- goto complete;
18831- }
18832-
18833- swap_limit(draw, 2);
18834- }
18835- } else {
18836-complete:
18837- fake_swap_complete(sna, client, draw, crtc, DRI2_EXCHANGE_COMPLETE, func, data);
18838- }
18839-
18840- *target_msc = current_msc + 1;
18841- return true;
18842-}
18843-
18844-static bool
18845-sna_dri2_schedule_xchg_crtc(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
18846- DRI2BufferPtr front, DRI2BufferPtr back,
18847- CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
18848- DRI2SwapEventPtr func, void *data)
18849-{
18850- struct sna *sna = to_sna_from_drawable(draw);
18851- uint64_t current_msc;
18852- bool sync, event;
18853-
18854- if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc))
18855- return false;
18856-
18857- sync = current_msc < *target_msc;
18858- event = dri2_chain(draw) == NULL;
18859- if (!sync || event) {
18860- DBG(("%s: performing immediate xchg only on pipe %d\n",
18861- __FUNCTION__, sna_crtc_to_pipe(crtc)));
18862- sna_dri2_xchg_crtc(sna, draw, crtc, front, back);
18863- }
18864- if (sync) {
18865- struct sna_dri2_event *info;
18866-
18867- info = sna_dri2_add_event(sna, draw, client);
18868- if (!info)
18869- goto complete;
18870-
18871- info->event_complete = func;
18872- info->event_data = data;
18873-
18874- info->front = sna_dri2_reference_buffer(front);
18875- info->back = sna_dri2_reference_buffer(back);
18876- info->type = SWAP_THROTTLE;
18877-
18878- if (event) {
18879- union drm_wait_vblank vbl;
18880-
18881- VG_CLEAR(vbl);
18882- vbl.request.type =
18883- DRM_VBLANK_RELATIVE |
18884- DRM_VBLANK_EVENT;
18885- vbl.request.sequence = 1;
18886- vbl.request.signal = (uintptr_t)info;
18887-
18888- info->queued = true;
18889- if (sna_wait_vblank(sna, &vbl, info->pipe)) {
18890- sna_dri2_event_free(info);
18891- goto complete;
18892- }
18893-
18894- swap_limit(draw, 2);
18895- }
18896- } else {
18897-complete:
18898- fake_swap_complete(sna, client, draw, crtc, DRI2_EXCHANGE_COMPLETE, func, data);
18899- }
18900-
18901- *target_msc = current_msc + 1;
18902- return true;
18903-}
18904-
18905 static bool has_pending_events(struct sna *sna)
18906 {
18907 struct pollfd pfd;
18908@@ -2830,11 +3199,11 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
18909 CARD64 remainder, DRI2SwapEventPtr func, void *data)
18910 {
18911 struct sna *sna = to_sna_from_drawable(draw);
18912- union drm_wait_vblank vbl;
18913 xf86CrtcPtr crtc = NULL;
18914 struct sna_dri2_event *info = NULL;
18915 int type = DRI2_EXCHANGE_COMPLETE;
18916 CARD64 current_msc;
18917+ bool immediate;
18918
18919 DBG(("%s: draw=%lu %dx%d, pixmap=%ld %dx%d, back=%u (refs=%d/%d, flush=%d) , front=%u (refs=%d/%d, flush=%d)\n",
18920 __FUNCTION__,
18921@@ -2860,33 +3229,22 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
18922 assert(get_private(front)->refcnt);
18923 assert(get_private(back)->refcnt);
18924
18925+ assert(get_private(back)->bo != get_private(front)->bo);
18926 assert(get_private(front)->bo->refcnt);
18927 assert(get_private(back)->bo->refcnt);
18928
18929- if (get_private(front)->pixmap != get_drawable_pixmap(draw)) {
18930- DBG(("%s: decoupled DRI2 front pixmap=%ld, actual pixmap=%ld\n",
18931- __FUNCTION__,
18932- get_private(front)->pixmap->drawable.serialNumber,
18933- get_drawable_pixmap(draw)->drawable.serialNumber));
18934- goto skip;
18935- }
18936-
18937 if (get_private(back)->stale) {
18938 DBG(("%s: stale back buffer\n", __FUNCTION__));
18939 goto skip;
18940 }
18941
18942- assert(sna_pixmap_from_drawable(draw)->flush);
18943-
18944 if (draw->type != DRAWABLE_PIXMAP) {
18945 WindowPtr win = (WindowPtr)draw;
18946 struct dri2_window *priv = dri2_window(win);
18947- if (priv->front) {
18948- assert(front == priv->front);
18949- assert(get_private(priv->front)->refcnt > 1);
18950- get_private(priv->front)->refcnt--;
18951- priv->front = NULL;
18952- }
18953+
18954+ if (priv->front)
18955+ front = priv->front;
18956+
18957 if (win->clipList.extents.x2 <= win->clipList.extents.x1 ||
18958 win->clipList.extents.y2 <= win->clipList.extents.y1) {
18959 DBG(("%s: window clipped (%d, %d), (%d, %d)\n",
18960@@ -2899,6 +3257,16 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
18961 }
18962 }
18963
18964+ if (get_private(front)->pixmap != get_drawable_pixmap(draw)) {
18965+ DBG(("%s: decoupled DRI2 front pixmap=%ld, actual pixmap=%ld\n",
18966+ __FUNCTION__,
18967+ get_private(front)->pixmap->drawable.serialNumber,
18968+ get_drawable_pixmap(draw)->drawable.serialNumber));
18969+ goto skip;
18970+ }
18971+
18972+ assert(sna_pixmap_from_drawable(draw)->flush);
18973+
18974 /* Drawable not displayed... just complete the swap */
18975 if ((sna->flags & SNA_NO_WAIT) == 0)
18976 crtc = sna_dri2_get_crtc(draw);
18977@@ -2914,109 +3282,106 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
18978 sna_mode_wakeup(sna);
18979 }
18980
18981- if (can_xchg(sna, draw, front, back) &&
18982- sna_dri2_schedule_xchg(client, draw, crtc, front, back,
18983+ immediate = immediate_swap(sna, draw, crtc,
18984 target_msc, divisor, remainder,
18985- func, data))
18986- return TRUE;
18987-
18988- if (can_xchg_crtc(sna, draw, front, back, crtc) &&
18989- sna_dri2_schedule_xchg_crtc(client, draw, crtc, front, back,
18990- target_msc, divisor, remainder,
18991- func, data))
18992- return TRUE;
18993+ &current_msc);
18994
18995 if (can_flip(sna, draw, front, back, crtc) &&
18996 sna_dri2_schedule_flip(client, draw, crtc, front, back,
18997- target_msc, divisor, remainder,
18998+ immediate, target_msc, current_msc,
18999 func, data))
19000 return TRUE;
19001
19002- VG_CLEAR(vbl);
19003-
19004- info = sna_dri2_add_event(sna, draw, client);
19005+ info = sna_dri2_add_event(sna, draw, client, crtc);
19006 if (!info)
19007 goto blit;
19008
19009 assert(info->crtc == crtc);
19010 info->event_complete = func;
19011 info->event_data = data;
19012+ info->signal = true;
19013
19014 info->front = sna_dri2_reference_buffer(front);
19015 info->back = sna_dri2_reference_buffer(back);
19016
19017- if (immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc)) {
19018+ if (immediate) {
19019 bool sync = current_msc < *target_msc;
19020- if (!sna_dri2_immediate_blit(sna, info, sync, true))
19021- sna_dri2_event_free(info);
19022+ sna_dri2_immediate_blit(sna, info, sync);
19023 *target_msc = current_msc + sync;
19024+ DBG(("%s: reported target_msc=%llu\n",
19025+ __FUNCTION__, *target_msc));
19026 return TRUE;
19027 }
19028
19029- vbl.request.type =
19030- DRM_VBLANK_ABSOLUTE |
19031- DRM_VBLANK_EVENT;
19032- vbl.request.signal = (uintptr_t)info;
19033-
19034- /*
19035- * If divisor is zero, or current_msc is smaller than target_msc
19036- * we just need to make sure target_msc passes before initiating
19037- * the swap.
19038- */
19039 info->type = SWAP;
19040- info->queued = true;
19041- if (divisor && current_msc >= *target_msc) {
19042- DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
19043- __FUNCTION__,
19044- (long long)current_msc,
19045- (long long)*target_msc,
19046- (long long)divisor,
19047- (long long)remainder));
19048-
19049- *target_msc = current_msc + remainder - current_msc % divisor;
19050- if (*target_msc <= current_msc)
19051- *target_msc += divisor;
19052- }
19053- vbl.request.sequence = draw_target_seq(draw, *target_msc - 1);
19054 if (*target_msc <= current_msc + 1) {
19055 DBG(("%s: performing blit before queueing\n", __FUNCTION__));
19056- assert(info->queued);
19057- info->bo = __sna_dri2_copy_region(sna, draw, NULL,
19058- back, front,
19059- true);
19060- info->type = SWAP_WAIT;
19061-
19062- vbl.request.type =
19063- DRM_VBLANK_RELATIVE |
19064- DRM_VBLANK_EVENT;
19065- vbl.request.sequence = 1;
19066+ __sna_dri2_copy_event(info, DRI2_SYNC);
19067+ info->type = SWAP_COMPLETE;
19068+ if (!sna_next_vblank(info))
19069+ goto fake;
19070+
19071+ DBG(("%s: reported target_msc=%llu\n",
19072+ __FUNCTION__, *target_msc));
19073 *target_msc = current_msc + 1;
19074- }
19075+ swap_limit(draw, 2);
19076+ } else {
19077+ if (!sna_wait_vblank(info,
19078+ draw_target_seq(draw, *target_msc - 1)))
19079+ goto blit;
19080
19081- assert(info->queued);
19082- if (sna_wait_vblank(sna, &vbl, info->pipe))
19083- goto blit;
19084+ DBG(("%s: reported target_msc=%llu (in)\n",
19085+ __FUNCTION__, *target_msc));
19086+ swap_limit(draw, 1);
19087+ }
19088
19089- DBG(("%s: reported target_msc=%llu\n", __FUNCTION__, *target_msc));
19090- swap_limit(draw, 1 + (info->type == SWAP_WAIT));
19091 return TRUE;
19092
19093 blit:
19094 DBG(("%s -- blit\n", __FUNCTION__));
19095- if (info)
19096- sna_dri2_event_free(info);
19097 if (can_xchg(sna, draw, front, back)) {
19098 sna_dri2_xchg(draw, front, back);
19099 } else {
19100- __sna_dri2_copy_region(sna, draw, NULL, back, front, false);
19101+ __sna_dri2_copy_region(sna, draw, NULL, back, front, 0);
19102+ front->flags = back->flags;
19103 type = DRI2_BLIT_COMPLETE;
19104 }
19105+ if (draw->type == DRAWABLE_PIXMAP)
19106+ goto fake;
19107 skip:
19108 DBG(("%s: unable to show frame, unblocking client\n", __FUNCTION__));
19109- if (crtc == NULL)
19110- crtc = sna_mode_first_crtc(sna);
19111- fake_swap_complete(sna, client, draw, crtc, type, func, data);
19112- *target_msc = 0; /* offscreen, so zero out target vblank count */
19113+ if (crtc == NULL && (sna->flags & SNA_NO_WAIT) == 0)
19114+ crtc = sna_primary_crtc(sna);
19115+ if (crtc && sna_crtc_is_on(crtc)) {
19116+ if (info == NULL)
19117+ info = sna_dri2_add_event(sna, draw, client, crtc);
19118+ if (info != dri2_chain(draw))
19119+ goto fake;
19120+
19121+ assert(info->crtc == crtc);
19122+
19123+ info->type = SWAP_COMPLETE;
19124+ info->event_complete = func;
19125+ info->event_data = data;
19126+ info->signal = true;
19127+
19128+ info->front = sna_dri2_reference_buffer(front);
19129+ info->back = sna_dri2_reference_buffer(back);
19130+
19131+ if (!sna_next_vblank(info))
19132+ goto fake;
19133+
19134+ swap_limit(draw, 2);
19135+ } else {
19136+fake:
19137+ /* XXX Use a Timer to throttle the client? */
19138+ fake_swap_complete(sna, client, draw, crtc, type, func, data);
19139+ if (info) {
19140+ info->signal = false;
19141+ sna_dri2_event_free(info);
19142+ }
19143+ }
19144+ DBG(("%s: reported target_msc=%llu (in)\n", __FUNCTION__, *target_msc));
19145 return TRUE;
19146 }
19147
19148@@ -3030,27 +3395,25 @@ sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
19149 struct sna *sna = to_sna_from_drawable(draw);
19150 xf86CrtcPtr crtc = sna_dri2_get_crtc(draw);
19151 const struct ust_msc *swap;
19152+ union drm_wait_vblank vbl;
19153
19154 DBG(("%s(draw=%ld, pipe=%d)\n", __FUNCTION__, draw->id,
19155- crtc ? sna_crtc_to_pipe(crtc) : -1));
19156+ crtc ? sna_crtc_pipe(crtc) : -1));
19157
19158- if (crtc != NULL) {
19159- union drm_wait_vblank vbl;
19160+ /* Drawable not displayed, make up a *monotonic* value */
19161+ if (crtc == NULL)
19162+ crtc = sna_primary_crtc(sna);
19163+ if (crtc == NULL)
19164+ return FALSE;
19165
19166- VG_CLEAR(vbl);
19167- vbl.request.type = _DRM_VBLANK_RELATIVE;
19168- vbl.request.sequence = 0;
19169- if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0)
19170- sna_crtc_record_vblank(crtc, &vbl);
19171- } else
19172- /* Drawable not displayed, make up a *monotonic* value */
19173- crtc = sna_mode_first_crtc(sna);
19174+ if (sna_query_vblank(sna, crtc, &vbl) == 0)
19175+ sna_crtc_record_vblank(crtc, &vbl);
19176
19177 swap = sna_crtc_last_swap(crtc);
19178 *msc = draw_current_msc(draw, crtc, swap->msc);
19179 *ust = ust64(swap->tv_sec, swap->tv_usec);
19180- DBG(("%s: msc=%llu, ust=%llu\n", __FUNCTION__,
19181- (long long)*msc, (long long)*ust));
19182+ DBG(("%s: msc=%llu [raw=%llu], ust=%llu\n", __FUNCTION__,
19183+ (long long)*msc, swap->msc, (long long)*ust));
19184 return TRUE;
19185 }
19186
19187@@ -3068,32 +3431,22 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
19188 struct sna_dri2_event *info = NULL;
19189 xf86CrtcPtr crtc;
19190 CARD64 current_msc;
19191- union drm_wait_vblank vbl;
19192 const struct ust_msc *swap;
19193- int pipe;
19194
19195 crtc = sna_dri2_get_crtc(draw);
19196 DBG(("%s(pipe=%d, target_msc=%llu, divisor=%llu, rem=%llu)\n",
19197- __FUNCTION__, crtc ? sna_crtc_to_pipe(crtc) : -1,
19198+ __FUNCTION__, crtc ? sna_crtc_pipe(crtc) : -1,
19199 (long long)target_msc,
19200 (long long)divisor,
19201 (long long)remainder));
19202
19203 /* Drawable not visible, return immediately */
19204 if (crtc == NULL)
19205- goto out_complete;
19206-
19207- pipe = sna_crtc_to_pipe(crtc);
19208-
19209- VG_CLEAR(vbl);
19210-
19211- /* Get current count */
19212- vbl.request.type = _DRM_VBLANK_RELATIVE;
19213- vbl.request.sequence = 0;
19214- if (sna_wait_vblank(sna, &vbl, pipe))
19215- goto out_complete;
19216+ crtc = sna_primary_crtc(sna);
19217+ if (crtc == NULL)
19218+ return FALSE;
19219
19220- current_msc = draw_current_msc(draw, crtc, sna_crtc_record_vblank(crtc, &vbl));
19221+ current_msc = get_current_msc(sna, draw, crtc);
19222
19223 /* If target_msc already reached or passed, set it to
19224 * current_msc to ensure we return a reasonable value back
19225@@ -3104,15 +3457,13 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
19226 if (divisor == 0 && current_msc >= target_msc)
19227 goto out_complete;
19228
19229- info = sna_dri2_add_event(sna, draw, client);
19230+ info = sna_dri2_add_event(sna, draw, client, crtc);
19231 if (!info)
19232 goto out_complete;
19233
19234 assert(info->crtc == crtc);
19235 info->type = WAITMSC;
19236
19237- vbl.request.signal = (uintptr_t)info;
19238- vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
19239 /*
19240 * If divisor is zero, or current_msc is smaller than target_msc,
19241 * we just need to make sure target_msc passes before waking up the
19242@@ -3129,10 +3480,8 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
19243 if (target_msc <= current_msc)
19244 target_msc += divisor;
19245 }
19246- vbl.request.sequence = draw_target_seq(draw, target_msc);
19247
19248- info->queued = true;
19249- if (sna_wait_vblank(sna, &vbl, pipe))
19250+ if (!sna_wait_vblank(info, draw_target_seq(draw, target_msc)))
19251 goto out_free_info;
19252
19253 DRI2BlockClient(client, draw);
19254@@ -3141,8 +3490,6 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
19255 out_free_info:
19256 sna_dri2_event_free(info);
19257 out_complete:
19258- if (crtc == NULL)
19259- crtc = sna_mode_first_crtc(sna);
19260 swap = sna_crtc_last_swap(crtc);
19261 DRI2WaitMSCComplete(client, draw,
19262 draw_current_msc(draw, crtc, swap->msc),
19263@@ -3231,9 +3578,18 @@ static bool is_level(const char **str)
19264 return false;
19265 }
19266
19267+static const char *options_get_dri(struct sna *sna)
19268+{
19269+#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
19270+ return xf86GetOptValString(sna->Options, OPTION_DRI);
19271+#else
19272+ return NULL;
19273+#endif
19274+}
19275+
19276 static const char *dri_driver_name(struct sna *sna)
19277 {
19278- const char *s = xf86GetOptValString(sna->Options, OPTION_DRI);
19279+ const char *s = options_get_dri(sna);
19280
19281 if (is_level(&s)) {
19282 if (sna->kgem.gen < 030)
19283@@ -3259,7 +3615,7 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
19284
19285 if (wedged(sna)) {
19286 xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
19287- "loading DRI2 whilst the GPU is wedged.\n");
19288+ "loading DRI2 whilst acceleration is disabled.\n");
19289 }
19290
19291 if (xf86LoaderCheckSymbol("DRI2Version"))
19292@@ -3274,7 +3630,7 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
19293 memset(&info, '\0', sizeof(info));
19294 info.fd = sna->kgem.fd;
19295 info.driverName = dri_driver_name(sna);
19296- info.deviceName = intel_get_client_name(sna->dev);
19297+ info.deviceName = intel_get_master_name(sna->dev);
19298
19299 DBG(("%s: loading dri driver '%s' [gen=%d] for device '%s'\n",
19300 __FUNCTION__, info.driverName, sna->kgem.gen, info.deviceName));
19301@@ -3299,11 +3655,12 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
19302 info.numDrivers = 2;
19303 info.driverNames = driverNames;
19304 driverNames[0] = info.driverName;
19305- driverNames[1] = info.driverName;
19306+ driverNames[1] = "va_gl";
19307 #endif
19308
19309 #if DRI2INFOREC_VERSION >= 6
19310 if (xorg_can_triple_buffer()) {
19311+ DBG(("%s: enabling Xorg triple buffering\n", __FUNCTION__));
19312 info.version = 6;
19313 info.SwapLimitValidate = sna_dri2_swap_limit_validate;
19314 info.ReuseBufferNotify = sna_dri2_reuse_buffer;
19315@@ -3311,8 +3668,10 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
19316 #endif
19317
19318 #if USE_ASYNC_SWAP
19319+ DBG(("%s: enabled async swap and buffer age\n", __FUNCTION__));
19320 info.version = 10;
19321 info.scheduleSwap0 = 1;
19322+ info.bufferAge = 1;
19323 #endif
19324
19325 return DRI2ScreenInit(screen, &info);
19326diff --git a/src/sna/sna_dri3.c b/src/sna/sna_dri3.c
19327index f586e24..52ae263 100644
19328--- a/src/sna/sna_dri3.c
19329+++ b/src/sna/sna_dri3.c
19330@@ -55,7 +55,7 @@ static inline void mark_dri3_pixmap(struct sna *sna, struct sna_pixmap *priv, st
19331 if (bo->exec)
19332 sna->kgem.flush = 1;
19333 if (bo == priv->gpu_bo)
19334- priv->flush |= 3;
19335+ priv->flush |= FLUSH_READ | FLUSH_WRITE;
19336 else
19337 priv->shm = true;
19338
19339@@ -270,6 +270,8 @@ static PixmapPtr sna_dri3_pixmap_from_fd(ScreenPtr screen,
19340 priv->ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr);
19341 } else {
19342 assert(priv->gpu_bo == bo);
19343+ priv->create = kgem_can_create_2d(&sna->kgem,
19344+ width, height, depth);
19345 priv->pinned |= PIN_DRI3;
19346 }
19347 list_add(&priv->cow_list, &sna->dri3.pixmaps);
19348@@ -325,6 +327,15 @@ static int sna_dri3_fd_from_pixmap(ScreenPtr screen,
19349 return -1;
19350 }
19351
19352+ if (bo->tiling && !sna->kgem.can_fence) {
19353+ if (!sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) {
19354+ DBG(("%s: unable to discard GPU tiling (%d) for DRI3 protocol\n",
19355+ __FUNCTION__, bo->tiling));
19356+ return -1;
19357+ }
19358+ bo = priv->gpu_bo;
19359+ }
19360+
19361 fd = kgem_bo_export_to_prime(&sna->kgem, bo);
19362 if (fd == -1) {
19363 DBG(("%s: exporting handle=%d to fd failed\n", __FUNCTION__, bo->handle));
19364diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
19365index 8a3599c..14ec2f6 100644
19366--- a/src/sna/sna_driver.c
19367+++ b/src/sna/sna_driver.c
19368@@ -57,6 +57,13 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
19369 #include <mi.h>
19370 #include <micmap.h>
19371
19372+#if defined(HAVE_X11_EXTENSIONS_DPMSCONST_H)
19373+#include <X11/extensions/dpmsconst.h>
19374+#else
19375+#define DPMSModeOn 0
19376+#define DPMSModeOff 3
19377+#endif
19378+
19379 #include <sys/ioctl.h>
19380 #include <sys/fcntl.h>
19381 #include <sys/poll.h>
19382@@ -69,6 +76,8 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
19383
19384 #if HAVE_DOT_GIT
19385 #include "git_version.h"
19386+#else
19387+#define git_version "not compiled from git"
19388 #endif
19389
19390 #ifdef TEARFREE
19391@@ -185,12 +194,12 @@ sna_set_fallback_mode(ScrnInfoPtr scrn)
19392
19393 xf86DisableUnusedFunctions(scrn);
19394 #ifdef RANDR_12_INTERFACE
19395- if (get_root_window(scrn->pScreen))
19396- xf86RandR12TellChanged(scrn->pScreen);
19397+ if (get_root_window(xf86ScrnToScreen(scrn)))
19398+ xf86RandR12TellChanged(xf86ScrnToScreen(scrn));
19399 #endif
19400 }
19401
19402-static Bool sna_set_desired_mode(struct sna *sna)
19403+static void sna_set_desired_mode(struct sna *sna)
19404 {
19405 ScrnInfoPtr scrn = sna->scrn;
19406
19407@@ -203,7 +212,6 @@ static Bool sna_set_desired_mode(struct sna *sna)
19408 }
19409
19410 sna_mode_check(sna);
19411- return TRUE;
19412 }
19413
19414 /**
19415@@ -222,7 +230,7 @@ static Bool sna_create_screen_resources(ScreenPtr screen)
19416 screen->width, screen->height, screen->rootDepth));
19417
19418 assert(sna->scrn == xf86ScreenToScrn(screen));
19419- assert(sna->scrn->pScreen == screen);
19420+ assert(to_screen_from_sna(sna) == screen);
19421
19422 /* free the data used during miInitScreen */
19423 free(screen->devPrivate);
19424@@ -273,33 +281,89 @@ static Bool sna_create_screen_resources(ScreenPtr screen)
19425 if (serverGeneration == 1 && (sna->flags & SNA_IS_HOSTED) == 0)
19426 sna_copy_fbcon(sna);
19427
19428- (void)sna_set_desired_mode(sna);
19429+ sna_set_desired_mode(sna);
19430 }
19431
19432 return TRUE;
19433 }
19434
19435-static Bool sna_save_screen(ScreenPtr screen, int mode)
19436+static void sna_dpms_set(ScrnInfoPtr scrn, int mode, int flags)
19437 {
19438- ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
19439+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
19440+ struct sna *sna = to_sna(scrn);
19441+ bool changed = false;
19442+ int i;
19443
19444- DBG(("%s(mode=%d)\n", __FUNCTION__, mode));
19445+ DBG(("%s(mode=%d, flags=%d), vtSema=%d => off?=%d\n",
19446+ __FUNCTION__, mode, flags, scrn->vtSema, mode!=DPMSModeOn));
19447 if (!scrn->vtSema)
19448- return FALSE;
19449+ return;
19450
19451- xf86SaveScreen(screen, mode);
19452- sna_crtc_config_notify(screen);
19453- return TRUE;
19454+ /* Opencoded version of xf86DPMSSet().
19455+ *
19456+ * The principle difference is to skip calling crtc->dpms() when
19457+ * turning off the display. This (on recent enough kernels at
19458+ * least) should be equivalent in power consumption, but require
19459+ * less work (hence quicker and less likely to fail) when switching
19460+ * back on.
19461+ */
19462+ if (mode != DPMSModeOn) {
19463+ if (sna->mode.hidden == 0) {
19464+ DBG(("%s: hiding %d outputs\n",
19465+ __FUNCTION__, config->num_output));
19466+ for (i = 0; i < config->num_output; i++) {
19467+ xf86OutputPtr output = config->output[i];
19468+ if (output->crtc != NULL)
19469+ output->funcs->dpms(output, mode);
19470+ }
19471+ sna->mode.hidden = sna->mode.front_active + 1;
19472+ sna->mode.front_active = 0;
19473+ changed = true;
19474+ }
19475+ } else {
19476+ /* Re-enable CRTC that have been forced off via other means */
19477+ if (sna->mode.hidden != 0) {
19478+ DBG(("%s: unhiding %d crtc, %d outputs\n",
19479+ __FUNCTION__, config->num_crtc, config->num_output));
19480+ sna->mode.front_active = sna->mode.hidden - 1;
19481+ sna->mode.hidden = 0;
19482+ for (i = 0; i < config->num_crtc; i++) {
19483+ xf86CrtcPtr crtc = config->crtc[i];
19484+ if (crtc->enabled)
19485+ crtc->funcs->dpms(crtc, mode);
19486+ }
19487+
19488+ for (i = 0; i < config->num_output; i++) {
19489+ xf86OutputPtr output = config->output[i];
19490+ if (output->crtc != NULL)
19491+ output->funcs->dpms(output, mode);
19492+ }
19493+ changed = true;
19494+ }
19495+ }
19496+
19497+ DBG(("%s: hiding outputs? %d, front active? %d, changed? %d\n",
19498+ __FUNCTION__, sna->mode.hidden, sna->mode.front_active, changed));
19499+
19500+ if (changed)
19501+ sna_crtc_config_notify(xf86ScrnToScreen(scrn));
19502 }
19503
19504-static void sna_dpms_set(ScrnInfoPtr scrn, int mode, int flags)
19505+static Bool sna_save_screen(ScreenPtr screen, int mode)
19506 {
19507- DBG(("%s(mode=%d, flags=%d)\n", __FUNCTION__, mode));
19508- if (!scrn->vtSema)
19509- return;
19510+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
19511
19512- xf86DPMSSet(scrn, mode, flags);
19513- sna_crtc_config_notify(xf86ScrnToScreen(scrn));
19514+ DBG(("%s(mode=%d [unblank=%d])\n",
19515+ __FUNCTION__, mode, xf86IsUnblank(mode)));
19516+
19517+ /* We have to unroll xf86SaveScreen() here as it is called
19518+ * by DPMSSet() nullifying our special handling crtc->dpms()
19519+ * in sna_dpms_set().
19520+ */
19521+ sna_dpms_set(scrn,
19522+ xf86IsUnblank(mode) ? DPMSModeOn : DPMSModeOff,
19523+ 0);
19524+ return TRUE;
19525 }
19526
19527 static void sna_selftest(void)
19528@@ -330,107 +394,6 @@ static void sna_setup_capabilities(ScrnInfoPtr scrn, int fd)
19529 #endif
19530 }
19531
19532-static int
19533-namecmp(const char *s1, const char *s2)
19534-{
19535- char c1, c2;
19536-
19537- if (!s1 || *s1 == 0) {
19538- if (!s2 || *s2 == 0)
19539- return 0;
19540- else
19541- return 1;
19542- }
19543-
19544- while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
19545- s1++;
19546-
19547- while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
19548- s2++;
19549-
19550- c1 = isupper(*s1) ? tolower(*s1) : *s1;
19551- c2 = isupper(*s2) ? tolower(*s2) : *s2;
19552- while (c1 == c2) {
19553- if (c1 == '\0')
19554- return 0;
19555-
19556- s1++;
19557- while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
19558- s1++;
19559-
19560- s2++;
19561- while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
19562- s2++;
19563-
19564- c1 = isupper(*s1) ? tolower(*s1) : *s1;
19565- c2 = isupper(*s2) ? tolower(*s2) : *s2;
19566- }
19567-
19568- return c1 - c2;
19569-}
19570-
19571-static Bool sna_option_cast_to_bool(struct sna *sna, int id, Bool val)
19572-{
19573- const char *str = xf86GetOptValString(sna->Options, id);
19574-
19575- if (str == NULL)
19576- return val;
19577-
19578- if (*str == '\0')
19579- return TRUE;
19580-
19581- if (namecmp(str, "1") == 0)
19582- return TRUE;
19583- if (namecmp(str, "on") == 0)
19584- return TRUE;
19585- if (namecmp(str, "true") == 0)
19586- return TRUE;
19587- if (namecmp(str, "yes") == 0)
19588- return TRUE;
19589-
19590- if (namecmp(str, "0") == 0)
19591- return FALSE;
19592- if (namecmp(str, "off") == 0)
19593- return FALSE;
19594- if (namecmp(str, "false") == 0)
19595- return FALSE;
19596- if (namecmp(str, "no") == 0)
19597- return FALSE;
19598-
19599- return val;
19600-}
19601-
19602-static unsigned sna_option_cast_to_unsigned(struct sna *sna, int id, unsigned val)
19603-{
19604- const char *str = xf86GetOptValString(sna->Options, id);
19605- unsigned v;
19606-
19607- if (str == NULL || *str == '\0')
19608- return val;
19609-
19610- if (namecmp(str, "on") == 0)
19611- return val;
19612- if (namecmp(str, "true") == 0)
19613- return val;
19614- if (namecmp(str, "yes") == 0)
19615- return val;
19616-
19617- if (namecmp(str, "0") == 0)
19618- return 0;
19619- if (namecmp(str, "off") == 0)
19620- return 0;
19621- if (namecmp(str, "false") == 0)
19622- return 0;
19623- if (namecmp(str, "no") == 0)
19624- return 0;
19625-
19626- v = atoi(str);
19627- if (v)
19628- return v;
19629-
19630- return val;
19631-}
19632-
19633 static Bool fb_supports_depth(int fd, int depth)
19634 {
19635 struct drm_i915_gem_create create;
19636@@ -472,7 +435,7 @@ static void setup_dri(struct sna *sna)
19637 sna->dri2.available = false;
19638 sna->dri3.available = false;
19639
19640- level = sna_option_cast_to_unsigned(sna, OPTION_DRI, ~0);
19641+ level = intel_option_cast_to_unsigned(sna->Options, OPTION_DRI, DEFAULT_DRI_LEVEL);
19642 #if HAVE_DRI3
19643 if (level >= 3)
19644 sna->dri3.available = !!xf86LoadSubModule(sna->scrn, "dri3");
19645@@ -612,8 +575,10 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int probe)
19646 }
19647
19648 intel_detect_chipset(scrn, sna->dev);
19649- xf86DrvMsg(scrn->scrnIndex, X_PROBED, "CPU: %s\n",
19650- sna_cpu_features_to_string(sna->cpu_features, buf));
19651+ xf86DrvMsg(scrn->scrnIndex, X_PROBED,
19652+ "CPU: %s; using a maximum of %d threads\n",
19653+ sna_cpu_features_to_string(sna->cpu_features, buf),
19654+ sna_use_threads(64*1024, 64*1024, 1));
19655
19656 if (!xf86SetDepthBpp(scrn, 24, 0, 0,
19657 Support32bppFb |
19658@@ -651,18 +616,11 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int probe)
19659 kgem_init(&sna->kgem, fd,
19660 xf86GetPciInfoForEntity(pEnt->index),
19661 sna->info->gen);
19662- if (xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_DISABLE, FALSE) ||
19663- !sna_option_cast_to_bool(sna, OPTION_ACCEL_METHOD, TRUE)) {
19664- xf86DrvMsg(sna->scrn->scrnIndex, X_CONFIG,
19665- "Disabling hardware acceleration.\n");
19666- sna->kgem.wedged = true;
19667- }
19668
19669 if (xf86ReturnOptValBool(sna->Options, OPTION_TILING_FB, FALSE))
19670 sna->flags |= SNA_LINEAR_FB;
19671-
19672- if (xf86ReturnOptValBool(sna->Options, OPTION_DELETE_DP12, FALSE))
19673- sna->flags |= SNA_REMOVE_OUTPUTS;
19674+ if (!sna->kgem.can_fence)
19675+ sna->flags |= SNA_LINEAR_FB;
19676
19677 if (!xf86ReturnOptValBool(sna->Options, OPTION_SWAPBUFFERS_WAIT, TRUE))
19678 sna->flags |= SNA_NO_WAIT;
19679@@ -723,9 +681,10 @@ cleanup:
19680
19681 static bool has_shadow(struct sna *sna)
19682 {
19683- if (!sna->mode.shadow_damage)
19684+ if (!sna->mode.shadow_enabled)
19685 return false;
19686
19687+ assert(sna->mode.shadow_damage);
19688 if (RegionNil(DamageRegion(sna->mode.shadow_damage)))
19689 return false;
19690
19691@@ -748,7 +707,7 @@ sna_block_handler(BLOCKHANDLER_ARGS_DECL)
19692 sna->BlockHandler(BLOCKHANDLER_ARGS);
19693
19694 if (*tv == NULL || ((*tv)->tv_usec | (*tv)->tv_sec) || has_shadow(sna))
19695- sna_accel_block_handler(sna, tv);
19696+ sna_accel_block(sna, tv);
19697 }
19698
19699 static void
19700@@ -770,8 +729,6 @@ sna_wakeup_handler(WAKEUPHANDLER_ARGS_DECL)
19701
19702 sna->WakeupHandler(WAKEUPHANDLER_ARGS);
19703
19704- sna_accel_wakeup_handler(sna);
19705-
19706 if (FD_ISSET(sna->kgem.fd, (fd_set*)read_mask)) {
19707 sna_mode_wakeup(sna);
19708 /* Clear the flag so that subsequent ZaphodHeads don't block */
19709@@ -780,42 +737,62 @@ sna_wakeup_handler(WAKEUPHANDLER_ARGS_DECL)
19710 }
19711
19712 #if HAVE_UDEV
19713+#include <sys/stat.h>
19714+
19715 static void
19716 sna_handle_uevents(int fd, void *closure)
19717 {
19718 struct sna *sna = closure;
19719- struct udev_device *dev;
19720- const char *str;
19721 struct stat s;
19722- dev_t udev_devnum;
19723+ struct pollfd pfd;
19724+ bool hotplug = false;
19725
19726 DBG(("%s\n", __FUNCTION__));
19727
19728- dev = udev_monitor_receive_device(sna->uevent_monitor);
19729- if (!dev)
19730- return;
19731+ pfd.fd = udev_monitor_get_fd(sna->uevent_monitor);
19732+ pfd.events = POLLIN;
19733+
19734+ if (fstat(sna->kgem.fd, &s))
19735+ memset(&s, 0, sizeof(s));
19736+
19737+ while (poll(&pfd, 1, 0) > 0) {
19738+ struct udev_device *dev;
19739+ dev_t devnum;
19740+
19741+ dev = udev_monitor_receive_device(sna->uevent_monitor);
19742+ if (dev == NULL)
19743+ break;
19744+
19745+ devnum = udev_device_get_devnum(dev);
19746+ if (memcmp(&s.st_rdev, &devnum, sizeof(dev_t)) == 0) {
19747+ const char *str;
19748+
19749+ str = udev_device_get_property_value(dev, "HOTPLUG");
19750+ if (str && atoi(str) == 1)
19751+ hotplug = true;
19752+ }
19753
19754- udev_devnum = udev_device_get_devnum(dev);
19755- if (fstat(sna->kgem.fd, &s) || memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t))) {
19756 udev_device_unref(dev);
19757- return;
19758 }
19759
19760- str = udev_device_get_property_value(dev, "HOTPLUG");
19761- if (str && atoi(str) == 1) {
19762- ScrnInfoPtr scrn = sna->scrn;
19763+ if (hotplug) {
19764+ DBG(("%s: hotplug event (vtSema?=%d)\n",
19765+ __FUNCTION__, sna->scrn->vtSema));
19766
19767- DBG(("%s: hotplug event (vtSema?=%d)\n", __FUNCTION__, scrn->vtSema));
19768-
19769- if (scrn->vtSema) {
19770- sna_mode_discover(sna);
19771- sna_mode_check(sna);
19772- RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
19773- } else
19774+ if (sna->scrn->vtSema)
19775+ sna_mode_discover(sna, true);
19776+ else
19777 sna->flags |= SNA_REPROBE;
19778 }
19779+}
19780
19781- udev_device_unref(dev);
19782+static bool has_randr(void)
19783+{
19784+#if HAS_DIXREGISTERPRIVATEKEY
19785+ return dixPrivateKeyRegistered(rrPrivKey);
19786+#else
19787+ return *rrPrivKey;
19788+#endif
19789 }
19790
19791 static void
19792@@ -833,7 +810,7 @@ sna_uevent_init(struct sna *sna)
19793 /* RandR will be disabled if Xinerama is active, and so generating
19794 * RR hotplug events is then verboten.
19795 */
19796- if (!dixPrivateKeyRegistered(rrPrivKey))
19797+ if (!has_randr())
19798 goto out;
19799
19800 u = NULL;
19801@@ -861,7 +838,8 @@ sna_uevent_init(struct sna *sna)
19802
19803 sna->uevent_monitor = mon;
19804 out:
19805- xf86DrvMsg(sna->scrn->scrnIndex, from, "display hotplug detection %s\n",
19806+ xf86DrvMsg(sna->scrn->scrnIndex, from,
19807+ "Display hotplug detection %s\n",
19808 sna->uevent_monitor ? "enabled" : "disabled");
19809 return;
19810
19811@@ -874,17 +852,10 @@ err_dev:
19812
19813 static bool sna_uevent_poll(struct sna *sna)
19814 {
19815- struct pollfd pfd;
19816-
19817 if (sna->uevent_monitor == NULL)
19818 return false;
19819
19820- pfd.fd = udev_monitor_get_fd(sna->uevent_monitor);
19821- pfd.events = POLLIN;
19822-
19823- while (poll(&pfd, 1, 0) > 0)
19824- sna_handle_uevents(pfd.fd, sna);
19825-
19826+ sna_handle_uevents(udev_monitor_get_fd(sna->uevent_monitor), sna);
19827 return true;
19828 }
19829
19830@@ -918,8 +889,10 @@ sna_randr_getinfo(ScreenPtr screen, Rotation *rotations)
19831 {
19832 struct sna *sna = to_sna_from_screen(screen);
19833
19834+ DBG(("%s()\n", __FUNCTION__));
19835+
19836 if (!sna_uevent_poll(sna))
19837- sna_mode_discover(sna);
19838+ sna_mode_discover(sna, false);
19839
19840 return sna->mode.rrGetInfo(screen, rotations);
19841 }
19842@@ -931,8 +904,8 @@ static void sna_leave_vt(VT_FUNC_ARGS_DECL)
19843
19844 DBG(("%s\n", __FUNCTION__));
19845
19846- sna_accel_leave(sna);
19847 sna_mode_reset(sna);
19848+ sna_accel_leave(sna);
19849
19850 if (intel_put_master(sna->dev))
19851 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
19852@@ -1098,7 +1071,7 @@ sna_screen_init(SCREEN_INIT_ARGS_DECL)
19853 DBG(("%s\n", __FUNCTION__));
19854
19855 assert(sna->scrn == scrn);
19856- assert(scrn->pScreen == NULL); /* set afterwards */
19857+ assert(to_screen_from_sna(sna) == NULL); /* set afterwards */
19858
19859 assert(sna->freed_pixmap == NULL);
19860
19861@@ -1244,20 +1217,15 @@ static Bool sna_enter_vt(VT_FUNC_ARGS_DECL)
19862 if (intel_get_master(sna->dev))
19863 return FALSE;
19864
19865+ sna_accel_enter(sna);
19866+
19867 if (sna->flags & SNA_REPROBE) {
19868- DBG(("%s: reporting deferred hotplug event\n",
19869- __FUNCTION__));
19870- sna_mode_discover(sna);
19871- RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
19872- sna->flags &= ~SNA_REPROBE;
19873+ DBG(("%s: reporting deferred hotplug event\n", __FUNCTION__));
19874+ sna_mode_discover(sna, true);
19875 }
19876
19877- if (!sna_set_desired_mode(sna)) {
19878- intel_put_master(sna->dev);
19879- return FALSE;
19880- }
19881+ sna_set_desired_mode(sna);
19882
19883- sna_accel_enter(sna);
19884 return TRUE;
19885 }
19886
19887@@ -1379,6 +1347,9 @@ static void describe_sna(ScrnInfoPtr scrn)
19888 xf86DrvMsg(scrn->scrnIndex, X_INFO,
19889 "SNA compiled: %s\n", BUILDER_DESCRIPTION);
19890 #endif
19891+#if HAS_DEBUG_FULL
19892+ ErrorF("SNA compiled with full debug logging; expect to run slowly\n");
19893+#endif
19894 #if !NDEBUG
19895 xf86DrvMsg(scrn->scrnIndex, X_INFO,
19896 "SNA compiled with assertions enabled\n");
19897@@ -1400,6 +1371,7 @@ static void describe_sna(ScrnInfoPtr scrn)
19898 "SNA compiled for use with valgrind\n");
19899 VALGRIND_PRINTF("SNA compiled for use with valgrind\n");
19900 #endif
19901+ DBG(("xf86-video-intel version: %s\n", git_version));
19902 DBG(("pixman version: %s\n", pixman_version_string()));
19903 }
19904
19905diff --git a/src/sna/sna_glyphs.c b/src/sna/sna_glyphs.c
19906index a5dfb06..6ee4033 100644
19907--- a/src/sna/sna_glyphs.c
19908+++ b/src/sna/sna_glyphs.c
19909@@ -74,7 +74,7 @@
19910 #define NO_GLYPHS_VIA_MASK 0
19911 #define FORCE_SMALL_MASK 0 /* -1 = never, 1 = always */
19912 #define NO_GLYPHS_SLOW 0
19913-#define NO_DISCARD_MASK 0
19914+#define DISCARD_MASK 0 /* -1 = never, 1 = always */
19915
19916 #define CACHE_PICTURE_SIZE 1024
19917 #define GLYPH_MIN_SIZE 8
19918@@ -185,7 +185,7 @@ void sna_glyphs_close(struct sna *sna)
19919 */
19920 bool sna_glyphs_create(struct sna *sna)
19921 {
19922- ScreenPtr screen = sna->scrn->pScreen;
19923+ ScreenPtr screen = to_screen_from_sna(sna);
19924 pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
19925 unsigned int formats[] = {
19926 PIXMAN_a8,
19927@@ -1094,6 +1094,9 @@ sna_glyph_get_image(GlyphPtr g, ScreenPtr s)
19928
19929 static inline bool use_small_mask(struct sna *sna, int16_t width, int16_t height, int depth)
19930 {
19931+ if (depth < 8)
19932+ return true;
19933+
19934 if (FORCE_SMALL_MASK)
19935 return FORCE_SMALL_MASK > 0;
19936
19937@@ -1156,12 +1159,6 @@ glyphs_via_mask(struct sna *sna,
19938 src_x += box.x1 - list->xOff;
19939 src_y += box.y1 - list->yOff;
19940
19941- if (format->depth < 8) {
19942- format = PictureMatchFormat(screen, 8, PICT_a8);
19943- if (!format)
19944- return false;
19945- }
19946-
19947 component_alpha = NeedsComponent(format->format);
19948 if (use_small_mask(sna, width, height, format->depth)) {
19949 pixman_image_t *mask_image;
19950@@ -1179,7 +1176,7 @@ use_small_mask:
19951 return false;
19952
19953 mask_image =
19954- pixman_image_create_bits(format->depth << 24 | format->format,
19955+ pixman_image_create_bits(pixmap->drawable.bitsPerPixel << 24 | format->format,
19956 width, height,
19957 pixmap->devPrivate.ptr,
19958 pixmap->devKind);
19959@@ -1386,10 +1383,11 @@ next_image:
19960 DBG(("%s: atlas format=%08x, mask format=%08x\n",
19961 __FUNCTION__,
19962 (int)p->atlas->format,
19963- (int)(format->depth << 24 | format->format)));
19964+ (int)mask->format));
19965
19966 memset(&tmp, 0, sizeof(tmp));
19967- if (p->atlas->format == (format->depth << 24 | format->format)) {
19968+ if (p->atlas->format == mask->format ||
19969+ alphaless(p->atlas->format) == mask->format) {
19970 ok = sna->render.composite(sna, PictOpAdd,
19971 p->atlas, NULL, mask,
19972 0, 0, 0, 0, 0, 0,
19973@@ -1561,6 +1559,9 @@ skip_glyph:
19974 }
19975 }
19976
19977+ assert(format);
19978+ DBG(("%s: format=%08d, depth=%d\n",
19979+ __FUNCTION__, format->format, format->depth));
19980 out:
19981 if (list_extents != stack_extents)
19982 free(list_extents);
19983@@ -1573,24 +1574,34 @@ static bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask,
19984 PictFormatPtr g;
19985 uint32_t color;
19986
19987- if (NO_DISCARD_MASK)
19988- return false;
19989+ if (DISCARD_MASK)
19990+ return DISCARD_MASK > 0;
19991
19992 DBG(("%s: nlist=%d, mask=%08x, depth %d, op=%d (bounded? %d)\n",
19993 __FUNCTION__, nlist,
19994 mask ? (unsigned)mask->format : 0, mask ? mask->depth : 0,
19995 op, op_is_bounded(op)));
19996
19997- if (nlist == 1 && list->len == 1)
19998- return true;
19999+ if (nlist == 1 && list->len == 1) {
20000+ if (mask == list->format)
20001+ return true;
20002+
20003+ g = list->format;
20004+ goto skip;
20005+ }
20006
20007- if (!op_is_bounded(op))
20008+ if (!op_is_bounded(op)) {
20009+ DBG(("%s: unbounded op, not discarding\n", __FUNCTION__));
20010 return false;
20011+ }
20012
20013 /* No glyphs overlap and we are not performing a mask conversion. */
20014 g = glyphs_format(nlist, list, glyphs);
20015- if (mask == g)
20016+ if (mask == g) {
20017+ DBG(("%s: mask matches glyphs format, no conversion, so discard mask\n",
20018+ __FUNCTION__));
20019 return true;
20020+ }
20021
20022 DBG(("%s: preferred mask format %08x, depth %d\n",
20023 __FUNCTION__, g ? (unsigned)g->format : 0, g ? g->depth : 0));
20024@@ -1605,18 +1616,41 @@ static bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask,
20025
20026 list++;
20027 }
20028+
20029+ if (!sna_picture_is_solid(src, &color))
20030+ return false;
20031+
20032+ return color >> 24 == 0xff;
20033 } else {
20034- if (PICT_FORMAT_A(mask->format) >= PICT_FORMAT_A(g->format))
20035+skip:
20036+ if (mask->format == g->format)
20037 return true;
20038
20039- if (g->depth != 1)
20040- return false;
20041- }
20042+ if (mask->format == alphaless(g->format))
20043+ return true;
20044+
20045+ if (PICT_FORMAT_TYPE(g->format) == PICT_TYPE_A &&
20046+ PICT_FORMAT_TYPE(mask->format) != PICT_TYPE_A)
20047+ return true;
20048
20049- if (!sna_picture_is_solid(src, &color))
20050 return false;
20051+ }
20052+}
20053
20054- return color >> 24 == 0xff;
20055+static uint32_t pixman_format(PictFormatPtr short_format)
20056+{
20057+ uint32_t bpp;
20058+
20059+ bpp = short_format->depth;
20060+ if (bpp <= 1)
20061+ bpp = 1;
20062+ else if (bpp <= 8)
20063+ bpp = 8;
20064+ else if (bpp <= 16)
20065+ bpp = 16;
20066+ else
20067+ bpp = 32;
20068+ return bpp << 24 | short_format->format;
20069 }
20070
20071 static void
20072@@ -1756,7 +1790,7 @@ next:
20073 if (sigtrap_get() == 0) {
20074 if (mask_format) {
20075 pixman_composite_glyphs(op, src_image, dst_image,
20076- mask_format->format | (mask_format->depth << 24),
20077+ pixman_format(mask_format),
20078 src_x + src_dx + region.extents.x1 - dst_x,
20079 src_y + src_dy + region.extents.y1 - dst_y,
20080 region.extents.x1, region.extents.y1,
20081@@ -1815,10 +1849,10 @@ out:
20082 x, y,
20083 mask_format->depth,
20084 (long)mask_format->format,
20085- (long)(mask_format->depth << 24 | mask_format->format),
20086+ (long)pixman_format(mask_format),
20087 NeedsComponent(mask_format->format)));
20088 mask_image =
20089- pixman_image_create_bits(mask_format->depth << 24 | mask_format->format,
20090+ pixman_image_create_bits(pixman_format(mask_format),
20091 region.extents.x2 - region.extents.x1,
20092 region.extents.y2 - region.extents.y1,
20093 NULL, 0);
20094@@ -2086,12 +2120,6 @@ glyphs_via_image(struct sna *sna,
20095 src_x += box.x1 - list->xOff;
20096 src_y += box.y1 - list->yOff;
20097
20098- if (format->depth < 8) {
20099- format = PictureMatchFormat(screen, 8, PICT_a8);
20100- if (!format)
20101- return false;
20102- }
20103-
20104 DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n",
20105 __FUNCTION__, (unsigned long)format->format,
20106 format->depth, (uint32_t)width*height*format->depth));
20107@@ -2104,7 +2132,7 @@ glyphs_via_image(struct sna *sna,
20108 return false;
20109
20110 mask_image =
20111- pixman_image_create_bits(format->depth << 24 | format->format,
20112+ pixman_image_create_bits(pixmap->drawable.bitsPerPixel << 24 | format->format,
20113 width, height,
20114 pixmap->devPrivate.ptr,
20115 pixmap->devKind);
20116diff --git a/src/sna/sna_io.c b/src/sna/sna_io.c
20117index d6aa129..d32bd58 100644
20118--- a/src/sna/sna_io.c
20119+++ b/src/sna/sna_io.c
20120@@ -105,8 +105,10 @@ read_boxes_inplace__cpu(struct kgem *kgem,
20121 if (!download_inplace__cpu(kgem, dst, bo, box, n))
20122 return false;
20123
20124+ if (bo->tiling == I915_TILING_Y)
20125+ return false;
20126+
20127 assert(kgem_bo_can_map__cpu(kgem, bo, false));
20128- assert(bo->tiling != I915_TILING_Y);
20129
20130 src = kgem_bo_map__cpu(kgem, bo);
20131 if (src == NULL)
20132@@ -281,6 +283,9 @@ fallback:
20133 if (box[n].y2 > extents.y2)
20134 extents.y2 = box[n].y2;
20135 }
20136+ if (!can_blt && sna->render.max_3d_size == 0)
20137+ goto fallback;
20138+
20139 if (kgem_bo_can_map(kgem, src_bo)) {
20140 /* Is it worth detiling? */
20141 if ((extents.y2 - extents.y1 - 1) * src_bo->pitch < 4096)
20142@@ -477,6 +482,7 @@ fallback:
20143 goto fallback;
20144 _kgem_set_mode(kgem, KGEM_BLT);
20145 }
20146+ kgem_bcs_set_tiling(&sna->kgem, src_bo, NULL);
20147
20148 tmp_nbox = nbox;
20149 tmp_box = box;
20150@@ -539,6 +545,7 @@ fallback:
20151 break;
20152
20153 _kgem_set_mode(kgem, KGEM_BLT);
20154+ kgem_bcs_set_tiling(&sna->kgem, src_bo, NULL);
20155 tmp_box += nbox_this_time;
20156 } while (1);
20157 } else {
20158@@ -597,6 +604,7 @@ fallback:
20159 break;
20160
20161 _kgem_set_mode(kgem, KGEM_BLT);
20162+ kgem_bcs_set_tiling(&sna->kgem, src_bo, NULL);
20163 tmp_box += nbox_this_time;
20164 } while (1);
20165 }
20166@@ -666,8 +674,10 @@ write_boxes_inplace__tiled(struct kgem *kgem,
20167 {
20168 uint8_t *dst;
20169
20170+ if (bo->tiling == I915_TILING_Y)
20171+ return false;
20172+
20173 assert(kgem->has_wc_mmap || kgem_bo_can_map__cpu(kgem, bo, true));
20174- assert(bo->tiling != I915_TILING_Y);
20175
20176 if (kgem_bo_can_map__cpu(kgem, bo, true)) {
20177 dst = kgem_bo_map__cpu(kgem, bo);
20178@@ -778,6 +788,15 @@ static bool __upload_inplace(struct kgem *kgem,
20179 if (FORCE_INPLACE)
20180 return FORCE_INPLACE > 0;
20181
20182+ if (bo->exec)
20183+ return false;
20184+
20185+ if (bo->flush)
20186+ return true;
20187+
20188+ if (kgem_bo_can_map__cpu(kgem, bo, true))
20189+ return true;
20190+
20191 /* If we are writing through the GTT, check first if we might be
20192 * able to almagamate a series of small writes into a single
20193 * operation.
20194@@ -849,6 +868,8 @@ bool sna_write_boxes(struct sna *sna, PixmapPtr dst,
20195 if (box[n].y2 > extents.y2)
20196 extents.y2 = box[n].y2;
20197 }
20198+ if (!can_blt && sna->render.max_3d_size == 0)
20199+ goto fallback;
20200
20201 /* Try to avoid switching rings... */
20202 if (!can_blt || kgem->ring == KGEM_RENDER ||
20203@@ -1038,6 +1059,7 @@ tile:
20204 goto fallback;
20205 _kgem_set_mode(kgem, KGEM_BLT);
20206 }
20207+ kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
20208
20209 if (kgem->gen >= 0100) {
20210 cmd |= 8;
20211@@ -1129,6 +1151,7 @@ tile:
20212 if (nbox) {
20213 _kgem_submit(kgem);
20214 _kgem_set_mode(kgem, KGEM_BLT);
20215+ kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
20216 }
20217
20218 kgem_bo_destroy(kgem, src_bo);
20219@@ -1224,6 +1247,7 @@ tile:
20220 if (nbox) {
20221 _kgem_submit(kgem);
20222 _kgem_set_mode(kgem, KGEM_BLT);
20223+ kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
20224 }
20225
20226 kgem_bo_destroy(kgem, src_bo);
20227@@ -1541,6 +1565,7 @@ tile:
20228 goto fallback;
20229 _kgem_set_mode(kgem, KGEM_BLT);
20230 }
20231+ kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
20232
20233 if (sna->kgem.gen >= 0100) {
20234 cmd |= 8;
20235@@ -1636,6 +1661,7 @@ tile:
20236 if (nbox) {
20237 _kgem_submit(kgem);
20238 _kgem_set_mode(kgem, KGEM_BLT);
20239+ kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
20240 }
20241
20242 kgem_bo_destroy(kgem, src_bo);
20243@@ -1732,6 +1758,7 @@ tile:
20244 if (nbox) {
20245 _kgem_submit(kgem);
20246 _kgem_set_mode(kgem, KGEM_BLT);
20247+ kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
20248 }
20249
20250 kgem_bo_destroy(kgem, src_bo);
20251diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c
20252index 6dd6fe8..2de5ddf 100644
20253--- a/src/sna/sna_present.c
20254+++ b/src/sna/sna_present.c
20255@@ -27,6 +27,7 @@
20256 #include <sys/types.h>
20257 #include <fcntl.h>
20258 #include <unistd.h>
20259+#include <sys/poll.h>
20260 #include <errno.h>
20261 #include <xf86drm.h>
20262
20263@@ -38,10 +39,16 @@
20264 static present_screen_info_rec present_info;
20265
20266 struct sna_present_event {
20267- uint64_t event_id;
20268 xf86CrtcPtr crtc;
20269+ struct sna *sna;
20270+ struct list link;
20271+ uint64_t *event_id;
20272+ uint64_t target_msc;
20273+ int n_event_id;
20274 };
20275
20276+static void sna_present_unflip(ScreenPtr screen, uint64_t event_id);
20277+
20278 static inline struct sna_present_event *
20279 to_present_event(uintptr_t data)
20280 {
20281@@ -50,9 +57,24 @@ to_present_event(uintptr_t data)
20282
20283 #define MARK_PRESENT(x) ((void *)((uintptr_t)(x) | 2))
20284
20285-static int pipe_from_crtc(RRCrtcPtr crtc)
20286+static inline xf86CrtcPtr unmask_crtc(xf86CrtcPtr crtc)
20287+{
20288+ return (xf86CrtcPtr)((uintptr_t)crtc & ~1);
20289+}
20290+
20291+static inline xf86CrtcPtr mark_crtc(xf86CrtcPtr crtc)
20292 {
20293- return crtc ? sna_crtc_to_pipe(crtc->devPrivate) : -1;
20294+ return (xf86CrtcPtr)((uintptr_t)crtc | 1);
20295+}
20296+
20297+static inline bool has_vblank(xf86CrtcPtr crtc)
20298+{
20299+ return (uintptr_t)crtc & 1;
20300+}
20301+
20302+static inline int pipe_from_crtc(RRCrtcPtr crtc)
20303+{
20304+ return crtc ? sna_crtc_pipe(crtc->devPrivate) : -1;
20305 }
20306
20307 static uint32_t pipe_select(int pipe)
20308@@ -74,6 +96,139 @@ static inline int sna_wait_vblank(struct sna *sna, union drm_wait_vblank *vbl, i
20309 return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl);
20310 }
20311
20312+static uint64_t gettime_ust64(void)
20313+{
20314+ struct timespec tv;
20315+
20316+ if (clock_gettime(CLOCK_MONOTONIC, &tv))
20317+ return GetTimeInMicros();
20318+
20319+ return ust64(tv.tv_sec, tv.tv_nsec / 1000);
20320+}
20321+
20322+static void vblank_complete(struct sna_present_event *info,
20323+ uint64_t ust, uint64_t msc)
20324+{
20325+ int n;
20326+
20327+ DBG(("%s: %d events complete\n", __FUNCTION__, info->n_event_id));
20328+ for (n = 0; n < info->n_event_id; n++) {
20329+ DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event=%lld complete%s\n", __FUNCTION__,
20330+ sna_crtc_pipe(unmask_crtc(info->crtc)),
20331+ (int)(ust / 1000000), (int)(ust % 1000000),
20332+ (long long)msc, (long long)info->target_msc,
20333+ (long long)info->event_id[n],
20334+ info->target_msc && msc == (uint32_t)info->target_msc ? "" : ": MISS"));
20335+ present_event_notify(info->event_id[n], ust, msc);
20336+ }
20337+ if (info->n_event_id > 1)
20338+ free(info->event_id);
20339+ list_del(&info->link);
20340+ free(info);
20341+}
20342+
20343+static uint32_t msc_to_delay(xf86CrtcPtr crtc, uint64_t target)
20344+{
20345+ const DisplayModeRec *mode = &crtc->desiredMode;
20346+ const struct ust_msc *swap = sna_crtc_last_swap(crtc);
20347+ int64_t delay, subframe;
20348+
20349+ delay = (target - swap->msc) * mode->VTotal * mode->HTotal / mode->Clock;
20350+ subframe = gettime_ust64() - swap_ust(swap);
20351+ subframe /= 1000;
20352+ if (subframe < delay)
20353+ delay -= subframe;
20354+ else
20355+ delay = 0;
20356+
20357+ DBG(("%s: sleep %d frames, %llu ms\n", __FUNCTION__,
20358+ (int)(target - swap->msc), (long long)delay));
20359+ assert(delay >= 0);
20360+ return delay;
20361+}
20362+
20363+static CARD32 sna_fake_vblank_handler(OsTimerPtr timer, CARD32 now, void *data)
20364+{
20365+ struct sna_present_event *info = data;
20366+ union drm_wait_vblank vbl;
20367+ uint64_t msc, ust;
20368+
20369+ DBG(("%s(event=%lldx%d, now=%d)\n", __FUNCTION__, (long long)info->event_id[0], info->n_event_id, now));
20370+
20371+ VG_CLEAR(vbl);
20372+ vbl.request.type = DRM_VBLANK_RELATIVE;
20373+ vbl.request.sequence = 0;
20374+ if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)) == 0) {
20375+ ust = ust64(vbl.reply.tval_sec, vbl.reply.tval_usec);
20376+ msc = sna_crtc_record_vblank(info->crtc, &vbl);
20377+ DBG(("%s: event=%lld, target msc=%lld, now %lld\n",
20378+ __FUNCTION__, (long long)info->event_id[0], (long long)info->target_msc, (long long)msc));
20379+ if (msc < info->target_msc) {
20380+ uint32_t delay;
20381+
20382+ DBG(("%s: too early, requeuing\n", __FUNCTION__));
20383+
20384+ vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
20385+ vbl.request.sequence = info->target_msc;
20386+ vbl.request.signal = (uintptr_t)MARK_PRESENT(info);
20387+ if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)) == 0) {
20388+ DBG(("%s: scheduled new vblank event for %lld\n", __FUNCTION__, (long long)info->target_msc));
20389+ free(timer);
20390+ return 0;
20391+ }
20392+
20393+ delay = msc_to_delay(info->crtc, info->target_msc);
20394+ if (delay) {
20395+ DBG(("%s: requeueing timer for %dms delay\n", __FUNCTION__, delay));
20396+ return delay;
20397+ }
20398+
20399+ /* As a last resort use a blocking wait.
20400+ * Less than a millisecond for a rare case.
20401+ */
20402+ DBG(("%s: blocking wait!\n", __FUNCTION__));
20403+ vbl.request.type = DRM_VBLANK_ABSOLUTE;
20404+ vbl.request.sequence = info->target_msc;
20405+ (void)sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc));
20406+ }
20407+ } else {
20408+ const struct ust_msc *swap = sna_crtc_last_swap(info->crtc);
20409+ ust = swap_ust(swap);
20410+ msc = swap->msc;
20411+ DBG(("%s: event=%lld, CRTC OFF, target msc=%lld, was %lld\n",
20412+ __FUNCTION__, (long long)info->event_id[0], (long long)info->target_msc, (long long)msc));
20413+ }
20414+
20415+ vblank_complete(info, ust, msc);
20416+ free(timer);
20417+ return 0;
20418+}
20419+
20420+static bool sna_fake_vblank(struct sna_present_event *info)
20421+{
20422+ uint64_t msc = sna_crtc_last_swap(info->crtc)->msc;
20423+ uint32_t delay;
20424+
20425+ assert(info->n_event_id == 1);
20426+
20427+ if (msc < info->target_msc)
20428+ delay = msc_to_delay(info->crtc, info->target_msc);
20429+ else
20430+ delay = 0;
20431+
20432+ DBG(("%s(event=%lld, target_msc=%lld, msc=%lld, delay=%ums)\n",
20433+ __FUNCTION__, (long long)info->event_id[0], (long long)info->target_msc, (long long)msc, delay));
20434+ if (delay == 0) {
20435+ const struct ust_msc *swap = sna_crtc_last_swap(info->crtc);
20436+ present_event_notify(info->event_id[0], swap_ust(swap), swap->msc);
20437+ list_del(&info->link);
20438+ free(info);
20439+ return true;
20440+ }
20441+
20442+ return TimerSet(NULL, 0, delay, sna_fake_vblank_handler, info);
20443+}
20444+
20445 static RRCrtcPtr
20446 sna_present_get_crtc(WindowPtr window)
20447 {
20448@@ -81,7 +236,10 @@ sna_present_get_crtc(WindowPtr window)
20449 BoxRec box;
20450 xf86CrtcPtr crtc;
20451
20452- DBG(("%s\n", __FUNCTION__));
20453+ DBG(("%s: window=%ld (pixmap=%ld), box=(%d, %d)x(%d, %d)\n",
20454+ __FUNCTION__, window->drawable.id, get_window_pixmap(window)->drawable.serialNumber,
20455+ window->drawable.x, window->drawable.y,
20456+ window->drawable.width, window->drawable.height));
20457
20458 box.x1 = window->drawable.x;
20459 box.y1 = window->drawable.y;
20460@@ -99,24 +257,31 @@ static int
20461 sna_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc)
20462 {
20463 struct sna *sna = to_sna_from_screen(crtc->pScreen);
20464- int pipe = pipe_from_crtc(crtc);
20465 union drm_wait_vblank vbl;
20466
20467- DBG(("%s(pipe=%d)\n", __FUNCTION__, pipe));
20468+ DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc->devPrivate)));
20469+ if (sna_crtc_has_vblank(crtc->devPrivate)) {
20470+ DBG(("%s: vblank active, reusing last swap msc/ust\n",
20471+ __FUNCTION__));
20472+ goto last;
20473+ }
20474
20475 VG_CLEAR(vbl);
20476 vbl.request.type = DRM_VBLANK_RELATIVE;
20477 vbl.request.sequence = 0;
20478- if (sna_wait_vblank(sna, &vbl, pipe) == 0) {
20479+ if (sna_wait_vblank(sna, &vbl, sna_crtc_pipe(crtc->devPrivate)) == 0) {
20480 *ust = ust64(vbl.reply.tval_sec, vbl.reply.tval_usec);
20481 *msc = sna_crtc_record_vblank(crtc->devPrivate, &vbl);
20482 } else {
20483- const struct ust_msc *swap = sna_crtc_last_swap(crtc->devPrivate);
20484- *ust = ust64(swap->tv_sec, swap->tv_usec);
20485+ const struct ust_msc *swap;
20486+last:
20487+ swap = sna_crtc_last_swap(crtc->devPrivate);
20488+ *ust = swap_ust(swap);
20489 *msc = swap->msc;
20490 }
20491
20492- DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld\n", __FUNCTION__, pipe,
20493+ DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld\n", __FUNCTION__,
20494+ sna_crtc_pipe(crtc->devPrivate),
20495 (int)(*ust / 1000000), (int)(*ust % 1000000),
20496 (long long)*msc));
20497
20498@@ -127,43 +292,97 @@ void
20499 sna_present_vblank_handler(struct drm_event_vblank *event)
20500 {
20501 struct sna_present_event *info = to_present_event(event->user_data);
20502+ xf86CrtcPtr crtc = info->crtc;
20503
20504- DBG(("%s: pipe=%d tv=%d.%06d msc=%d, event %lld complete\n", __FUNCTION__,
20505- sna_crtc_to_pipe(info->crtc),
20506- event->tv_sec, event->tv_usec, event->sequence,
20507- (long long)info->event_id));
20508- present_event_notify(info->event_id,
20509- ust64(event->tv_sec, event->tv_usec),
20510- sna_crtc_record_event(info->crtc, event));
20511- free(info);
20512+ vblank_complete(info,
20513+ ust64(event->tv_sec, event->tv_usec),
20514+ sna_crtc_record_event(unmask_crtc(crtc), event));
20515+ if (has_vblank(crtc))
20516+ sna_crtc_clear_vblank(unmask_crtc(crtc));
20517 }
20518
20519 static int
20520 sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
20521 {
20522 struct sna *sna = to_sna_from_screen(crtc->pScreen);
20523- struct sna_present_event *event;
20524+ struct sna_present_event *info, *tmp;
20525+ const struct ust_msc *swap;
20526 union drm_wait_vblank vbl;
20527
20528 DBG(("%s(pipe=%d, event=%lld, msc=%lld)\n",
20529- __FUNCTION__, pipe_from_crtc(crtc),
20530+ __FUNCTION__, sna_crtc_pipe(crtc->devPrivate),
20531 (long long)event_id, (long long)msc));
20532
20533- event = malloc(sizeof(struct sna_present_event));
20534- if (event == NULL)
20535+ swap = sna_crtc_last_swap(crtc->devPrivate);
20536+ warn_unless((int64_t)(msc - swap->msc) >= 0);
20537+ if ((int64_t)(msc - swap->msc) <= 0) {
20538+ DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event=%lld complete\n", __FUNCTION__,
20539+ sna_crtc_pipe(crtc->devPrivate),
20540+ swap->tv_sec, swap->tv_usec,
20541+ (long long)swap->msc, (long long)msc,
20542+ (long long)event_id));
20543+ present_event_notify(event_id, swap_ust(swap), swap->msc);
20544+ return Success;
20545+ }
20546+
20547+ list_for_each_entry(tmp, &sna->present.vblank_queue, link) {
20548+ if (tmp->target_msc == msc &&
20549+ unmask_crtc(tmp->crtc) == crtc->devPrivate) {
20550+ uint64_t *events = tmp->event_id;
20551+
20552+ if (is_power_of_two(tmp->n_event_id)) {
20553+ events = malloc(2*sizeof(uint64_t)*tmp->n_event_id);
20554+ if (events == NULL)
20555+ return BadAlloc;
20556+
20557+ memcpy(events,
20558+ tmp->event_id,
20559+ tmp->n_event_id*sizeof(uint64_t));
20560+ if (tmp->n_event_id != 1)
20561+ free(tmp->event_id);
20562+ tmp->event_id = events;
20563+ }
20564+
20565+ DBG(("%s: appending event=%lld to vblank %lld x %d\n",
20566+ __FUNCTION__, (long long)event_id, (long long)msc, tmp->n_event_id+1));
20567+ events[tmp->n_event_id++] = event_id;
20568+ return Success;
20569+ }
20570+ if ((int64_t)(tmp->target_msc - msc) > 0) {
20571+ DBG(("%s: previous target_msc=%lld invalid for coalescing\n",
20572+ __FUNCTION__, (long long)tmp->target_msc));
20573+ break;
20574+ }
20575+ }
20576+
20577+ info = malloc(sizeof(struct sna_present_event) + sizeof(uint64_t));
20578+ if (info == NULL)
20579 return BadAlloc;
20580
20581- event->event_id = event_id;
20582- event->crtc = crtc->devPrivate;
20583+ info->crtc = crtc->devPrivate;
20584+ info->sna = sna;
20585+ info->target_msc = msc;
20586+ info->event_id = (uint64_t *)(info + 1);
20587+ info->event_id[0] = event_id;
20588+ info->n_event_id = 1;
20589+ list_add_tail(&info->link, &tmp->link);
20590
20591 VG_CLEAR(vbl);
20592 vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
20593 vbl.request.sequence = msc;
20594- vbl.request.signal = (uintptr_t)MARK_PRESENT(event);
20595- if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(event->crtc))) {
20596+ vbl.request.signal = (uintptr_t)MARK_PRESENT(info);
20597+ if (sna_wait_vblank(sna, &vbl, sna_crtc_pipe(info->crtc))) {
20598 DBG(("%s: vblank enqueue failed\n", __FUNCTION__));
20599- free(event);
20600- return BadMatch;
20601+ if (!sna_fake_vblank(info)) {
20602+ list_del(&info->link);
20603+ free(info);
20604+ return BadAlloc;
20605+ }
20606+ } else {
20607+ if (msc - swap->msc == 1) {
20608+ sna_crtc_set_vblank(info->crtc);
20609+ info->crtc = mark_crtc(info->crtc);
20610+ }
20611 }
20612
20613 return Success;
20614@@ -180,14 +399,6 @@ sna_present_abort_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
20615 static void
20616 sna_present_flush(WindowPtr window)
20617 {
20618- PixmapPtr pixmap = get_window_pixmap(window);
20619- struct sna_pixmap *priv;
20620-
20621- DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
20622-
20623- priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE);
20624- if (priv && priv->gpu_bo)
20625- kgem_scanout_flush(&to_sna_from_pixmap(pixmap)->kgem, priv->gpu_bo);
20626 }
20627
20628 static bool
20629@@ -201,8 +412,13 @@ check_flip__crtc(struct sna *sna,
20630
20631 assert(sna->scrn->vtSema);
20632
20633- if (sna->mode.shadow_active) {
20634- DBG(("%s: shadow buffer active\n", __FUNCTION__));
20635+ if (!sna->mode.front_active) {
20636+ DBG(("%s: DPMS off, no flips\n", __FUNCTION__));
20637+ return FALSE;
20638+ }
20639+
20640+ if (sna->mode.rr_active) {
20641+ DBG(("%s: RandR transformation active\n", __FUNCTION__));
20642 return false;
20643 }
20644
20645@@ -224,6 +440,11 @@ sna_present_check_flip(RRCrtcPtr crtc,
20646 pixmap->drawable.serialNumber,
20647 sync_flip));
20648
20649+ if (!sna->scrn->vtSema) {
20650+ DBG(("%s: VT switched away, no flips\n", __FUNCTION__));
20651+ return FALSE;
20652+ }
20653+
20654 if (sna->flags & SNA_NO_FLIP) {
20655 DBG(("%s: flips not suported\n", __FUNCTION__));
20656 return FALSE;
20657@@ -231,7 +452,7 @@ sna_present_check_flip(RRCrtcPtr crtc,
20658
20659 if (sync_flip) {
20660 if ((sna->flags & SNA_HAS_FLIP) == 0) {
20661- DBG(("%s: async flips not suported\n", __FUNCTION__));
20662+ DBG(("%s: sync flips not suported\n", __FUNCTION__));
20663 return FALSE;
20664 }
20665 } else {
20666@@ -257,24 +478,33 @@ sna_present_check_flip(RRCrtcPtr crtc,
20667 return FALSE;
20668 }
20669
20670- return TRUE;
20671-}
20672-
20673-static uint64_t gettime_ust64(void)
20674-{
20675- struct timespec tv;
20676-
20677- if (clock_gettime(CLOCK_MONOTONIC, &tv))
20678- return 0;
20679+ if (flip->pinned) {
20680+ assert(flip->gpu_bo);
20681+ if (sna->flags & SNA_LINEAR_FB) {
20682+ if (flip->gpu_bo->tiling != I915_TILING_NONE) {
20683+ DBG(("%s: pined bo, tilng=%d needs NONE\n",
20684+ __FUNCTION__, flip->gpu_bo->tiling));
20685+ return FALSE;
20686+ }
20687+ } else {
20688+ if (!sna->kgem.can_scanout_y &&
20689+ flip->gpu_bo->tiling == I915_TILING_Y) {
20690+ DBG(("%s: pined bo, tilng=%d and can't scanout Y\n",
20691+ __FUNCTION__, flip->gpu_bo->tiling));
20692+ return FALSE;
20693+ }
20694+ }
20695+ }
20696
20697- return ust64(tv.tv_sec, tv.tv_nsec / 1000);
20698+ return TRUE;
20699 }
20700
20701 static Bool
20702-page_flip__async(RRCrtcPtr crtc,
20703- uint64_t event_id,
20704- uint64_t target_msc,
20705- struct kgem_bo *bo)
20706+flip__async(struct sna *sna,
20707+ RRCrtcPtr crtc,
20708+ uint64_t event_id,
20709+ uint64_t target_msc,
20710+ struct kgem_bo *bo)
20711 {
20712 DBG(("%s(pipe=%d, event=%lld, handle=%d)\n",
20713 __FUNCTION__,
20714@@ -282,17 +512,17 @@ page_flip__async(RRCrtcPtr crtc,
20715 (long long)event_id,
20716 bo->handle));
20717
20718- if (!sna_page_flip(to_sna_from_screen(crtc->pScreen), bo, NULL, NULL)) {
20719+ if (!sna_page_flip(sna, bo, NULL, NULL)) {
20720 DBG(("%s: async pageflip failed\n", __FUNCTION__));
20721 present_info.capabilities &= ~PresentCapabilityAsync;
20722 return FALSE;
20723 }
20724
20725- DBG(("%s: pipe=%d tv=%d.%06d msc=%d, event %lld complete\n", __FUNCTION__,
20726+ DBG(("%s: pipe=%d tv=%ld.%06d msc=%lld (target=%lld), event=%lld complete\n", __FUNCTION__,
20727 pipe_from_crtc(crtc),
20728- gettime_ust64() / 1000000, gettime_ust64() % 1000000,
20729- sna_crtc_last_swap(crtc->devPrivate)->msc,
20730- (long long)event_id));
20731+ (long)(gettime_ust64() / 1000000), (int)(gettime_ust64() % 1000000),
20732+ crtc ? (long long)sna_crtc_last_swap(crtc->devPrivate)->msc : 0LL,
20733+ (long long)target_msc, (long long)event_id));
20734 present_event_notify(event_id, gettime_ust64(), target_msc);
20735 return TRUE;
20736 }
20737@@ -303,7 +533,8 @@ present_flip_handler(struct drm_event_vblank *event, void *data)
20738 struct sna_present_event *info = data;
20739 struct ust_msc swap;
20740
20741- DBG(("%s(sequence=%d)\n", __FUNCTION__, event->sequence));
20742+ DBG(("%s(sequence=%d): event=%lld\n", __FUNCTION__, event->sequence, (long long)info->event_id[0]));
20743+ assert(info->n_event_id == 1);
20744
20745 if (info->crtc == NULL) {
20746 swap.tv_sec = event->tv_sec;
20747@@ -312,22 +543,33 @@ present_flip_handler(struct drm_event_vblank *event, void *data)
20748 } else
20749 swap = *sna_crtc_last_swap(info->crtc);
20750
20751- DBG(("%s: pipe=%d, tv=%d.%06d msc %lld, event %lld complete\n", __FUNCTION__,
20752- info->crtc ? sna_crtc_to_pipe(info->crtc) : -1,
20753+ DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld (target %lld), event=%lld complete%s\n", __FUNCTION__,
20754+ info->crtc ? sna_crtc_pipe(info->crtc) : -1,
20755 swap.tv_sec, swap.tv_usec, (long long)swap.msc,
20756- (long long)info->event_id));
20757- present_event_notify(info->event_id, ust64(swap.tv_sec, swap.tv_usec), swap.msc);
20758+ (long long)info->target_msc,
20759+ (long long)info->event_id[0],
20760+ info->target_msc && info->target_msc == swap.msc ? "" : ": MISS"));
20761+ present_event_notify(info->event_id[0], swap_ust(&swap), swap.msc);
20762+ if (info->crtc)
20763+ sna_crtc_clear_vblank(info->crtc);
20764+
20765+ if (info->sna->present.unflip) {
20766+ DBG(("%s: executing queued unflip (event=%lld)\n", __FUNCTION__, (long long)info->sna->present.unflip));
20767+ sna_present_unflip(xf86ScrnToScreen(info->sna->scrn),
20768+ info->sna->present.unflip);
20769+ info->sna->present.unflip = 0;
20770+ }
20771 free(info);
20772 }
20773
20774 static Bool
20775-page_flip(ScreenPtr screen,
20776- RRCrtcPtr crtc,
20777- uint64_t event_id,
20778- struct kgem_bo *bo)
20779+flip(struct sna *sna,
20780+ RRCrtcPtr crtc,
20781+ uint64_t event_id,
20782+ uint64_t target_msc,
20783+ struct kgem_bo *bo)
20784 {
20785- struct sna *sna = to_sna_from_screen(screen);
20786- struct sna_present_event *event;
20787+ struct sna_present_event *info;
20788
20789 DBG(("%s(pipe=%d, event=%lld, handle=%d)\n",
20790 __FUNCTION__,
20791@@ -335,18 +577,25 @@ page_flip(ScreenPtr screen,
20792 (long long)event_id,
20793 bo->handle));
20794
20795- event = malloc(sizeof(struct sna_present_event));
20796- if (event == NULL)
20797+ info = malloc(sizeof(struct sna_present_event)+sizeof(uint64_t));
20798+ if (info == NULL)
20799 return FALSE;
20800
20801- event->event_id = event_id;
20802- event->crtc = crtc ? crtc->devPrivate : NULL;
20803- if (!sna_page_flip(sna, bo, present_flip_handler, event)) {
20804+ info->crtc = crtc ? crtc->devPrivate : NULL;
20805+ info->sna = sna;
20806+ info->event_id = (uint64_t *)(info + 1);
20807+ info->event_id[0] = event_id;
20808+ info->n_event_id = 1;
20809+ info->target_msc = target_msc;
20810+
20811+ if (!sna_page_flip(sna, bo, present_flip_handler, info)) {
20812 DBG(("%s: pageflip failed\n", __FUNCTION__));
20813- free(event);
20814+ free(info);
20815 return FALSE;
20816 }
20817
20818+ if (info->crtc)
20819+ sna_crtc_set_vblank(info->crtc);
20820 return TRUE;
20821 }
20822
20823@@ -358,12 +607,48 @@ get_flip_bo(PixmapPtr pixmap)
20824
20825 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
20826
20827- priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | __MOVE_FORCE);
20828+ priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | __MOVE_SCANOUT | __MOVE_FORCE);
20829 if (priv == NULL) {
20830 DBG(("%s: cannot force pixmap to the GPU\n", __FUNCTION__));
20831 return NULL;
20832 }
20833
20834+ if (priv->gpu_bo->scanout)
20835+ return priv->gpu_bo;
20836+
20837+ if (sna->kgem.has_llc && !wedged(sna) && !priv->pinned) {
20838+ struct kgem_bo *bo;
20839+ uint32_t tiling;
20840+
20841+ tiling = I915_TILING_NONE;
20842+ if ((sna->flags & SNA_LINEAR_FB) == 0)
20843+ tiling = I915_TILING_X;
20844+
20845+ bo = kgem_create_2d(&sna->kgem,
20846+ pixmap->drawable.width,
20847+ pixmap->drawable.height,
20848+ pixmap->drawable.bitsPerPixel,
20849+ tiling, CREATE_SCANOUT | CREATE_CACHED);
20850+ if (bo) {
20851+ BoxRec box;
20852+
20853+ box.x1 = box.y1 = 0;
20854+ box.x2 = pixmap->drawable.width;
20855+ box.y2 = pixmap->drawable.height;
20856+
20857+ if (sna->render.copy_boxes(sna, GXcopy,
20858+ &pixmap->drawable, priv->gpu_bo, 0, 0,
20859+ &pixmap->drawable, bo, 0, 0,
20860+ &box, 1, 0)) {
20861+ sna_pixmap_unmap(pixmap, priv);
20862+ kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
20863+
20864+ priv->gpu_bo = bo;
20865+ } else
20866+ kgem_bo_destroy(&sna->kgem, bo);
20867+ }
20868+ }
20869+
20870 if (sna->flags & SNA_LINEAR_FB &&
20871 priv->gpu_bo->tiling &&
20872 !sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) {
20873@@ -372,12 +657,12 @@ get_flip_bo(PixmapPtr pixmap)
20874 }
20875
20876 if (priv->gpu_bo->tiling == I915_TILING_Y &&
20877+ !sna->kgem.can_scanout_y &&
20878 !sna_pixmap_change_tiling(pixmap, I915_TILING_X)) {
20879 DBG(("%s: invalid Y-tiling, cannot convert\n", __FUNCTION__));
20880 return NULL;
20881 }
20882
20883- priv->pinned |= PIN_SCANOUT;
20884 return priv->gpu_bo;
20885 }
20886
20887@@ -388,6 +673,7 @@ sna_present_flip(RRCrtcPtr crtc,
20888 PixmapPtr pixmap,
20889 Bool sync_flip)
20890 {
20891+ struct sna *sna = to_sna_from_pixmap(pixmap);
20892 struct kgem_bo *bo;
20893
20894 DBG(("%s(pipe=%d, event=%lld, msc=%lld, pixmap=%ld, sync?=%d)\n",
20895@@ -397,11 +683,34 @@ sna_present_flip(RRCrtcPtr crtc,
20896 (long long)target_msc,
20897 pixmap->drawable.serialNumber, sync_flip));
20898
20899- if (!check_flip__crtc(to_sna_from_pixmap(pixmap), crtc)) {
20900+ if (!check_flip__crtc(sna, crtc)) {
20901 DBG(("%s: flip invalid for CRTC\n", __FUNCTION__));
20902 return FALSE;
20903 }
20904
20905+ assert(sna->present.unflip == 0);
20906+
20907+ if (sna->flags & SNA_TEAR_FREE) {
20908+ DBG(("%s: disabling TearFree (was %s) in favour of Present flips\n",
20909+ __FUNCTION__, sna->mode.shadow_enabled ? "enabled" : "disabled"));
20910+ sna->mode.shadow_enabled = false;
20911+ }
20912+ assert(!sna->mode.shadow_enabled);
20913+
20914+ if (sna->mode.flip_active) {
20915+ struct pollfd pfd;
20916+
20917+ DBG(("%s: flips still pending, stalling\n", __FUNCTION__));
20918+ pfd.fd = sna->kgem.fd;
20919+ pfd.events = POLLIN;
20920+ do {
20921+ if (poll(&pfd, 1, -1) != 1)
20922+ return FALSE;
20923+
20924+ sna_mode_wakeup(sna);
20925+ } while (sna->mode.flip_active);
20926+ }
20927+
20928 bo = get_flip_bo(pixmap);
20929 if (bo == NULL) {
20930 DBG(("%s: flip invalid bo\n", __FUNCTION__));
20931@@ -409,9 +718,9 @@ sna_present_flip(RRCrtcPtr crtc,
20932 }
20933
20934 if (sync_flip)
20935- return page_flip(crtc->pScreen, crtc, event_id, bo);
20936+ return flip(sna, crtc, event_id, target_msc, bo);
20937 else
20938- return page_flip__async(crtc, event_id, target_msc, bo);
20939+ return flip__async(sna, crtc, event_id, target_msc, bo);
20940 }
20941
20942 static void
20943@@ -421,29 +730,53 @@ sna_present_unflip(ScreenPtr screen, uint64_t event_id)
20944 struct kgem_bo *bo;
20945
20946 DBG(("%s(event=%lld)\n", __FUNCTION__, (long long)event_id));
20947- if (sna->mode.front_active == 0 || sna->mode.shadow_active) {
20948+ if (sna->mode.front_active == 0 || sna->mode.rr_active) {
20949 const struct ust_msc *swap;
20950
20951 DBG(("%s: no CRTC active, perform no-op flip\n", __FUNCTION__));
20952
20953 notify:
20954- swap = sna_crtc_last_swap(sna_mode_first_crtc(sna));
20955- DBG(("%s: pipe=%d, tv=%d.%06d msc %lld, event %lld complete\n", __FUNCTION__,
20956+ swap = sna_crtc_last_swap(sna_primary_crtc(sna));
20957+ DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld, event=%lld complete\n", __FUNCTION__,
20958 -1,
20959 swap->tv_sec, swap->tv_usec, (long long)swap->msc,
20960 (long long)event_id));
20961- present_event_notify(event_id,
20962- ust64(swap->tv_sec, swap->tv_usec),
20963- swap->msc);
20964+ present_event_notify(event_id, swap_ust(swap), swap->msc);
20965 return;
20966 }
20967
20968+ assert(!sna->mode.shadow_enabled);
20969+ if (sna->mode.flip_active) {
20970+ DBG(("%s: %d outstanding flips, queueing unflip\n", __FUNCTION__, sna->mode.flip_active));
20971+ assert(sna->present.unflip == 0);
20972+ sna->present.unflip = event_id;
20973+ return;
20974+ }
20975+
20976+ if (sna->flags & SNA_TEAR_FREE) {
20977+ DBG(("%s: %s TearFree after Present flips\n",
20978+ __FUNCTION__, sna->mode.shadow_damage != NULL ? "enabling" : "disabling"));
20979+ sna->mode.shadow_enabled = sna->mode.shadow_damage != NULL;
20980+ }
20981+
20982 bo = get_flip_bo(screen->GetScreenPixmap(screen));
20983- if (bo == NULL || !page_flip(screen, NULL, event_id, bo)) {
20984+ if (bo == NULL) {
20985+reset_mode:
20986 DBG(("%s: failed, trying to restore original mode\n", __FUNCTION__));
20987 xf86SetDesiredModes(sna->scrn);
20988 goto notify;
20989 }
20990+
20991+ assert(sna_pixmap(screen->GetScreenPixmap(screen))->pinned & PIN_SCANOUT);
20992+
20993+ if (sna->flags & SNA_HAS_ASYNC_FLIP) {
20994+ DBG(("%s: trying async flip restore\n", __FUNCTION__));
20995+ if (flip__async(sna, NULL, event_id, 0, bo))
20996+ return;
20997+ }
20998+
20999+ if (!flip(sna, NULL, event_id, 0, bo))
21000+ goto reset_mode;
21001 }
21002
21003 static present_screen_info_rec present_info = {
21004@@ -463,10 +796,13 @@ static present_screen_info_rec present_info = {
21005
21006 bool sna_present_open(struct sna *sna, ScreenPtr screen)
21007 {
21008+ DBG(("%s(num_crtc=%d)\n", __FUNCTION__, sna->mode.num_real_crtc));
21009+
21010 if (sna->mode.num_real_crtc == 0)
21011 return false;
21012
21013 sna_present_update(sna);
21014+ list_init(&sna->present.vblank_queue);
21015
21016 return present_screen_init(screen, &present_info);
21017 }
21018diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
21019index 3fbb9ec..d8b7756 100644
21020--- a/src/sna/sna_render.c
21021+++ b/src/sna/sna_render.c
21022@@ -54,7 +54,7 @@ sna_format_for_depth(int depth)
21023 {
21024 switch (depth) {
21025 case 1: return PICT_a1;
21026- case 4: return PICT_a4;
21027+ case 4: return PICT_x4a4;
21028 case 8: return PICT_a8;
21029 case 15: return PICT_x1r5g5b5;
21030 case 16: return PICT_r5g6b5;
21031@@ -272,18 +272,6 @@ no_render_context_switch(struct kgem *kgem,
21032 }
21033
21034 static void
21035-no_render_retire(struct kgem *kgem)
21036-{
21037- (void)kgem;
21038-}
21039-
21040-static void
21041-no_render_expire(struct kgem *kgem)
21042-{
21043- (void)kgem;
21044-}
21045-
21046-static void
21047 no_render_fini(struct sna *sna)
21048 {
21049 (void)sna;
21050@@ -316,8 +304,6 @@ const char *no_render_init(struct sna *sna)
21051 render->fini = no_render_fini;
21052
21053 sna->kgem.context_switch = no_render_context_switch;
21054- sna->kgem.retire = no_render_retire;
21055- sna->kgem.expire = no_render_expire;
21056 if (sna->kgem.has_blt)
21057 sna->kgem.ring = KGEM_BLT;
21058
21059@@ -567,6 +553,7 @@ static struct kgem_bo *upload(struct sna *sna,
21060 assert(priv->gpu_damage == NULL);
21061 assert(priv->gpu_bo == NULL);
21062 assert(bo->proxy != NULL);
21063+ sna_damage_all(&priv->cpu_damage, pixmap);
21064 kgem_proxy_bo_attach(bo, &priv->gpu_bo);
21065 }
21066 }
21067@@ -1275,6 +1262,7 @@ sna_render_picture_extract(struct sna *sna,
21068 assert(priv->gpu_damage == NULL);
21069 assert(priv->gpu_bo == NULL);
21070 assert(bo->proxy != NULL);
21071+ sna_damage_all(&priv->cpu_damage, pixmap);
21072 kgem_proxy_bo_attach(bo, &priv->gpu_bo);
21073 }
21074 }
21075@@ -2183,11 +2171,11 @@ copy_overlap(struct sna *sna, uint8_t alu,
21076 ret = (sna->render.copy_boxes(sna, GXcopy,
21077 draw, bo, src_dx, src_dy,
21078 &tmp->drawable, tmp_bo, -extents->x1, -extents->y1,
21079- box, n , 0) &&
21080+ box, n, 0) &&
21081 sna->render.copy_boxes(sna, alu,
21082 &tmp->drawable, tmp_bo, -extents->x1, -extents->y1,
21083 draw, bo, dst_dx, dst_dy,
21084- box, n , 0));
21085+ box, n, 0));
21086
21087 screen->DestroyPixmap(tmp);
21088 return ret;
21089@@ -2336,6 +2324,9 @@ memcpy_copy_boxes(struct sna *sna, uint8_t op,
21090 if (op != GXcopy)
21091 return false;
21092
21093+ if (src_draw->depth != dst_draw->depth)
21094+ return false;
21095+
21096 clipped = (n > 1 ||
21097 box->x1 + dx > 0 ||
21098 box->y1 + dy > 0 ||
21099@@ -2380,4 +2371,5 @@ void
21100 sna_render_mark_wedged(struct sna *sna)
21101 {
21102 sna->render.copy_boxes = memcpy_copy_boxes;
21103+ sna->render.prefer_gpu = 0;
21104 }
21105diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h
21106index 6e1fa48..1baf945 100644
21107--- a/src/sna/sna_render.h
21108+++ b/src/sna/sna_render.h
21109@@ -238,8 +238,9 @@ struct sna_render {
21110 int16_t w, int16_t h,
21111 unsigned flags,
21112 struct sna_composite_op *tmp);
21113-#define COMPOSITE_PARTIAL 0x1
21114-#define COMPOSITE_FALLBACK 0x80000000
21115+#define COMPOSITE_PARTIAL 0x1
21116+#define COMPOSITE_UPLOAD 0x40000000
21117+#define COMPOSITE_FALLBACK 0x80000000
21118
21119 bool (*check_composite_spans)(struct sna *sna, uint8_t op,
21120 PicturePtr dst, PicturePtr src,
21121@@ -286,6 +287,8 @@ struct sna_render {
21122 #define COPY_LAST 0x1
21123 #define COPY_SYNC 0x2
21124 #define COPY_NO_OVERLAP 0x4
21125+#define COPY_SMALL 0x8
21126+#define COPY_DRI 0x10
21127
21128 bool (*copy)(struct sna *sna, uint8_t alu,
21129 PixmapPtr src, struct kgem_bo *src_bo,
21130@@ -538,7 +541,7 @@ enum {
21131
21132 struct gen8_render_state {
21133 unsigned gt;
21134-
21135+ const struct gt_info *info;
21136 struct kgem_bo *general_bo;
21137
21138 uint32_t vs_state;
21139diff --git a/src/sna/sna_render_inline.h b/src/sna/sna_render_inline.h
21140index 10fbbfe..e162e37 100644
21141--- a/src/sna/sna_render_inline.h
21142+++ b/src/sna/sna_render_inline.h
21143@@ -304,6 +304,12 @@ color_convert(uint32_t pixel,
21144 return pixel;
21145 }
21146
21147+inline static uint32_t
21148+solid_color(uint32_t format, uint32_t pixel)
21149+{
21150+ return color_convert(pixel, format, PICT_a8r8g8b8);
21151+}
21152+
21153 inline static bool dst_use_gpu(PixmapPtr pixmap)
21154 {
21155 struct sna_pixmap *priv = sna_pixmap(pixmap);
21156diff --git a/src/sna/sna_tiling.c b/src/sna/sna_tiling.c
21157index 308efc0..8e2627f 100644
21158--- a/src/sna/sna_tiling.c
21159+++ b/src/sna/sna_tiling.c
21160@@ -369,8 +369,7 @@ sna_tiling_composite_spans_boxes(struct sna *sna,
21161 const BoxRec *box, int nbox, float opacity)
21162 {
21163 while (nbox--)
21164- sna_tiling_composite_spans_box(sna, op->base.priv, box++, opacity);
21165- (void)sna;
21166+ sna_tiling_composite_spans_box(sna, op, box++, opacity);
21167 }
21168
21169 fastcall static void
21170@@ -581,6 +580,7 @@ sna_tiling_composite_spans(uint32_t op,
21171 tile->rects = tile->rects_embedded;
21172 tile->rect_count = 0;
21173 tile->rect_size = ARRAY_SIZE(tile->rects_embedded);
21174+ COMPILE_TIME_ASSERT(sizeof(tile->rects_embedded[0]) >= sizeof(struct sna_tile_span));
21175
21176 tmp->box = sna_tiling_composite_spans_box;
21177 tmp->boxes = sna_tiling_composite_spans_boxes;
21178diff --git a/src/sna/sna_trapezoids_boxes.c b/src/sna/sna_trapezoids_boxes.c
21179index 9900e3f..bbf8375 100644
21180--- a/src/sna/sna_trapezoids_boxes.c
21181+++ b/src/sna/sna_trapezoids_boxes.c
21182@@ -198,7 +198,7 @@ composite_aligned_boxes(struct sna *sna,
21183 if (op == PictOpClear && sna->clear)
21184 src = sna->clear;
21185
21186- DBG(("%s: clipped extents (%d, %d), (%d, %d); now offset by (%d, %d), orgin (%d, %d)\n",
21187+ DBG(("%s: clipped extents (%d, %d), (%d, %d); now offset by (%d, %d), origin (%d, %d)\n",
21188 __FUNCTION__,
21189 clip.extents.x1, clip.extents.y1,
21190 clip.extents.x2, clip.extents.y2,
21191@@ -592,6 +592,8 @@ lerp32_opacity(PixmapPtr scratch,
21192 uint32_t *ptr;
21193 int stride, i;
21194
21195+ sigtrap_assert_active();
21196+
21197 ptr = (uint32_t*)((uint8_t *)scratch->devPrivate.ptr + scratch->devKind * y);
21198 ptr += x;
21199 stride = scratch->devKind / 4;
21200diff --git a/src/sna/sna_trapezoids_imprecise.c b/src/sna/sna_trapezoids_imprecise.c
21201index 37def2f..8bc7c8a 100644
21202--- a/src/sna/sna_trapezoids_imprecise.c
21203+++ b/src/sna/sna_trapezoids_imprecise.c
21204@@ -962,6 +962,16 @@ tor_add_trapezoid(struct tor *tor,
21205 const xTrapezoid *t,
21206 int dx, int dy)
21207 {
21208+ if (!xTrapezoidValid(t)) {
21209+ __DBG(("%s: skipping invalid trapezoid: top=%d, bottom=%d, left=(%d, %d), (%d, %d), right=(%d, %d), (%d, %d)\n",
21210+ __FUNCTION__,
21211+ t->top, t->bottom,
21212+ t->left.p1.x, t->left.p1.y,
21213+ t->left.p2.x, t->left.p2.y,
21214+ t->right.p1.x, t->right.p1.y,
21215+ t->right.p2.x, t->right.p2.y));
21216+ return;
21217+ }
21218 polygon_add_edge(tor->polygon, t, &t->left, 1, dx, dy);
21219 polygon_add_edge(tor->polygon, t, &t->right, -1, dx, dy);
21220 }
21221@@ -1687,31 +1697,27 @@ struct span_thread {
21222 #define SPAN_THREAD_MAX_BOXES (8192/sizeof(struct sna_opacity_box))
21223 struct span_thread_boxes {
21224 const struct sna_composite_spans_op *op;
21225+ const BoxRec *clip_start, *clip_end;
21226 int num_boxes;
21227 struct sna_opacity_box boxes[SPAN_THREAD_MAX_BOXES];
21228 };
21229
21230-static void span_thread_add_boxes(struct sna *sna, void *data,
21231- const BoxRec *box, int count, float alpha)
21232+static void span_thread_add_box(struct sna *sna, void *data,
21233+ const BoxRec *box, float alpha)
21234 {
21235 struct span_thread_boxes *b = data;
21236
21237- __DBG(("%s: adding %d boxes with alpha=%f\n",
21238- __FUNCTION__, count, alpha));
21239+ __DBG(("%s: adding box with alpha=%f\n", __FUNCTION__, alpha));
21240
21241- assert(count > 0 && count <= SPAN_THREAD_MAX_BOXES);
21242- if (unlikely(b->num_boxes + count > SPAN_THREAD_MAX_BOXES)) {
21243- DBG(("%s: flushing %d boxes, adding %d\n", __FUNCTION__, b->num_boxes, count));
21244- assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES);
21245+ if (unlikely(b->num_boxes == SPAN_THREAD_MAX_BOXES)) {
21246+ DBG(("%s: flushing %d boxes\n", __FUNCTION__, b->num_boxes));
21247 b->op->thread_boxes(sna, b->op, b->boxes, b->num_boxes);
21248 b->num_boxes = 0;
21249 }
21250
21251- do {
21252- b->boxes[b->num_boxes].box = *box++;
21253- b->boxes[b->num_boxes].alpha = alpha;
21254- b->num_boxes++;
21255- } while (--count);
21256+ b->boxes[b->num_boxes].box = *box++;
21257+ b->boxes[b->num_boxes].alpha = alpha;
21258+ b->num_boxes++;
21259 assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES);
21260 }
21261
21262@@ -1722,8 +1728,22 @@ span_thread_box(struct sna *sna,
21263 const BoxRec *box,
21264 int coverage)
21265 {
21266+ struct span_thread_boxes *b = (struct span_thread_boxes *)op;
21267+
21268 __DBG(("%s: %d -> %d @ %d\n", __FUNCTION__, box->x1, box->x2, coverage));
21269- span_thread_add_boxes(sna, op, box, 1, AREA_TO_ALPHA(coverage));
21270+ if (b->num_boxes) {
21271+ struct sna_opacity_box *bb = &b->boxes[b->num_boxes-1];
21272+ if (bb->box.x1 == box->x1 &&
21273+ bb->box.x2 == box->x2 &&
21274+ bb->box.y2 == box->y1 &&
21275+ bb->alpha == AREA_TO_ALPHA(coverage)) {
21276+ bb->box.y2 = box->y2;
21277+ __DBG(("%s: contracted double row: %d -> %d\n", __func__, bb->box.y1, bb->box.y2));
21278+ return;
21279+ }
21280+ }
21281+
21282+ span_thread_add_box(sna, op, box, AREA_TO_ALPHA(coverage));
21283 }
21284
21285 static void
21286@@ -1733,20 +1753,28 @@ span_thread_clipped_box(struct sna *sna,
21287 const BoxRec *box,
21288 int coverage)
21289 {
21290- pixman_region16_t region;
21291+ struct span_thread_boxes *b = (struct span_thread_boxes *)op;
21292+ const BoxRec *c;
21293
21294 __DBG(("%s: %d -> %d @ %f\n", __FUNCTION__, box->x1, box->x2,
21295 AREA_TO_ALPHA(coverage)));
21296
21297- pixman_region_init_rects(&region, box, 1);
21298- RegionIntersect(&region, &region, clip);
21299- if (region_num_rects(&region)) {
21300- span_thread_add_boxes(sna, op,
21301- region_rects(&region),
21302- region_num_rects(&region),
21303- AREA_TO_ALPHA(coverage));
21304+ b->clip_start =
21305+ find_clip_box_for_y(b->clip_start, b->clip_end, box->y1);
21306+
21307+ c = b->clip_start;
21308+ while (c != b->clip_end) {
21309+ BoxRec clipped;
21310+
21311+ if (box->y2 <= c->y1)
21312+ break;
21313+
21314+ clipped = *box;
21315+ if (!box_intersect(&clipped, c++))
21316+ continue;
21317+
21318+ span_thread_add_box(sna, op, &clipped, AREA_TO_ALPHA(coverage));
21319 }
21320- pixman_region_fini(&region);
21321 }
21322
21323 static span_func_t
21324@@ -1777,6 +1805,16 @@ thread_choose_span(struct sna_composite_spans_op *tmp,
21325 return span;
21326 }
21327
21328+inline static void
21329+span_thread_boxes_init(struct span_thread_boxes *boxes,
21330+ const struct sna_composite_spans_op *op,
21331+ const RegionRec *clip)
21332+{
21333+ boxes->op = op;
21334+ region_get_boxes(clip, &boxes->clip_start, &boxes->clip_end);
21335+ boxes->num_boxes = 0;
21336+}
21337+
21338 static void
21339 span_thread(void *arg)
21340 {
21341@@ -1789,8 +1827,7 @@ span_thread(void *arg)
21342 if (!tor_init(&tor, &thread->extents, 2*thread->ntrap))
21343 return;
21344
21345- boxes.op = thread->op;
21346- boxes.num_boxes = 0;
21347+ span_thread_boxes_init(&boxes, thread->op, thread->clip);
21348
21349 y1 = thread->extents.y1 - thread->draw_y;
21350 y2 = thread->extents.y2 - thread->draw_y;
21351@@ -2190,6 +2227,52 @@ static void _tor_blt_src(struct inplace *in, const BoxRec *box, uint8_t v)
21352 } while (--h);
21353 }
21354
21355+struct clipped_span {
21356+ span_func_t span;
21357+ const BoxRec *clip_start, *clip_end;
21358+};
21359+
21360+static void
21361+tor_blt_clipped(struct sna *sna,
21362+ struct sna_composite_spans_op *op,
21363+ pixman_region16_t *clip,
21364+ const BoxRec *box,
21365+ int coverage)
21366+{
21367+ struct clipped_span *cs = (struct clipped_span *)clip;
21368+ const BoxRec *c;
21369+
21370+ cs->clip_start =
21371+ find_clip_box_for_y(cs->clip_start, cs->clip_end, box->y1);
21372+
21373+ c = cs->clip_start;
21374+ while (c != cs->clip_end) {
21375+ BoxRec clipped;
21376+
21377+ if (box->y2 <= c->y1)
21378+ break;
21379+
21380+ clipped = *box;
21381+ if (!box_intersect(&clipped, c++))
21382+ continue;
21383+
21384+ cs->span(sna, op, NULL, &clipped, coverage);
21385+ }
21386+}
21387+
21388+inline static span_func_t
21389+clipped_span(struct clipped_span *cs,
21390+ span_func_t span,
21391+ const RegionRec *clip)
21392+{
21393+ if (clip->data) {
21394+ cs->span = span;
21395+ region_get_boxes(clip, &cs->clip_start, &cs->clip_end);
21396+ span = tor_blt_clipped;
21397+ }
21398+ return span;
21399+}
21400+
21401 static void
21402 tor_blt_src(struct sna *sna,
21403 struct sna_composite_spans_op *op,
21404@@ -2203,25 +2286,6 @@ tor_blt_src(struct sna *sna,
21405 }
21406
21407 static void
21408-tor_blt_src_clipped(struct sna *sna,
21409- struct sna_composite_spans_op *op,
21410- pixman_region16_t *clip,
21411- const BoxRec *box,
21412- int coverage)
21413-{
21414- pixman_region16_t region;
21415- int n;
21416-
21417- pixman_region_init_rects(&region, box, 1);
21418- RegionIntersect(&region, &region, clip);
21419- n = region_num_rects(&region);
21420- box = region_rects(&region);
21421- while (n--)
21422- tor_blt_src(sna, op, NULL, box++, coverage);
21423- pixman_region_fini(&region);
21424-}
21425-
21426-static void
21427 tor_blt_in(struct sna *sna,
21428 struct sna_composite_spans_op *op,
21429 pixman_region16_t *clip,
21430@@ -2253,25 +2317,6 @@ tor_blt_in(struct sna *sna,
21431 }
21432
21433 static void
21434-tor_blt_in_clipped(struct sna *sna,
21435- struct sna_composite_spans_op *op,
21436- pixman_region16_t *clip,
21437- const BoxRec *box,
21438- int coverage)
21439-{
21440- pixman_region16_t region;
21441- int n;
21442-
21443- pixman_region_init_rects(&region, box, 1);
21444- RegionIntersect(&region, &region, clip);
21445- n = region_num_rects(&region);
21446- box = region_rects(&region);
21447- while (n--)
21448- tor_blt_in(sna, op, NULL, box++, coverage);
21449- pixman_region_fini(&region);
21450-}
21451-
21452-static void
21453 tor_blt_add(struct sna *sna,
21454 struct sna_composite_spans_op *op,
21455 pixman_region16_t *clip,
21456@@ -2310,25 +2355,6 @@ tor_blt_add(struct sna *sna,
21457 }
21458
21459 static void
21460-tor_blt_add_clipped(struct sna *sna,
21461- struct sna_composite_spans_op *op,
21462- pixman_region16_t *clip,
21463- const BoxRec *box,
21464- int coverage)
21465-{
21466- pixman_region16_t region;
21467- int n;
21468-
21469- pixman_region_init_rects(&region, box, 1);
21470- RegionIntersect(&region, &region, clip);
21471- n = region_num_rects(&region);
21472- box = region_rects(&region);
21473- while (n--)
21474- tor_blt_add(sna, op, NULL, box++, coverage);
21475- pixman_region_fini(&region);
21476-}
21477-
21478-static void
21479 tor_blt_lerp32(struct sna *sna,
21480 struct sna_composite_spans_op *op,
21481 pixman_region16_t *clip,
21482@@ -2343,6 +2369,7 @@ tor_blt_lerp32(struct sna *sna,
21483 if (coverage == 0)
21484 return;
21485
21486+ sigtrap_assert_active();
21487 ptr += box->y1 * stride + box->x1;
21488
21489 h = box->y2 - box->y1;
21490@@ -2383,25 +2410,6 @@ tor_blt_lerp32(struct sna *sna,
21491 }
21492 }
21493
21494-static void
21495-tor_blt_lerp32_clipped(struct sna *sna,
21496- struct sna_composite_spans_op *op,
21497- pixman_region16_t *clip,
21498- const BoxRec *box,
21499- int coverage)
21500-{
21501- pixman_region16_t region;
21502- int n;
21503-
21504- pixman_region_init_rects(&region, box, 1);
21505- RegionIntersect(&region, &region, clip);
21506- n = region_num_rects(&region);
21507- box = region_rects(&region);
21508- while (n--)
21509- tor_blt_lerp32(sna, op, NULL, box++, coverage);
21510- pixman_region_fini(&region);
21511-}
21512-
21513 struct pixman_inplace {
21514 pixman_image_t *image, *source, *mask;
21515 uint32_t color;
21516@@ -2431,24 +2439,6 @@ pixmask_span_solid(struct sna *sna,
21517 pi->dx + box->x1, pi->dy + box->y1,
21518 box->x2 - box->x1, box->y2 - box->y1);
21519 }
21520-static void
21521-pixmask_span_solid__clipped(struct sna *sna,
21522- struct sna_composite_spans_op *op,
21523- pixman_region16_t *clip,
21524- const BoxRec *box,
21525- int coverage)
21526-{
21527- pixman_region16_t region;
21528- int n;
21529-
21530- pixman_region_init_rects(&region, box, 1);
21531- RegionIntersect(&region, &region, clip);
21532- n = region_num_rects(&region);
21533- box = region_rects(&region);
21534- while (n--)
21535- pixmask_span_solid(sna, op, NULL, box++, coverage);
21536- pixman_region_fini(&region);
21537-}
21538
21539 static void
21540 pixmask_span(struct sna *sna,
21541@@ -2471,24 +2461,6 @@ pixmask_span(struct sna *sna,
21542 pi->dx + box->x1, pi->dy + box->y1,
21543 box->x2 - box->x1, box->y2 - box->y1);
21544 }
21545-static void
21546-pixmask_span__clipped(struct sna *sna,
21547- struct sna_composite_spans_op *op,
21548- pixman_region16_t *clip,
21549- const BoxRec *box,
21550- int coverage)
21551-{
21552- pixman_region16_t region;
21553- int n;
21554-
21555- pixman_region_init_rects(&region, box, 1);
21556- RegionIntersect(&region, &region, clip);
21557- n = region_num_rects(&region);
21558- box = region_rects(&region);
21559- while (n--)
21560- pixmask_span(sna, op, NULL, box++, coverage);
21561- pixman_region_fini(&region);
21562-}
21563
21564 struct inplace_x8r8g8b8_thread {
21565 xTrapezoid *traps;
21566@@ -2507,6 +2479,7 @@ static void inplace_x8r8g8b8_thread(void *arg)
21567 struct inplace_x8r8g8b8_thread *thread = arg;
21568 struct tor tor;
21569 span_func_t span;
21570+ struct clipped_span clipped;
21571 RegionPtr clip;
21572 int y1, y2, n;
21573
21574@@ -2537,12 +2510,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
21575 inplace.stride = pixmap->devKind;
21576 inplace.color = thread->color;
21577
21578- if (clip->data)
21579- span = tor_blt_lerp32_clipped;
21580- else
21581- span = tor_blt_lerp32;
21582+ span = clipped_span(&clipped, tor_blt_lerp32, clip);
21583
21584- tor_render(NULL, &tor, (void*)&inplace, clip, span, false);
21585+ tor_render(NULL, &tor,
21586+ (void*)&inplace, (void*)&clipped,
21587+ span, false);
21588 } else if (thread->is_solid) {
21589 struct pixman_inplace pi;
21590
21591@@ -2555,12 +2527,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
21592 1, 1, pi.bits, 0);
21593 pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
21594
21595- if (clip->data)
21596- span = pixmask_span_solid__clipped;
21597- else
21598- span = pixmask_span_solid;
21599+ span = clipped_span(&clipped, pixmask_span_solid, clip);
21600
21601- tor_render(NULL, &tor, (void*)&pi, clip, span, false);
21602+ tor_render(NULL, &tor,
21603+ (void*)&pi, (void *)&clipped,
21604+ span, false);
21605
21606 pixman_image_unref(pi.source);
21607 pixman_image_unref(pi.image);
21608@@ -2579,12 +2550,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
21609 pi.bits = pixman_image_get_data(pi.mask);
21610 pi.op = thread->op;
21611
21612- if (clip->data)
21613- span = pixmask_span__clipped;
21614- else
21615- span = pixmask_span;
21616+ span = clipped_span(&clipped, pixmask_span, clip);
21617
21618- tor_render(NULL, &tor, (void*)&pi, clip, span, false);
21619+ tor_render(NULL, &tor,
21620+ (void*)&pi, (void *)&clipped,
21621+ span, false);
21622
21623 pixman_image_unref(pi.mask);
21624 pixman_image_unref(pi.source);
21625@@ -2698,6 +2668,7 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
21626 if (num_threads == 1) {
21627 struct tor tor;
21628 span_func_t span;
21629+ struct clipped_span clipped;
21630
21631 if (!tor_init(&tor, &region.extents, 2*ntrap))
21632 return true;
21633@@ -2723,17 +2694,15 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
21634 inplace.stride = pixmap->devKind;
21635 inplace.color = color;
21636
21637- if (dst->pCompositeClip->data)
21638- span = tor_blt_lerp32_clipped;
21639- else
21640- span = tor_blt_lerp32;
21641+ span = clipped_span(&clipped, tor_blt_lerp32, dst->pCompositeClip);
21642
21643 DBG(("%s: render inplace op=%d, color=%08x\n",
21644 __FUNCTION__, op, color));
21645
21646 if (sigtrap_get() == 0) {
21647- tor_render(NULL, &tor, (void*)&inplace,
21648- dst->pCompositeClip, span, false);
21649+ tor_render(NULL, &tor,
21650+ (void*)&inplace, (void*)&clipped,
21651+ span, false);
21652 sigtrap_put();
21653 }
21654 } else if (is_solid) {
21655@@ -2748,15 +2717,12 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
21656 1, 1, pi.bits, 0);
21657 pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
21658
21659- if (dst->pCompositeClip->data)
21660- span = pixmask_span_solid__clipped;
21661- else
21662- span = pixmask_span_solid;
21663+ span = clipped_span(&clipped, pixmask_span_solid, dst->pCompositeClip);
21664
21665 if (sigtrap_get() == 0) {
21666- tor_render(NULL, &tor, (void*)&pi,
21667- dst->pCompositeClip, span,
21668- false);
21669+ tor_render(NULL, &tor,
21670+ (void*)&pi, (void*)&clipped,
21671+ span, false);
21672 sigtrap_put();
21673 }
21674
21675@@ -2777,15 +2743,12 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
21676 pi.bits = pixman_image_get_data(pi.mask);
21677 pi.op = op;
21678
21679- if (dst->pCompositeClip->data)
21680- span = pixmask_span__clipped;
21681- else
21682- span = pixmask_span;
21683+ span = clipped_span(&clipped, pixmask_span, dst->pCompositeClip);
21684
21685 if (sigtrap_get() == 0) {
21686- tor_render(NULL, &tor, (void*)&pi,
21687- dst->pCompositeClip, span,
21688- false);
21689+ tor_render(NULL, &tor,
21690+ (void*)&pi, (void*)&clipped,
21691+ span, false);
21692 sigtrap_put();
21693 }
21694
21695@@ -2847,9 +2810,9 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
21696
21697 struct inplace_thread {
21698 xTrapezoid *traps;
21699- RegionPtr clip;
21700 span_func_t span;
21701 struct inplace inplace;
21702+ struct clipped_span clipped;
21703 BoxRec extents;
21704 int dx, dy;
21705 int draw_x, draw_y;
21706@@ -2874,8 +2837,9 @@ static void inplace_thread(void *arg)
21707 tor_add_trapezoid(&tor, &thread->traps[n], thread->dx, thread->dy);
21708 }
21709
21710- tor_render(NULL, &tor, (void*)&thread->inplace,
21711- thread->clip, thread->span, thread->unbounded);
21712+ tor_render(NULL, &tor,
21713+ (void*)&thread->inplace, (void*)&thread->clipped,
21714+ thread->span, thread->unbounded);
21715
21716 tor_fini(&tor);
21717 }
21718@@ -2889,6 +2853,7 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
21719 bool fallback)
21720 {
21721 struct inplace inplace;
21722+ struct clipped_span clipped;
21723 span_func_t span;
21724 PixmapPtr pixmap;
21725 struct sna_pixmap *priv;
21726@@ -3005,21 +2970,12 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
21727 region.extents.x2, region.extents.y2));
21728
21729 if (op == PictOpSrc) {
21730- if (dst->pCompositeClip->data)
21731- span = tor_blt_src_clipped;
21732- else
21733- span = tor_blt_src;
21734+ span = tor_blt_src;
21735 } else if (op == PictOpIn) {
21736- if (dst->pCompositeClip->data)
21737- span = tor_blt_in_clipped;
21738- else
21739- span = tor_blt_in;
21740+ span = tor_blt_in;
21741 } else {
21742 assert(op == PictOpAdd);
21743- if (dst->pCompositeClip->data)
21744- span = tor_blt_add_clipped;
21745- else
21746- span = tor_blt_add;
21747+ span = tor_blt_add;
21748 }
21749
21750 DBG(("%s: move-to-cpu\n", __FUNCTION__));
21751@@ -3037,6 +2993,8 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
21752 inplace.stride = pixmap->devKind;
21753 inplace.opacity = color >> 24;
21754
21755+ span = clipped_span(&clipped, span, dst->pCompositeClip);
21756+
21757 num_threads = 1;
21758 if ((flags & COMPOSITE_SPANS_RECTILINEAR) == 0)
21759 num_threads = sna_use_threads(region.extents.x2 - region.extents.x1,
21760@@ -3057,8 +3015,9 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
21761 }
21762
21763 if (sigtrap_get() == 0) {
21764- tor_render(NULL, &tor, (void*)&inplace,
21765- dst->pCompositeClip, span, unbounded);
21766+ tor_render(NULL, &tor,
21767+ (void*)&inplace, (void *)&clipped,
21768+ span, unbounded);
21769 sigtrap_put();
21770 }
21771
21772@@ -3075,8 +3034,8 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
21773 threads[0].traps = traps;
21774 threads[0].ntrap = ntrap;
21775 threads[0].inplace = inplace;
21776+ threads[0].clipped = clipped;
21777 threads[0].extents = region.extents;
21778- threads[0].clip = dst->pCompositeClip;
21779 threads[0].span = span;
21780 threads[0].unbounded = unbounded;
21781 threads[0].dx = dx;
21782@@ -3707,8 +3666,7 @@ tristrip_thread(void *arg)
21783 if (!tor_init(&tor, &thread->extents, 2*thread->count))
21784 return;
21785
21786- boxes.op = thread->op;
21787- boxes.num_boxes = 0;
21788+ span_thread_boxes_init(&boxes, thread->op, thread->clip);
21789
21790 cw = 0; ccw = 1;
21791 polygon_add_line(tor.polygon,
21792@@ -3874,7 +3832,7 @@ imprecise_tristrip_span_converter(struct sna *sna,
21793 break;
21794 } while (1);
21795 polygon_add_line(tor.polygon,
21796- &points[cw], &points[2+ccw],
21797+ &points[cw], &points[ccw],
21798 dx, dy);
21799 assert(tor.polygon->num_edges <= 2*count);
21800
21801diff --git a/src/sna/sna_trapezoids_mono.c b/src/sna/sna_trapezoids_mono.c
21802index 808703a..07a7867 100644
21803--- a/src/sna/sna_trapezoids_mono.c
21804+++ b/src/sna/sna_trapezoids_mono.c
21805@@ -72,13 +72,14 @@ struct mono {
21806 struct sna *sna;
21807 struct sna_composite_op op;
21808 pixman_region16_t clip;
21809+ const BoxRec *clip_start, *clip_end;
21810
21811 fastcall void (*span)(struct mono *, int, int, BoxPtr);
21812
21813 struct mono_polygon polygon;
21814 };
21815
21816-#define I(x) pixman_fixed_to_int ((x) + pixman_fixed_1_minus_e/2)
21817+#define I(x) pixman_fixed_to_int((x) + pixman_fixed_1_minus_e/2)
21818
21819 static struct quorem
21820 floored_muldivrem(int32_t x, int32_t a, int32_t b)
21821@@ -249,22 +250,22 @@ mono_add_line(struct mono *mono,
21822
21823 e->dxdy = floored_muldivrem(dx, pixman_fixed_1, dy);
21824
21825- e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1_minus_e/2 - p1->y,
21826+ e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1/2 - p1->y,
21827 dx, dy);
21828 e->x.quo += p1->x;
21829 e->x.rem -= dy;
21830
21831 e->dy = dy;
21832-
21833- __DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n",
21834- __FUNCTION__,
21835- I(e->x.quo), e->x.quo, e->x.rem, e->dy,
21836- e->dxdy.quo, e->dxdy.rem, e->dy));
21837 }
21838 e->x.quo += dst_x*pixman_fixed_1;
21839+ __DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n",
21840+ __FUNCTION__,
21841+ I(e->x.quo), e->x.quo, e->x.rem, e->dy,
21842+ e->dxdy.quo, e->dxdy.rem, e->dy));
21843
21844 {
21845 struct mono_edge **ptail = &polygon->y_buckets[ytop - mono->clip.extents.y1];
21846+ assert(ytop - mono->clip.extents.y1 < mono->clip.extents.y2 - mono->clip.extents.y1);
21847 if (*ptail)
21848 (*ptail)->prev = e;
21849 e->next = *ptail;
21850@@ -368,6 +369,10 @@ static struct mono_edge *mono_filter(struct mono_edge *edges)
21851 e->x.rem == n->x.rem &&
21852 e->dxdy.quo == n->dxdy.quo &&
21853 e->dxdy.rem == n->dxdy.rem) {
21854+ assert(e->dy == n->dy);
21855+ __DBG(("%s: discarding cancellation pair (%d.%d) + (%d.%d)\n",
21856+ __FUNCTION__, e->x.quo, e->x.rem, e->dxdy.quo, e->dxdy.rem));
21857+
21858 if (e->prev)
21859 e->prev->next = n->next;
21860 else
21861@@ -378,8 +383,11 @@ static struct mono_edge *mono_filter(struct mono_edge *edges)
21862 break;
21863
21864 e = n->next;
21865- } else
21866+ } else {
21867+ __DBG(("%s: adding edge (%d.%d) + (%d.%d)/%d, height=%d\n",
21868+ __FUNCTION__, n->x.quo, n->x.rem, n->dxdy.quo, n->dxdy.rem, n->dy, n->height_left));
21869 e = n;
21870+ }
21871 }
21872
21873 return edges;
21874@@ -474,6 +482,34 @@ mono_span__fast(struct mono *c, int x1, int x2, BoxPtr box)
21875 c->op.box(c->sna, &c->op, box);
21876 }
21877
21878+fastcall static void
21879+mono_span__clipped(struct mono *c, int x1, int x2, BoxPtr box)
21880+{
21881+ const BoxRec *b;
21882+
21883+ __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2));
21884+
21885+ c->clip_start =
21886+ find_clip_box_for_y(c->clip_start, c->clip_end, box->y1);
21887+
21888+ b = c->clip_start;
21889+ while (b != c->clip_end) {
21890+ BoxRec clipped;
21891+
21892+ if (box->y2 <= b->y1)
21893+ break;
21894+
21895+ clipped.x1 = x1;
21896+ clipped.x2 = x2;
21897+ clipped.y1 = box->y1;
21898+ clipped.y2 = box->y2;
21899+ if (!box_intersect(&clipped, b++))
21900+ continue;
21901+
21902+ c->op.box(c->sna, &c->op, &clipped);
21903+ }
21904+}
21905+
21906 struct mono_span_thread_boxes {
21907 const struct sna_composite_op *op;
21908 #define MONO_SPAN_MAX_BOXES (8192/sizeof(BoxRec))
21909@@ -482,40 +518,45 @@ struct mono_span_thread_boxes {
21910 };
21911
21912 inline static void
21913-thread_mono_span_add_boxes(struct mono *c, const BoxRec *box, int count)
21914+thread_mono_span_add_box(struct mono *c, const BoxRec *box)
21915 {
21916 struct mono_span_thread_boxes *b = c->op.priv;
21917
21918- assert(count > 0 && count <= MONO_SPAN_MAX_BOXES);
21919- if (unlikely(b->num_boxes + count > MONO_SPAN_MAX_BOXES)) {
21920+ if (unlikely(b->num_boxes == MONO_SPAN_MAX_BOXES)) {
21921 b->op->thread_boxes(c->sna, b->op, b->boxes, b->num_boxes);
21922 b->num_boxes = 0;
21923 }
21924
21925- memcpy(b->boxes + b->num_boxes, box, count*sizeof(BoxRec));
21926- b->num_boxes += count;
21927+ b->boxes[b->num_boxes++] = *box;
21928 assert(b->num_boxes <= MONO_SPAN_MAX_BOXES);
21929 }
21930
21931 fastcall static void
21932 thread_mono_span_clipped(struct mono *c, int x1, int x2, BoxPtr box)
21933 {
21934- pixman_region16_t region;
21935+ const BoxRec *b;
21936
21937 __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2));
21938
21939- box->x1 = x1;
21940- box->x2 = x2;
21941+ c->clip_start =
21942+ find_clip_box_for_y(c->clip_start, c->clip_end, box->y1);
21943
21944- assert(c->clip.data);
21945+ b = c->clip_start;
21946+ while (b != c->clip_end) {
21947+ BoxRec clipped;
21948+
21949+ if (box->y2 <= b->y1)
21950+ break;
21951+
21952+ clipped.x1 = x1;
21953+ clipped.x2 = x2;
21954+ clipped.y1 = box->y1;
21955+ clipped.y2 = box->y2;
21956+ if (!box_intersect(&clipped, b++))
21957+ continue;
21958
21959- pixman_region_init_rects(&region, box, 1);
21960- RegionIntersect(&region, &region, &c->clip);
21961- if (region_num_rects(&region))
21962- thread_mono_span_add_boxes(c,
21963- region_rects(&region),
21964- region_num_rects(&region));
21965- pixman_region_fini(&region);
21966+ thread_mono_span_add_box(c, &clipped);
21967+ }
21968 }
21969
21970 fastcall static void
21971@@ -525,7 +566,7 @@ thread_mono_span(struct mono *c, int x1, int x2, BoxPtr box)
21972
21973 box->x1 = x1;
21974 box->x2 = x2;
21975- thread_mono_span_add_boxes(c, box, 1);
21976+ thread_mono_span_add_box(c, box);
21977 }
21978
21979 inline static void
21980@@ -537,6 +578,8 @@ mono_row(struct mono *c, int16_t y, int16_t h)
21981 int winding = 0;
21982 BoxRec box;
21983
21984+ __DBG(("%s: y=%d, h=%d\n", __FUNCTION__, y, h));
21985+
21986 DBG_MONO_EDGES(edge);
21987 VALIDATE_MONO_EDGES(&c->head);
21988
21989@@ -547,6 +590,8 @@ mono_row(struct mono *c, int16_t y, int16_t h)
21990 struct mono_edge *next = edge->next;
21991 int16_t xend = I(edge->x.quo);
21992
21993+ __DBG(("%s: adding edge dir=%d [winding=%d], x=%d [%d]\n",
21994+ __FUNCTION__, edge->dir, winding + edge->dir, xend, edge->x.quo));
21995 if (--edge->height_left) {
21996 if (edge->dy) {
21997 edge->x.quo += edge->dxdy.quo;
21998@@ -555,6 +600,8 @@ mono_row(struct mono *c, int16_t y, int16_t h)
21999 ++edge->x.quo;
22000 edge->x.rem -= edge->dy;
22001 }
22002+ __DBG(("%s: stepped edge (%d.%d) + (%d.%d)/%d, height=%d, prev_x=%d\n",
22003+ __FUNCTION__, edge->x.quo, edge->x.rem, edge->dxdy.quo, edge->dxdy.rem, edge->dy, edge->height_left, edge->x.quo));
22004 }
22005
22006 if (edge->x.quo < prev_x) {
22007@@ -578,17 +625,22 @@ mono_row(struct mono *c, int16_t y, int16_t h)
22008 winding += edge->dir;
22009 if (winding == 0) {
22010 assert(I(next->x.quo) >= xend);
22011- if (I(next->x.quo) > xend + 1) {
22012+ if (I(next->x.quo) > xend) {
22013+ __DBG(("%s: end span: %d\n", __FUNCTION__, xend));
22014 if (xstart < c->clip.extents.x1)
22015 xstart = c->clip.extents.x1;
22016 if (xend > c->clip.extents.x2)
22017 xend = c->clip.extents.x2;
22018- if (xend > xstart)
22019+ if (xend > xstart) {
22020+ __DBG(("%s: emit span [%d, %d]\n", __FUNCTION__, xstart, xend));
22021 c->span(c, xstart, xend, &box);
22022+ }
22023 xstart = INT16_MIN;
22024 }
22025- } else if (xstart == INT16_MIN)
22026+ } else if (xstart == INT16_MIN) {
22027+ __DBG(("%s: starting new span: %d\n", __FUNCTION__, xend));
22028 xstart = xend;
22029+ }
22030
22031 edge = next;
22032 }
22033@@ -650,9 +702,14 @@ mono_render(struct mono *mono)
22034 for (i = 0; i < h; i = j) {
22035 j = i + 1;
22036
22037+ __DBG(("%s: row=%d, new edges? %d\n", __FUNCTION__,
22038+ i, polygon->y_buckets[i] != NULL));
22039+
22040 if (polygon->y_buckets[i])
22041 mono_merge_edges(mono, polygon->y_buckets[i]);
22042
22043+ __DBG(("%s: row=%d, vertical? %d\n", __FUNCTION__,
22044+ i, mono->is_vertical));
22045 if (mono->is_vertical) {
22046 struct mono_edge *e = mono->head.next;
22047 int min_height = h - i;
22048@@ -667,6 +724,7 @@ mono_render(struct mono *mono)
22049 j++;
22050 if (j != i + 1)
22051 mono_step_edges(mono, j - (i + 1));
22052+ __DBG(("%s: %d vertical rows\n", __FUNCTION__, j-i));
22053 }
22054
22055 mono_row(mono, i, j-i);
22056@@ -717,6 +775,7 @@ mono_span_thread(void *arg)
22057 if (RegionNil(&mono.clip))
22058 return;
22059 }
22060+ region_get_boxes(&mono.clip, &mono.clip_start, &mono.clip_end);
22061
22062 boxes.op = thread->op;
22063 boxes.num_boxes = 0;
22064@@ -891,9 +950,12 @@ mono_trapezoids_span_converter(struct sna *sna,
22065
22066 if (mono.clip.data == NULL && mono.op.damage == NULL)
22067 mono.span = mono_span__fast;
22068+ else if (mono.clip.data != NULL && mono.op.damage == NULL)
22069+ mono.span = mono_span__clipped;
22070 else
22071 mono.span = mono_span;
22072
22073+ region_get_boxes(&mono.clip, &mono.clip_start, &mono.clip_end);
22074 mono_render(&mono);
22075 mono.op.done(mono.sna, &mono.op);
22076 mono_fini(&mono);
22077@@ -939,6 +1001,7 @@ mono_trapezoids_span_converter(struct sna *sna,
22078 mono.clip.extents.x2 - mono.clip.extents.x1,
22079 mono.clip.extents.y2 - mono.clip.extents.y1,
22080 COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) {
22081+ region_get_boxes(&mono.clip, &mono.clip_start, &mono.clip_end);
22082 mono_render(&mono);
22083 mono.op.done(mono.sna, &mono.op);
22084 }
22085@@ -974,6 +1037,7 @@ mono_inplace_fill_box(struct sna *sna,
22086 box->x2 - box->x1,
22087 box->y2 - box->y1,
22088 fill->color));
22089+ sigtrap_assert_active();
22090 pixman_fill(fill->data, fill->stride, fill->bpp,
22091 box->x1, box->y1,
22092 box->x2 - box->x1,
22093@@ -995,6 +1059,7 @@ mono_inplace_fill_boxes(struct sna *sna,
22094 box->x2 - box->x1,
22095 box->y2 - box->y1,
22096 fill->color));
22097+ sigtrap_assert_active();
22098 pixman_fill(fill->data, fill->stride, fill->bpp,
22099 box->x1, box->y1,
22100 box->x2 - box->x1,
22101@@ -1382,10 +1447,13 @@ mono_triangles_span_converter(struct sna *sna,
22102 mono_render(&mono);
22103 mono.op.done(mono.sna, &mono.op);
22104 }
22105+ mono_fini(&mono);
22106
22107 if (!was_clear && !operator_is_bounded(op)) {
22108 xPointFixed p1, p2;
22109
22110+ DBG(("%s: performing unbounded clear\n", __FUNCTION__));
22111+
22112 if (!mono_init(&mono, 2+3*count))
22113 return false;
22114
22115@@ -1431,7 +1499,6 @@ mono_triangles_span_converter(struct sna *sna,
22116 mono_fini(&mono);
22117 }
22118
22119- mono_fini(&mono);
22120 REGION_UNINIT(NULL, &mono.clip);
22121 return true;
22122 }
22123diff --git a/src/sna/sna_trapezoids_precise.c b/src/sna/sna_trapezoids_precise.c
22124index 9187ab4..242b4ac 100644
22125--- a/src/sna/sna_trapezoids_precise.c
22126+++ b/src/sna/sna_trapezoids_precise.c
22127@@ -1023,6 +1023,16 @@ tor_init(struct tor *converter, const BoxRec *box, int num_edges)
22128 static void
22129 tor_add_trapezoid(struct tor *tor, const xTrapezoid *t, int dx, int dy)
22130 {
22131+ if (!xTrapezoidValid(t)) {
22132+ __DBG(("%s: skipping invalid trapezoid: top=%d, bottom=%d, left=(%d, %d), (%d, %d), right=(%d, %d), (%d, %d)\n",
22133+ __FUNCTION__,
22134+ t->top, t->bottom,
22135+ t->left.p1.x, t->left.p1.y,
22136+ t->left.p2.x, t->left.p2.y,
22137+ t->right.p1.x, t->right.p1.y,
22138+ t->right.p2.x, t->right.p2.y));
22139+ return;
22140+ }
22141 polygon_add_edge(tor->polygon, t, &t->left, 1, dx, dy);
22142 polygon_add_edge(tor->polygon, t, &t->right, -1, dx, dy);
22143 }
22144@@ -1635,31 +1645,27 @@ struct span_thread {
22145 #define SPAN_THREAD_MAX_BOXES (8192/sizeof(struct sna_opacity_box))
22146 struct span_thread_boxes {
22147 const struct sna_composite_spans_op *op;
22148+ const BoxRec *clip_start, *clip_end;
22149 int num_boxes;
22150 struct sna_opacity_box boxes[SPAN_THREAD_MAX_BOXES];
22151 };
22152
22153-static void span_thread_add_boxes(struct sna *sna, void *data,
22154- const BoxRec *box, int count, float alpha)
22155+static void span_thread_add_box(struct sna *sna, void *data,
22156+ const BoxRec *box, float alpha)
22157 {
22158 struct span_thread_boxes *b = data;
22159
22160- __DBG(("%s: adding %d boxes with alpha=%f\n",
22161- __FUNCTION__, count, alpha));
22162+ __DBG(("%s: adding box with alpha=%f\n", __FUNCTION__, alpha));
22163
22164- assert(count > 0 && count <= SPAN_THREAD_MAX_BOXES);
22165- if (unlikely(b->num_boxes + count > SPAN_THREAD_MAX_BOXES)) {
22166- DBG(("%s: flushing %d boxes, adding %d\n", __FUNCTION__, b->num_boxes, count));
22167- assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES);
22168+ if (unlikely(b->num_boxes == SPAN_THREAD_MAX_BOXES)) {
22169+ DBG(("%s: flushing %d boxes\n", __FUNCTION__, b->num_boxes));
22170 b->op->thread_boxes(sna, b->op, b->boxes, b->num_boxes);
22171 b->num_boxes = 0;
22172 }
22173
22174- do {
22175- b->boxes[b->num_boxes].box = *box++;
22176- b->boxes[b->num_boxes].alpha = alpha;
22177- b->num_boxes++;
22178- } while (--count);
22179+ b->boxes[b->num_boxes].box = *box++;
22180+ b->boxes[b->num_boxes].alpha = alpha;
22181+ b->num_boxes++;
22182 assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES);
22183 }
22184
22185@@ -1670,8 +1676,22 @@ span_thread_box(struct sna *sna,
22186 const BoxRec *box,
22187 int coverage)
22188 {
22189+ struct span_thread_boxes *b = (struct span_thread_boxes *)op;
22190+
22191 __DBG(("%s: %d -> %d @ %d\n", __FUNCTION__, box->x1, box->x2, coverage));
22192- span_thread_add_boxes(sna, op, box, 1, AREA_TO_FLOAT(coverage));
22193+ if (b->num_boxes) {
22194+ struct sna_opacity_box *bb = &b->boxes[b->num_boxes-1];
22195+ if (bb->box.x1 == box->x1 &&
22196+ bb->box.x2 == box->x2 &&
22197+ bb->box.y2 == box->y1 &&
22198+ bb->alpha == AREA_TO_FLOAT(coverage)) {
22199+ bb->box.y2 = box->y2;
22200+ __DBG(("%s: contracted double row: %d -> %d\n", __func__, bb->box.y1, bb->box.y2));
22201+ return;
22202+ }
22203+ }
22204+
22205+ span_thread_add_box(sna, op, box, AREA_TO_FLOAT(coverage));
22206 }
22207
22208 static void
22209@@ -1681,20 +1701,28 @@ span_thread_clipped_box(struct sna *sna,
22210 const BoxRec *box,
22211 int coverage)
22212 {
22213- pixman_region16_t region;
22214+ struct span_thread_boxes *b = (struct span_thread_boxes *)op;
22215+ const BoxRec *c;
22216
22217 __DBG(("%s: %d -> %d @ %f\n", __FUNCTION__, box->x1, box->x2,
22218 AREA_TO_FLOAT(coverage)));
22219
22220- pixman_region_init_rects(&region, box, 1);
22221- RegionIntersect(&region, &region, clip);
22222- if (region_num_rects(&region)) {
22223- span_thread_add_boxes(sna, op,
22224- region_rects(&region),
22225- region_num_rects(&region),
22226- AREA_TO_FLOAT(coverage));
22227+ b->clip_start =
22228+ find_clip_box_for_y(b->clip_start, b->clip_end, box->y1);
22229+
22230+ c = b->clip_start;
22231+ while (c != b->clip_end) {
22232+ BoxRec clipped;
22233+
22234+ if (box->y2 <= c->y1)
22235+ break;
22236+
22237+ clipped = *box;
22238+ if (!box_intersect(&clipped, c++))
22239+ continue;
22240+
22241+ span_thread_add_box(sna, op, &clipped, AREA_TO_FLOAT(coverage));
22242 }
22243- pixman_region_fini(&region);
22244 }
22245
22246 static span_func_t
22247@@ -1712,7 +1740,7 @@ thread_choose_span(struct sna_composite_spans_op *tmp,
22248
22249 assert(!is_mono(dst, maskFormat));
22250 assert(tmp->thread_boxes);
22251- DBG(("%s: clipped? %d\n", __FUNCTION__, clip->data != NULL));
22252+ DBG(("%s: clipped? %d x %d\n", __FUNCTION__, clip->data != NULL, region_num_rects(clip)));
22253 if (clip->data)
22254 span = span_thread_clipped_box;
22255 else
22256@@ -1721,6 +1749,17 @@ thread_choose_span(struct sna_composite_spans_op *tmp,
22257 return span;
22258 }
22259
22260+inline static void
22261+span_thread_boxes_init(struct span_thread_boxes *boxes,
22262+ const struct sna_composite_spans_op *op,
22263+ const RegionRec *clip)
22264+{
22265+ boxes->op = op;
22266+ boxes->clip_start = region_rects(clip);
22267+ boxes->clip_end = boxes->clip_start + region_num_rects(clip);
22268+ boxes->num_boxes = 0;
22269+}
22270+
22271 static void
22272 span_thread(void *arg)
22273 {
22274@@ -1733,8 +1772,7 @@ span_thread(void *arg)
22275 if (!tor_init(&tor, &thread->extents, 2*thread->ntrap))
22276 return;
22277
22278- boxes.op = thread->op;
22279- boxes.num_boxes = 0;
22280+ span_thread_boxes_init(&boxes, thread->op, thread->clip);
22281
22282 y1 = thread->extents.y1 - thread->draw_y;
22283 y2 = thread->extents.y2 - thread->draw_y;
22284@@ -2183,6 +2221,52 @@ static force_inline uint8_t coverage_opacity(int coverage, uint8_t opacity)
22285 return opacity == 255 ? coverage : mul_8_8(coverage, opacity);
22286 }
22287
22288+struct clipped_span {
22289+ span_func_t span;
22290+ const BoxRec *clip_start, *clip_end;
22291+};
22292+
22293+static void
22294+tor_blt_clipped(struct sna *sna,
22295+ struct sna_composite_spans_op *op,
22296+ pixman_region16_t *clip,
22297+ const BoxRec *box,
22298+ int coverage)
22299+{
22300+ struct clipped_span *cs = (struct clipped_span *)clip;
22301+ const BoxRec *c;
22302+
22303+ cs->clip_start =
22304+ find_clip_box_for_y(cs->clip_start, cs->clip_end, box->y1);
22305+
22306+ c = cs->clip_start;
22307+ while (c != cs->clip_end) {
22308+ BoxRec clipped;
22309+
22310+ if (box->y2 <= c->y1)
22311+ break;
22312+
22313+ clipped = *box;
22314+ if (!box_intersect(&clipped, c++))
22315+ continue;
22316+
22317+ cs->span(sna, op, NULL, &clipped, coverage);
22318+ }
22319+}
22320+
22321+inline static span_func_t
22322+clipped_span(struct clipped_span *cs,
22323+ span_func_t span,
22324+ const RegionRec *clip)
22325+{
22326+ if (clip->data) {
22327+ cs->span = span;
22328+ region_get_boxes(clip, &cs->clip_start, &cs->clip_end);
22329+ span = tor_blt_clipped;
22330+ }
22331+ return span;
22332+}
22333+
22334 static void _tor_blt_src(struct inplace *in, const BoxRec *box, uint8_t v)
22335 {
22336 uint8_t *ptr = in->ptr;
22337@@ -2218,25 +2302,6 @@ tor_blt_src(struct sna *sna,
22338 }
22339
22340 static void
22341-tor_blt_src_clipped(struct sna *sna,
22342- struct sna_composite_spans_op *op,
22343- pixman_region16_t *clip,
22344- const BoxRec *box,
22345- int coverage)
22346-{
22347- pixman_region16_t region;
22348- int n;
22349-
22350- pixman_region_init_rects(&region, box, 1);
22351- RegionIntersect(&region, &region, clip);
22352- n = region_num_rects(&region);
22353- box = region_rects(&region);
22354- while (n--)
22355- tor_blt_src(sna, op, NULL, box++, coverage);
22356- pixman_region_fini(&region);
22357-}
22358-
22359-static void
22360 tor_blt_in(struct sna *sna,
22361 struct sna_composite_spans_op *op,
22362 pixman_region16_t *clip,
22363@@ -2268,25 +2333,6 @@ tor_blt_in(struct sna *sna,
22364 }
22365
22366 static void
22367-tor_blt_in_clipped(struct sna *sna,
22368- struct sna_composite_spans_op *op,
22369- pixman_region16_t *clip,
22370- const BoxRec *box,
22371- int coverage)
22372-{
22373- pixman_region16_t region;
22374- int n;
22375-
22376- pixman_region_init_rects(&region, box, 1);
22377- RegionIntersect(&region, &region, clip);
22378- n = region_num_rects(&region);
22379- box = region_rects(&region);
22380- while (n--)
22381- tor_blt_in(sna, op, NULL, box++, coverage);
22382- pixman_region_fini(&region);
22383-}
22384-
22385-static void
22386 tor_blt_add(struct sna *sna,
22387 struct sna_composite_spans_op *op,
22388 pixman_region16_t *clip,
22389@@ -2325,25 +2371,6 @@ tor_blt_add(struct sna *sna,
22390 }
22391
22392 static void
22393-tor_blt_add_clipped(struct sna *sna,
22394- struct sna_composite_spans_op *op,
22395- pixman_region16_t *clip,
22396- const BoxRec *box,
22397- int coverage)
22398-{
22399- pixman_region16_t region;
22400- int n;
22401-
22402- pixman_region_init_rects(&region, box, 1);
22403- RegionIntersect(&region, &region, clip);
22404- n = region_num_rects(&region);
22405- box = region_rects(&region);
22406- while (n--)
22407- tor_blt_add(sna, op, NULL, box++, coverage);
22408- pixman_region_fini(&region);
22409-}
22410-
22411-static void
22412 tor_blt_lerp32(struct sna *sna,
22413 struct sna_composite_spans_op *op,
22414 pixman_region16_t *clip,
22415@@ -2358,6 +2385,7 @@ tor_blt_lerp32(struct sna *sna,
22416 if (coverage == 0)
22417 return;
22418
22419+ sigtrap_assert_active();
22420 ptr += box->y1 * stride + box->x1;
22421
22422 h = box->y2 - box->y1;
22423@@ -2396,25 +2424,6 @@ tor_blt_lerp32(struct sna *sna,
22424 }
22425 }
22426
22427-static void
22428-tor_blt_lerp32_clipped(struct sna *sna,
22429- struct sna_composite_spans_op *op,
22430- pixman_region16_t *clip,
22431- const BoxRec *box,
22432- int coverage)
22433-{
22434- pixman_region16_t region;
22435- int n;
22436-
22437- pixman_region_init_rects(&region, box, 1);
22438- RegionIntersect(&region, &region, clip);
22439- n = region_num_rects(&region);
22440- box = region_rects(&region);
22441- while (n--)
22442- tor_blt_lerp32(sna, op, NULL, box++, coverage);
22443- pixman_region_fini(&region);
22444-}
22445-
22446 struct pixman_inplace {
22447 pixman_image_t *image, *source, *mask;
22448 uint32_t color;
22449@@ -2442,24 +2451,6 @@ pixmask_span_solid(struct sna *sna,
22450 pi->dx + box->x1, pi->dy + box->y1,
22451 box->x2 - box->x1, box->y2 - box->y1);
22452 }
22453-static void
22454-pixmask_span_solid__clipped(struct sna *sna,
22455- struct sna_composite_spans_op *op,
22456- pixman_region16_t *clip,
22457- const BoxRec *box,
22458- int coverage)
22459-{
22460- pixman_region16_t region;
22461- int n;
22462-
22463- pixman_region_init_rects(&region, box, 1);
22464- RegionIntersect(&region, &region, clip);
22465- n = region_num_rects(&region);
22466- box = region_rects(&region);
22467- while (n--)
22468- pixmask_span_solid(sna, op, NULL, box++, coverage);
22469- pixman_region_fini(&region);
22470-}
22471
22472 static void
22473 pixmask_span(struct sna *sna,
22474@@ -2480,24 +2471,6 @@ pixmask_span(struct sna *sna,
22475 pi->dx + box->x1, pi->dy + box->y1,
22476 box->x2 - box->x1, box->y2 - box->y1);
22477 }
22478-static void
22479-pixmask_span__clipped(struct sna *sna,
22480- struct sna_composite_spans_op *op,
22481- pixman_region16_t *clip,
22482- const BoxRec *box,
22483- int coverage)
22484-{
22485- pixman_region16_t region;
22486- int n;
22487-
22488- pixman_region_init_rects(&region, box, 1);
22489- RegionIntersect(&region, &region, clip);
22490- n = region_num_rects(&region);
22491- box = region_rects(&region);
22492- while (n--)
22493- pixmask_span(sna, op, NULL, box++, coverage);
22494- pixman_region_fini(&region);
22495-}
22496
22497 struct inplace_x8r8g8b8_thread {
22498 xTrapezoid *traps;
22499@@ -2516,6 +2489,7 @@ static void inplace_x8r8g8b8_thread(void *arg)
22500 struct inplace_x8r8g8b8_thread *thread = arg;
22501 struct tor tor;
22502 span_func_t span;
22503+ struct clipped_span clipped;
22504 RegionPtr clip;
22505 int y1, y2, n;
22506
22507@@ -2546,12 +2520,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
22508 inplace.stride = pixmap->devKind;
22509 inplace.color = thread->color;
22510
22511- if (clip->data)
22512- span = tor_blt_lerp32_clipped;
22513- else
22514- span = tor_blt_lerp32;
22515+ span = clipped_span(&clipped, tor_blt_lerp32, clip);
22516
22517- tor_render(NULL, &tor, (void*)&inplace, clip, span, false);
22518+ tor_render(NULL, &tor,
22519+ (void*)&inplace, (void *)&clipped,
22520+ span, false);
22521 } else if (thread->is_solid) {
22522 struct pixman_inplace pi;
22523
22524@@ -2564,10 +2537,7 @@ static void inplace_x8r8g8b8_thread(void *arg)
22525 1, 1, pi.bits, 0);
22526 pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
22527
22528- if (clip->data)
22529- span = pixmask_span_solid__clipped;
22530- else
22531- span = pixmask_span_solid;
22532+ span = clipped_span(&clipped, pixmask_span_solid, clip);
22533
22534 tor_render(NULL, &tor, (void*)&pi, clip, span, false);
22535
22536@@ -2588,12 +2558,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
22537 pi.bits = pixman_image_get_data(pi.mask);
22538 pi.op = thread->op;
22539
22540- if (clip->data)
22541- span = pixmask_span__clipped;
22542- else
22543- span = pixmask_span;
22544+ span = clipped_span(&clipped, pixmask_span, clip);
22545
22546- tor_render(NULL, &tor, (void*)&pi, clip, span, false);
22547+ tor_render(NULL, &tor,
22548+ (void*)&pi, (void *)&clipped,
22549+ span, false);
22550
22551 pixman_image_unref(pi.mask);
22552 pixman_image_unref(pi.source);
22553@@ -2712,6 +2681,7 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
22554 if (num_threads == 1) {
22555 struct tor tor;
22556 span_func_t span;
22557+ struct clipped_span clipped;
22558
22559 if (!tor_init(&tor, &region.extents, 2*ntrap))
22560 return true;
22561@@ -2737,17 +2707,14 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
22562 inplace.stride = pixmap->devKind;
22563 inplace.color = color;
22564
22565- if (dst->pCompositeClip->data)
22566- span = tor_blt_lerp32_clipped;
22567- else
22568- span = tor_blt_lerp32;
22569-
22570+ span = clipped_span(&clipped, tor_blt_lerp32, dst->pCompositeClip);
22571 DBG(("%s: render inplace op=%d, color=%08x\n",
22572 __FUNCTION__, op, color));
22573
22574 if (sigtrap_get() == 0) {
22575- tor_render(NULL, &tor, (void*)&inplace,
22576- dst->pCompositeClip, span, false);
22577+ tor_render(NULL, &tor,
22578+ (void*)&inplace, (void*)&clipped,
22579+ span, false);
22580 sigtrap_put();
22581 }
22582 } else if (is_solid) {
22583@@ -2762,15 +2729,11 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
22584 1, 1, pi.bits, 0);
22585 pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
22586
22587- if (dst->pCompositeClip->data)
22588- span = pixmask_span_solid__clipped;
22589- else
22590- span = pixmask_span_solid;
22591-
22592+ span = clipped_span(&clipped, pixmask_span_solid, dst->pCompositeClip);
22593 if (sigtrap_get() == 0) {
22594- tor_render(NULL, &tor, (void*)&pi,
22595- dst->pCompositeClip, span,
22596- false);
22597+ tor_render(NULL, &tor,
22598+ (void*)&pi, (void*)&clipped,
22599+ span, false);
22600 sigtrap_put();
22601 }
22602
22603@@ -2791,15 +2754,11 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
22604 pi.bits = pixman_image_get_data(pi.mask);
22605 pi.op = op;
22606
22607- if (dst->pCompositeClip->data)
22608- span = pixmask_span__clipped;
22609- else
22610- span = pixmask_span;
22611-
22612+ span = clipped_span(&clipped, pixmask_span, dst->pCompositeClip);
22613 if (sigtrap_get() == 0) {
22614- tor_render(NULL, &tor, (void*)&pi,
22615- dst->pCompositeClip, span,
22616- false);
22617+ tor_render(NULL, &tor,
22618+ (void*)&pi, (void *)&clipped,
22619+ span, false);
22620 sigtrap_put();
22621 }
22622
22623@@ -2861,9 +2820,9 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
22624
22625 struct inplace_thread {
22626 xTrapezoid *traps;
22627- RegionPtr clip;
22628 span_func_t span;
22629 struct inplace inplace;
22630+ struct clipped_span clipped;
22631 BoxRec extents;
22632 int dx, dy;
22633 int draw_x, draw_y;
22634@@ -2888,8 +2847,9 @@ static void inplace_thread(void *arg)
22635 tor_add_trapezoid(&tor, &thread->traps[n], thread->dx, thread->dy);
22636 }
22637
22638- tor_render(NULL, &tor, (void*)&thread->inplace,
22639- thread->clip, thread->span, thread->unbounded);
22640+ tor_render(NULL, &tor,
22641+ (void*)&thread->inplace, (void*)&thread->clipped,
22642+ thread->span, thread->unbounded);
22643
22644 tor_fini(&tor);
22645 }
22646@@ -2903,6 +2863,7 @@ precise_trapezoid_span_inplace(struct sna *sna,
22647 bool fallback)
22648 {
22649 struct inplace inplace;
22650+ struct clipped_span clipped;
22651 span_func_t span;
22652 PixmapPtr pixmap;
22653 struct sna_pixmap *priv;
22654@@ -3020,21 +2981,12 @@ precise_trapezoid_span_inplace(struct sna *sna,
22655 dst->pCompositeClip->data != NULL));
22656
22657 if (op == PictOpSrc) {
22658- if (dst->pCompositeClip->data)
22659- span = tor_blt_src_clipped;
22660- else
22661- span = tor_blt_src;
22662+ span = tor_blt_src;
22663 } else if (op == PictOpIn) {
22664- if (dst->pCompositeClip->data)
22665- span = tor_blt_in_clipped;
22666- else
22667- span = tor_blt_in;
22668+ span = tor_blt_in;
22669 } else {
22670 assert(op == PictOpAdd);
22671- if (dst->pCompositeClip->data)
22672- span = tor_blt_add_clipped;
22673- else
22674- span = tor_blt_add;
22675+ span = tor_blt_add;
22676 }
22677
22678 DBG(("%s: move-to-cpu(dst)\n", __FUNCTION__));
22679@@ -3052,6 +3004,8 @@ precise_trapezoid_span_inplace(struct sna *sna,
22680 inplace.stride = pixmap->devKind;
22681 inplace.opacity = color >> 24;
22682
22683+ span = clipped_span(&clipped, span, dst->pCompositeClip);
22684+
22685 num_threads = 1;
22686 if (!NO_GPU_THREADS &&
22687 (flags & COMPOSITE_SPANS_RECTILINEAR) == 0)
22688@@ -3074,8 +3028,9 @@ precise_trapezoid_span_inplace(struct sna *sna,
22689 }
22690
22691 if (sigtrap_get() == 0) {
22692- tor_render(NULL, &tor, (void*)&inplace,
22693- dst->pCompositeClip, span, unbounded);
22694+ tor_render(NULL, &tor,
22695+ (void*)&inplace, (void *)&clipped,
22696+ span, unbounded);
22697 sigtrap_put();
22698 }
22699
22700@@ -3093,7 +3048,7 @@ precise_trapezoid_span_inplace(struct sna *sna,
22701 threads[0].ntrap = ntrap;
22702 threads[0].inplace = inplace;
22703 threads[0].extents = region.extents;
22704- threads[0].clip = dst->pCompositeClip;
22705+ threads[0].clipped = clipped;
22706 threads[0].span = span;
22707 threads[0].unbounded = unbounded;
22708 threads[0].dx = dx;
22709@@ -3316,8 +3271,7 @@ tristrip_thread(void *arg)
22710 if (!tor_init(&tor, &thread->extents, 2*thread->count))
22711 return;
22712
22713- boxes.op = thread->op;
22714- boxes.num_boxes = 0;
22715+ span_thread_boxes_init(&boxes, thread->op, thread->clip);
22716
22717 cw = 0; ccw = 1;
22718 polygon_add_line(tor.polygon,
22719diff --git a/src/sna/sna_video.c b/src/sna/sna_video.c
22720index ed0e7b3..e2b11c3 100644
22721--- a/src/sna/sna_video.c
22722+++ b/src/sna/sna_video.c
22723@@ -591,6 +591,72 @@ use_gtt: /* copy data, must use GTT so that we keep the overlay uncached */
22724 return true;
22725 }
22726
22727+void sna_video_fill_colorkey(struct sna_video *video,
22728+ const RegionRec *clip)
22729+{
22730+ struct sna *sna = video->sna;
22731+ PixmapPtr front = sna->front;
22732+ struct kgem_bo *bo = __sna_pixmap_get_bo(front);
22733+ uint8_t *dst, *tmp;
22734+ int w, width;
22735+
22736+ if (video->AlwaysOnTop || RegionEqual(&video->clip, (RegionPtr)clip))
22737+ return;
22738+
22739+ assert(bo);
22740+ if (!wedged(sna) &&
22741+ sna_blt_fill_boxes(sna, GXcopy, bo,
22742+ front->drawable.bitsPerPixel,
22743+ video->color_key,
22744+ region_rects(clip),
22745+ region_num_rects(clip))) {
22746+ RegionCopy(&video->clip, (RegionPtr)clip);
22747+ return;
22748+ }
22749+
22750+ dst = kgem_bo_map__gtt(&sna->kgem, bo);
22751+ if (dst == NULL)
22752+ return;
22753+
22754+ w = front->drawable.bitsPerPixel/8;
22755+ width = (clip->extents.x2 - clip->extents.x1) * w;
22756+ tmp = malloc(width);
22757+ if (tmp == NULL)
22758+ return;
22759+
22760+ memcpy(tmp, &video->color_key, w);
22761+ while (2 * w < width) {
22762+ memcpy(tmp + w, tmp, w);
22763+ w *= 2;
22764+ }
22765+ if (w < width)
22766+ memcpy(tmp + w, tmp, width - w);
22767+
22768+ if (sigtrap_get() == 0) {
22769+ const BoxRec *box = region_rects(clip);
22770+ int n = region_num_rects(clip);
22771+
22772+ w = front->drawable.bitsPerPixel/8;
22773+ do {
22774+ int y = box->y1;
22775+ uint8_t *row = dst + y*bo->pitch + w*box->x1;
22776+
22777+ width = (box->x2 - box->x1) * w;
22778+ while (y < box->y2) {
22779+ memcpy(row, tmp, width);
22780+ row += bo->pitch;
22781+ y++;
22782+ }
22783+ box++;
22784+ } while (--n);
22785+ sigtrap_put();
22786+
22787+ RegionCopy(&video->clip, (RegionPtr)clip);
22788+ }
22789+
22790+ free(tmp);
22791+}
22792+
22793 XvAdaptorPtr sna_xv_adaptor_alloc(struct sna *sna)
22794 {
22795 XvAdaptorPtr new_adaptors;
22796diff --git a/src/sna/sna_video.h b/src/sna/sna_video.h
22797index f21605f..dfb8c0c 100644
22798--- a/src/sna/sna_video.h
22799+++ b/src/sna/sna_video.h
22800@@ -193,6 +193,9 @@ bool
22801 sna_video_copy_data(struct sna_video *video,
22802 struct sna_video_frame *frame,
22803 const uint8_t *buf);
22804+void
22805+sna_video_fill_colorkey(struct sna_video *video,
22806+ const RegionRec *clip);
22807
22808 void sna_video_buffer_fini(struct sna_video *video);
22809
22810diff --git a/src/sna/sna_video_overlay.c b/src/sna/sna_video_overlay.c
22811index ac81f1a..d782113 100644
22812--- a/src/sna/sna_video_overlay.c
22813+++ b/src/sna/sna_video_overlay.c
22814@@ -130,7 +130,7 @@ static int sna_video_overlay_stop(ddStopVideo_ARGS)
22815
22816 DBG(("%s()\n", __FUNCTION__));
22817
22818- REGION_EMPTY(scrn->pScreen, &video->clip);
22819+ REGION_EMPTY(to_screen_from_sna(sna), &video->clip);
22820
22821 request.flags = 0;
22822 (void)drmIoctl(sna->kgem.fd,
22823@@ -551,15 +551,7 @@ sna_video_overlay_put_image(ddPutImage_ARGS)
22824 ret = Success;
22825 if (sna_video_overlay_show
22826 (sna, video, &frame, crtc, &dstBox, src_w, src_h, drw_w, drw_h)) {
22827- //xf86XVFillKeyHelperDrawable(draw, video->color_key, &clip);
22828- if (!video->AlwaysOnTop && !RegionEqual(&video->clip, &clip) &&
22829- sna_blt_fill_boxes(sna, GXcopy,
22830- __sna_pixmap_get_bo(sna->front),
22831- sna->front->drawable.bitsPerPixel,
22832- video->color_key,
22833- region_rects(&clip),
22834- region_num_rects(&clip)))
22835- RegionCopy(&video->clip, &clip);
22836+ sna_video_fill_colorkey(video, &clip);
22837 sna_window_set_port((WindowPtr)draw, port);
22838 } else {
22839 DBG(("%s: failed to show video frame\n", __FUNCTION__));
22840diff --git a/src/sna/sna_video_sprite.c b/src/sna/sna_video_sprite.c
22841index 92230f9..7c8a73f 100644
22842--- a/src/sna/sna_video_sprite.c
22843+++ b/src/sna/sna_video_sprite.c
22844@@ -81,14 +81,11 @@ static int sna_video_sprite_stop(ddStopVideo_ARGS)
22845 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(video->sna->scrn);
22846 int i;
22847
22848- for (i = 0; i < config->num_crtc; i++) {
22849+ for (i = 0; i < video->sna->mode.num_real_crtc; i++) {
22850 xf86CrtcPtr crtc = config->crtc[i];
22851 int pipe;
22852
22853- if (sna_crtc_id(crtc) == 0)
22854- break;
22855-
22856- pipe = sna_crtc_to_pipe(crtc);
22857+ pipe = sna_crtc_pipe(crtc);
22858 if (video->bo[pipe] == NULL)
22859 continue;
22860
22861@@ -221,7 +218,7 @@ sna_video_sprite_show(struct sna *sna,
22862 BoxPtr dstBox)
22863 {
22864 struct local_mode_set_plane s;
22865- int pipe = sna_crtc_to_pipe(crtc);
22866+ int pipe = sna_crtc_pipe(crtc);
22867
22868 /* XXX handle video spanning multiple CRTC */
22869
22870@@ -402,7 +399,7 @@ static int sna_video_sprite_put_image(ddPutImage_ARGS)
22871 goto err;
22872 }
22873
22874- for (i = 0; i < config->num_crtc; i++) {
22875+ for (i = 0; i < video->sna->mode.num_real_crtc; i++) {
22876 xf86CrtcPtr crtc = config->crtc[i];
22877 struct sna_video_frame frame;
22878 int pipe;
22879@@ -411,10 +408,7 @@ static int sna_video_sprite_put_image(ddPutImage_ARGS)
22880 RegionRec reg;
22881 Rotation rotation;
22882
22883- if (sna_crtc_id(crtc) == 0)
22884- break;
22885-
22886- pipe = sna_crtc_to_pipe(crtc);
22887+ pipe = sna_crtc_pipe(crtc);
22888
22889 sna_video_frame_init(video, format->id, width, height, &frame);
22890
22891@@ -527,14 +521,7 @@ off:
22892 goto err;
22893 }
22894
22895- if (!video->AlwaysOnTop && !RegionEqual(&video->clip, &clip) &&
22896- sna_blt_fill_boxes(sna, GXcopy,
22897- __sna_pixmap_get_bo(sna->front),
22898- sna->front->drawable.bitsPerPixel,
22899- video->color_key,
22900- region_rects(&clip),
22901- region_num_rects(&clip)))
22902- RegionCopy(&video->clip, &clip);
22903+ sna_video_fill_colorkey(video, &clip);
22904 sna_window_set_port((WindowPtr)draw, port);
22905
22906 return Success;
22907@@ -618,7 +605,7 @@ static bool sna_video_has_sprites(struct sna *sna)
22908
22909 for (i = 0; i < sna->mode.num_real_crtc; i++) {
22910 if (!sna_crtc_to_sprite(config->crtc[i])) {
22911- DBG(("%s: no sprite found on pipe %d\n", __FUNCTION__, sna_crtc_to_pipe(config->crtc[i])));
22912+ DBG(("%s: no sprite found on pipe %d\n", __FUNCTION__, sna_crtc_pipe(config->crtc[i])));
22913 return false;
22914 }
22915 }
22916diff --git a/src/sna/sna_video_textured.c b/src/sna/sna_video_textured.c
22917index 9501193..3f14a59 100644
22918--- a/src/sna/sna_video_textured.c
22919+++ b/src/sna/sna_video_textured.c
22920@@ -149,9 +149,13 @@ sna_video_textured_put_image(ddPutImage_ARGS)
22921 BoxRec dstBox;
22922 RegionRec clip;
22923 xf86CrtcPtr crtc;
22924+ int16_t dx, dy;
22925 bool flush = false;
22926 bool ret;
22927
22928+ if (wedged(sna))
22929+ return BadAlloc;
22930+
22931 clip.extents.x1 = draw->x + drw_x;
22932 clip.extents.y1 = draw->y + drw_y;
22933 clip.extents.x2 = clip.extents.x1 + drw_w;
22934@@ -181,6 +185,9 @@ sna_video_textured_put_image(ddPutImage_ARGS)
22935 &clip))
22936 return Success;
22937
22938+ if (get_drawable_deltas(draw, pixmap, &dx, &dy))
22939+ RegionTranslate(&clip, dx, dy);
22940+
22941 flags = MOVE_WRITE | __MOVE_FORCE;
22942 if (clip.data)
22943 flags |= MOVE_READ;
22944@@ -234,7 +241,7 @@ sna_video_textured_put_image(ddPutImage_ARGS)
22945 DBG(("%s: failed to render video\n", __FUNCTION__));
22946 ret = BadAlloc;
22947 } else
22948- DamageDamageRegion(draw, &clip);
22949+ DamageDamageRegion(&pixmap->drawable, &clip);
22950
22951 kgem_bo_destroy(&sna->kgem, frame.bo);
22952
22953@@ -316,7 +323,7 @@ void sna_video_textured_setup(struct sna *sna, ScreenPtr screen)
22954
22955 if (!sna->render.video) {
22956 xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
22957- "Textured video not supported on this hardware\n");
22958+ "Textured video not supported on this hardware or backend\n");
22959 return;
22960 }
22961
22962diff --git a/src/sna/xassert.h b/src/sna/xassert.h
22963index 1bcfd08..28796b8 100644
22964--- a/src/sna/xassert.h
22965+++ b/src/sna/xassert.h
22966@@ -43,6 +43,23 @@
22967 xorg_backtrace(); \
22968 FatalError("%s:%d assertion '%s' failed\n", __func__, __LINE__, #E); \
22969 } while (0)
22970+
22971+#define warn_unless(E) do if (unlikely(!(E))) { \
22972+ static int __warn_once__; \
22973+ if (!__warn_once__) { \
22974+ xorg_backtrace(); \
22975+ ErrorF("%s:%d assertion '%s' failed\n", __func__, __LINE__, #E); \
22976+ __warn_once__ = 1; \
22977+ } \
22978+} while (0)
22979+
22980+#define dbg(EXPR) EXPR
22981+
22982+#else
22983+
22984+#define warn_unless(E)
22985+#define dbg(EXPR)
22986+
22987 #endif
22988
22989 #endif /* __XASSERT_H__ */
22990diff --git a/src/uxa/i965_video.c b/src/uxa/i965_video.c
22991index 68e6fd3..438ab90 100644
22992--- a/src/uxa/i965_video.c
22993+++ b/src/uxa/i965_video.c
22994@@ -37,7 +37,6 @@
22995 #include "fourcc.h"
22996
22997 #include "intel.h"
22998-#include "intel_xvmc.h"
22999 #include "intel_uxa.h"
23000 #include "i830_reg.h"
23001 #include "i965_reg.h"
23002diff --git a/src/uxa/intel.h b/src/uxa/intel.h
23003index 1b7e533..37b23e9 100644
23004--- a/src/uxa/intel.h
23005+++ b/src/uxa/intel.h
23006@@ -121,7 +121,6 @@ typedef struct intel_screen_private {
23007
23008 void *modes;
23009 drm_intel_bo *front_buffer, *back_buffer;
23010- unsigned int back_name;
23011 long front_pitch, front_tiling;
23012
23013 dri_bufmgr *bufmgr;
23014@@ -285,8 +284,6 @@ typedef struct intel_screen_private {
23015 Bool has_kernel_flush;
23016 Bool needs_flush;
23017
23018- struct _DRI2FrameEvent *pending_flip[MAX_PIPES];
23019-
23020 /* Broken-out options. */
23021 OptionInfoPtr Options;
23022
23023@@ -368,6 +365,7 @@ typedef void (*intel_drm_abort_proc)(ScrnInfoPtr scrn,
23024
23025 extern uint32_t intel_drm_queue_alloc(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data, intel_drm_handler_proc handler, intel_drm_abort_proc abort);
23026 extern void intel_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), void *match_data);
23027+extern void intel_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq);
23028
23029 extern int intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc);
23030 extern int intel_crtc_id(xf86CrtcPtr crtc);
23031@@ -408,7 +406,6 @@ typedef struct _DRI2FrameEvent {
23032 ClientPtr client;
23033 enum DRI2FrameEventType type;
23034 int frame;
23035- int pipe;
23036
23037 struct list drawable_resource, client_resource;
23038
23039@@ -418,7 +415,12 @@ typedef struct _DRI2FrameEvent {
23040 DRI2BufferPtr front;
23041 DRI2BufferPtr back;
23042
23043- struct _DRI2FrameEvent *chain;
23044+ /* current scanout for triple buffer */
23045+ int old_width;
23046+ int old_height;
23047+ int old_pitch;
23048+ int old_tiling;
23049+ dri_bo *old_buffer;
23050 } DRI2FrameEventRec, *DRI2FrameEventPtr;
23051
23052 extern Bool intel_do_pageflip(intel_screen_private *intel,
23053@@ -456,10 +458,6 @@ extern xf86CrtcPtr intel_covering_crtc(ScrnInfoPtr scrn, BoxPtr box,
23054
23055 Bool I830DRI2ScreenInit(ScreenPtr pScreen);
23056 void I830DRI2CloseScreen(ScreenPtr pScreen);
23057-void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
23058- unsigned int tv_usec, DRI2FrameEventPtr flip_info);
23059-void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
23060- unsigned int tv_usec, DRI2FrameEventPtr flip_info);
23061
23062 /* intel_dri3.c */
23063 Bool intel_dri3_screen_init(ScreenPtr screen);
23064diff --git a/src/uxa/intel_display.c b/src/uxa/intel_display.c
23065index 7b4d4e0..8bf0184 100644
23066--- a/src/uxa/intel_display.c
23067+++ b/src/uxa/intel_display.c
23068@@ -89,11 +89,11 @@ struct intel_mode {
23069 struct list outputs;
23070 struct list crtcs;
23071
23072- void *pageflip_data;
23073- intel_pageflip_handler_proc pageflip_handler;
23074- intel_pageflip_abort_proc pageflip_abort;
23075-
23076- Bool delete_dp_12_displays;
23077+ struct {
23078+ intel_pageflip_handler_proc handler;
23079+ intel_pageflip_abort_proc abort;
23080+ void *data;
23081+ } pageflip;
23082 };
23083
23084 struct intel_pageflip {
23085@@ -114,7 +114,6 @@ struct intel_crtc {
23086 struct list link;
23087 PixmapPtr scanout_pixmap;
23088 uint32_t scanout_fb_id;
23089- int32_t vblank_offset;
23090 uint32_t msc_prev;
23091 uint64_t msc_high;
23092 };
23093@@ -193,7 +192,7 @@ intel_output_backlight_init(xf86OutputPtr output)
23094
23095 str = xf86GetOptValString(intel->Options, OPTION_BACKLIGHT);
23096 if (str != NULL) {
23097- if (backlight_exists(str) != BL_NONE) {
23098+ if (backlight_exists(str)) {
23099 intel_output->backlight_active_level =
23100 backlight_open(&intel_output->backlight,
23101 strdup(str));
23102@@ -867,6 +866,48 @@ intel_output_attach_edid(xf86OutputPtr output)
23103 xf86OutputSetEDID(output, mon);
23104 }
23105
23106+static void
23107+intel_output_attach_tile(xf86OutputPtr output)
23108+{
23109+#if XF86_OUTPUT_VERSION >= 3
23110+ struct intel_output *intel_output = output->driver_private;
23111+ drmModeConnectorPtr koutput = intel_output->mode_output;
23112+ struct intel_mode *mode = intel_output->mode;
23113+ drmModePropertyBlobPtr blob = NULL;
23114+ struct xf86CrtcTileInfo tile_info, *set = NULL;
23115+ int i;
23116+
23117+ for (i = 0; koutput && i < koutput->count_props; i++) {
23118+ drmModePropertyPtr props;
23119+
23120+ props = drmModeGetProperty(mode->fd, koutput->props[i]);
23121+ if (!props)
23122+ continue;
23123+
23124+ if (!(props->flags & DRM_MODE_PROP_BLOB)) {
23125+ drmModeFreeProperty(props);
23126+ continue;
23127+ }
23128+
23129+ if (!strcmp(props->name, "TILE")) {
23130+ blob = drmModeGetPropertyBlob(mode->fd,
23131+ koutput->prop_values[i]);
23132+ }
23133+ drmModeFreeProperty(props);
23134+ }
23135+
23136+ if (blob) {
23137+ if (xf86OutputParseKMSTile(blob->data,
23138+ blob->length,
23139+ &tile_info))
23140+ set = &tile_info;
23141+ drmModeFreePropertyBlob(blob);
23142+ }
23143+
23144+ xf86OutputSetTile(output, set);
23145+#endif
23146+}
23147+
23148 static DisplayModePtr
23149 intel_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
23150 {
23151@@ -922,6 +963,7 @@ intel_output_get_modes(xf86OutputPtr output)
23152 int i;
23153
23154 intel_output_attach_edid(output);
23155+ intel_output_attach_tile(output);
23156
23157 if (!koutput)
23158 return Modes;
23159@@ -1492,6 +1534,7 @@ intel_output_init(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_
23160 intel_output = output->driver_private;
23161 intel_output->output_id = mode_res->connectors[num];
23162 intel_output->mode_output = koutput;
23163+ RROutputChanged(output->randr_output, TRUE);
23164 return;
23165 }
23166 }
23167@@ -1650,9 +1693,6 @@ intel_pageflip_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data);
23168 static void
23169 intel_pageflip_complete(struct intel_mode *mode);
23170
23171-static void
23172-intel_drm_abort_seq (ScrnInfoPtr scrn, uint32_t seq);
23173-
23174 Bool
23175 intel_do_pageflip(intel_screen_private *intel,
23176 dri_bo *new_front,
23177@@ -1671,23 +1711,30 @@ intel_do_pageflip(intel_screen_private *intel,
23178 uint32_t new_fb_id;
23179 uint32_t flags;
23180 uint32_t seq;
23181+ int err = 0;
23182 int i;
23183
23184 /*
23185+ * We only have a single length queue in the kernel, so any
23186+ * attempts to schedule a second flip before processing the first
23187+ * is a bug. Punt it back to the caller.
23188+ */
23189+ if (mode->flip_count)
23190+ return FALSE;
23191+
23192+ /*
23193 * Create a new handle for the back buffer
23194 */
23195 if (drmModeAddFB(mode->fd, scrn->virtualX, scrn->virtualY,
23196 scrn->depth, scrn->bitsPerPixel, pitch,
23197- new_front->handle, &new_fb_id))
23198+ new_front->handle, &new_fb_id)) {
23199+ err = errno;
23200 goto error_out;
23201+ }
23202
23203 drm_intel_bo_disable_reuse(new_front);
23204 intel_flush(intel);
23205
23206- mode->pageflip_data = pageflip_data;
23207- mode->pageflip_handler = pageflip_handler;
23208- mode->pageflip_abort = pageflip_abort;
23209-
23210 /*
23211 * Queue flips on all enabled CRTCs
23212 * Note that if/when we get per-CRTC buffers, we'll have to update this.
23213@@ -1699,6 +1746,7 @@ intel_do_pageflip(intel_screen_private *intel,
23214 */
23215 mode->fe_msc = 0;
23216 mode->fe_usec = 0;
23217+ memset(&mode->pageflip, 0, sizeof(mode->pageflip));
23218
23219 flags = DRM_MODE_PAGE_FLIP_EVENT;
23220 if (async)
23221@@ -1711,8 +1759,7 @@ intel_do_pageflip(intel_screen_private *intel,
23222
23223 flip = calloc(1, sizeof(struct intel_pageflip));
23224 if (flip == NULL) {
23225- xf86DrvMsg(scrn->scrnIndex, X_WARNING,
23226- "flip queue: carrier alloc failed.\n");
23227+ err = errno;
23228 goto error_undo;
23229 }
23230
23231@@ -1724,33 +1771,30 @@ intel_do_pageflip(intel_screen_private *intel,
23232
23233 seq = intel_drm_queue_alloc(scrn, config->crtc[i], flip, intel_pageflip_handler, intel_pageflip_abort);
23234 if (!seq) {
23235+ err = errno;
23236 free(flip);
23237 goto error_undo;
23238 }
23239
23240-again:
23241+ mode->flip_count++;
23242+
23243 if (drmModePageFlip(mode->fd,
23244 crtc_id(crtc),
23245 new_fb_id,
23246 flags, (void *)(uintptr_t)seq)) {
23247- if (intel_mode_read_drm_events(intel)) {
23248- xf86DrvMsg(scrn->scrnIndex, X_WARNING,
23249- "flip queue retry\n");
23250- goto again;
23251- }
23252- xf86DrvMsg(scrn->scrnIndex, X_WARNING,
23253- "flip queue failed: %s\n", strerror(errno));
23254- if (seq)
23255- intel_drm_abort_seq(scrn, seq);
23256- free(flip);
23257+ err = errno;
23258+ intel_drm_abort_seq(scrn, seq);
23259 goto error_undo;
23260 }
23261- mode->flip_count++;
23262 }
23263
23264 mode->old_fb_id = mode->fb_id;
23265 mode->fb_id = new_fb_id;
23266
23267+ mode->pageflip.data = pageflip_data;
23268+ mode->pageflip.handler = pageflip_handler;
23269+ mode->pageflip.abort = pageflip_abort;
23270+
23271 if (!mode->flip_count)
23272 intel_pageflip_complete(mode);
23273
23274@@ -1765,7 +1809,7 @@ error_undo:
23275
23276 error_out:
23277 xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
23278- strerror(errno));
23279+ strerror(err));
23280
23281 mode->flip_count = 0;
23282 return FALSE;
23283@@ -1839,7 +1883,7 @@ intel_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), v
23284 /*
23285 * Abort by drm queue sequence number
23286 */
23287-static void
23288+void
23289 intel_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq)
23290 {
23291 struct intel_drm_queue *q;
23292@@ -1911,7 +1955,6 @@ intel_sequence_to_crtc_msc(xf86CrtcPtr crtc, uint32_t sequence)
23293 {
23294 struct intel_crtc *intel_crtc = crtc->driver_private;
23295
23296- sequence += intel_crtc->vblank_offset;
23297 if ((int32_t) (sequence - intel_crtc->msc_prev) < -0x40000000)
23298 intel_crtc->msc_high += 0x100000000L;
23299 intel_crtc->msc_prev = sequence;
23300@@ -1935,37 +1978,10 @@ intel_get_crtc_msc_ust(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t *msc, uint64
23301 return 0;
23302 }
23303
23304-/*
23305- * Convert a 64-bit adjusted MSC value into a 32-bit kernel sequence number,
23306- * removing the high 32 bits and subtracting out the vblank_offset term.
23307- *
23308- * This also updates the vblank_offset when it notices that the value should
23309- * change.
23310- */
23311-
23312-#define MAX_VBLANK_OFFSET 1000
23313-
23314 uint32_t
23315 intel_crtc_msc_to_sequence(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t expect)
23316 {
23317- struct intel_crtc *intel_crtc = crtc->driver_private;
23318- uint64_t msc, ust;
23319-
23320- if (intel_get_crtc_msc_ust(scrn, crtc, &msc, &ust) == 0) {
23321- int64_t diff = expect - msc;
23322-
23323- /* We're way off here, assume that the kernel has lost its mind
23324- * and smack the vblank back to something sensible
23325- */
23326- if (diff < -MAX_VBLANK_OFFSET || diff > MAX_VBLANK_OFFSET) {
23327- intel_crtc->vblank_offset += (int32_t) diff;
23328- if (intel_crtc->vblank_offset > -MAX_VBLANK_OFFSET &&
23329- intel_crtc->vblank_offset < MAX_VBLANK_OFFSET)
23330- intel_crtc->vblank_offset = 0;
23331- }
23332- }
23333-
23334- return (uint32_t) (expect - intel_crtc->vblank_offset);
23335+ return (uint32_t)expect;
23336 }
23337
23338 /*
23339@@ -1998,14 +2014,13 @@ intel_drm_handler(int fd, uint32_t frame, uint32_t sec, uint32_t usec, void *use
23340 static void
23341 intel_pageflip_complete(struct intel_mode *mode)
23342 {
23343- /* Release framebuffer */
23344- drmModeRmFB(mode->fd, mode->old_fb_id);
23345-
23346- if (!mode->pageflip_handler)
23347+ if (!mode->pageflip.handler)
23348 return;
23349
23350- mode->pageflip_handler(mode->fe_msc, mode->fe_usec,
23351- mode->pageflip_data);
23352+ /* Release framebuffer */
23353+ drmModeRmFB(mode->fd, mode->old_fb_id);
23354+ mode->pageflip.handler(mode->fe_msc, mode->fe_usec,
23355+ mode->pageflip.data);
23356 }
23357
23358 /*
23359@@ -2045,6 +2060,7 @@ intel_pageflip_handler(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
23360
23361 if (!mode)
23362 return;
23363+
23364 intel_pageflip_complete(mode);
23365 }
23366
23367@@ -2060,13 +2076,12 @@ intel_pageflip_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data)
23368 if (!mode)
23369 return;
23370
23371- /* Release framebuffer */
23372- drmModeRmFB(mode->fd, mode->old_fb_id);
23373-
23374- if (!mode->pageflip_abort)
23375+ if (!mode->pageflip.abort)
23376 return;
23377
23378- mode->pageflip_abort(mode->pageflip_data);
23379+ /* Release framebuffer */
23380+ drmModeRmFB(mode->fd, mode->old_fb_id);
23381+ mode->pageflip.abort(mode->pageflip.data);
23382 }
23383
23384 /*
23385@@ -2231,10 +2246,6 @@ Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
23386 intel->use_pageflipping = TRUE;
23387 }
23388
23389- if (xf86ReturnOptValBool(intel->Options, OPTION_DELETE_DP12, FALSE)) {
23390- mode->delete_dp_12_displays = TRUE;
23391- }
23392-
23393 intel->modes = mode;
23394 drmModeFreeResources(mode_res);
23395 return TRUE;
23396@@ -2498,12 +2509,11 @@ intel_mode_hotplug(struct intel_screen_private *intel)
23397 int i, j;
23398 Bool found;
23399 Bool changed = FALSE;
23400- struct intel_mode *mode = intel->modes;
23401+
23402 mode_res = drmModeGetResources(intel->drmSubFD);
23403 if (!mode_res)
23404 goto out;
23405
23406-restart_destroy:
23407 for (i = 0; i < config->num_output; i++) {
23408 xf86OutputPtr output = config->output[i];
23409 struct intel_output *intel_output;
23410@@ -2522,13 +2532,9 @@ restart_destroy:
23411 drmModeFreeConnector(intel_output->mode_output);
23412 intel_output->mode_output = NULL;
23413 intel_output->output_id = -1;
23414+ RROutputChanged(output->randr_output, TRUE);
23415
23416 changed = TRUE;
23417- if (mode->delete_dp_12_displays) {
23418- RROutputDestroy(output->randr_output);
23419- xf86OutputDestroy(output);
23420- goto restart_destroy;
23421- }
23422 }
23423
23424 /* find new output ids we don't have outputs for */
23425@@ -2552,10 +2558,8 @@ restart_destroy:
23426 intel_output_init(scrn, intel->modes, mode_res, i, 1);
23427 }
23428
23429- if (changed) {
23430- RRSetChanged(xf86ScrnToScreen(scrn));
23431+ if (changed)
23432 RRTellChanged(xf86ScrnToScreen(scrn));
23433- }
23434
23435 drmModeFreeResources(mode_res);
23436 out:
23437diff --git a/src/uxa/intel_dri.c b/src/uxa/intel_dri.c
23438index f61c621..524826d 100644
23439--- a/src/uxa/intel_dri.c
23440+++ b/src/uxa/intel_dri.c
23441@@ -81,6 +81,47 @@ static DevPrivateKeyRec i830_client_key;
23442 static int i830_client_key;
23443 #endif
23444
23445+static void I830DRI2FlipEventHandler(unsigned int frame,
23446+ unsigned int tv_sec,
23447+ unsigned int tv_usec,
23448+ DRI2FrameEventPtr flip_info);
23449+
23450+static void I830DRI2FrameEventHandler(unsigned int frame,
23451+ unsigned int tv_sec,
23452+ unsigned int tv_usec,
23453+ DRI2FrameEventPtr swap_info);
23454+
23455+static void
23456+i830_dri2_del_frame_event(DRI2FrameEventPtr info);
23457+
23458+static uint32_t pipe_select(int pipe)
23459+{
23460+ if (pipe > 1)
23461+ return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
23462+ else if (pipe > 0)
23463+ return DRM_VBLANK_SECONDARY;
23464+ else
23465+ return 0;
23466+}
23467+
23468+static void
23469+intel_dri2_vblank_handler(ScrnInfoPtr scrn,
23470+ xf86CrtcPtr crtc,
23471+ uint64_t msc,
23472+ uint64_t usec,
23473+ void *data)
23474+{
23475+ I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, data);
23476+}
23477+
23478+static void
23479+intel_dri2_vblank_abort(ScrnInfoPtr scrn,
23480+ xf86CrtcPtr crtc,
23481+ void *data)
23482+{
23483+ i830_dri2_del_frame_event(data);
23484+}
23485+
23486 static uint32_t pixmap_flink(PixmapPtr pixmap)
23487 {
23488 struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(pixmap);
23489@@ -135,9 +176,6 @@ I830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments,
23490 pixmap = NULL;
23491 if (attachments[i] == DRI2BufferFrontLeft) {
23492 pixmap = get_front_buffer(drawable);
23493-
23494- if (pixmap == NULL)
23495- drawable = &(get_drawable_pixmap(drawable)->drawable);
23496 } else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) {
23497 pixmap = pDepthPixmap;
23498 pixmap->refcnt++;
23499@@ -246,11 +284,8 @@ I830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment,
23500 }
23501
23502 pixmap = NULL;
23503- if (attachment == DRI2BufferFrontLeft) {
23504+ if (attachment == DRI2BufferFrontLeft)
23505 pixmap = get_front_buffer(drawable);
23506- if (pixmap == NULL)
23507- drawable = &(get_drawable_pixmap(drawable)->drawable);
23508- }
23509
23510 if (pixmap == NULL) {
23511 unsigned int hint = INTEL_CREATE_PIXMAP_DRI2;
23512@@ -673,6 +708,20 @@ i830_dri2_del_frame_event(DRI2FrameEventPtr info)
23513 if (info->back)
23514 I830DRI2DestroyBuffer(NULL, info->back);
23515
23516+ if (info->old_buffer) {
23517+ /* Check that the old buffer still matches the front buffer
23518+ * in case a mode change occurred before we woke up.
23519+ */
23520+ if (info->intel->back_buffer == NULL &&
23521+ info->old_width == info->intel->scrn->virtualX &&
23522+ info->old_height == info->intel->scrn->virtualY &&
23523+ info->old_pitch == info->intel->front_pitch &&
23524+ info->old_tiling == info->intel->front_tiling)
23525+ info->intel->back_buffer = info->old_buffer;
23526+ else
23527+ dri_bo_unreference(info->old_buffer);
23528+ }
23529+
23530 free(info);
23531 }
23532
23533@@ -708,16 +757,14 @@ static void
23534 I830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front, DRI2BufferPtr back)
23535 {
23536 I830DRI2BufferPrivatePtr front_priv, back_priv;
23537- int tmp;
23538 struct intel_uxa_pixmap *new_front;
23539
23540 front_priv = front->driverPrivate;
23541 back_priv = back->driverPrivate;
23542
23543 /* Swap BO names so DRI works */
23544- tmp = front->name;
23545 front->name = back->name;
23546- back->name = tmp;
23547+ back->name = pixmap_flink(front_priv->pixmap);
23548
23549 /* Swap pixmap bos */
23550 new_front = intel_exchange_pixmap_buffers(intel,
23551@@ -753,87 +800,30 @@ I830DRI2FlipAbort(void *pageflip_data)
23552 i830_dri2_del_frame_event(info);
23553 }
23554
23555-/*
23556- * Our internal swap routine takes care of actually exchanging, blitting, or
23557- * flipping buffers as necessary.
23558- */
23559 static Bool
23560-I830DRI2ScheduleFlip(struct intel_screen_private *intel,
23561- DrawablePtr draw,
23562- DRI2FrameEventPtr info)
23563+allocate_back_buffer(struct intel_screen_private *intel)
23564 {
23565- I830DRI2BufferPrivatePtr priv = info->back->driverPrivate;
23566- drm_intel_bo *new_back, *old_back;
23567- int tmp_name;
23568-
23569- if (!intel->use_triple_buffer) {
23570- info->type = DRI2_SWAP;
23571- if (!intel_do_pageflip(intel,
23572- get_pixmap_bo(priv),
23573- info->pipe, FALSE, info,
23574- I830DRI2FlipComplete,
23575- I830DRI2FlipAbort))
23576- return FALSE;
23577-
23578- I830DRI2ExchangeBuffers(intel, info->front, info->back);
23579- return TRUE;
23580- }
23581+ drm_intel_bo *bo;
23582+ int pitch;
23583+ uint32_t tiling;
23584
23585- if (intel->pending_flip[info->pipe]) {
23586- assert(intel->pending_flip[info->pipe]->chain == NULL);
23587- intel->pending_flip[info->pipe]->chain = info;
23588+ if (intel->back_buffer)
23589 return TRUE;
23590- }
23591
23592- if (intel->back_buffer == NULL) {
23593- new_back = drm_intel_bo_alloc(intel->bufmgr, "front buffer",
23594- intel->front_buffer->size, 0);
23595- if (new_back == NULL)
23596- return FALSE;
23597-
23598- if (intel->front_tiling != I915_TILING_NONE) {
23599- uint32_t tiling = intel->front_tiling;
23600- drm_intel_bo_set_tiling(new_back, &tiling, intel->front_pitch);
23601- if (tiling != intel->front_tiling) {
23602- drm_intel_bo_unreference(new_back);
23603- return FALSE;
23604- }
23605- }
23606-
23607- drm_intel_bo_disable_reuse(new_back);
23608- dri_bo_flink(new_back, &intel->back_name);
23609- } else {
23610- new_back = intel->back_buffer;
23611- intel->back_buffer = NULL;
23612- }
23613+ bo = intel_allocate_framebuffer(intel->scrn,
23614+ intel->scrn->virtualX,
23615+ intel->scrn->virtualY,
23616+ intel->cpp,
23617+ &pitch, &tiling);
23618+ if (bo == NULL)
23619+ return FALSE;
23620
23621- old_back = get_pixmap_bo(priv);
23622- if (!intel_do_pageflip(intel, old_back, info->pipe, FALSE, info, I830DRI2FlipComplete, I830DRI2FlipAbort)) {
23623- intel->back_buffer = new_back;
23624+ if (pitch != intel->front_pitch || tiling != intel->front_tiling) {
23625+ drm_intel_bo_unreference(bo);
23626 return FALSE;
23627 }
23628- info->type = DRI2_SWAP_CHAIN;
23629- intel->pending_flip[info->pipe] = info;
23630-
23631- priv = info->front->driverPrivate;
23632-
23633- /* Exchange the current front-buffer with the fresh bo */
23634-
23635- intel->back_buffer = intel->front_buffer;
23636- drm_intel_bo_reference(intel->back_buffer);
23637- intel_set_pixmap_bo(priv->pixmap, new_back);
23638- drm_intel_bo_unreference(new_back);
23639-
23640- tmp_name = info->front->name;
23641- info->front->name = intel->back_name;
23642- intel->back_name = tmp_name;
23643
23644- /* Then flip DRI2 pointers and update the screen pixmap */
23645- I830DRI2ExchangeBuffers(intel, info->front, info->back);
23646- DRI2SwapComplete(info->client, draw, 0, 0, 0,
23647- DRI2_EXCHANGE_COMPLETE,
23648- info->event_complete,
23649- info->event_data);
23650+ intel->back_buffer = bo;
23651 return TRUE;
23652 }
23653
23654@@ -889,8 +879,88 @@ can_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back)
23655 return TRUE;
23656 }
23657
23658-void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
23659- unsigned int tv_usec, DRI2FrameEventPtr swap_info)
23660+static Bool
23661+queue_flip(struct intel_screen_private *intel,
23662+ DrawablePtr draw,
23663+ DRI2FrameEventPtr info)
23664+{
23665+ xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
23666+ I830DRI2BufferPrivatePtr priv = info->back->driverPrivate;
23667+ drm_intel_bo *old_back = get_pixmap_bo(priv);
23668+
23669+ if (crtc == NULL)
23670+ return FALSE;
23671+
23672+ if (!can_exchange(draw, info->front, info->back))
23673+ return FALSE;
23674+
23675+ if (!intel_do_pageflip(intel, old_back,
23676+ intel_crtc_to_pipe(crtc),
23677+ FALSE, info,
23678+ I830DRI2FlipComplete, I830DRI2FlipAbort))
23679+ return FALSE;
23680+
23681+#if DRI2INFOREC_VERSION >= 6
23682+ if (intel->use_triple_buffer && allocate_back_buffer(intel)) {
23683+ info->old_width = intel->scrn->virtualX;
23684+ info->old_height = intel->scrn->virtualY;
23685+ info->old_pitch = intel->front_pitch;
23686+ info->old_tiling = intel->front_tiling;
23687+ info->old_buffer = intel->front_buffer;
23688+ dri_bo_reference(info->old_buffer);
23689+
23690+ priv = info->front->driverPrivate;
23691+ intel_set_pixmap_bo(priv->pixmap, intel->back_buffer);
23692+
23693+ dri_bo_unreference(intel->back_buffer);
23694+ intel->back_buffer = NULL;
23695+
23696+ DRI2SwapLimit(draw, 2);
23697+ } else
23698+ DRI2SwapLimit(draw, 1);
23699+#endif
23700+
23701+ /* Then flip DRI2 pointers and update the screen pixmap */
23702+ I830DRI2ExchangeBuffers(intel, info->front, info->back);
23703+ return TRUE;
23704+}
23705+
23706+static Bool
23707+queue_swap(struct intel_screen_private *intel,
23708+ DrawablePtr draw,
23709+ DRI2FrameEventPtr info)
23710+{
23711+ xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
23712+ drmVBlank vbl;
23713+
23714+ if (crtc == NULL)
23715+ return FALSE;
23716+
23717+ vbl.request.type =
23718+ DRM_VBLANK_RELATIVE |
23719+ DRM_VBLANK_EVENT |
23720+ pipe_select(intel_crtc_to_pipe(crtc));
23721+ vbl.request.sequence = 1;
23722+ vbl.request.signal =
23723+ intel_drm_queue_alloc(intel->scrn, crtc, info,
23724+ intel_dri2_vblank_handler,
23725+ intel_dri2_vblank_abort);
23726+ if (vbl.request.signal == 0)
23727+ return FALSE;
23728+
23729+ info->type = DRI2_SWAP;
23730+ if (drmWaitVBlank(intel->drmSubFD, &vbl)) {
23731+ intel_drm_abort_seq(intel->scrn, vbl.request.signal);
23732+ return FALSE;
23733+ }
23734+
23735+ return TRUE;
23736+}
23737+
23738+static void I830DRI2FrameEventHandler(unsigned int frame,
23739+ unsigned int tv_sec,
23740+ unsigned int tv_usec,
23741+ DRI2FrameEventPtr swap_info)
23742 {
23743 intel_screen_private *intel = swap_info->intel;
23744 DrawablePtr drawable;
23745@@ -906,24 +976,22 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
23746 return;
23747 }
23748
23749-
23750 switch (swap_info->type) {
23751 case DRI2_FLIP:
23752 /* If we can still flip... */
23753- if (can_exchange(drawable, swap_info->front, swap_info->back) &&
23754- I830DRI2ScheduleFlip(intel, drawable, swap_info))
23755- return;
23756-
23757- /* else fall through to exchange/blit */
23758- case DRI2_SWAP: {
23759- I830DRI2FallbackBlitSwap(drawable,
23760- swap_info->front, swap_info->back);
23761- DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec,
23762- DRI2_BLIT_COMPLETE,
23763- swap_info->client ? swap_info->event_complete : NULL,
23764- swap_info->event_data);
23765- break;
23766- }
23767+ if (!queue_flip(intel, drawable, swap_info) &&
23768+ !queue_swap(intel, drawable, swap_info)) {
23769+ case DRI2_SWAP:
23770+ I830DRI2FallbackBlitSwap(drawable,
23771+ swap_info->front, swap_info->back);
23772+ DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec,
23773+ DRI2_BLIT_COMPLETE,
23774+ swap_info->client ? swap_info->event_complete : NULL,
23775+ swap_info->event_data);
23776+ break;
23777+ }
23778+ return;
23779+
23780 case DRI2_WAITMSC:
23781 if (swap_info->client)
23782 DRI2WaitMSCComplete(swap_info->client, drawable,
23783@@ -939,12 +1007,13 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
23784 i830_dri2_del_frame_event(swap_info);
23785 }
23786
23787-void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
23788- unsigned int tv_usec, DRI2FrameEventPtr flip_info)
23789+static void I830DRI2FlipEventHandler(unsigned int frame,
23790+ unsigned int tv_sec,
23791+ unsigned int tv_usec,
23792+ DRI2FrameEventPtr flip_info)
23793 {
23794 struct intel_screen_private *intel = flip_info->intel;
23795 DrawablePtr drawable;
23796- DRI2FrameEventPtr chain;
23797
23798 drawable = NULL;
23799 if (flip_info->drawable_id)
23800@@ -954,6 +1023,7 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
23801
23802 /* We assume our flips arrive in order, so we don't check the frame */
23803 switch (flip_info->type) {
23804+ case DRI2_FLIP:
23805 case DRI2_SWAP:
23806 if (!drawable)
23807 break;
23808@@ -984,35 +1054,6 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
23809 flip_info->event_data);
23810 break;
23811
23812- case DRI2_SWAP_CHAIN:
23813- assert(intel->pending_flip[flip_info->pipe] == flip_info);
23814- intel->pending_flip[flip_info->pipe] = NULL;
23815-
23816- chain = flip_info->chain;
23817- if (chain) {
23818- DrawablePtr chain_drawable = NULL;
23819- if (chain->drawable_id)
23820- dixLookupDrawable(&chain_drawable,
23821- chain->drawable_id,
23822- serverClient,
23823- M_ANY, DixWriteAccess);
23824- if (chain_drawable == NULL) {
23825- i830_dri2_del_frame_event(chain);
23826- } else if (!can_exchange(chain_drawable, chain->front, chain->back) ||
23827- !I830DRI2ScheduleFlip(intel, chain_drawable, chain)) {
23828- I830DRI2FallbackBlitSwap(chain_drawable,
23829- chain->front,
23830- chain->back);
23831-
23832- DRI2SwapComplete(chain->client, chain_drawable, frame, tv_sec, tv_usec,
23833- DRI2_BLIT_COMPLETE,
23834- chain->client ? chain->event_complete : NULL,
23835- chain->event_data);
23836- i830_dri2_del_frame_event(chain);
23837- }
23838- }
23839- break;
23840-
23841 default:
23842 xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
23843 "%s: unknown vblank event received\n", __func__);
23844@@ -1023,38 +1064,6 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
23845 i830_dri2_del_frame_event(flip_info);
23846 }
23847
23848-static uint32_t pipe_select(int pipe)
23849-{
23850- if (pipe > 1)
23851- return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
23852- else if (pipe > 0)
23853- return DRM_VBLANK_SECONDARY;
23854- else
23855- return 0;
23856-}
23857-
23858-static void
23859-intel_dri2_vblank_handler(ScrnInfoPtr scrn,
23860- xf86CrtcPtr crtc,
23861- uint64_t msc,
23862- uint64_t usec,
23863- void *data)
23864-{
23865- DRI2FrameEventPtr swap_info = data;
23866-
23867- I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, swap_info);
23868-}
23869-
23870-static void
23871-intel_dri2_vblank_abort(ScrnInfoPtr scrn,
23872- xf86CrtcPtr crtc,
23873- void *data)
23874-{
23875- DRI2FrameEventPtr swap_info = data;
23876-
23877- i830_dri2_del_frame_event(swap_info);
23878-}
23879-
23880 /*
23881 * ScheduleSwap is responsible for requesting a DRM vblank event for the
23882 * appropriate frame.
23883@@ -1089,7 +1098,6 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
23884 int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
23885 int flip = 0;
23886 DRI2FrameEventPtr swap_info = NULL;
23887- enum DRI2FrameEventType swap_type = DRI2_SWAP;
23888 uint64_t current_msc, current_ust;
23889 uint64_t request_msc;
23890 uint32_t seq;
23891@@ -1109,7 +1117,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
23892 swap_info->event_data = data;
23893 swap_info->front = front;
23894 swap_info->back = back;
23895- swap_info->pipe = pipe;
23896+ swap_info->type = DRI2_SWAP;
23897
23898 if (!i830_dri2_add_frame_event(swap_info)) {
23899 free(swap_info);
23900@@ -1124,20 +1132,27 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
23901 if (ret)
23902 goto blit_fallback;
23903
23904- /* Flips need to be submitted one frame before */
23905+ /*
23906+ * If we can, schedule the flip directly from here rather
23907+ * than waiting for an event from the kernel for the current
23908+ * (or a past) MSC.
23909+ */
23910+ if (divisor == 0 &&
23911+ current_msc >= *target_msc &&
23912+ queue_flip(intel, draw, swap_info))
23913+ return TRUE;
23914+
23915 if (can_exchange(draw, front, back)) {
23916- swap_type = DRI2_FLIP;
23917- flip = 1;
23918+ swap_info->type = DRI2_FLIP;
23919+ /* Flips need to be submitted one frame before */
23920+ if (*target_msc > 0)
23921+ --*target_msc;
23922+ flip = 1;
23923 }
23924
23925- swap_info->type = swap_type;
23926-
23927- /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
23928- * Do it early, so handling of different timing constraints
23929- * for divisor, remainder and msc vs. target_msc works.
23930- */
23931- if (*target_msc > 0)
23932- *target_msc -= flip;
23933+#if DRI2INFOREC_VERSION >= 6
23934+ DRI2SwapLimit(draw, 1);
23935+#endif
23936
23937 /*
23938 * If divisor is zero, or current_msc is smaller than target_msc
23939@@ -1145,15 +1160,6 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
23940 * the swap.
23941 */
23942 if (divisor == 0 || current_msc < *target_msc) {
23943- /*
23944- * If we can, schedule the flip directly from here rather
23945- * than waiting for an event from the kernel for the current
23946- * (or a past) MSC.
23947- */
23948- if (flip && divisor == 0 && current_msc >= *target_msc &&
23949- I830DRI2ScheduleFlip(intel, draw, swap_info))
23950- return TRUE;
23951-
23952 vbl.request.type =
23953 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
23954
23955@@ -1168,7 +1174,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
23956 * current_msc to ensure we return a reasonable value back
23957 * to the caller. This makes swap_interval logic more robust.
23958 */
23959- if (current_msc >= *target_msc)
23960+ if (current_msc > *target_msc)
23961 *target_msc = current_msc;
23962
23963 seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
23964@@ -1183,6 +1189,8 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
23965 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
23966 "divisor 0 get vblank counter failed: %s\n",
23967 strerror(errno));
23968+ intel_drm_abort_seq(intel->scrn, seq);
23969+ swap_info = NULL;
23970 goto blit_fallback;
23971 }
23972
23973@@ -1332,7 +1340,6 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
23974
23975 if (!i830_dri2_add_frame_event(wait_info)) {
23976 free(wait_info);
23977- wait_info = NULL;
23978 goto out_complete;
23979 }
23980
23981@@ -1374,7 +1381,8 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
23982 strerror(errno));
23983 limit--;
23984 }
23985- goto out_free;
23986+ intel_drm_abort_seq(intel->scrn, seq);
23987+ goto out_complete;
23988 }
23989
23990 wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
23991@@ -1417,7 +1425,8 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
23992 strerror(errno));
23993 limit--;
23994 }
23995- goto out_free;
23996+ intel_drm_abort_seq(intel->scrn, seq);
23997+ goto out_complete;
23998 }
23999
24000 wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
24001@@ -1440,13 +1449,92 @@ static int has_i830_dri(void)
24002 return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0;
24003 }
24004
24005-static const char *dri_driver_name(intel_screen_private *intel)
24006+static int
24007+namecmp(const char *s1, const char *s2)
24008+{
24009+ char c1, c2;
24010+
24011+ if (!s1 || *s1 == 0) {
24012+ if (!s2 || *s2 == 0)
24013+ return 0;
24014+ else
24015+ return 1;
24016+ }
24017+
24018+ while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
24019+ s1++;
24020+
24021+ while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
24022+ s2++;
24023+
24024+ c1 = isupper(*s1) ? tolower(*s1) : *s1;
24025+ c2 = isupper(*s2) ? tolower(*s2) : *s2;
24026+ while (c1 == c2) {
24027+ if (c1 == '\0')
24028+ return 0;
24029+
24030+ s1++;
24031+ while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
24032+ s1++;
24033+
24034+ s2++;
24035+ while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
24036+ s2++;
24037+
24038+ c1 = isupper(*s1) ? tolower(*s1) : *s1;
24039+ c2 = isupper(*s2) ? tolower(*s2) : *s2;
24040+ }
24041+
24042+ return c1 - c2;
24043+}
24044+
24045+static Bool is_level(const char **str)
24046+{
24047+ const char *s = *str;
24048+ char *end;
24049+ unsigned val;
24050+
24051+ if (s == NULL || *s == '\0')
24052+ return TRUE;
24053+
24054+ if (namecmp(s, "on") == 0)
24055+ return TRUE;
24056+ if (namecmp(s, "true") == 0)
24057+ return TRUE;
24058+ if (namecmp(s, "yes") == 0)
24059+ return TRUE;
24060+
24061+ if (namecmp(s, "0") == 0)
24062+ return TRUE;
24063+ if (namecmp(s, "off") == 0)
24064+ return TRUE;
24065+ if (namecmp(s, "false") == 0)
24066+ return TRUE;
24067+ if (namecmp(s, "no") == 0)
24068+ return TRUE;
24069+
24070+ val = strtoul(s, &end, 0);
24071+ if (val && *end == '\0')
24072+ return TRUE;
24073+ if (val && *end == ':')
24074+ *str = end + 1;
24075+ return FALSE;
24076+}
24077+
24078+static const char *options_get_dri(intel_screen_private *intel)
24079 {
24080 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
24081- const char *s = xf86GetOptValString(intel->Options, OPTION_DRI);
24082- Bool dummy;
24083+ return xf86GetOptValString(intel->Options, OPTION_DRI);
24084+#else
24085+ return NULL;
24086+#endif
24087+}
24088
24089- if (s == NULL || xf86getBoolValue(&dummy, s)) {
24090+static const char *dri_driver_name(intel_screen_private *intel)
24091+{
24092+ const char *s = options_get_dri(intel);
24093+
24094+ if (is_level(&s)) {
24095 if (INTEL_INFO(intel)->gen < 030)
24096 return has_i830_dri() ? "i830" : "i915";
24097 else if (INTEL_INFO(intel)->gen < 040)
24098@@ -1456,14 +1544,6 @@ static const char *dri_driver_name(intel_screen_private *intel)
24099 }
24100
24101 return s;
24102-#else
24103- if (INTEL_INFO(intel)->gen < 030)
24104- return has_i830_dri() ? "i830" : "i915";
24105- else if (INTEL_INFO(intel)->gen < 040)
24106- return "i915";
24107- else
24108- return "i965";
24109-#endif
24110 }
24111
24112 Bool I830DRI2ScreenInit(ScreenPtr screen)
24113@@ -1544,7 +1624,7 @@ Bool I830DRI2ScreenInit(ScreenPtr screen)
24114 info.numDrivers = 2;
24115 info.driverNames = driverNames;
24116 driverNames[0] = info.driverName;
24117- driverNames[1] = info.driverName;
24118+ driverNames[1] = "va_gl";
24119 #endif
24120
24121 return DRI2ScreenInit(screen, &info);
24122diff --git a/src/uxa/intel_driver.c b/src/uxa/intel_driver.c
24123index 2793da5..8f76b34 100644
24124--- a/src/uxa/intel_driver.c
24125+++ b/src/uxa/intel_driver.c
24126@@ -237,24 +237,17 @@ static Bool I830GetEarlyOptions(ScrnInfoPtr scrn)
24127 return TRUE;
24128 }
24129
24130-static Bool intel_option_cast_string_to_bool(intel_screen_private *intel,
24131- int id, Bool val)
24132-{
24133-#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
24134- xf86getBoolValue(&val, xf86GetOptValString(intel->Options, id));
24135- return val;
24136-#else
24137- return val;
24138-#endif
24139-}
24140-
24141 static void intel_check_dri_option(ScrnInfoPtr scrn)
24142 {
24143 intel_screen_private *intel = intel_get_screen_private(scrn);
24144+ unsigned level;
24145
24146 intel->dri2 = intel->dri3 = DRI_NONE;
24147- if (!intel_option_cast_string_to_bool(intel, OPTION_DRI, TRUE))
24148- intel->dri2 = intel->dri3 = DRI_DISABLED;
24149+ level = intel_option_cast_to_unsigned(intel->Options, OPTION_DRI, DEFAULT_DRI_LEVEL);
24150+ if (level < 3)
24151+ intel->dri3 = DRI_DISABLED;
24152+ if (level < 2)
24153+ intel->dri2 = DRI_DISABLED;
24154
24155 if (scrn->depth != 16 && scrn->depth != 24 && scrn->depth != 30) {
24156 xf86DrvMsg(scrn->scrnIndex, X_CONFIG,
24157@@ -371,8 +364,8 @@ static Bool can_accelerate_blt(struct intel_screen_private *intel)
24158 if (INTEL_INFO(intel)->gen == -1)
24159 return FALSE;
24160
24161- if (xf86ReturnOptValBool(intel->Options, OPTION_ACCEL_DISABLE, FALSE) ||
24162- !intel_option_cast_string_to_bool(intel, OPTION_ACCEL_METHOD, TRUE)) {
24163+ if (!xf86ReturnOptValBool(intel->Options, OPTION_ACCEL_ENABLE, TRUE) ||
24164+ !intel_option_cast_to_bool(intel->Options, OPTION_ACCEL_METHOD, TRUE)) {
24165 xf86DrvMsg(intel->scrn->scrnIndex, X_CONFIG,
24166 "Disabling hardware acceleration.\n");
24167 return FALSE;
24168@@ -735,6 +728,8 @@ intel_flush_callback(CallbackListPtr *list,
24169 }
24170
24171 #if HAVE_UDEV
24172+#include <sys/stat.h>
24173+
24174 static void
24175 I830HandleUEvents(int fd, void *closure)
24176 {
24177@@ -771,6 +766,15 @@ I830HandleUEvents(int fd, void *closure)
24178 udev_device_unref(dev);
24179 }
24180
24181+static int has_randr(void)
24182+{
24183+#if HAS_DIXREGISTERPRIVATEKEY
24184+ return dixPrivateKeyRegistered(rrPrivKey);
24185+#else
24186+ return *rrPrivKey;
24187+#endif
24188+}
24189+
24190 static void
24191 I830UeventInit(ScrnInfoPtr scrn)
24192 {
24193@@ -780,6 +784,10 @@ I830UeventInit(ScrnInfoPtr scrn)
24194 Bool hotplug;
24195 MessageType from = X_CONFIG;
24196
24197+ /* Without RR, nothing we can do here */
24198+ if (!has_randr())
24199+ return;
24200+
24201 if (!xf86GetOptValBool(intel->Options, OPTION_HOTPLUG, &hotplug)) {
24202 from = X_DEFAULT;
24203 hotplug = TRUE;
24204diff --git a/src/uxa/intel_hwmc.c b/src/uxa/intel_hwmc.c
24205index 829cb8e..7854060 100644
24206--- a/src/uxa/intel_hwmc.c
24207+++ b/src/uxa/intel_hwmc.c
24208@@ -193,7 +193,7 @@ Bool intel_xvmc_adaptor_init(ScreenPtr pScreen)
24209 intel_screen_private *intel = intel_get_screen_private(scrn);
24210 struct pci_device *pci;
24211 static XF86MCAdaptorRec *pAdapt;
24212- char *name;
24213+ const char *name;
24214 char buf[64];
24215
24216 if (!intel->XvMCEnabled)
24217diff --git a/src/uxa/intel_memory.c b/src/uxa/intel_memory.c
24218index 0c6cf30..b2d7a36 100644
24219--- a/src/uxa/intel_memory.c
24220+++ b/src/uxa/intel_memory.c
24221@@ -42,7 +42,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24222 * This is the video memory allocator. Our memory allocation is different from
24223 * other graphics chips, where you have a fixed amount of graphics memory
24224 * available that you want to put to the best use. Instead, we have almost no
24225- * memory pre-allocated, and we have to choose an appropriate amount of sytem
24226+ * memory pre-allocated, and we have to choose an appropriate amount of system
24227 * memory to use.
24228 *
24229 * The allocations we might do:
24230diff --git a/src/uxa/intel_present.c b/src/uxa/intel_present.c
24231index d20043f..a7f904c 100644
24232--- a/src/uxa/intel_present.c
24233+++ b/src/uxa/intel_present.c
24234@@ -343,29 +343,33 @@ intel_present_unflip(ScreenPtr screen, uint64_t event_id)
24235 {
24236 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
24237 intel_screen_private *intel = intel_get_screen_private(scrn);
24238- struct intel_present_vblank_event *event;
24239 PixmapPtr pixmap = screen->GetScreenPixmap(screen);
24240+ struct intel_present_vblank_event *event = NULL;
24241 dri_bo *bo;
24242- Bool ret;
24243
24244 if (!intel_present_check_flip(NULL, screen->root, pixmap, true))
24245- return;
24246+ goto fail;
24247
24248 bo = intel_get_pixmap_bo(pixmap);
24249 if (!bo)
24250- return;
24251+ goto fail;
24252
24253 event = calloc(1, sizeof(struct intel_present_vblank_event));
24254 if (!event)
24255- return;
24256+ goto fail;
24257
24258 event->event_id = event_id;
24259
24260- ret = intel_do_pageflip(intel, bo, -1, FALSE, event, intel_present_flip_event, intel_present_flip_abort);
24261- if (!ret) {
24262- xf86DrvMsg(scrn->scrnIndex, X_ERROR,
24263- "present unflip failed\n");
24264- }
24265+ if (!intel_do_pageflip(intel, bo, -1, FALSE, event,
24266+ intel_present_flip_event,
24267+ intel_present_flip_abort))
24268+ goto fail;
24269+
24270+ return;
24271+fail:
24272+ xf86SetDesiredModes(scrn);
24273+ present_event_notify(event_id, 0, 0);
24274+ free(event);
24275 }
24276
24277 static present_screen_info_rec intel_present_screen_info = {
24278diff --git a/test/Makefile.am b/test/Makefile.am
24279index 66ed8eb..7d88810 100644
24280--- a/test/Makefile.am
24281+++ b/test/Makefile.am
24282@@ -5,6 +5,7 @@ stress_TESTS = \
24283 basic-rectangle \
24284 basic-string \
24285 basic-copyarea \
24286+ basic-copyplane \
24287 basic-copyarea-size \
24288 basic-putimage \
24289 basic-lines \
24290@@ -12,8 +13,10 @@ stress_TESTS = \
24291 DrawSegments \
24292 cursor-test \
24293 render-fill \
24294+ render-glyphs \
24295 render-trapezoid \
24296 render-trapezoid-image \
24297+ render-triangle \
24298 render-fill-copy \
24299 render-composite-solid \
24300 render-composite-solid-mask \
24301@@ -28,6 +31,7 @@ stress_TESTS = \
24302 if DRI2
24303 stress_TESTS += \
24304 dri2-race \
24305+ dri2-speed \
24306 dri2-swap \
24307 dri2-test \
24308 $(NULL)
24309@@ -37,6 +41,7 @@ if X11_DRI3
24310 stress_TESTS += \
24311 dri3-test \
24312 present-test \
24313+ present-speed \
24314 $(NULL)
24315 endif
24316 check_PROGRAMS = $(stress_TESTS)
24317diff --git a/test/basic-copyplane.c b/test/basic-copyplane.c
24318new file mode 100644
24319index 0000000..f049b82
24320--- /dev/null
24321+++ b/test/basic-copyplane.c
24322@@ -0,0 +1,99 @@
24323+#include <stdint.h>
24324+#include <stdio.h>
24325+#include <stdlib.h>
24326+
24327+#include <X11/Xutil.h> /* for XDestroyImage */
24328+#include <pixman.h> /* for pixman blt functions */
24329+
24330+#include "test.h"
24331+
24332+static uint8_t clock_bits[] = {0x3C, 0x5E, 0xEF, 0xF7, 0x87, 0xFF, 0x7E, 0x3C};
24333+
24334+/* https://bugs.freedesktop.org/show_bug.cgi?id=91499 */
24335+static void draw_clock(struct test_display *t, Drawable d,
24336+ uint8_t alu, int x, int y, uint32_t fg, uint32_t bg)
24337+{
24338+ Pixmap pixmap;
24339+ XGCValues val;
24340+ GC gc;
24341+
24342+ val.graphics_exposures = 0;
24343+ val.function = alu;
24344+ val.foreground = fg;
24345+ val.background = fg;
24346+
24347+ gc = XCreateGC(t->dpy, d,
24348+ GCGraphicsExposures | GCForeground | GCBackground | GCFunction,
24349+ &val);
24350+ pixmap = XCreateBitmapFromData(t->dpy, d, (char *)clock_bits, 8, 8);
24351+
24352+ XCopyPlane(t->dpy, pixmap, d, gc, 0, 0, 8, 8, x, y, 1);
24353+
24354+ XFreePixmap(t->dpy, pixmap);
24355+ XFreeGC(t->dpy, gc);
24356+}
24357+
24358+static void clear(struct test_display *dpy, struct test_target *tt)
24359+{
24360+ XRenderColor render_color = {0};
24361+ XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color,
24362+ 0, 0, tt->width, tt->height);
24363+}
24364+
24365+static void clock_tests(struct test *t, int reps, int sets, enum target target)
24366+{
24367+ struct test_target out, ref;
24368+ int r, s;
24369+
24370+ printf("Testing clock (%s): ", test_target_name(target));
24371+ fflush(stdout);
24372+
24373+ test_target_create_render(&t->out, target, &out);
24374+ clear(&t->out, &out);
24375+
24376+ test_target_create_render(&t->ref, target, &ref);
24377+ clear(&t->ref, &ref);
24378+
24379+ for (s = 0; s < sets; s++) {
24380+ for (r = 0; r < reps; r++) {
24381+ int x = rand() % (out.width - 8);
24382+ int y = rand() % (out.height - 8);
24383+ uint8_t alu = rand() % (GXset + 1);
24384+ uint32_t bg = rand();
24385+ uint32_t fg = rand();
24386+
24387+ draw_clock(&t->out, out.draw, alu, x, y, fg, bg);
24388+ draw_clock(&t->ref, ref.draw, alu, x, y, fg, bg);
24389+ }
24390+
24391+ test_compare(t,
24392+ out.draw, out.format,
24393+ ref.draw, ref.format,
24394+ 0, 0, out.width, out.height,
24395+ "");
24396+ }
24397+
24398+ printf("passed [%d iterations x %d]\n", reps, sets);
24399+
24400+ test_target_destroy_render(&t->out, &out);
24401+ test_target_destroy_render(&t->ref, &ref);
24402+}
24403+
24404+int main(int argc, char **argv)
24405+{
24406+ struct test test;
24407+ int i;
24408+
24409+ test_init(&test, argc, argv);
24410+
24411+ for (i = 0; i <= DEFAULT_ITERATIONS; i++) {
24412+ int reps = REPS(i), sets = SETS(i);
24413+ enum target t;
24414+
24415+ for (t = TARGET_FIRST; t <= TARGET_LAST; t++) {
24416+ clock_tests(&test, reps, sets, t);
24417+ }
24418+ }
24419+
24420+ return 0;
24421+}
24422diff --git a/test/dri2-race.c b/test/dri2-race.c
24423index 8862c84..c589f2b 100644
24424--- a/test/dri2-race.c
24425+++ b/test/dri2-race.c
24426@@ -5,6 +5,10 @@
24427 #include <X11/Xlib.h>
24428 #include <X11/Xutil.h>
24429 #include <X11/extensions/Xfixes.h>
24430+#include <X11/Xlib-xcb.h>
24431+#include <xcb/xcb.h>
24432+#include <xcb/xcbext.h>
24433+#include <xcb/dri2.h>
24434 #include <unistd.h>
24435 #include <fcntl.h>
24436 #include <string.h>
24437@@ -17,6 +21,16 @@
24438
24439 #define COUNT 60
24440
24441+static uint32_t upper_32_bits(uint64_t val)
24442+{
24443+ return val >> 32;
24444+}
24445+
24446+static uint32_t lower_32_bits(uint64_t val)
24447+{
24448+ return val & 0xffffffff;
24449+}
24450+
24451 static int dri2_open(Display *dpy)
24452 {
24453 drm_auth_t auth;
24454@@ -41,15 +55,36 @@ static int dri2_open(Display *dpy)
24455 return fd;
24456 }
24457
24458-static void run(Display *dpy, int width, int height,
24459- unsigned int *attachments, int nattachments,
24460- const char *name)
24461+static void swap_buffers(Display *dpy, Window win, int divisor,
24462+ unsigned int *attachments, int nattachments)
24463+{
24464+ xcb_connection_t *c = XGetXCBConnection(dpy);
24465+ unsigned int seq[2];
24466+
24467+ seq[0] = xcb_dri2_swap_buffers_unchecked(c, win,
24468+ 0, 0, 0, divisor, 0, 0).sequence;
24469+
24470+
24471+ seq[1] = xcb_dri2_get_buffers_unchecked(c, win,
24472+ nattachments, nattachments,
24473+ attachments).sequence;
24474+
24475+ xcb_flush(c);
24476+ xcb_discard_reply(c, seq[0]);
24477+ xcb_discard_reply(c, seq[1]);
24478+}
24479+
24480+static void race_window(Display *dpy, int width, int height,
24481+ unsigned int *attachments, int nattachments,
24482+ const char *name)
24483 {
24484 Window win;
24485 XSetWindowAttributes attr;
24486 int count, loop;
24487 DRI2Buffer *buffers;
24488
24489+ printf("%s(%s)\n", __func__, name);
24490+
24491 /* Be nasty and install a fullscreen window on top so that we
24492 * can guarantee we do not get clipped by children.
24493 */
24494@@ -75,13 +110,234 @@ static void run(Display *dpy, int width, int height,
24495 for (count = 0; count < loop; count++)
24496 DRI2SwapBuffers(dpy, win, 0, 0, 0);
24497 XDestroyWindow(dpy, win);
24498+ printf("."); fflush(stdout);
24499+ } while (--loop);
24500+ printf("*\n");
24501+
24502+ loop = 100;
24503+ do {
24504+ win = XCreateWindow(dpy, DefaultRootWindow(dpy),
24505+ 0, 0, width, height, 0,
24506+ DefaultDepth(dpy, DefaultScreen(dpy)),
24507+ InputOutput,
24508+ DefaultVisual(dpy, DefaultScreen(dpy)),
24509+ CWOverrideRedirect, &attr);
24510+ XMapWindow(dpy, win);
24511+
24512+ DRI2CreateDrawable(dpy, win);
24513+
24514+ buffers = DRI2GetBuffers(dpy, win, &width, &height,
24515+ attachments, nattachments, &count);
24516+ if (count != nattachments)
24517+ return;
24518+
24519+ free(buffers);
24520+ for (count = 0; count < loop; count++)
24521+ DRI2SwapBuffers(dpy, win, 0, 1, 0);
24522+ XDestroyWindow(dpy, win);
24523+ printf("."); fflush(stdout);
24524+ } while (--loop);
24525+ printf("*\n");
24526+
24527+ loop = 100;
24528+ do {
24529+ win = XCreateWindow(dpy, DefaultRootWindow(dpy),
24530+ 0, 0, width, height, 0,
24531+ DefaultDepth(dpy, DefaultScreen(dpy)),
24532+ InputOutput,
24533+ DefaultVisual(dpy, DefaultScreen(dpy)),
24534+ CWOverrideRedirect, &attr);
24535+ XMapWindow(dpy, win);
24536+
24537+ DRI2CreateDrawable(dpy, win);
24538+
24539+ buffers = DRI2GetBuffers(dpy, win, &width, &height,
24540+ attachments, nattachments, &count);
24541+ if (count != nattachments)
24542+ return;
24543+
24544+ free(buffers);
24545+ for (count = 0; count < loop; count++)
24546+ swap_buffers(dpy, win, 0, attachments, nattachments);
24547+ XDestroyWindow(dpy, win);
24548+ printf("."); fflush(stdout);
24549+ } while (--loop);
24550+ printf("*\n");
24551+
24552+ loop = 100;
24553+ do {
24554+ win = XCreateWindow(dpy, DefaultRootWindow(dpy),
24555+ 0, 0, width, height, 0,
24556+ DefaultDepth(dpy, DefaultScreen(dpy)),
24557+ InputOutput,
24558+ DefaultVisual(dpy, DefaultScreen(dpy)),
24559+ CWOverrideRedirect, &attr);
24560+ XMapWindow(dpy, win);
24561+
24562+ DRI2CreateDrawable(dpy, win);
24563+
24564+ buffers = DRI2GetBuffers(dpy, win, &width, &height,
24565+ attachments, nattachments, &count);
24566+ if (count != nattachments)
24567+ return;
24568+
24569+ free(buffers);
24570+ for (count = 0; count < loop; count++)
24571+ swap_buffers(dpy, win, 1, attachments, nattachments);
24572+ XDestroyWindow(dpy, win);
24573+ printf("."); fflush(stdout);
24574+ } while (--loop);
24575+ printf("*\n");
24576+
24577+ loop = 100;
24578+ do {
24579+ uint64_t ignore, msc;
24580+ xcb_connection_t *c = XGetXCBConnection(dpy);
24581+
24582+ win = XCreateWindow(dpy, DefaultRootWindow(dpy),
24583+ 0, 0, width, height, 0,
24584+ DefaultDepth(dpy, DefaultScreen(dpy)),
24585+ InputOutput,
24586+ DefaultVisual(dpy, DefaultScreen(dpy)),
24587+ CWOverrideRedirect, &attr);
24588+ XMapWindow(dpy, win);
24589+
24590+ DRI2CreateDrawable(dpy, win);
24591+ DRI2GetMSC(dpy, win, &ignore, &msc, &ignore);
24592+ for (count = 0; count < loop; count++)
24593+ xcb_discard_reply(c,
24594+ xcb_dri2_wait_msc(c, win,
24595+ upper_32_bits(msc + count + 1),
24596+ lower_32_bits(msc + count + 1),
24597+ 0, 1, 0, 0).sequence);
24598+ XFlush(dpy);
24599+ XDestroyWindow(dpy, win);
24600+ printf("."); fflush(stdout);
24601 } while (--loop);
24602+ printf("*\n");
24603
24604 XSync(dpy, 1);
24605 sleep(2);
24606 XSync(dpy, 1);
24607 }
24608
24609+static void race_client(int width, int height,
24610+ unsigned int *attachments, int nattachments,
24611+ const char *name)
24612+{
24613+ XSetWindowAttributes attr;
24614+ int count, loop;
24615+
24616+ printf("%s(%s)\n", __func__, name);
24617+
24618+ /* Be nasty and install a fullscreen window on top so that we
24619+ * can guarantee we do not get clipped by children.
24620+ */
24621+ attr.override_redirect = 1;
24622+ loop = 100;
24623+ do {
24624+ Display *dpy = XOpenDisplay(NULL);
24625+ Window win = XCreateWindow(dpy, DefaultRootWindow(dpy),
24626+ 0, 0, width, height, 0,
24627+ DefaultDepth(dpy, DefaultScreen(dpy)),
24628+ InputOutput,
24629+ DefaultVisual(dpy, DefaultScreen(dpy)),
24630+ CWOverrideRedirect, &attr);
24631+
24632+ XMapWindow(dpy, win);
24633+
24634+ DRI2CreateDrawable(dpy, win);
24635+ free(DRI2GetBuffers(dpy, win, &width, &height,
24636+ attachments, nattachments, &count));
24637+ if (count != nattachments)
24638+ return;
24639+
24640+ for (count = 0; count < loop; count++)
24641+ DRI2SwapBuffers(dpy, win, 0, 0, 0);
24642+ XCloseDisplay(dpy);
24643+ printf("."); fflush(stdout);
24644+ } while (--loop);
24645+ printf("*\n");
24646+
24647+ loop = 100;
24648+ do {
24649+ Display *dpy = XOpenDisplay(NULL);
24650+ Window win = XCreateWindow(dpy, DefaultRootWindow(dpy),
24651+ 0, 0, width, height, 0,
24652+ DefaultDepth(dpy, DefaultScreen(dpy)),
24653+ InputOutput,
24654+ DefaultVisual(dpy, DefaultScreen(dpy)),
24655+ CWOverrideRedirect, &attr);
24656+
24657+ XMapWindow(dpy, win);
24658+
24659+ DRI2CreateDrawable(dpy, win);
24660+ free(DRI2GetBuffers(dpy, win, &width, &height,
24661+ attachments, nattachments, &count));
24662+ if (count != nattachments)
24663+ return;
24664+
24665+ for (count = 0; count < loop; count++)
24666+ swap_buffers(dpy, win, 0, attachments, nattachments);
24667+ XCloseDisplay(dpy);
24668+ printf("."); fflush(stdout);
24669+ } while (--loop);
24670+ printf("*\n");
24671+
24672+ loop = 100;
24673+ do {
24674+ Display *dpy = XOpenDisplay(NULL);
24675+ Window win = XCreateWindow(dpy, DefaultRootWindow(dpy),
24676+ 0, 0, width, height, 0,
24677+ DefaultDepth(dpy, DefaultScreen(dpy)),
24678+ InputOutput,
24679+ DefaultVisual(dpy, DefaultScreen(dpy)),
24680+ CWOverrideRedirect, &attr);
24681+
24682+ XMapWindow(dpy, win);
24683+
24684+ DRI2CreateDrawable(dpy, win);
24685+ free(DRI2GetBuffers(dpy, win, &width, &height,
24686+ attachments, nattachments, &count));
24687+ if (count != nattachments)
24688+ return;
24689+
24690+ for (count = 0; count < loop; count++)
24691+ swap_buffers(dpy, win, 1, attachments, nattachments);
24692+ XCloseDisplay(dpy);
24693+ printf("."); fflush(stdout);
24694+ } while (--loop);
24695+ printf("*\n");
24696+
24697+ loop = 100;
24698+ do {
24699+ uint64_t ignore, msc;
24700+ Display *dpy = XOpenDisplay(NULL);
24701+ xcb_connection_t *c = XGetXCBConnection(dpy);
24702+ Window win = XCreateWindow(dpy, DefaultRootWindow(dpy),
24703+ 0, 0, width, height, 0,
24704+ DefaultDepth(dpy, DefaultScreen(dpy)),
24705+ InputOutput,
24706+ DefaultVisual(dpy, DefaultScreen(dpy)),
24707+ CWOverrideRedirect, &attr);
24708+
24709+ XMapWindow(dpy, win);
24710+
24711+ DRI2CreateDrawable(dpy, win);
24712+ DRI2GetMSC(dpy, win, &ignore, &msc, &ignore);
24713+ for (count = 0; count < loop; count++)
24714+ xcb_discard_reply(c,
24715+ xcb_dri2_wait_msc(c, win,
24716+ upper_32_bits(msc + count + 1),
24717+ lower_32_bits(msc + count + 1),
24718+ 0, 1, 0, 0).sequence);
24719+ XFlush(dpy);
24720+ XCloseDisplay(dpy);
24721+ printf("."); fflush(stdout);
24722+ } while (--loop);
24723+ printf("*\n");
24724+}
24725+
24726 int main(void)
24727 {
24728 Display *dpy;
24729@@ -101,13 +357,17 @@ int main(void)
24730
24731 width = WidthOfScreen(DefaultScreenOfDisplay(dpy));
24732 height = HeightOfScreen(DefaultScreenOfDisplay(dpy));
24733- run(dpy, width, height, attachments, 1, "fullscreen");
24734- run(dpy, width, height, attachments, 2, "fullscreen (with front)");
24735+ race_window(dpy, width, height, attachments, 1, "fullscreen");
24736+ race_window(dpy, width, height, attachments, 2, "fullscreen (with front)");
24737+ race_client(width, height, attachments, 1, "fullscreen");
24738+ race_client(width, height, attachments, 2, "fullscreen (with front)");
24739
24740 width /= 2;
24741 height /= 2;
24742- run(dpy, width, height, attachments, 1, "windowed");
24743- run(dpy, width, height, attachments, 2, "windowed (with front)");
24744+ race_window(dpy, width, height, attachments, 1, "windowed");
24745+ race_window(dpy, width, height, attachments, 2, "windowed (with front)");
24746+ race_client(width, height, attachments, 1, "windowed");
24747+ race_client(width, height, attachments, 2, "windowed (with front)");
24748
24749 return 0;
24750 }
24751diff --git a/test/dri2-speed.c b/test/dri2-speed.c
24752new file mode 100644
24753index 0000000..87b9d0b
24754--- /dev/null
24755+++ b/test/dri2-speed.c
24756@@ -0,0 +1,342 @@
24757+/*
24758+ * Copyright (c) 2015 Intel Corporation
24759+ *
24760+ * Permission is hereby granted, free of charge, to any person obtaining a
24761+ * copy of this software and associated documentation files (the "Software"),
24762+ * to deal in the Software without restriction, including without limitation
24763+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
24764+ * and/or sell copies of the Software, and to permit persons to whom the
24765+ * Software is furnished to do so, subject to the following conditions:
24766+ *
24767+ * The above copyright notice and this permission notice (including the next
24768+ * paragraph) shall be included in all copies or substantial portions of the
24769+ * Software.
24770+ *
24771+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24772+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24773+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24774+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24775+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24776+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24777+ * SOFTWARE.
24778+ *
24779+ */
24780+
24781+#ifdef HAVE_CONFIG_H
24782+#include "config.h"
24783+#endif
24784+
24785+#include <X11/Xlib.h>
24786+#include <X11/Xatom.h>
24787+#include <X11/Xlib-xcb.h>
24788+#include <X11/Xutil.h>
24789+#include <X11/Xlibint.h>
24790+#include <X11/extensions/dpms.h>
24791+#include <X11/extensions/randr.h>
24792+#include <X11/extensions/Xcomposite.h>
24793+#include <X11/extensions/Xdamage.h>
24794+#include <X11/extensions/Xrandr.h>
24795+#include <xcb/xcb.h>
24796+#include <xcb/dri2.h>
24797+#include <xf86drm.h>
24798+
24799+#include <stdio.h>
24800+#include <string.h>
24801+#include <fcntl.h>
24802+#include <unistd.h>
24803+#include <assert.h>
24804+#include <errno.h>
24805+#include <setjmp.h>
24806+#include <signal.h>
24807+
24808+#include "dri2.h"
24809+
24810+static int _x_error_occurred;
24811+
24812+static int
24813+_check_error_handler(Display *display,
24814+ XErrorEvent *event)
24815+{
24816+ printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
24817+ DisplayString(display),
24818+ event->serial,
24819+ event->error_code,
24820+ event->request_code,
24821+ event->minor_code);
24822+ _x_error_occurred++;
24823+ return False; /* ignored */
24824+}
24825+
24826+static double elapsed(const struct timespec *start,
24827+ const struct timespec *end)
24828+{
24829+ return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000;
24830+}
24831+
24832+static void run(Display *dpy, Window win, const char *name)
24833+{
24834+ xcb_connection_t *c = XGetXCBConnection(dpy);
24835+ struct timespec start, end;
24836+ int n, completed = 0;
24837+
24838+ _x_error_occurred = 0;
24839+
24840+ clock_gettime(CLOCK_MONOTONIC, &start);
24841+ do {
24842+ for (n = 0; n < 1000; n++) {
24843+ unsigned int attachments[] = { DRI2BufferBackLeft };
24844+ unsigned int seq[2];
24845+
24846+ seq[0] = xcb_dri2_swap_buffers_unchecked(c, win,
24847+ 0, 0, 0, 0, 0, 0).sequence;
24848+
24849+
24850+ seq[1] = xcb_dri2_get_buffers_unchecked(c, win,
24851+ 1, 1, attachments).sequence;
24852+
24853+ xcb_flush(c);
24854+ xcb_discard_reply(c, seq[0]);
24855+ xcb_discard_reply(c, seq[1]);
24856+ completed++;
24857+ }
24858+ clock_gettime(CLOCK_MONOTONIC, &end);
24859+ } while (end.tv_sec < start.tv_sec + 10);
24860+
24861+ XSync(dpy, True);
24862+ if (_x_error_occurred)
24863+ abort();
24864+
24865+ printf("%s: Completed %d swaps in %.1fs, %.3fus each (%.1f FPS)\n",
24866+ name, completed, elapsed(&start, &end) / 1000000,
24867+ elapsed(&start, &end) / completed,
24868+ completed / (elapsed(&start, &end) / 1000000));
24869+}
24870+
24871+static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
24872+{
24873+ XRRScreenResources *res;
24874+
24875+ res = XRRGetScreenResourcesCurrent(dpy, window);
24876+ if (res == NULL)
24877+ res = XRRGetScreenResources(dpy, window);
24878+
24879+ return res;
24880+}
24881+
24882+static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
24883+{
24884+ int i;
24885+
24886+ for (i = 0; i < res->nmode; i++) {
24887+ if (res->modes[i].id == id)
24888+ return &res->modes[i];
24889+ }
24890+
24891+ return NULL;
24892+}
24893+
24894+static int dri2_open(Display *dpy)
24895+{
24896+ drm_auth_t auth;
24897+ char *driver, *device;
24898+ int fd;
24899+
24900+ if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device))
24901+ return -1;
24902+
24903+ printf ("Connecting to %s driver on %s\n", driver, device);
24904+
24905+ fd = open(device, O_RDWR);
24906+ if (fd < 0)
24907+ return -1;
24908+
24909+ if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
24910+ return -1;
24911+
24912+ if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic))
24913+ return -1;
24914+
24915+ return fd;
24916+}
24917+
24918+static void fullscreen(Display *dpy, Window win)
24919+{
24920+ Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
24921+ XChangeProperty(dpy, win,
24922+ XInternAtom(dpy, "_NET_WM_STATE", False),
24923+ XA_ATOM, 32, PropModeReplace,
24924+ (unsigned char *)&atom, 1);
24925+}
24926+
24927+static int has_composite(Display *dpy)
24928+{
24929+ int event, error;
24930+ int major, minor;
24931+
24932+ if (!XDamageQueryExtension (dpy, &event, &error))
24933+ return 0;
24934+
24935+ if (!XCompositeQueryExtension(dpy, &event, &error))
24936+ return 0;
24937+
24938+ XCompositeQueryVersion(dpy, &major, &minor);
24939+
24940+ return major > 0 || minor >= 4;
24941+}
24942+
24943+int main(void)
24944+{
24945+ Display *dpy;
24946+ Window root, win;
24947+ XRRScreenResources *res;
24948+ XRRCrtcInfo **original_crtc;
24949+ XSetWindowAttributes attr;
24950+ int i, j, fd;
24951+
24952+ attr.override_redirect = 1;
24953+
24954+ dpy = XOpenDisplay(NULL);
24955+ if (dpy == NULL)
24956+ return 77;
24957+
24958+ fd = dri2_open(dpy);
24959+ if (fd < 0)
24960+ return 77;
24961+
24962+ if (DPMSQueryExtension(dpy, &i, &i))
24963+ DPMSDisable(dpy);
24964+
24965+ root = DefaultRootWindow(dpy);
24966+
24967+ signal(SIGALRM, SIG_IGN);
24968+ XSetErrorHandler(_check_error_handler);
24969+
24970+ res = NULL;
24971+ if (XRRQueryVersion(dpy, &i, &i))
24972+ res = _XRRGetScreenResourcesCurrent(dpy, root);
24973+ if (res == NULL)
24974+ return 77;
24975+
24976+ original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc);
24977+ for (i = 0; i < res->ncrtc; i++)
24978+ original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
24979+
24980+ printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc);
24981+ for (i = 0; i < res->ncrtc; i++)
24982+ XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
24983+ 0, 0, None, RR_Rotate_0, NULL, 0);
24984+
24985+ DRI2CreateDrawable(dpy, root);
24986+ DRI2SwapInterval(dpy, root, 0);
24987+ run(dpy, root, "off");
24988+ XSync(dpy, True);
24989+
24990+ for (i = 0; i < res->noutput; i++) {
24991+ XRROutputInfo *output;
24992+ XRRModeInfo *mode;
24993+
24994+ output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
24995+ if (output == NULL)
24996+ continue;
24997+
24998+ mode = NULL;
24999+ if (res->nmode)
25000+ mode = lookup_mode(res, output->modes[0]);
25001+
25002+ for (j = 0; mode && j < 2*output->ncrtc; j++) {
25003+ int c = j;
25004+ if (c >= output->ncrtc)
25005+ c = 2*output->ncrtc - j - 1;
25006+
25007+ printf("[%d, %d] -- OUTPUT:%ld, CRTC:%ld: %dx%d\n",
25008+ i, c, (long)res->outputs[i], (long)output->crtcs[c],
25009+ mode->width, mode->height);
25010+ XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
25011+ 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1);
25012+
25013+ run(dpy, root, "root");
25014+ XSync(dpy, True);
25015+
25016+ win = XCreateWindow(dpy, root,
25017+ 0, 0, mode->width, mode->height, 0,
25018+ DefaultDepth(dpy, DefaultScreen(dpy)),
25019+ InputOutput,
25020+ DefaultVisual(dpy, DefaultScreen(dpy)),
25021+ CWOverrideRedirect, &attr);
25022+ DRI2CreateDrawable(dpy, win);
25023+ DRI2SwapInterval(dpy, win, 0);
25024+ fullscreen(dpy, win);
25025+ XMapWindow(dpy, win);
25026+ run(dpy, win, "fullscreen");
25027+ XDestroyWindow(dpy, win);
25028+ XSync(dpy, True);
25029+
25030+ win = XCreateWindow(dpy, root,
25031+ 0, 0, mode->width, mode->height, 0,
25032+ DefaultDepth(dpy, DefaultScreen(dpy)),
25033+ InputOutput,
25034+ DefaultVisual(dpy, DefaultScreen(dpy)),
25035+ CWOverrideRedirect, &attr);
25036+ DRI2CreateDrawable(dpy, win);
25037+ DRI2SwapInterval(dpy, win, 0);
25038+ XMapWindow(dpy, win);
25039+ run(dpy, win, "windowed");
25040+ XDestroyWindow(dpy, win);
25041+ XSync(dpy, True);
25042+
25043+ if (has_composite(dpy)) {
25044+ Damage damage;
25045+
25046+ _x_error_occurred = 0;
25047+ win = XCreateWindow(dpy, root,
25048+ 0, 0, mode->width, mode->height, 0,
25049+ DefaultDepth(dpy, DefaultScreen(dpy)),
25050+ InputOutput,
25051+ DefaultVisual(dpy, DefaultScreen(dpy)),
25052+ CWOverrideRedirect, &attr);
25053+ XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
25054+ damage = XDamageCreate(dpy, win, XDamageReportRawRectangles);
25055+ DRI2CreateDrawable(dpy, win);
25056+ DRI2SwapInterval(dpy, win, 0);
25057+ XMapWindow(dpy, win);
25058+ XSync(dpy, True);
25059+ if (!_x_error_occurred)
25060+ run(dpy, win, "composited");
25061+ XDamageDestroy(dpy, damage);
25062+ XDestroyWindow(dpy, win);
25063+ XSync(dpy, True);
25064+ }
25065+
25066+ win = XCreateWindow(dpy, root,
25067+ 0, 0, mode->width/2, mode->height/2, 0,
25068+ DefaultDepth(dpy, DefaultScreen(dpy)),
25069+ InputOutput,
25070+ DefaultVisual(dpy, DefaultScreen(dpy)),
25071+ CWOverrideRedirect, &attr);
25072+ DRI2CreateDrawable(dpy, win);
25073+ DRI2SwapInterval(dpy, win, 0);
25074+ XMapWindow(dpy, win);
25075+ run(dpy, win, "half");
25076+ XDestroyWindow(dpy, win);
25077+ XSync(dpy, True);
25078+
25079+ XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
25080+ 0, 0, None, RR_Rotate_0, NULL, 0);
25081+ }
25082+
25083+ XRRFreeOutputInfo(output);
25084+ }
25085+
25086+ for (i = 0; i < res->ncrtc; i++)
25087+ XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
25088+ original_crtc[i]->x,
25089+ original_crtc[i]->y,
25090+ original_crtc[i]->mode,
25091+ original_crtc[i]->rotation,
25092+ original_crtc[i]->outputs,
25093+ original_crtc[i]->noutput);
25094+
25095+ if (DPMSQueryExtension(dpy, &i, &i))
25096+ DPMSEnable(dpy);
25097+ return 0;
25098+}
25099diff --git a/test/dri2-test.c b/test/dri2-test.c
25100index dd4179f..88c0e4c 100644
25101--- a/test/dri2-test.c
25102+++ b/test/dri2-test.c
25103@@ -6,6 +6,10 @@
25104 #include <X11/Xutil.h>
25105 #include <X11/extensions/Xfixes.h>
25106 #include <X11/extensions/Xrandr.h>
25107+#include <X11/Xlib-xcb.h>
25108+#include <xcb/xcb.h>
25109+#include <xcb/xcbext.h>
25110+#include <xcb/dri2.h>
25111 #include <unistd.h>
25112 #include <fcntl.h>
25113 #include <string.h>
25114@@ -101,16 +105,41 @@ static uint64_t check_msc(Display *dpy, Window win, uint64_t last_msc)
25115 return current_msc;
25116 }
25117
25118+static void wait_next_vblank(Display *dpy, Window win)
25119+{
25120+ uint64_t msc, ust, sbc;
25121+ DRI2WaitMSC(dpy, win, 0, 1, 0, &ust, &msc, &sbc);
25122+}
25123+
25124+static void swap_buffers(xcb_connection_t *c, Window win,
25125+ unsigned int *attachments, int nattachments)
25126+{
25127+ unsigned int seq[2];
25128+
25129+ seq[0] = xcb_dri2_swap_buffers_unchecked(c, win,
25130+ 0, 0, 0, 0, 0, 0).sequence;
25131+
25132+
25133+ seq[1] = xcb_dri2_get_buffers_unchecked(c, win,
25134+ nattachments, nattachments,
25135+ attachments).sequence;
25136+
25137+ xcb_flush(c);
25138+ xcb_discard_reply(c, seq[0]);
25139+ xcb_discard_reply(c, seq[1]);
25140+}
25141+
25142 static void run(Display *dpy, int width, int height,
25143 unsigned int *attachments, int nattachments,
25144 const char *name)
25145 {
25146+ xcb_connection_t *c = XGetXCBConnection(dpy);
25147 Window win;
25148 XSetWindowAttributes attr;
25149 int count;
25150 DRI2Buffer *buffers;
25151 struct timespec start, end;
25152- uint64_t msc;
25153+ uint64_t start_msc, end_msc;
25154
25155 /* Be nasty and install a fullscreen window on top so that we
25156 * can guarantee we do not get clipped by children.
25157@@ -125,42 +154,59 @@ static void run(Display *dpy, int width, int height,
25158 XMapWindow(dpy, win);
25159
25160 DRI2CreateDrawable(dpy, win);
25161- msc = check_msc(dpy, win, 0);
25162+ DRI2SwapInterval(dpy, win, 1);
25163+ start_msc = check_msc(dpy, win, 0);
25164
25165 buffers = DRI2GetBuffers(dpy, win, &width, &height,
25166 attachments, nattachments, &count);
25167 if (count != nattachments)
25168 return;
25169
25170- msc = check_msc(dpy, win, msc);
25171+ swap_buffers(c, win, attachments, nattachments);
25172+ start_msc = check_msc(dpy, win, start_msc);
25173 clock_gettime(CLOCK_MONOTONIC, &start);
25174 for (count = 0; count < COUNT; count++)
25175- DRI2SwapBuffers(dpy, win, 0, 0, 0);
25176- msc = check_msc(dpy, win, msc);
25177+ swap_buffers(c, win, attachments, nattachments);
25178+ end_msc = check_msc(dpy, win, start_msc);
25179 clock_gettime(CLOCK_MONOTONIC, &end);
25180- printf("%d %s (%dx%d) swaps in %fs.\n",
25181- count, name, width, height, elapsed(&start, &end));
25182+ printf("%d [%ld] %s (%dx%d) swaps in %fs.\n",
25183+ count, (long)(end_msc - start_msc),
25184+ name, width, height, elapsed(&start, &end));
25185
25186- msc = check_msc(dpy, win, msc);
25187+ swap_buffers(c, win, attachments, nattachments);
25188+ start_msc = check_msc(dpy, win, end_msc);
25189 clock_gettime(CLOCK_MONOTONIC, &start);
25190 for (count = 0; count < COUNT; count++)
25191 dri2_copy_swap(dpy, win, width, height, nattachments == 2);
25192- msc = check_msc(dpy, win, msc);
25193+ end_msc = check_msc(dpy, win, start_msc);
25194 clock_gettime(CLOCK_MONOTONIC, &end);
25195
25196- printf("%d %s (%dx%d) blits in %fs.\n",
25197- count, name, width, height, elapsed(&start, &end));
25198+ printf("%d [%ld] %s (%dx%d) blits in %fs.\n",
25199+ count, (long)(end_msc - start_msc),
25200+ name, width, height, elapsed(&start, &end));
25201
25202 DRI2SwapInterval(dpy, win, 0);
25203
25204- msc = check_msc(dpy, win, msc);
25205+ swap_buffers(c, win, attachments, nattachments);
25206+ start_msc = check_msc(dpy, win, end_msc);
25207+ clock_gettime(CLOCK_MONOTONIC, &start);
25208+ for (count = 0; count < COUNT; count++)
25209+ swap_buffers(c, win, attachments, nattachments);
25210+ end_msc = check_msc(dpy, win, start_msc);
25211+ clock_gettime(CLOCK_MONOTONIC, &end);
25212+ printf("%d [%ld] %s (%dx%d) vblank=0 swaps in %fs.\n",
25213+ count, (long)(end_msc - start_msc),
25214+ name, width, height, elapsed(&start, &end));
25215+
25216+ start_msc = check_msc(dpy, win, end_msc);
25217 clock_gettime(CLOCK_MONOTONIC, &start);
25218 for (count = 0; count < COUNT; count++)
25219- DRI2SwapBuffers(dpy, win, 0, 0, 0);
25220- msc = check_msc(dpy, win, msc);
25221+ wait_next_vblank(dpy, win);
25222+ end_msc = check_msc(dpy, win, start_msc);
25223 clock_gettime(CLOCK_MONOTONIC, &end);
25224- printf("%d %s (%dx%d) vblank=0 swaps in %fs.\n",
25225- count, name, width, height, elapsed(&start, &end));
25226+ printf("%d [%ld] %s waits in %fs.\n",
25227+ count, (long)(end_msc - start_msc),
25228+ name, elapsed(&start, &end));
25229
25230 XDestroyWindow(dpy, win);
25231 free(buffers);
25232diff --git a/test/dri3-test.c b/test/dri3-test.c
25233index c66da31..7e98f95 100644
25234--- a/test/dri3-test.c
25235+++ b/test/dri3-test.c
25236@@ -1020,6 +1020,67 @@ fail:
25237 return 1;
25238 }
25239
25240+static int gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
25241+{
25242+ struct drm_i915_gem_set_tiling set_tiling;
25243+
25244+ set_tiling.handle = handle;
25245+ set_tiling.tiling_mode = tiling;
25246+ set_tiling.stride = stride;
25247+
25248+ return drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0;
25249+}
25250+
25251+static int test_tiling(Display *dpy, int device)
25252+{
25253+ Window root = RootWindow(dpy, DefaultScreen(dpy));
25254+ const int tiling[] = { I915_TILING_NONE, I915_TILING_X, I915_TILING_Y };
25255+ int line = -1;
25256+ int t;
25257+
25258+ _x_error_occurred = 0;
25259+
25260+ for (t = 0; t < sizeof(tiling)/sizeof(tiling[0]); t++) {
25261+ uint32_t src;
25262+ int src_fd;
25263+ Pixmap src_pix;
25264+
25265+ src = gem_create(device, 4*4096);
25266+ if (!src) {
25267+ line = __LINE__;
25268+ goto fail;
25269+ }
25270+
25271+ gem_set_tiling(device, src, tiling[t], 512);
25272+
25273+ src_fd = gem_export(device, src);
25274+ if (src_fd < 0) {
25275+ line = __LINE__;
25276+ goto fail;
25277+ }
25278+
25279+ src_pix = dri3_create_pixmap(dpy, root,
25280+ 128, 32, 32,
25281+ src_fd, 32, 512, 4*4096);
25282+ XSync(dpy, True);
25283+ if (_x_error_occurred) {
25284+ line = __LINE__;
25285+ goto fail;
25286+ }
25287+ XFreePixmap(dpy, src_pix);
25288+ _x_error_occurred = 0;
25289+
25290+ close(src_fd);
25291+ gem_close(device, src);
25292+ }
25293+
25294+ return 0;
25295+
25296+fail:
25297+ printf("%s failed with tiling %d, line %d\n", __func__, tiling[t], line);
25298+ return 1;
25299+}
25300+
25301 static int
25302 _check_error_handler(Display *display,
25303 XErrorEvent *event)
25304@@ -1060,6 +1121,7 @@ int main(void)
25305
25306 error += test_bad_size(dpy, device);
25307 error += test_bad_pitch(dpy, device);
25308+ error += test_tiling(dpy, device);
25309
25310 error += test_shm(dpy, device, 400, 300);
25311 error += test_shm(dpy, device, 300, 400);
25312diff --git a/test/dri3.c b/test/dri3.c
25313index 45f3285..e564462 100644
25314--- a/test/dri3.c
25315+++ b/test/dri3.c
25316@@ -29,6 +29,7 @@
25317 #include <xcb/dri3.h>
25318 #include <xcb/sync.h>
25319 #include <unistd.h>
25320+#include <stdlib.h>
25321
25322 #include "dri3.h"
25323
25324@@ -109,12 +110,45 @@ void dri3_fence_free(Display *dpy, struct dri3_fence *fence)
25325 xcb_sync_destroy_fence(c, fence->xid);
25326 }
25327
25328+static void dri3_query_version(xcb_connection_t *c, int *major, int *minor)
25329+{
25330+ xcb_dri3_query_version_reply_t *reply;
25331+
25332+ reply = xcb_dri3_query_version_reply(c,
25333+ xcb_dri3_query_version(c,
25334+ XCB_DRI3_MAJOR_VERSION,
25335+ XCB_DRI3_MINOR_VERSION),
25336+ NULL);
25337+ if (reply != NULL) {
25338+ *major = reply->major_version;
25339+ *minor = reply->minor_version;
25340+ free(reply);
25341+ }
25342+}
25343+
25344+static int dri3_exists(xcb_connection_t *c)
25345+{
25346+ const xcb_query_extension_reply_t *ext;
25347+ int major, minor;
25348+
25349+ major = minor = -1;
25350+
25351+ ext = xcb_get_extension_data(c, &xcb_dri3_id);
25352+ if (ext != NULL && ext->present)
25353+ dri3_query_version(c, &major, &minor);
25354+
25355+ return major >= 0;
25356+}
25357+
25358 int dri3_open__full(Display *dpy, Window root, unsigned provider)
25359 {
25360 xcb_connection_t *c = XGetXCBConnection(dpy);
25361 xcb_dri3_open_cookie_t cookie;
25362 xcb_dri3_open_reply_t *reply;
25363
25364+ if (!dri3_exists(c))
25365+ return -1;
25366+
25367 cookie = xcb_dri3_open(c, root, provider);
25368 reply = xcb_dri3_open_reply(c, cookie, NULL);
25369
25370diff --git a/test/present-speed.c b/test/present-speed.c
25371new file mode 100644
25372index 0000000..4d33904
25373--- /dev/null
25374+++ b/test/present-speed.c
25375@@ -0,0 +1,615 @@
25376+/*
25377+ * Copyright (c) 2015 Intel Corporation
25378+ *
25379+ * Permission is hereby granted, free of charge, to any person obtaining a
25380+ * copy of this software and associated documentation files (the "Software"),
25381+ * to deal in the Software without restriction, including without limitation
25382+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
25383+ * and/or sell copies of the Software, and to permit persons to whom the
25384+ * Software is furnished to do so, subject to the following conditions:
25385+ *
25386+ * The above copyright notice and this permission notice (including the next
25387+ * paragraph) shall be included in all copies or substantial portions of the
25388+ * Software.
25389+ *
25390+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25391+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25392+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25393+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25394+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25395+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25396+ * SOFTWARE.
25397+ *
25398+ */
25399+
25400+#ifdef HAVE_CONFIG_H
25401+#include "config.h"
25402+#endif
25403+
25404+#include <X11/Xlib.h>
25405+#include <X11/Xatom.h>
25406+#include <X11/Xlib-xcb.h>
25407+#include <X11/xshmfence.h>
25408+#include <X11/Xutil.h>
25409+#include <X11/Xlibint.h>
25410+#include <X11/extensions/Xcomposite.h>
25411+#include <X11/extensions/Xdamage.h>
25412+#include <X11/extensions/dpms.h>
25413+#include <X11/extensions/randr.h>
25414+#include <X11/extensions/Xrandr.h>
25415+#include <xcb/xcb.h>
25416+#include <xcb/present.h>
25417+#include <xcb/dri3.h>
25418+#include <xcb/xfixes.h>
25419+#include <xf86drm.h>
25420+#include <i915_drm.h>
25421+
25422+#include <stdio.h>
25423+#include <string.h>
25424+#include <fcntl.h>
25425+#include <unistd.h>
25426+#include <assert.h>
25427+#include <errno.h>
25428+#include <setjmp.h>
25429+#include <signal.h>
25430+
25431+#include "dri3.h"
25432+
25433+static int _x_error_occurred;
25434+static uint32_t stamp;
25435+
25436+struct list {
25437+ struct list *next, *prev;
25438+};
25439+
25440+static void
25441+list_init(struct list *list)
25442+{
25443+ list->next = list->prev = list;
25444+}
25445+
25446+static inline void
25447+__list_add(struct list *entry,
25448+ struct list *prev,
25449+ struct list *next)
25450+{
25451+ next->prev = entry;
25452+ entry->next = next;
25453+ entry->prev = prev;
25454+ prev->next = entry;
25455+}
25456+
25457+static inline void
25458+list_add(struct list *entry, struct list *head)
25459+{
25460+ __list_add(entry, head, head->next);
25461+}
25462+
25463+static inline void
25464+__list_del(struct list *prev, struct list *next)
25465+{
25466+ next->prev = prev;
25467+ prev->next = next;
25468+}
25469+
25470+static inline void
25471+_list_del(struct list *entry)
25472+{
25473+ __list_del(entry->prev, entry->next);
25474+}
25475+
25476+static inline void
25477+list_move(struct list *list, struct list *head)
25478+{
25479+ if (list->prev != head) {
25480+ _list_del(list);
25481+ list_add(list, head);
25482+ }
25483+}
25484+
25485+#define __container_of(ptr, sample, member) \
25486+ (void *)((char *)(ptr) - ((char *)&(sample)->member - (char *)(sample)))
25487+
25488+#define list_for_each_entry(pos, head, member) \
25489+ for (pos = __container_of((head)->next, pos, member); \
25490+ &pos->member != (head); \
25491+ pos = __container_of(pos->member.next, pos, member))
25492+
25493+static int
25494+_check_error_handler(Display *display,
25495+ XErrorEvent *event)
25496+{
25497+ printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
25498+ DisplayString(display),
25499+ event->serial,
25500+ event->error_code,
25501+ event->request_code,
25502+ event->minor_code);
25503+ _x_error_occurred++;
25504+ return False; /* ignored */
25505+}
25506+
25507+static double elapsed(const struct timespec *start,
25508+ const struct timespec *end)
25509+{
25510+ return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000;
25511+}
25512+
25513+struct buffer {
25514+ struct list link;
25515+ Pixmap pixmap;
25516+ struct dri3_fence fence;
25517+ int fd;
25518+ int busy;
25519+};
25520+
25521+#define DRI3 1
25522+#define NOCOPY 2
25523+static void run(Display *dpy, Window win, const char *name, unsigned options)
25524+{
25525+ xcb_connection_t *c = XGetXCBConnection(dpy);
25526+ struct timespec start, end;
25527+#define N_BACK 8
25528+ char test_name[128];
25529+ struct buffer buffer[N_BACK];
25530+ struct list mru;
25531+ Window root;
25532+ unsigned int width, height;
25533+ unsigned border, depth;
25534+ unsigned present_flags = XCB_PRESENT_OPTION_ASYNC;
25535+ xcb_xfixes_region_t update = 0;
25536+ int completed = 0;
25537+ int queued = 0;
25538+ uint32_t eid;
25539+ void *Q;
25540+ int i, n;
25541+
25542+ list_init(&mru);
25543+
25544+ XGetGeometry(dpy, win,
25545+ &root, &i, &n, &width, &height, &border, &depth);
25546+
25547+ _x_error_occurred = 0;
25548+
25549+ for (n = 0; n < N_BACK; n++) {
25550+ buffer[n].pixmap =
25551+ XCreatePixmap(dpy, win, width, height, depth);
25552+ buffer[n].fence.xid = 0;
25553+ buffer[n].fd = -1;
25554+ if (options & DRI3) {
25555+ xcb_dri3_buffer_from_pixmap_reply_t *reply;
25556+ int *fds;
25557+
25558+ if (dri3_create_fence(dpy, win, &buffer[n].fence))
25559+ return;
25560+
25561+ reply = xcb_dri3_buffer_from_pixmap_reply (c,
25562+ xcb_dri3_buffer_from_pixmap(c, buffer[n].pixmap),
25563+ NULL);
25564+ if (reply == NULL)
25565+ return;
25566+
25567+ fds = xcb_dri3_buffer_from_pixmap_reply_fds (c, reply);
25568+ buffer[n].fd = fds[0];
25569+ free(reply);
25570+
25571+ /* start idle */
25572+ xshmfence_trigger(buffer[n].fence.addr);
25573+ }
25574+ buffer[n].busy = 0;
25575+ list_add(&buffer[n].link, &mru);
25576+ }
25577+ if (options & NOCOPY) {
25578+ update = xcb_generate_id(c);
25579+ xcb_xfixes_create_region(c, update, 0, NULL);
25580+ present_flags |= XCB_PRESENT_OPTION_COPY;
25581+ }
25582+
25583+ eid = xcb_generate_id(c);
25584+ xcb_present_select_input(c, eid, win,
25585+ (options & NOCOPY ? 0 : XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY) |
25586+ XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
25587+ Q = xcb_register_for_special_xge(c, &xcb_present_id, eid, &stamp);
25588+
25589+ clock_gettime(CLOCK_MONOTONIC, &start);
25590+ do {
25591+ for (n = 0; n < 1000; n++) {
25592+ struct buffer *tmp, *b = NULL;
25593+ list_for_each_entry(tmp, &mru, link) {
25594+ if (!tmp->busy) {
25595+ b = tmp;
25596+ break;
25597+ }
25598+ }
25599+ while (b == NULL) {
25600+ xcb_present_generic_event_t *ev;
25601+
25602+ ev = (xcb_present_generic_event_t *)
25603+ xcb_wait_for_special_event(c, Q);
25604+ if (ev == NULL)
25605+ abort();
25606+
25607+ do {
25608+ switch (ev->evtype) {
25609+ case XCB_PRESENT_COMPLETE_NOTIFY:
25610+ completed++;
25611+ queued--;
25612+ break;
25613+
25614+ case XCB_PRESENT_EVENT_IDLE_NOTIFY:
25615+ {
25616+ xcb_present_idle_notify_event_t *ie = (xcb_present_idle_notify_event_t *)ev;
25617+ assert(ie->serial < N_BACK);
25618+ buffer[ie->serial].busy = 0;
25619+ if (b == NULL)
25620+ b = &buffer[ie->serial];
25621+ break;
25622+ }
25623+ }
25624+ free(ev);
25625+ } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
25626+ }
25627+
25628+ b->busy = (options & NOCOPY) == 0;
25629+ if (b->fence.xid) {
25630+ xshmfence_await(b->fence.addr);
25631+ xshmfence_reset(b->fence.addr);
25632+ }
25633+ xcb_present_pixmap(c, win, b->pixmap, b - buffer,
25634+ 0, /* valid */
25635+ update, /* update */
25636+ 0, /* x_off */
25637+ 0, /* y_off */
25638+ None,
25639+ None, /* wait fence */
25640+ b->fence.xid,
25641+ present_flags,
25642+ 0, /* target msc */
25643+ 0, /* divisor */
25644+ 0, /* remainder */
25645+ 0, NULL);
25646+ list_move(&b->link, &mru);
25647+ queued++;
25648+ xcb_flush(c);
25649+ }
25650+ clock_gettime(CLOCK_MONOTONIC, &end);
25651+ } while (end.tv_sec < start.tv_sec + 10);
25652+
25653+ while (queued) {
25654+ xcb_present_generic_event_t *ev;
25655+
25656+ ev = (xcb_present_generic_event_t *)
25657+ xcb_wait_for_special_event(c, Q);
25658+ if (ev == NULL)
25659+ abort();
25660+
25661+ do {
25662+ switch (ev->evtype) {
25663+ case XCB_PRESENT_COMPLETE_NOTIFY:
25664+ completed++;
25665+ queued--;
25666+ break;
25667+
25668+ case XCB_PRESENT_EVENT_IDLE_NOTIFY:
25669+ break;
25670+ }
25671+ free(ev);
25672+ } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
25673+ }
25674+ clock_gettime(CLOCK_MONOTONIC, &end);
25675+
25676+ if (update)
25677+ xcb_xfixes_destroy_region(c, update);
25678+ for (n = 0; n < N_BACK; n++) {
25679+ if (buffer[n].fence.xid)
25680+ dri3_fence_free(dpy, &buffer[n].fence);
25681+ if (buffer[n].fd != -1)
25682+ close(buffer[n].fd);
25683+ XFreePixmap(dpy, buffer[n].pixmap);
25684+ }
25685+
25686+ XSync(dpy, True);
25687+ if (_x_error_occurred)
25688+ abort();
25689+
25690+ xcb_present_select_input(c, eid, win, 0);
25691+ XSync(dpy, True);
25692+ xcb_unregister_for_special_event(c, Q);
25693+
25694+ test_name[0] = '\0';
25695+ if (options) {
25696+ snprintf(test_name, sizeof(test_name), "(%s%s )",
25697+ options & NOCOPY ? " no-copy" : "",
25698+ options & DRI3 ? " dri3" : "");
25699+ }
25700+ printf("%s%s: Completed %d presents in %.1fs, %.3fus each (%.1f FPS)\n",
25701+ name, test_name,
25702+ completed, elapsed(&start, &end) / 1000000,
25703+ elapsed(&start, &end) / completed,
25704+ completed / (elapsed(&start, &end) / 1000000));
25705+}
25706+
25707+static int has_present(Display *dpy)
25708+{
25709+ xcb_connection_t *c = XGetXCBConnection(dpy);
25710+ xcb_generic_error_t *error = NULL;
25711+ void *reply;
25712+
25713+ reply = xcb_present_query_version_reply(c,
25714+ xcb_present_query_version(c,
25715+ XCB_PRESENT_MAJOR_VERSION,
25716+ XCB_PRESENT_MINOR_VERSION),
25717+ &error);
25718+
25719+ free(reply);
25720+ free(error);
25721+ if (reply == NULL) {
25722+ fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy));
25723+ return 0;
25724+ }
25725+
25726+ return 1;
25727+}
25728+
25729+static int has_composite(Display *dpy)
25730+{
25731+ int event, error;
25732+ int major, minor;
25733+
25734+ if (!XDamageQueryExtension (dpy, &event, &error))
25735+ return 0;
25736+
25737+ if (!XCompositeQueryExtension(dpy, &event, &error))
25738+ return 0;
25739+
25740+ XCompositeQueryVersion(dpy, &major, &minor);
25741+
25742+ return major > 0 || minor >= 4;
25743+}
25744+
25745+static int dri3_query_version(Display *dpy, int *major, int *minor)
25746+{
25747+ xcb_connection_t *c = XGetXCBConnection(dpy);
25748+ xcb_dri3_query_version_reply_t *reply;
25749+ xcb_generic_error_t *error;
25750+
25751+ *major = *minor = -1;
25752+
25753+ reply = xcb_dri3_query_version_reply(c,
25754+ xcb_dri3_query_version(c,
25755+ XCB_DRI3_MAJOR_VERSION,
25756+ XCB_DRI3_MINOR_VERSION),
25757+ &error);
25758+ free(error);
25759+ if (reply == NULL)
25760+ return -1;
25761+
25762+ *major = reply->major_version;
25763+ *minor = reply->minor_version;
25764+ free(reply);
25765+
25766+ return 0;
25767+}
25768+
25769+static int has_dri3(Display *dpy)
25770+{
25771+ const xcb_query_extension_reply_t *ext;
25772+ int major, minor;
25773+
25774+ ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id);
25775+ if (ext == NULL || !ext->present)
25776+ return 0;
25777+
25778+ if (dri3_query_version(dpy, &major, &minor) < 0)
25779+ return 0;
25780+
25781+ return major >= 0;
25782+}
25783+
25784+static int has_xfixes(Display *dpy)
25785+{
25786+ xcb_connection_t *c = XGetXCBConnection(dpy);
25787+ const xcb_query_extension_reply_t *ext;
25788+ void *reply;
25789+
25790+ ext = xcb_get_extension_data(c, &xcb_xfixes_id);
25791+ if (ext == NULL || !ext->present)
25792+ return 0;
25793+
25794+ reply = xcb_xfixes_query_version_reply(c,
25795+ xcb_xfixes_query_version(c,
25796+ XCB_XFIXES_MAJOR_VERSION,
25797+ XCB_XFIXES_MINOR_VERSION),
25798+ NULL);
25799+ free(reply);
25800+
25801+ return reply != NULL;
25802+}
25803+
25804+static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
25805+{
25806+ XRRScreenResources *res;
25807+
25808+ res = XRRGetScreenResourcesCurrent(dpy, window);
25809+ if (res == NULL)
25810+ res = XRRGetScreenResources(dpy, window);
25811+
25812+ return res;
25813+}
25814+
25815+static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
25816+{
25817+ int i;
25818+
25819+ for (i = 0; i < res->nmode; i++) {
25820+ if (res->modes[i].id == id)
25821+ return &res->modes[i];
25822+ }
25823+
25824+ return NULL;
25825+}
25826+
25827+static void fullscreen(Display *dpy, Window win)
25828+{
25829+ Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
25830+ XChangeProperty(dpy, win,
25831+ XInternAtom(dpy, "_NET_WM_STATE", False),
25832+ XA_ATOM, 32, PropModeReplace,
25833+ (unsigned char *)&atom, 1);
25834+}
25835+
25836+static void loop(Display *dpy, XRRScreenResources *res, unsigned options)
25837+{
25838+ Window root = DefaultRootWindow(dpy);
25839+ Window win;
25840+ XSetWindowAttributes attr;
25841+ int i, j;
25842+
25843+ attr.override_redirect = 1;
25844+
25845+ run(dpy, root, "off", options);
25846+ XSync(dpy, True);
25847+
25848+ for (i = 0; i < res->noutput; i++) {
25849+ XRROutputInfo *output;
25850+ XRRModeInfo *mode;
25851+
25852+ output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
25853+ if (output == NULL)
25854+ continue;
25855+
25856+ mode = NULL;
25857+ if (res->nmode)
25858+ mode = lookup_mode(res, output->modes[0]);
25859+
25860+ for (j = 0; mode && j < 2*output->ncrtc; j++) {
25861+ int c = j;
25862+ if (c >= output->ncrtc)
25863+ c = 2*output->ncrtc - j - 1;
25864+
25865+ printf("[%d, %d] -- OUTPUT:%ld, CRTC:%ld: %dx%d\n",
25866+ i, c, (long)res->outputs[i], (long)output->crtcs[c],
25867+ mode->width, mode->height);
25868+ XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
25869+ 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1);
25870+
25871+ run(dpy, root, "root", options);
25872+ XSync(dpy, True);
25873+
25874+ win = XCreateWindow(dpy, root,
25875+ 0, 0, mode->width, mode->height, 0,
25876+ DefaultDepth(dpy, DefaultScreen(dpy)),
25877+ InputOutput,
25878+ DefaultVisual(dpy, DefaultScreen(dpy)),
25879+ CWOverrideRedirect, &attr);
25880+ fullscreen(dpy, win);
25881+ XMapWindow(dpy, win);
25882+ run(dpy, win, "fullscreen", options);
25883+ XDestroyWindow(dpy, win);
25884+ XSync(dpy, True);
25885+
25886+ win = XCreateWindow(dpy, root,
25887+ 0, 0, mode->width, mode->height, 0,
25888+ DefaultDepth(dpy, DefaultScreen(dpy)),
25889+ InputOutput,
25890+ DefaultVisual(dpy, DefaultScreen(dpy)),
25891+ CWOverrideRedirect, &attr);
25892+ XMapWindow(dpy, win);
25893+ run(dpy, win, "windowed", options);
25894+ XDestroyWindow(dpy, win);
25895+ XSync(dpy, True);
25896+
25897+ if (has_composite(dpy)) {
25898+ Damage damage;
25899+
25900+ _x_error_occurred = 0;
25901+ win = XCreateWindow(dpy, root,
25902+ 0, 0, mode->width, mode->height, 0,
25903+ DefaultDepth(dpy, DefaultScreen(dpy)),
25904+ InputOutput,
25905+ DefaultVisual(dpy, DefaultScreen(dpy)),
25906+ CWOverrideRedirect, &attr);
25907+ XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
25908+ damage = XDamageCreate(dpy, win, XDamageReportRawRectangles);
25909+ XMapWindow(dpy, win);
25910+ XSync(dpy, True);
25911+ if (!_x_error_occurred)
25912+ run(dpy, win, "composited", options);
25913+ XDamageDestroy(dpy, damage);
25914+ XDestroyWindow(dpy, win);
25915+ XSync(dpy, True);
25916+ }
25917+
25918+ win = XCreateWindow(dpy, root,
25919+ 0, 0, mode->width/2, mode->height/2, 0,
25920+ DefaultDepth(dpy, DefaultScreen(dpy)),
25921+ InputOutput,
25922+ DefaultVisual(dpy, DefaultScreen(dpy)),
25923+ CWOverrideRedirect, &attr);
25924+ XMapWindow(dpy, win);
25925+ run(dpy, win, "half", options);
25926+ XDestroyWindow(dpy, win);
25927+ XSync(dpy, True);
25928+
25929+ XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
25930+ 0, 0, None, RR_Rotate_0, NULL, 0);
25931+ }
25932+
25933+ XRRFreeOutputInfo(output);
25934+ }
25935+}
25936+
25937+int main(void)
25938+{
25939+ Display *dpy;
25940+ XRRScreenResources *res;
25941+ XRRCrtcInfo **original_crtc;
25942+ int i;
25943+
25944+ dpy = XOpenDisplay(NULL);
25945+ if (dpy == NULL)
25946+ return 77;
25947+
25948+ if (!has_present(dpy))
25949+ return 77;
25950+
25951+ if (DPMSQueryExtension(dpy, &i, &i))
25952+ DPMSDisable(dpy);
25953+
25954+ signal(SIGALRM, SIG_IGN);
25955+ XSetErrorHandler(_check_error_handler);
25956+
25957+ res = NULL;
25958+ if (XRRQueryVersion(dpy, &i, &i))
25959+ res = _XRRGetScreenResourcesCurrent(dpy, DefaultRootWindow(dpy));
25960+ if (res == NULL)
25961+ return 77;
25962+
25963+ original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc);
25964+ for (i = 0; i < res->ncrtc; i++)
25965+ original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
25966+
25967+ printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc);
25968+ for (i = 0; i < res->ncrtc; i++)
25969+ XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
25970+ 0, 0, None, RR_Rotate_0, NULL, 0);
25971+
25972+ loop(dpy, res, 0);
25973+ if (has_xfixes(dpy))
25974+ loop(dpy, res, NOCOPY);
25975+ if (has_dri3(dpy))
25976+ loop(dpy, res, DRI3);
25977+
25978+ for (i = 0; i < res->ncrtc; i++)
25979+ XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
25980+ original_crtc[i]->x,
25981+ original_crtc[i]->y,
25982+ original_crtc[i]->mode,
25983+ original_crtc[i]->rotation,
25984+ original_crtc[i]->outputs,
25985+ original_crtc[i]->noutput);
25986+
25987+ if (DPMSQueryExtension(dpy, &i, &i))
25988+ DPMSEnable(dpy);
25989+ return 0;
25990+}
25991diff --git a/test/present-test.c b/test/present-test.c
25992index 6b562eb..b33fd2e 100644
25993--- a/test/present-test.c
25994+++ b/test/present-test.c
25995@@ -31,7 +31,9 @@
25996 #include <X11/xshmfence.h>
25997 #include <X11/Xutil.h>
25998 #include <X11/Xlibint.h>
25999+#include <X11/extensions/dpms.h>
26000 #include <X11/extensions/randr.h>
26001+#include <X11/extensions/Xcomposite.h>
26002 #include <X11/extensions/Xrandr.h>
26003 #include <X11/extensions/Xrender.h>
26004 #include <X11/extensions/XShm.h>
26005@@ -44,6 +46,8 @@
26006 #endif
26007 #include <xcb/xcb.h>
26008 #include <xcb/present.h>
26009+#include <xcb/xfixes.h>
26010+#include <xcb/dri3.h>
26011 #include <xf86drm.h>
26012 #include <i915_drm.h>
26013
26014@@ -134,12 +138,14 @@ static void *setup_msc(Display *dpy, Window win)
26015 return q;
26016 }
26017
26018-static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc)
26019+static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc, uint64_t *ust)
26020 {
26021 xcb_connection_t *c = XGetXCBConnection(dpy);
26022+ static uint32_t serial = 1;
26023 uint64_t msc = 0;
26024+ int complete = 0;
26025
26026- xcb_present_notify_msc(c, win, 0, 0, 0, 0);
26027+ xcb_present_notify_msc(c, win, serial ^ 0xcc00ffee, 0, 0, 0);
26028 xcb_flush(c);
26029
26030 do {
26031@@ -151,82 +157,1044 @@ static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc)
26032 break;
26033
26034 ce = (xcb_present_complete_notify_event_t *)ev;
26035- if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
26036+ if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
26037+ ce->serial == (serial ^ 0xcc00ffee)) {
26038 msc = ce->msc;
26039+ if (ust)
26040+ *ust = ce->ust;
26041+ complete = 1;
26042+ }
26043+ free(ev);
26044+ } while (!complete);
26045+
26046+ if ((int64_t)(msc - last_msc) < 0) {
26047+ printf("Invalid MSC: was %llu, now %llu\n",
26048+ (long long)last_msc, (long long)msc);
26049+ }
26050+
26051+ if (++serial == 0)
26052+ serial = 1;
26053+
26054+ return msc;
26055+}
26056+
26057+static uint64_t wait_vblank(Display *dpy, Window win, void *q)
26058+{
26059+ xcb_connection_t *c = XGetXCBConnection(dpy);
26060+ static uint32_t serial = 1;
26061+ uint64_t msc = 0;
26062+ int complete = 0;
26063+
26064+ xcb_present_notify_msc(c, win, serial ^ 0xdeadbeef, 0, 1, 0);
26065+ xcb_flush(c);
26066+
26067+ do {
26068+ xcb_present_complete_notify_event_t *ce;
26069+ xcb_generic_event_t *ev;
26070+
26071+ ev = xcb_wait_for_special_event(c, q);
26072+ if (ev == NULL)
26073+ break;
26074+
26075+ ce = (xcb_present_complete_notify_event_t *)ev;
26076+ if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
26077+ ce->serial == (serial ^ 0xdeadbeef)) {
26078+ msc = ce->msc;
26079+ complete = 1;
26080+ }
26081+ free(ev);
26082+ } while (!complete);
26083+
26084+ if (++serial == 0)
26085+ serial = 1;
26086+
26087+ return msc;
26088+}
26089+
26090+static uint64_t msc_interval(Display *dpy, Window win, void *q)
26091+{
26092+ xcb_connection_t *c = XGetXCBConnection(dpy);
26093+ uint64_t msc, ust;
26094+ int complete = 0;
26095+
26096+ msc = check_msc(dpy, win, q, 0, NULL);
26097+
26098+ xcb_present_notify_msc(c, win, 0xc0ffee00, msc, 0, 0);
26099+ xcb_present_notify_msc(c, win, 0xc0ffee01, msc + 10, 0, 0);
26100+ xcb_flush(c);
26101+
26102+ ust = msc = 0;
26103+ do {
26104+ xcb_present_complete_notify_event_t *ce;
26105+ xcb_generic_event_t *ev;
26106+
26107+ ev = xcb_wait_for_special_event(c, q);
26108+ if (ev == NULL)
26109+ break;
26110+
26111+ ce = (xcb_present_complete_notify_event_t *)ev;
26112+ if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
26113+ ce->serial == 0xc0ffee00) {
26114+ msc -= ce->msc;
26115+ ust -= ce->ust;
26116+ complete++;
26117+ }
26118+ if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
26119+ ce->serial == 0xc0ffee01) {
26120+ msc += ce->msc;
26121+ ust += ce->ust;
26122+ complete++;
26123+ }
26124+ free(ev);
26125+ } while (complete != 2);
26126+
26127+ return (ust + msc/2) / msc;
26128+}
26129+
26130+static void teardown_msc(Display *dpy, void *q)
26131+{
26132+ xcb_unregister_for_special_event(XGetXCBConnection(dpy), q);
26133+}
26134+
26135+static int test_whole(Display *dpy, Window win, const char *phase)
26136+{
26137+ xcb_connection_t *c = XGetXCBConnection(dpy);
26138+ Pixmap pixmap;
26139+ struct dri3_fence fence;
26140+ Window root;
26141+ unsigned int width, height;
26142+ unsigned border, depth;
26143+ int x, y, ret = 1;
26144+
26145+ XGetGeometry(dpy, win,
26146+ &root, &x, &y, &width, &height, &border, &depth);
26147+
26148+ if (dri3_create_fence(dpy, win, &fence))
26149+ return 0;
26150+
26151+ printf("%s: Testing simple flip: %dx%d\n", phase, width, height);
26152+ _x_error_occurred = 0;
26153+
26154+ xshmfence_reset(fence.addr);
26155+
26156+ pixmap = XCreatePixmap(dpy, win, width, height, depth);
26157+ xcb_present_pixmap(c, win, pixmap, 0,
26158+ 0, /* valid */
26159+ 0, /* update */
26160+ 0, /* x_off */
26161+ 0, /* y_off */
26162+ None,
26163+ None, /* wait fence */
26164+ fence.xid,
26165+ XCB_PRESENT_OPTION_NONE,
26166+ 0, /* target msc */
26167+ 0, /* divisor */
26168+ 0, /* remainder */
26169+ 0, NULL);
26170+ XFreePixmap(dpy, pixmap);
26171+
26172+ pixmap = XCreatePixmap(dpy, win, width, height, depth);
26173+ xcb_present_pixmap(c, win, pixmap, 0,
26174+ 0, /* valid */
26175+ 0, /* update */
26176+ 0, /* x_off */
26177+ 0, /* y_off */
26178+ None,
26179+ None, /* wait fence */
26180+ None, /* sync fence */
26181+ XCB_PRESENT_OPTION_NONE,
26182+ 0, /* target msc */
26183+ 0, /* divisor */
26184+ 0, /* remainder */
26185+ 0, NULL);
26186+ XFreePixmap(dpy, pixmap);
26187+ XFlush(dpy);
26188+
26189+ ret = !!xshmfence_await(fence.addr);
26190+ dri3_fence_free(dpy, &fence);
26191+
26192+ XSync(dpy, True);
26193+ ret += !!_x_error_occurred;
26194+
26195+ return ret;
26196+}
26197+
26198+static uint64_t flush_flips(Display *dpy, Window win, Pixmap pixmap, void *Q, uint64_t *ust)
26199+{
26200+ xcb_connection_t *c = XGetXCBConnection(dpy);
26201+ uint64_t msc;
26202+ int complete;
26203+
26204+ msc = check_msc(dpy, win, Q, 0, NULL);
26205+ xcb_present_pixmap(c, win, pixmap,
26206+ 0xdeadbeef, /* serial */
26207+ 0, /* valid */
26208+ 0, /* update */
26209+ 0, /* x_off */
26210+ 0, /* y_off */
26211+ None,
26212+ None, /* wait fence */
26213+ None,
26214+ XCB_PRESENT_OPTION_NONE,
26215+ msc + 60, /* target msc */
26216+ 0, /* divisor */
26217+ 0, /* remainder */
26218+ 0, NULL);
26219+ xcb_flush(c);
26220+ complete = 0;
26221+ do {
26222+ xcb_present_complete_notify_event_t *ce;
26223+ xcb_generic_event_t *ev;
26224+
26225+ ev = xcb_wait_for_special_event(c, Q);
26226+ if (ev == NULL)
26227+ break;
26228+
26229+ ce = (xcb_present_complete_notify_event_t *)ev;
26230+ complete = (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP &&
26231+ ce->serial == 0xdeadbeef);
26232+ free(ev);
26233+ } while (!complete);
26234+ XSync(dpy, True);
26235+
26236+ return check_msc(dpy, win, Q, msc, ust);
26237+}
26238+
26239+static int test_double(Display *dpy, Window win, const char *phase, void *Q)
26240+{
26241+#define COUNT (15*60)
26242+ xcb_connection_t *c = XGetXCBConnection(dpy);
26243+ Pixmap pixmap;
26244+ Window root;
26245+ unsigned int width, height;
26246+ unsigned border, depth;
26247+ int x, y, n, ret;
26248+ struct {
26249+ uint64_t msc, ust;
26250+ } frame[COUNT+1];
26251+ int offset = 0;
26252+
26253+ XGetGeometry(dpy, win,
26254+ &root, &x, &y, &width, &height, &border, &depth);
26255+
26256+ printf("%s: Testing flip double buffering: %dx%d\n", phase, width, height);
26257+ _x_error_occurred = 0;
26258+
26259+ pixmap = XCreatePixmap(dpy, win, width, height, depth);
26260+ flush_flips(dpy, win, pixmap, Q, NULL);
26261+ for (n = 0; n <= COUNT; n++) {
26262+ int complete;
26263+
26264+ xcb_present_pixmap(c, win, pixmap, n,
26265+ 0, /* valid */
26266+ 0, /* update */
26267+ 0, /* x_off */
26268+ 0, /* y_off */
26269+ None,
26270+ None, /* wait fence */
26271+ None,
26272+ XCB_PRESENT_OPTION_NONE,
26273+ 0, /* target msc */
26274+ 0, /* divisor */
26275+ 0, /* remainder */
26276+ 0, NULL);
26277+ xcb_flush(c);
26278+
26279+ complete = 0;
26280+ do {
26281+ xcb_present_complete_notify_event_t *ce;
26282+ xcb_generic_event_t *ev;
26283+
26284+ ev = xcb_wait_for_special_event(c, Q);
26285+ if (ev == NULL)
26286+ break;
26287+
26288+ ce = (xcb_present_complete_notify_event_t *)ev;
26289+ if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP &&
26290+ ce->serial == n) {
26291+ frame[n].msc = ce->msc;
26292+ frame[n].ust = ce->ust;
26293+ complete = 1;
26294+ }
26295+ free(ev);
26296+ } while (!complete);
26297+ }
26298+ XFreePixmap(dpy, pixmap);
26299+
26300+ XSync(dpy, True);
26301+ ret = !!_x_error_occurred;
26302+
26303+ if (frame[COUNT].msc - frame[0].msc != COUNT) {
26304+ printf("Expected %d frames interval, %d elapsed instead\n",
26305+ COUNT, (int)(frame[COUNT].msc - frame[0].msc));
26306+ for (n = 0; n <= COUNT; n++) {
26307+ if (frame[n].msc - frame[0].msc != n + offset) {
26308+ printf("frame[%d]: msc=%03lld, ust=%lld\n", n,
26309+ (long long)(frame[n].msc - frame[0].msc),
26310+ (long long)(frame[n].ust - frame[0].ust));
26311+ offset = frame[n].msc - frame[0].msc - n;
26312+ ret++;
26313+ }
26314+ }
26315+ }
26316+
26317+ return ret;
26318+}
26319+
26320+static int test_future(Display *dpy, Window win, const char *phase, void *Q)
26321+{
26322+ xcb_connection_t *c = XGetXCBConnection(dpy);
26323+ Pixmap pixmap;
26324+ struct dri3_fence fence;
26325+ Window root;
26326+ unsigned int width, height;
26327+ unsigned border, depth;
26328+ int x, y, ret = 0, n;
26329+ uint64_t msc, ust;
26330+ int complete;
26331+ int early = 0, late = 0;
26332+ int earliest = 0, latest = 0;
26333+ uint64_t interval;
26334+
26335+ XGetGeometry(dpy, win,
26336+ &root, &x, &y, &width, &height, &border, &depth);
26337+
26338+ if (dri3_create_fence(dpy, win, &fence))
26339+ return 0;
26340+
26341+ printf("%s: Testing flips into the future: %dx%d\n", phase, width, height);
26342+ _x_error_occurred = 0;
26343+
26344+ interval = msc_interval(dpy, win, Q);
26345+
26346+ pixmap = XCreatePixmap(dpy, win, width, height, depth);
26347+ msc = flush_flips(dpy, win, pixmap, Q, &ust);
26348+ for (n = 1; n <= 10; n++)
26349+ xcb_present_pixmap(c, win, pixmap,
26350+ n, /* serial */
26351+ 0, /* valid */
26352+ 0, /* update */
26353+ 0, /* x_off */
26354+ 0, /* y_off */
26355+ None,
26356+ None, /* wait fence */
26357+ None,
26358+ XCB_PRESENT_OPTION_NONE,
26359+ msc + 60 + n*15*60, /* target msc */
26360+ 0, /* divisor */
26361+ 0, /* remainder */
26362+ 0, NULL);
26363+ xcb_present_pixmap(c, win, pixmap,
26364+ 0xdeadbeef, /* serial */
26365+ 0, /* valid */
26366+ 0, /* update */
26367+ 0, /* x_off */
26368+ 0, /* y_off */
26369+ None,
26370+ None, /* wait fence */
26371+ None,
26372+ XCB_PRESENT_OPTION_NONE,
26373+ msc + 60 + n*15*60, /* target msc */
26374+ 0, /* divisor */
26375+ 0, /* remainder */
26376+ 0, NULL);
26377+ xcb_flush(c);
26378+
26379+ complete = 0;
26380+ do {
26381+ xcb_present_complete_notify_event_t *ce;
26382+ xcb_generic_event_t *ev;
26383+
26384+ ev = xcb_wait_for_special_event(c, Q);
26385+ if (ev == NULL)
26386+ break;
26387+
26388+ ce = (xcb_present_complete_notify_event_t *)ev;
26389+ assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP);
26390+
26391+ if (ce->serial == 0xdeadbeef) {
26392+ int64_t time;
26393+
26394+ time = ce->ust - (ust + (60 + 15*60*n) * interval);
26395+ if (time < -(int64_t)interval) {
26396+ fprintf(stderr,
26397+ "\tflips completed too early by %lldms\n",
26398+ (long long)(-time / 1000));
26399+ } else if (time > (int64_t)interval) {
26400+ fprintf(stderr,
26401+ "\tflips completed too late by %lldms\n",
26402+ (long long)(time / 1000));
26403+ }
26404+ complete = 1;
26405+ } else {
26406+ int diff = (int64_t)(ce->msc - (15*60*ce->serial + msc + 60));
26407+ if (diff < 0) {
26408+ if (-diff > earliest) {
26409+ fprintf(stderr, "\tframe %d displayed early by %d frames\n", ce->serial, -diff);
26410+ earliest = -diff;
26411+ }
26412+ early++;
26413+ ret++;
26414+ } else if (diff > 0) {
26415+ if (diff > latest) {
26416+ fprintf(stderr, "\tframe %d displayed late by %d frames\n", ce->serial, diff);
26417+ latest = diff;
26418+ }
26419+ late++;
26420+ ret++;
26421+ }
26422+ }
26423+ free(ev);
26424+ } while (!complete);
26425+
26426+ if (early)
26427+ printf("\t%d frames shown too early (worst %d)!\n", early, earliest);
26428+ if (late)
26429+ printf("\t%d frames shown too late (worst %d)!\n", late, latest);
26430+
26431+ ret += !!_x_error_occurred;
26432+
26433+ return ret;
26434+}
26435+
26436+static int test_exhaustion(Display *dpy, Window win, const char *phase, void *Q)
26437+{
26438+#define N_VBLANKS 256 /* kernel event queue length: 128 vblanks */
26439+ xcb_connection_t *c = XGetXCBConnection(dpy);
26440+ Pixmap pixmap;
26441+ struct dri3_fence fence[2];
26442+ Window root;
26443+ xcb_xfixes_region_t region;
26444+ unsigned int width, height;
26445+ unsigned border, depth;
26446+ int x, y, ret = 0, n;
26447+ uint64_t target, final;
26448+
26449+ XGetGeometry(dpy, win,
26450+ &root, &x, &y, &width, &height, &border, &depth);
26451+
26452+ if (dri3_create_fence(dpy, win, &fence[0]) ||
26453+ dri3_create_fence(dpy, win, &fence[1]))
26454+ return 0;
26455+
26456+ printf("%s: Testing flips with long vblank queues: %dx%d\n", phase, width, height);
26457+ _x_error_occurred = 0;
26458+
26459+ region = xcb_generate_id(c);
26460+ xcb_xfixes_create_region(c, region, 0, NULL);
26461+
26462+ pixmap = XCreatePixmap(dpy, win, width, height, depth);
26463+ xshmfence_reset(fence[0].addr);
26464+ xshmfence_reset(fence[1].addr);
26465+ target = check_msc(dpy, win, Q, 0, NULL);
26466+ for (n = N_VBLANKS; n--; )
26467+ xcb_present_pixmap(c, win, pixmap, 0,
26468+ 0, /* valid */
26469+ region, /* update */
26470+ 0, /* x_off */
26471+ 0, /* y_off */
26472+ None,
26473+ None, /* wait fence */
26474+ None,
26475+ XCB_PRESENT_OPTION_NONE,
26476+ target + N_VBLANKS, /* target msc */
26477+ 1, /* divisor */
26478+ 0, /* remainder */
26479+ 0, NULL);
26480+ xcb_present_pixmap(c, win, pixmap, 0,
26481+ region, /* valid */
26482+ region, /* update */
26483+ 0, /* x_off */
26484+ 0, /* y_off */
26485+ None,
26486+ None, /* wait fence */
26487+ fence[0].xid,
26488+ XCB_PRESENT_OPTION_NONE,
26489+ target, /* target msc */
26490+ 0, /* divisor */
26491+ 0, /* remainder */
26492+ 0, NULL);
26493+ for (n = 1; n < N_VBLANKS; n++)
26494+ xcb_present_pixmap(c, win, pixmap, 0,
26495+ region, /* valid */
26496+ region, /* update */
26497+ 0, /* x_off */
26498+ 0, /* y_off */
26499+ None,
26500+ None, /* wait fence */
26501+ None,
26502+ XCB_PRESENT_OPTION_NONE,
26503+ target + n, /* target msc */
26504+ 0, /* divisor */
26505+ 0, /* remainder */
26506+ 0, NULL);
26507+ xcb_present_pixmap(c, win, pixmap, 0,
26508+ region, /* valid */
26509+ region, /* update */
26510+ 0, /* x_off */
26511+ 0, /* y_off */
26512+ None,
26513+ None, /* wait fence */
26514+ fence[1].xid,
26515+ XCB_PRESENT_OPTION_NONE,
26516+ target + N_VBLANKS, /* target msc */
26517+ 0, /* divisor */
26518+ 0, /* remainder */
26519+ 0, NULL);
26520+ xcb_flush(c);
26521+
26522+ ret += !!xshmfence_await(fence[0].addr);
26523+ final = check_msc(dpy, win, Q, 0, NULL);
26524+ if (final < target) {
26525+ printf("\tFirst flip too early, MSC was %llu, expected %llu\n",
26526+ (long long)final, (long long)target);
26527+ ret++;
26528+ } else if (final > target + 1) {
26529+ printf("\tFirst flip too late, MSC was %llu, expected %llu\n",
26530+ (long long)final, (long long)target);
26531+ ret++;
26532+ }
26533+
26534+ ret += !!xshmfence_await(fence[1].addr);
26535+ final = check_msc(dpy, win, Q, 0, NULL);
26536+ if (final < target + N_VBLANKS) {
26537+ printf("\tLast flip too early, MSC was %llu, expected %llu\n",
26538+ (long long)final, (long long)(target + N_VBLANKS));
26539+ ret++;
26540+ } else if (final > target + N_VBLANKS + 1) {
26541+ printf("\tLast flip too late, MSC was %llu, expected %llu\n",
26542+ (long long)final, (long long)(target + N_VBLANKS));
26543+ ret++;
26544+ }
26545+
26546+ flush_flips(dpy, win, pixmap, Q, NULL);
26547+
26548+ XFreePixmap(dpy, pixmap);
26549+ xcb_xfixes_destroy_region(c, region);
26550+ dri3_fence_free(dpy, &fence[1]);
26551+ dri3_fence_free(dpy, &fence[0]);
26552+
26553+ XSync(dpy, True);
26554+ ret += !!_x_error_occurred;
26555+
26556+ return ret;
26557+#undef N_VBLANKS
26558+}
26559+
26560+static int test_accuracy(Display *dpy, Window win, const char *phase, void *Q)
26561+{
26562+#define N_VBLANKS (60 * 120) /* ~2 minutes */
26563+ xcb_connection_t *c = XGetXCBConnection(dpy);
26564+ Pixmap pixmap;
26565+ Window root;
26566+ unsigned int width, height;
26567+ unsigned border, depth;
26568+ int x, y, ret = 0, n;
26569+ uint64_t target;
26570+ int early = 0, late = 0;
26571+ int earliest = 0, latest = 0;
26572+ int complete;
26573+
26574+ XGetGeometry(dpy, win,
26575+ &root, &x, &y, &width, &height, &border, &depth);
26576+
26577+ printf("%s: Testing flip accuracy: %dx%d\n", phase, width, height);
26578+ _x_error_occurred = 0;
26579+
26580+ pixmap = XCreatePixmap(dpy, win, width, height, depth);
26581+ target = flush_flips(dpy, win, pixmap, Q, NULL);
26582+ for (n = 0; n <= N_VBLANKS; n++)
26583+ xcb_present_pixmap(c, win, pixmap,
26584+ n, /* serial */
26585+ 0, /* valid */
26586+ 0, /* update */
26587+ 0, /* x_off */
26588+ 0, /* y_off */
26589+ None,
26590+ None, /* wait fence */
26591+ None,
26592+ XCB_PRESENT_OPTION_NONE,
26593+ target + 60 + n, /* target msc */
26594+ 0, /* divisor */
26595+ 0, /* remainder */
26596+ 0, NULL);
26597+ xcb_present_pixmap(c, win, pixmap,
26598+ 0xdeadbeef, /* serial */
26599+ 0, /* valid */
26600+ 0, /* update */
26601+ 0, /* x_off */
26602+ 0, /* y_off */
26603+ None,
26604+ None, /* wait fence */
26605+ None,
26606+ XCB_PRESENT_OPTION_NONE,
26607+ target + 60 + n, /* target msc */
26608+ 0, /* divisor */
26609+ 0, /* remainder */
26610+ 0, NULL);
26611+ xcb_flush(c);
26612+
26613+ complete = 0;
26614+ do {
26615+ xcb_present_complete_notify_event_t *ce;
26616+ xcb_generic_event_t *ev;
26617+
26618+ ev = xcb_wait_for_special_event(c, Q);
26619+ if (ev == NULL)
26620+ break;
26621+
26622+ ce = (xcb_present_complete_notify_event_t *)ev;
26623+ assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP);
26624+
26625+ if (ce->serial != 0xdeadbeef) {
26626+ int diff = (int64_t)(ce->msc - (target + ce->serial + 60));
26627+ if (diff < 0) {
26628+ if (-diff > earliest) {
26629+ fprintf(stderr, "\tframe %d displayed early by %d frames\n", ce->serial, -diff);
26630+ earliest = -diff;
26631+ }
26632+ early++;
26633+ ret++;
26634+ } else if (diff > 0) {
26635+ if (diff > latest) {
26636+ fprintf(stderr, "\tframe %d displayed late by %d frames\n", ce->serial, diff);
26637+ latest = diff;
26638+ }
26639+ late++;
26640+ ret++;
26641+ }
26642+ } else
26643+ complete = 1;
26644+ free(ev);
26645+ } while (!complete);
26646+
26647+ if (early)
26648+ printf("\t%d frames shown too early (worst %d)!\n", early, earliest);
26649+ if (late)
26650+ printf("\t%d frames shown too late (worst %d)!\n", late, latest);
26651+
26652+ XFreePixmap(dpy, pixmap);
26653+
26654+ XSync(dpy, True);
26655+ ret += !!_x_error_occurred;
26656+
26657+ return ret;
26658+#undef N_VBLANKS
26659+}
26660+
26661+static int test_modulus(Display *dpy, Window win, const char *phase, void *Q)
26662+{
26663+ xcb_connection_t *c = XGetXCBConnection(dpy);
26664+ Pixmap pixmap;
26665+ Window root;
26666+ unsigned int width, height;
26667+ unsigned border, depth;
26668+ xcb_xfixes_region_t region;
26669+ int x, y, ret = 0;
26670+ uint64_t target;
26671+ int early = 0, late = 0;
26672+ int earliest = 0, latest = 0;
26673+ int complete;
26674+
26675+ XGetGeometry(dpy, win,
26676+ &root, &x, &y, &width, &height, &border, &depth);
26677+
26678+ printf("%s: Testing flip modulus: %dx%d\n", phase, width, height);
26679+ _x_error_occurred = 0;
26680+
26681+ region = xcb_generate_id(c);
26682+ xcb_xfixes_create_region(c, region, 0, NULL);
26683+
26684+ pixmap = XCreatePixmap(dpy, win, width, height, depth);
26685+ target = flush_flips(dpy, win, pixmap, Q, NULL);
26686+ for (x = 1; x <= 7; x++) {
26687+ for (y = 0; y < x; y++) {
26688+ xcb_present_pixmap(c, win, pixmap,
26689+ y << 16 | x, /* serial */
26690+ region, /* valid */
26691+ region, /* update */
26692+ 0, /* x_off */
26693+ 0, /* y_off */
26694+ None,
26695+ None, /* wait fence */
26696+ None,
26697+ XCB_PRESENT_OPTION_NONE,
26698+ 0, /* target msc */
26699+ x, /* divisor */
26700+ y, /* remainder */
26701+ 0, NULL);
26702+ }
26703+ }
26704+ xcb_present_pixmap(c, win, pixmap,
26705+ 0xdeadbeef, /* serial */
26706+ 0, /* valid */
26707+ 0, /* update */
26708+ 0, /* x_off */
26709+ 0, /* y_off */
26710+ None,
26711+ None, /* wait fence */
26712+ None,
26713+ XCB_PRESENT_OPTION_NONE,
26714+ target + 2*x, /* target msc */
26715+ 0, /* divisor */
26716+ 0, /* remainder */
26717+ 0, NULL);
26718+ xcb_flush(c);
26719+
26720+ complete = 0;
26721+ do {
26722+ xcb_present_complete_notify_event_t *ce;
26723+ xcb_generic_event_t *ev;
26724+
26725+ ev = xcb_wait_for_special_event(c, Q);
26726+ if (ev == NULL)
26727+ break;
26728+
26729+ ce = (xcb_present_complete_notify_event_t *)ev;
26730+ if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
26731+ break;
26732+
26733+ assert(ce->serial);
26734+ if (ce->serial != 0xdeadbeef) {
26735+ uint64_t msc;
26736+ int diff;
26737+
26738+ x = ce->serial & 0xffff;
26739+ y = ce->serial >> 16;
26740+
26741+ msc = target;
26742+ msc -= target % x;
26743+ msc += y;
26744+ if (msc <= target)
26745+ msc += x;
26746+
26747+ diff = (int64_t)(ce->msc - msc);
26748+ if (diff < 0) {
26749+ if (-diff > earliest) {
26750+ fprintf(stderr, "\tframe (%d, %d) displayed early by %d frames\n", y, x, -diff);
26751+ earliest = -diff;
26752+ }
26753+ early++;
26754+ ret++;
26755+ } else if (diff > 0) {
26756+ if (diff > latest) {
26757+ fprintf(stderr, "\tframe (%d, %d) displayed late by %d frames\n", y, x, diff);
26758+ latest = diff;
26759+ }
26760+ late++;
26761+ ret++;
26762+ }
26763+ } else
26764+ complete = 1;
26765+ free(ev);
26766+ } while (!complete);
26767+
26768+ if (early)
26769+ printf("\t%d frames shown too early (worst %d)!\n", early, earliest);
26770+ if (late)
26771+ printf("\t%d frames shown too late (worst %d)!\n", late, latest);
26772+
26773+ XFreePixmap(dpy, pixmap);
26774+ xcb_xfixes_destroy_region(c, region);
26775+
26776+ XSync(dpy, True);
26777+ ret += !!_x_error_occurred;
26778+
26779+ return ret;
26780+}
26781+
26782+static int test_future_msc(Display *dpy, void *Q)
26783+{
26784+ xcb_connection_t *c = XGetXCBConnection(dpy);
26785+ Window root = DefaultRootWindow(dpy);
26786+ int ret = 0, n;
26787+ uint64_t msc, ust;
26788+ int complete;
26789+ int early = 0, late = 0;
26790+ int earliest = 0, latest = 0;
26791+ uint64_t interval;
26792+
26793+ printf("Testing notifies into the future\n");
26794+ _x_error_occurred = 0;
26795+
26796+ interval = msc_interval(dpy, root, Q);
26797+ msc = check_msc(dpy, root, Q, 0, &ust);
26798+
26799+ for (n = 1; n <= 10; n++)
26800+ xcb_present_notify_msc(c, root, n, msc + 60 + n*15*60, 0, 0);
26801+ xcb_present_notify_msc(c, root, 0xdeadbeef, msc + 60 + n*15*60, 0, 0);
26802+ xcb_flush(c);
26803+
26804+ complete = 0;
26805+ do {
26806+ xcb_present_complete_notify_event_t *ce;
26807+ xcb_generic_event_t *ev;
26808+
26809+ ev = xcb_wait_for_special_event(c, Q);
26810+ if (ev == NULL)
26811+ break;
26812+
26813+ ce = (xcb_present_complete_notify_event_t *)ev;
26814+ assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
26815+
26816+ if (ce->serial == 0xdeadbeef) {
26817+ int64_t time;
26818+
26819+ time = ce->ust - (ust + (60 + 15*60*n) * interval);
26820+ if (time < -(int64_t)interval) {
26821+ fprintf(stderr,
26822+ "\tnotifies completed too early by %lldms\n",
26823+ (long long)(-time / 1000));
26824+ } else if (time > (int64_t)interval) {
26825+ fprintf(stderr,
26826+ "\tnotifies completed too late by %lldms\n",
26827+ (long long)(time / 1000));
26828+ }
26829+ complete = 1;
26830+ } else {
26831+ int diff = (int64_t)(ce->msc - (15*60*ce->serial + msc + 60));
26832+ if (diff < 0) {
26833+ if (-diff > earliest) {
26834+ fprintf(stderr, "\tnotify %d early by %d msc\n", ce->serial, -diff);
26835+ earliest = -diff;
26836+ }
26837+ early++;
26838+ ret++;
26839+ } else if (diff > 0) {
26840+ if (diff > latest) {
26841+ fprintf(stderr, "\tnotify %d late by %d msc\n", ce->serial, diff);
26842+ latest = diff;
26843+ }
26844+ late++;
26845+ ret++;
26846+ }
26847+ }
26848 free(ev);
26849- } while (msc == 0);
26850+ } while (!complete);
26851
26852- if (msc < last_msc) {
26853- printf("Invalid MSC: was %llu, now %llu\n",
26854- (long long)last_msc, (long long)msc);
26855- }
26856+ if (early)
26857+ printf("\t%d notifies too early (worst %d)!\n", early, earliest);
26858+ if (late)
26859+ printf("\t%d notifies too late (worst %d)!\n", late, latest);
26860
26861- return msc;
26862+ XSync(dpy, True);
26863+ ret += !!_x_error_occurred;
26864+
26865+ return ret;
26866 }
26867
26868-static void teardown_msc(Display *dpy, void *q)
26869+static int test_exhaustion_msc(Display *dpy, void *Q)
26870 {
26871- xcb_unregister_for_special_event(XGetXCBConnection(dpy), q);
26872+#define N_VBLANKS 256 /* kernel event queue length: 128 vblanks */
26873+ xcb_connection_t *c = XGetXCBConnection(dpy);
26874+ Window root = DefaultRootWindow(dpy);
26875+ int ret = 0, n, complete;
26876+ int earliest = 0, early = 0;
26877+ int latest = 0, late = 0;
26878+ uint64_t msc;
26879+
26880+ printf("Testing notifies with long queues\n");
26881+ _x_error_occurred = 0;
26882+
26883+ msc = check_msc(dpy, root, Q, 0, NULL);
26884+ for (n = N_VBLANKS; n--; )
26885+ xcb_present_notify_msc(c, root, N_VBLANKS, msc + N_VBLANKS, 0, 0);
26886+ for (n = 1; n <= N_VBLANKS ; n++)
26887+ xcb_present_notify_msc(c, root, n, msc + n, 0, 0);
26888+ xcb_flush(c);
26889+
26890+ complete = 2*N_VBLANKS;
26891+ do {
26892+ xcb_present_complete_notify_event_t *ce;
26893+ xcb_generic_event_t *ev;
26894+ int diff;
26895+
26896+ ev = xcb_wait_for_special_event(c, Q);
26897+ if (ev == NULL)
26898+ break;
26899+
26900+ ce = (xcb_present_complete_notify_event_t *)ev;
26901+ assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
26902+
26903+ diff = (int64_t)(ce->msc - msc - ce->serial);
26904+ if (diff < 0) {
26905+ if (-diff > earliest) {
26906+ fprintf(stderr, "\tnotify %d early by %d msc\n",(int)ce->serial, -diff);
26907+ earliest = -diff;
26908+ }
26909+ early++;
26910+ ret++;
26911+ } else if (diff > 0) {
26912+ if (diff > latest) {
26913+ fprintf(stderr, "\tnotify %d late by %d msc\n", (int)ce->serial, diff);
26914+ latest = diff;
26915+ }
26916+ late++;
26917+ ret++;
26918+ }
26919+ free(ev);
26920+ } while (--complete);
26921+
26922+ if (early)
26923+ printf("\t%d notifies too early (worst %d)!\n", early, earliest);
26924+ if (late)
26925+ printf("\t%d notifies too late (worst %d)!\n", late, latest);
26926+
26927+ XSync(dpy, True);
26928+ ret += !!_x_error_occurred;
26929+
26930+ return ret;
26931+#undef N_VBLANKS
26932 }
26933-static int test_whole(Display *dpy)
26934+
26935+static int test_accuracy_msc(Display *dpy, void *Q)
26936 {
26937- Pixmap pixmap;
26938- struct dri3_fence fence;
26939- Window root;
26940- unsigned int width, height;
26941- unsigned border, depth;
26942- int x, y, ret = 1;
26943+#define N_VBLANKS (60 * 120) /* ~2 minutes */
26944+ xcb_connection_t *c = XGetXCBConnection(dpy);
26945+ Window root = DefaultRootWindow(dpy);
26946+ int ret = 0, n;
26947+ uint64_t msc;
26948+ int early = 0, late = 0;
26949+ int earliest = 0, latest = 0;
26950+ int complete;
26951
26952- XGetGeometry(dpy, DefaultRootWindow(dpy),
26953- &root, &x, &y, &width, &height, &border, &depth);
26954+ printf("Testing notify accuracy\n");
26955+ _x_error_occurred = 0;
26956
26957- if (dri3_create_fence(dpy, root, &fence))
26958- return 0;
26959+ msc = check_msc(dpy, root, Q, 0, NULL);
26960+ for (n = 0; n <= N_VBLANKS; n++)
26961+ xcb_present_notify_msc(c, root, n, msc + 60 + n, 0, 0);
26962+ xcb_present_notify_msc(c, root, 0xdeadbeef, msc + 60 + n, 0, 0);
26963+ xcb_flush(c);
26964+
26965+ complete = 0;
26966+ do {
26967+ xcb_present_complete_notify_event_t *ce;
26968+ xcb_generic_event_t *ev;
26969+
26970+ ev = xcb_wait_for_special_event(c, Q);
26971+ if (ev == NULL)
26972+ break;
26973+
26974+ ce = (xcb_present_complete_notify_event_t *)ev;
26975+ assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
26976+
26977+ if (ce->serial != 0xdeadbeef) {
26978+ int diff = (int64_t)(ce->msc - (msc + ce->serial + 60));
26979+ if (diff < 0) {
26980+ if (-diff > earliest) {
26981+ fprintf(stderr, "\tnotify %d early by %d msc\n", ce->serial, -diff);
26982+ earliest = -diff;
26983+ }
26984+ early++;
26985+ ret++;
26986+ } else if (diff > 0) {
26987+ if (diff > latest) {
26988+ fprintf(stderr, "\tnotify %d late by %d msc\n", ce->serial, diff);
26989+ latest = diff;
26990+ }
26991+ late++;
26992+ ret++;
26993+ }
26994+ } else
26995+ complete = 1;
26996+ free(ev);
26997+ } while (!complete);
26998+
26999+ if (early)
27000+ printf("\t%d notifies too early (worst %d)!\n", early, earliest);
27001+ if (late)
27002+ printf("\t%d notifies too late (worst %d)!\n", late, latest);
27003
27004- printf("Testing whole screen flip: %dx%d\n", width, height);
27005+ XSync(dpy, True);
27006+ ret += !!_x_error_occurred;
27007+
27008+ return ret;
27009+#undef N_VBLANKS
27010+}
27011+
27012+static int test_modulus_msc(Display *dpy, void *Q)
27013+{
27014+ xcb_connection_t *c = XGetXCBConnection(dpy);
27015+ Window root = DefaultRootWindow(dpy);
27016+ xcb_present_complete_notify_event_t *ce;
27017+ xcb_generic_event_t *ev;
27018+ int x, y, ret = 0;
27019+ uint64_t target;
27020+ int early = 0, late = 0;
27021+ int earliest = 0, latest = 0;
27022+ int complete;
27023+
27024+ printf("Testing notify modulus\n");
27025 _x_error_occurred = 0;
27026
27027- xshmfence_reset(fence.addr);
27028+ target = wait_vblank(dpy, root, Q);
27029
27030- pixmap = XCreatePixmap(dpy, root, width, height, depth);
27031- xcb_present_pixmap(XGetXCBConnection(dpy),
27032- root, pixmap,
27033- 0, /* sbc */
27034- 0, /* valid */
27035- 0, /* update */
27036- 0, /* x_off */
27037- 0, /* y_off */
27038- None,
27039- None, /* wait fence */
27040- fence.xid,
27041- XCB_PRESENT_OPTION_NONE,
27042- 0, /* target msc */
27043- 0, /* divisor */
27044- 0, /* remainder */
27045- 0, NULL);
27046- XFreePixmap(dpy, pixmap);
27047+ xcb_present_notify_msc(c, root, 0, 0, 0, 0);
27048+ for (x = 1; x <= 19; x++) {
27049+ for (y = 0; y < x; y++)
27050+ xcb_present_notify_msc(c, root, y << 16 | x, 0, x, y);
27051+ }
27052+ xcb_present_notify_msc(c, root, 0xdeadbeef, target + 2*x, 0, 0);
27053+ xcb_flush(c);
27054
27055- pixmap = XCreatePixmap(dpy, root, width, height, depth);
27056- xcb_present_pixmap(XGetXCBConnection(dpy),
27057- root, pixmap,
27058- 0, /* sbc */
27059- 0, /* valid */
27060- 0, /* update */
27061- 0, /* x_off */
27062- 0, /* y_off */
27063- None,
27064- None, /* wait fence */
27065- None, /* sync fence */
27066- XCB_PRESENT_OPTION_NONE,
27067- 0, /* target msc */
27068- 0, /* divisor */
27069- 0, /* remainder */
27070- 0, NULL);
27071- XFreePixmap(dpy, pixmap);
27072- XFlush(dpy);
27073+ ev = xcb_wait_for_special_event(c, Q);
27074+ if (ev) {
27075+ ce = (xcb_present_complete_notify_event_t *)ev;
27076+ assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
27077+ assert(ce->serial == 0);
27078+ assert(target == ce->msc);
27079+ target = ce->msc;
27080+ }
27081
27082- ret = !!xshmfence_await(fence.addr);
27083- dri3_fence_free(dpy, &fence);
27084+ complete = 0;
27085+ do {
27086+ ev = xcb_wait_for_special_event(c, Q);
27087+ if (ev == NULL)
27088+ break;
27089+
27090+ ce = (xcb_present_complete_notify_event_t *)ev;
27091+ assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
27092+
27093+ assert(ce->serial);
27094+ if (ce->serial != 0xdeadbeef) {
27095+ uint64_t msc;
27096+ int diff;
27097+
27098+ x = ce->serial & 0xffff;
27099+ y = ce->serial >> 16;
27100+
27101+ msc = target;
27102+ msc -= target % x;
27103+ msc += y;
27104+ if (msc <= target)
27105+ msc += x;
27106+
27107+ diff = (int64_t)(ce->msc - msc);
27108+ if (diff < 0) {
27109+ if (-diff > earliest) {
27110+ fprintf(stderr, "\tnotify (%d, %d) early by %d msc (target %lld, reported %lld)\n", y, x, -diff, (long long)msc, (long long)ce->msc);
27111+ earliest = -diff;
27112+ }
27113+ early++;
27114+ ret++;
27115+ } else if (diff > 0) {
27116+ if (diff > latest) {
27117+ fprintf(stderr, "\tnotify (%d, %d) late by %d msc (target %lld, reported %lld)\n", y, x, diff, (long long)msc, (long long)ce->msc);
27118+ latest = diff;
27119+ }
27120+ late++;
27121+ ret++;
27122+ }
27123+ } else
27124+ complete = 1;
27125+ free(ev);
27126+ } while (!complete);
27127+
27128+ if (early)
27129+ printf("\t%d notifies too early (worst %d)!\n", early, earliest);
27130+ if (late)
27131+ printf("\t%d notifies too late (worst %d)!\n", late, latest);
27132
27133 XSync(dpy, True);
27134 ret += !!_x_error_occurred;
27135@@ -279,8 +1247,6 @@ static int for_each_crtc(Display *dpy,
27136 for (i = 0; i < res->ncrtc; i++)
27137 original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
27138
27139- printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc);
27140-
27141 for (i = 0; i < res->noutput; i++) {
27142 XRROutputInfo *output;
27143 XRRModeInfo *mode;
27144@@ -322,7 +1288,7 @@ static int for_each_crtc(Display *dpy,
27145 free(original_crtc);
27146 XRRFreeScreenResources(res);
27147
27148- return j;
27149+ return err;
27150 }
27151
27152 struct test_crtc {
27153@@ -335,6 +1301,7 @@ struct test_crtc {
27154 uint64_t msc;
27155 };
27156 #define SYNC 0x1
27157+#define FUTURE 0x2
27158
27159 static int __test_crtc(Display *dpy, RRCrtc crtc,
27160 int width, int height,
27161@@ -344,7 +1311,7 @@ static int __test_crtc(Display *dpy, RRCrtc crtc,
27162 Pixmap pixmap;
27163 int err = 0;
27164
27165- test->msc = check_msc(dpy, test->win, test->queue, test->msc);
27166+ test->msc = check_msc(dpy, test->win, test->queue, test->msc, NULL);
27167
27168 if (test->flags & SYNC)
27169 xshmfence_reset(test->fence.addr);
27170@@ -361,16 +1328,14 @@ static int __test_crtc(Display *dpy, RRCrtc crtc,
27171 None, /* wait fence */
27172 test->flags & SYNC ? test->fence.xid : None,
27173 XCB_PRESENT_OPTION_NONE,
27174- 0, /* target msc */
27175+ test->msc, /* target msc */
27176 1, /* divisor */
27177 0, /* remainder */
27178 0, NULL);
27179- XFreePixmap(dpy, pixmap);
27180-
27181 if (test->flags & SYNC) {
27182- pixmap = XCreatePixmap(dpy, test->win, width, height, test->depth);
27183+ Pixmap tmp = XCreatePixmap(dpy, test->win, width, height, test->depth);
27184 xcb_present_pixmap(XGetXCBConnection(dpy),
27185- test->win, pixmap,
27186+ test->win, tmp,
27187 1, /* sbc */
27188 0, /* valid */
27189 0, /* update */
27190@@ -380,16 +1345,17 @@ static int __test_crtc(Display *dpy, RRCrtc crtc,
27191 None, /* wait fence */
27192 None, /* sync fence */
27193 XCB_PRESENT_OPTION_NONE,
27194- 1, /* target msc */
27195+ test->msc + (test->flags & FUTURE ? 5 * 16 : 1), /* target msc */
27196 1, /* divisor */
27197 0, /* remainder */
27198 0, NULL);
27199- XFreePixmap(dpy, pixmap);
27200+ XFreePixmap(dpy, tmp);
27201 XFlush(dpy);
27202 err += !!xshmfence_await(test->fence.addr);
27203 }
27204+ XFreePixmap(dpy, pixmap);
27205
27206- test->msc = check_msc(dpy, test->win, test->queue, test->msc);
27207+ test->msc = check_msc(dpy, test->win, test->queue, test->msc, NULL);
27208 return err;
27209 }
27210
27211@@ -410,15 +1376,23 @@ static int test_crtc(Display *dpy, void *queue, uint64_t last_msc)
27212
27213 printf("Testing each crtc, without waiting for each flip\n");
27214 test.flags = 0;
27215+ test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
27216 err += for_each_crtc(dpy, __test_crtc, &test);
27217+ test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
27218
27219 printf("Testing each crtc, waiting for flips to complete\n");
27220 test.flags = SYNC;
27221+ test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
27222 err += for_each_crtc(dpy, __test_crtc, &test);
27223+ test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
27224
27225- test.msc = check_msc(dpy, test.win, test.queue, test.msc);
27226- dri3_fence_free(dpy, &test.fence);
27227+ printf("Testing each crtc, with future flips\n");
27228+ test.flags = FUTURE | SYNC;
27229+ test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
27230+ err += for_each_crtc(dpy, __test_crtc, &test);
27231+ test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
27232
27233+ dri3_fence_free(dpy, &test.fence);
27234 XSync(dpy, True);
27235 err += !!_x_error_occurred;
27236
27237@@ -536,6 +1510,31 @@ static int gem_set_caching(int fd, uint32_t handle, int caching)
27238 return drmIoctl(fd, LOCAL_IOCTL_I915_GEM_SET_CACHING, &arg) == 0;
27239 }
27240
27241+static int gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
27242+{
27243+ struct drm_i915_gem_set_tiling set_tiling;
27244+ int err;
27245+
27246+restart:
27247+ set_tiling.handle = handle;
27248+ set_tiling.tiling_mode = tiling;
27249+ set_tiling.stride = stride;
27250+
27251+ if (drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0)
27252+ return 1;
27253+
27254+ err = errno;
27255+ if (err == EINTR)
27256+ goto restart;
27257+
27258+ if (err == EAGAIN) {
27259+ sched_yield();
27260+ goto restart;
27261+ }
27262+
27263+ return 0;
27264+}
27265+
27266 static int gem_export(int fd, uint32_t handle)
27267 {
27268 struct drm_prime_handle args;
27269@@ -557,6 +1556,126 @@ static void gem_close(int fd, uint32_t handle)
27270 (void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close);
27271 }
27272
27273+static int test_dri3_tiling(Display *dpy)
27274+{
27275+ Window win = DefaultRootWindow(dpy);
27276+ const int tiling[] = { I915_TILING_NONE, I915_TILING_X, I915_TILING_Y };
27277+ Window root;
27278+ unsigned int width, height;
27279+ unsigned border, depth, bpp;
27280+ unsigned stride, size;
27281+ void *Q;
27282+ int x, y;
27283+ int device;
27284+ int line = -1;
27285+ int t;
27286+
27287+ device = dri3_open(dpy);
27288+ if (device < 0)
27289+ return 0;
27290+
27291+ if (!is_intel(device))
27292+ return 0;
27293+
27294+ printf("Opened Intel DRI3 device\n");
27295+
27296+ XGetGeometry(dpy, win, &root, &x, &y,
27297+ &width, &height, &border, &depth);
27298+
27299+ switch (depth) {
27300+ case 8: bpp = 8; break;
27301+ case 15: case 16: bpp = 16; break;
27302+ case 24: case 32: bpp = 32; break;
27303+ default: return 0;
27304+ }
27305+
27306+ stride = ALIGN(width * bpp/8, 512);
27307+ size = PAGE_ALIGN(stride * ALIGN(height, 32));
27308+ printf("Creating DRI3 %dx%d (source stride=%d, size=%d) for GTT\n",
27309+ width, height, stride, size);
27310+
27311+ _x_error_occurred = 0;
27312+ Q = setup_msc(dpy, root);
27313+
27314+ for (t = 0; t < sizeof(tiling)/sizeof(tiling[0]); t++) {
27315+ uint64_t msc;
27316+ uint32_t src;
27317+ int src_fd;
27318+ Pixmap src_pix;
27319+
27320+ src = gem_create(device, size);
27321+ if (!src) {
27322+ line = __LINE__;
27323+ goto fail;
27324+ }
27325+
27326+ gem_set_tiling(device, src, tiling[t], stride);
27327+
27328+ src_fd = gem_export(device, src);
27329+ if (src_fd < 0) {
27330+ line = __LINE__;
27331+ goto fail;
27332+ }
27333+
27334+ src_pix = dri3_create_pixmap(dpy, root,
27335+ width, height, depth,
27336+ src_fd, bpp, stride, size);
27337+
27338+ msc = wait_vblank(dpy, root, Q);
27339+
27340+ xcb_present_pixmap(XGetXCBConnection(dpy),
27341+ win, src_pix,
27342+ 0, /* sbc */
27343+ 0, /* valid */
27344+ 0, /* update */
27345+ 0, /* x_off */
27346+ 0, /* y_off */
27347+ None,
27348+ None, /* wait fence */
27349+ None,
27350+ XCB_PRESENT_OPTION_NONE,
27351+ msc + 2, /* target msc */
27352+ 1, /* divisor */
27353+ 0, /* remainder */
27354+ 0, NULL);
27355+
27356+ xcb_present_pixmap(XGetXCBConnection(dpy),
27357+ win, src_pix,
27358+ 0, /* sbc */
27359+ 0, /* valid */
27360+ 0, /* update */
27361+ 0, /* x_off */
27362+ 0, /* y_off */
27363+ None,
27364+ None, /* wait fence */
27365+ None,
27366+ XCB_PRESENT_OPTION_NONE,
27367+ msc + 3, /* target msc */
27368+ 1, /* divisor */
27369+ 0, /* remainder */
27370+ 0, NULL);
27371+
27372+ XSync(dpy, True);
27373+ if (_x_error_occurred) {
27374+ line = __LINE__;
27375+ goto fail;
27376+ }
27377+ XFreePixmap(dpy, src_pix);
27378+ _x_error_occurred = 0;
27379+
27380+ close(src_fd);
27381+ gem_close(device, src);
27382+ }
27383+
27384+ teardown_msc(dpy, Q);
27385+ return 0;
27386+
27387+fail:
27388+ printf("%s failed with tiling %d, line %d\n", __func__, tiling[t], line);
27389+ teardown_msc(dpy, Q);
27390+ return 1;
27391+}
27392+
27393 static int test_dri3(Display *dpy)
27394 {
27395 Window win = DefaultRootWindow(dpy);
27396@@ -670,8 +1789,32 @@ fail:
27397 static int has_present(Display *dpy)
27398 {
27399 xcb_connection_t *c = XGetXCBConnection(dpy);
27400- xcb_present_query_version_reply_t *reply;
27401 xcb_generic_error_t *error = NULL;
27402+ void *reply;
27403+
27404+ reply = xcb_xfixes_query_version_reply(c,
27405+ xcb_xfixes_query_version(c,
27406+ XCB_XFIXES_MAJOR_VERSION,
27407+ XCB_XFIXES_MINOR_VERSION),
27408+ &error);
27409+ free(reply);
27410+ free(error);
27411+ if (reply == NULL) {
27412+ fprintf(stderr, "XFixes not supported on %s\n", DisplayString(dpy));
27413+ return 0;
27414+ }
27415+
27416+ reply = xcb_dri3_query_version_reply(c,
27417+ xcb_dri3_query_version(c,
27418+ XCB_DRI3_MAJOR_VERSION,
27419+ XCB_DRI3_MINOR_VERSION),
27420+ &error);
27421+ free(reply);
27422+ free(error);
27423+ if (reply == NULL) {
27424+ fprintf(stderr, "DRI3 not supported on %s\n", DisplayString(dpy));
27425+ return 0;
27426+ }
27427
27428 reply = xcb_present_query_version_reply(c,
27429 xcb_present_query_version(c,
27430@@ -681,14 +1824,32 @@ static int has_present(Display *dpy)
27431
27432 free(reply);
27433 free(error);
27434+ if (reply == NULL) {
27435+ fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy));
27436+ return 0;
27437+ }
27438+
27439+ return 1;
27440+}
27441
27442- return reply != NULL;
27443+static int has_composite(Display *dpy)
27444+{
27445+ int event, error;
27446+ int major, minor;
27447+
27448+ if (!XCompositeQueryExtension(dpy, &event, &error))
27449+ return 0;
27450+
27451+ XCompositeQueryVersion(dpy, &major, &minor);
27452+
27453+ return major > 0 || minor >= 4;
27454 }
27455
27456 int main(void)
27457 {
27458 Display *dpy;
27459 Window root;
27460+ int dummy;
27461 int error = 0;
27462 uint64_t last_msc;
27463 void *queue;
27464@@ -700,27 +1861,132 @@ int main(void)
27465 if (!has_present(dpy))
27466 return 77;
27467
27468+ if (DPMSQueryExtension(dpy, &dummy, &dummy))
27469+ DPMSDisable(dpy);
27470+
27471 root = DefaultRootWindow(dpy);
27472
27473 signal(SIGALRM, SIG_IGN);
27474 XSetErrorHandler(_check_error_handler);
27475
27476 queue = setup_msc(dpy, root);
27477- last_msc = check_msc(dpy, root, queue, 0);
27478+ last_msc = check_msc(dpy, root, queue, 0, NULL);
27479+
27480+ error += test_future_msc(dpy, queue);
27481+ last_msc = check_msc(dpy, root, queue, last_msc, NULL);
27482+
27483+ error += test_accuracy_msc(dpy, queue);
27484+ last_msc = check_msc(dpy, root, queue, last_msc, NULL);
27485+
27486+ error += test_modulus_msc(dpy, queue);
27487+ last_msc = check_msc(dpy, root, queue, last_msc, NULL);
27488+
27489+ error += test_exhaustion_msc(dpy, queue);
27490+ last_msc = check_msc(dpy, root, queue, last_msc, NULL);
27491+
27492+ for (dummy = 0; dummy <= 3; dummy++) {
27493+ Window win;
27494+ uint64_t msc = 0;
27495+ XSetWindowAttributes attr;
27496+ Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
27497+ unsigned int width, height;
27498+ unsigned border, depth;
27499+ const char *phase;
27500+ int x, y;
27501+ void *Q;
27502+
27503+ attr.override_redirect = 1;
27504+
27505+ XGetGeometry(dpy, root, &win, &x, &y,
27506+ &width, &height, &border, &depth);
27507+
27508+ _x_error_occurred = 0;
27509+ switch (dummy) {
27510+ case 0:
27511+ win = root;
27512+ phase = "root";
27513+ break;
27514+ case 1:
27515+ win = XCreateWindow(dpy, root,
27516+ 0, 0, width, height, 0, depth,
27517+ InputOutput, visual,
27518+ CWOverrideRedirect, &attr);
27519+ phase = "fullscreen";
27520+ break;
27521+ case 2:
27522+ win = XCreateWindow(dpy, root,
27523+ 0, 0, width/2, height/2, 0, depth,
27524+ InputOutput, visual,
27525+ CWOverrideRedirect, &attr);
27526+ phase = "window";
27527+ break;
27528+ case 3:
27529+ if (!has_composite(dpy))
27530+ continue;
27531+
27532+ win = XCreateWindow(dpy, root,
27533+ 0, 0, width, height, 0,
27534+ DefaultDepth(dpy, DefaultScreen(dpy)),
27535+ InputOutput,
27536+ DefaultVisual(dpy, DefaultScreen(dpy)),
27537+ CWOverrideRedirect, &attr);
27538+ XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
27539+ phase = "composite";
27540+ break;
27541+
27542+ default:
27543+ phase = "broken";
27544+ win = root;
27545+ abort();
27546+ break;
27547+ }
27548+
27549+ XMapWindow(dpy, win);
27550+ XSync(dpy, True);
27551+ if (_x_error_occurred)
27552+ continue;
27553+
27554+ Q = setup_msc(dpy, win);
27555+ msc = check_msc(dpy, win, Q, msc, NULL);
27556
27557- error += test_whole(dpy);
27558- last_msc = check_msc(dpy, root, queue, last_msc);
27559+ error += test_whole(dpy, win, phase);
27560+ msc = check_msc(dpy, win, Q, msc, NULL);
27561+
27562+ error += test_double(dpy, win, phase, Q);
27563+ msc = check_msc(dpy, win, Q, msc, NULL);
27564+
27565+ error += test_future(dpy, win, phase, Q);
27566+ msc = check_msc(dpy, win, Q, msc, NULL);
27567+
27568+ error += test_accuracy(dpy, win, phase, Q);
27569+ msc = check_msc(dpy, win, Q, msc, NULL);
27570+
27571+ error += test_modulus(dpy, win, phase, Q);
27572+ msc = check_msc(dpy, win, Q, msc, NULL);
27573+
27574+ error += test_exhaustion(dpy, win, phase, Q);
27575+ msc = check_msc(dpy, win, Q, msc, NULL);
27576+
27577+ teardown_msc(dpy, Q);
27578+ if (win != root)
27579+ XDestroyWindow(dpy, win);
27580+ }
27581
27582 error += test_crtc(dpy, queue, last_msc);
27583- last_msc = check_msc(dpy, root, queue, last_msc);
27584+ last_msc = check_msc(dpy, root, queue, last_msc, NULL);
27585
27586 error += test_shm(dpy);
27587- last_msc = check_msc(dpy, root, queue, last_msc);
27588+ last_msc = check_msc(dpy, root, queue, last_msc, NULL);
27589
27590 error += test_dri3(dpy);
27591- last_msc = check_msc(dpy, root, queue, last_msc);
27592+ last_msc = check_msc(dpy, root, queue, last_msc, NULL);
27593+
27594+ error += test_dri3_tiling(dpy);
27595+ last_msc = check_msc(dpy, root, queue, last_msc, NULL);
27596
27597 teardown_msc(dpy, queue);
27598
27599+ if (DPMSQueryExtension(dpy, &dummy, &dummy))
27600+ DPMSEnable(dpy);
27601 return !!error;
27602 }
27603diff --git a/test/render-glyphs.c b/test/render-glyphs.c
27604new file mode 100644
27605index 0000000..8822e36
27606--- /dev/null
27607+++ b/test/render-glyphs.c
27608@@ -0,0 +1,441 @@
27609+#include <stdint.h>
27610+#include <stdio.h>
27611+#include <stdlib.h>
27612+#include <stdbool.h>
27613+#include <stdarg.h>
27614+#include <string.h>
27615+
27616+#include <X11/Xutil.h> /* for XDestroyImage */
27617+#include <pixman.h> /* for pixman blt functions */
27618+
27619+#include "test.h"
27620+
27621+static const XRenderColor colors[] = {
27622+ /* red, green, blue, alpha */
27623+ { 0 },
27624+ { 0, 0, 0, 0xffff },
27625+ { 0xffff, 0, 0, 0xffff },
27626+ { 0, 0xffff, 0, 0xffff },
27627+ { 0, 0, 0xffff, 0xffff },
27628+ { 0xffff, 0xffff, 0xffff, 0xffff },
27629+};
27630+
27631+static struct clip {
27632+ void *func;
27633+} clips[] = {
27634+ { NULL },
27635+};
27636+
27637+static int _x_error_occurred;
27638+
27639+static int
27640+_check_error_handler(Display *display,
27641+ XErrorEvent *event)
27642+{
27643+ _x_error_occurred = 1;
27644+ return False; /* ignored */
27645+}
27646+
27647+static void clear(struct test_display *dpy,
27648+ struct test_target *tt,
27649+ const XRenderColor *c)
27650+{
27651+ XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, c,
27652+ 0, 0, tt->width, tt->height);
27653+}
27654+
27655+static bool check_op(struct test_display *dpy, int op, struct test_target *tt)
27656+{
27657+ XRenderColor render_color = {0};
27658+
27659+ XSync(dpy->dpy, True);
27660+ _x_error_occurred = 0;
27661+
27662+ XRenderFillRectangle(dpy->dpy, op,
27663+ tt->picture, &render_color,
27664+ 0, 0, 0, 0);
27665+
27666+ XSync(dpy->dpy, True);
27667+ return _x_error_occurred == 0;
27668+}
27669+
27670+struct glyph_iter {
27671+ enum {
27672+ GLYPHS, OP, DST, SRC, MASK, CLIP,
27673+ } stage;
27674+
27675+ int glyph_format;
27676+ int op;
27677+ int dst_color;
27678+ int src_color;
27679+ int mask_format;
27680+ int clip;
27681+
27682+ struct {
27683+ struct test_display *dpy;
27684+ struct test_target tt;
27685+ GlyphSet glyphset;
27686+ Picture src;
27687+ XRenderPictFormat *mask_format;
27688+ } ref, out;
27689+};
27690+
27691+static void glyph_iter_init(struct glyph_iter *gi,
27692+ struct test *t, enum target target)
27693+{
27694+ memset(gi, 0, sizeof(*gi));
27695+
27696+ gi->out.dpy = &t->out;
27697+ test_target_create_render(&t->out, target, &gi->out.tt);
27698+
27699+ gi->ref.dpy = &t->ref;
27700+ test_target_create_render(&t->ref, target, &gi->ref.tt);
27701+
27702+ gi->stage = GLYPHS;
27703+ gi->glyph_format = -1;
27704+ gi->op = -1;
27705+ gi->dst_color = -1;
27706+ gi->src_color = -1;
27707+ gi->mask_format = -1;
27708+ gi->clip = -1;
27709+}
27710+
27711+static void render_clear(char *image, int image_size, int bpp)
27712+{
27713+ memset(image, 0, image_size);
27714+}
27715+
27716+static void render_black(char *image, int image_size, int bpp)
27717+{
27718+ if (bpp == 4) {
27719+ uint32_t *p = (uint32_t *)image;
27720+ image_size /= 4;
27721+ while (image_size--)
27722+ *p++ = 0x000000ff;
27723+ } else
27724+ memset(image, 0x55, image_size);
27725+}
27726+
27727+static void render_green(char *image, int image_size, int bpp)
27728+{
27729+ if (bpp == 4) {
27730+ uint32_t *p = (uint32_t *)image;
27731+ image_size /= 4;
27732+ while (image_size--)
27733+ *p++ = 0xffff0000;
27734+ } else
27735+ memset(image, 0xaa, image_size);
27736+}
27737+
27738+static void render_white(char *image, int image_size, int bpp)
27739+{
27740+ memset(image, 0xff, image_size);
27741+}
27742+
27743+static GlyphSet create_glyphs(Display *dpy, int format_id)
27744+{
27745+#define N_GLYPHS 4
27746+ XRenderPictFormat *format;
27747+ XGlyphInfo glyph = { 8, 8, 0, 0, 8, 0 };
27748+ char image[4*8*8];
27749+ GlyphSet glyphset;
27750+ Glyph gid;
27751+ int image_size;
27752+ int bpp;
27753+ int n;
27754+
27755+ format = XRenderFindStandardFormat(dpy, format_id);
27756+ if (format == NULL)
27757+ return 0;
27758+
27759+ switch (format_id) {
27760+ case PictStandardARGB32:
27761+ case PictStandardRGB24:
27762+ image_size = 4 * 8 * 8;
27763+ bpp = 4;
27764+ break;
27765+ case PictStandardA8:
27766+ case PictStandardA4:
27767+ image_size = 8 * 8;
27768+ bpp = 1;
27769+ break;
27770+ case PictStandardA1:
27771+ image_size = 8;
27772+ bpp = 0;
27773+ break;
27774+ default:
27775+ return 0;
27776+ }
27777+
27778+ glyphset = XRenderCreateGlyphSet(dpy, format);
27779+ for (n = 0; n < N_GLYPHS; n++) {
27780+ gid = n;
27781+
27782+ switch (n) {
27783+ case 0: render_clear(image, image_size, bpp); break;
27784+ case 1: render_black(image, image_size, bpp); break;
27785+ case 2: render_green(image, image_size, bpp); break;
27786+ case 3: render_white(image, image_size, bpp); break;
27787+ }
27788+
27789+ XRenderAddGlyphs(dpy, glyphset,
27790+ &gid, &glyph, 1, image, image_size);
27791+ }
27792+
27793+ return glyphset;
27794+}
27795+
27796+static const char *glyph_name(int n)
27797+{
27798+ switch (n) {
27799+ case 0: return "clear";
27800+ case 1: return "black";
27801+ case 2: return "green";
27802+ case 3: return "white";
27803+ default: return "unknown";
27804+ }
27805+}
27806+
27807+static bool glyph_iter_next(struct glyph_iter *gi)
27808+{
27809+restart:
27810+ if (gi->stage == GLYPHS) {
27811+ if (++gi->glyph_format == PictStandardNUM)
27812+ return false;
27813+
27814+ if (gi->out.glyphset)
27815+ XRenderFreeGlyphSet(gi->out.dpy->dpy,
27816+ gi->out.glyphset);
27817+ gi->out.glyphset = create_glyphs(gi->out.dpy->dpy,
27818+ gi->glyph_format);
27819+
27820+ if (gi->ref.glyphset)
27821+ XRenderFreeGlyphSet(gi->ref.dpy->dpy,
27822+ gi->ref.glyphset);
27823+ gi->ref.glyphset = create_glyphs(gi->ref.dpy->dpy,
27824+ gi->glyph_format);
27825+
27826+ gi->stage++;
27827+ }
27828+
27829+ if (gi->stage == OP) {
27830+ do {
27831+ if (++gi->op == 255)
27832+ goto reset_op;
27833+ } while (!check_op(gi->out.dpy, gi->op, &gi->out.tt) ||
27834+ !check_op(gi->ref.dpy, gi->op, &gi->ref.tt));
27835+
27836+ gi->stage++;
27837+ }
27838+
27839+ if (gi->stage == DST) {
27840+ if (++gi->dst_color == ARRAY_SIZE(colors))
27841+ goto reset_dst;
27842+
27843+ gi->stage++;
27844+ }
27845+
27846+ if (gi->stage == SRC) {
27847+ if (++gi->src_color == ARRAY_SIZE(colors))
27848+ goto reset_src;
27849+
27850+ if (gi->ref.src)
27851+ XRenderFreePicture(gi->ref.dpy->dpy, gi->ref.src);
27852+ gi->ref.src = XRenderCreateSolidFill(gi->ref.dpy->dpy,
27853+ &colors[gi->src_color]);
27854+
27855+ if (gi->out.src)
27856+ XRenderFreePicture(gi->out.dpy->dpy, gi->out.src);
27857+ gi->out.src = XRenderCreateSolidFill(gi->out.dpy->dpy,
27858+ &colors[gi->src_color]);
27859+
27860+ gi->stage++;
27861+ }
27862+
27863+ if (gi->stage == MASK) {
27864+ if (++gi->mask_format > PictStandardNUM)
27865+ goto reset_mask;
27866+
27867+ if (gi->mask_format == PictStandardRGB24)
27868+ gi->mask_format++;
27869+
27870+ if (gi->mask_format < PictStandardNUM) {
27871+ gi->out.mask_format = XRenderFindStandardFormat(gi->out.dpy->dpy,
27872+ gi->mask_format);
27873+ gi->ref.mask_format = XRenderFindStandardFormat(gi->ref.dpy->dpy,
27874+ gi->mask_format);
27875+ } else {
27876+ gi->out.mask_format = NULL;
27877+ gi->ref.mask_format = NULL;
27878+ }
27879+
27880+ gi->stage++;
27881+ }
27882+
27883+ if (gi->stage == CLIP) {
27884+ if (++gi->clip == ARRAY_SIZE(clips))
27885+ goto reset_clip;
27886+
27887+ gi->stage++;
27888+ }
27889+
27890+ gi->stage--;
27891+ return true;
27892+
27893+reset_op:
27894+ gi->op = -1;
27895+reset_dst:
27896+ gi->dst_color = -1;
27897+reset_src:
27898+ gi->src_color = -1;
27899+reset_mask:
27900+ gi->mask_format = -1;
27901+reset_clip:
27902+ gi->clip = -1;
27903+ gi->stage--;
27904+ goto restart;
27905+}
27906+
27907+static void glyph_iter_fini(struct glyph_iter *gi)
27908+{
27909+ if (gi->out.glyphset)
27910+ XRenderFreeGlyphSet (gi->out.dpy->dpy, gi->out.glyphset);
27911+ if (gi->ref.glyphset)
27912+ XRenderFreeGlyphSet (gi->ref.dpy->dpy, gi->ref.glyphset);
27913+
27914+ test_target_destroy_render(gi->out.dpy, &gi->out.tt);
27915+ test_target_destroy_render(gi->ref.dpy, &gi->ref.tt);
27916+}
27917+
27918+static const char *stdformat_to_str(int id)
27919+{
27920+ switch (id) {
27921+ case PictStandardARGB32: return "ARGB32";
27922+ case PictStandardRGB24: return "RGB24";
27923+ case PictStandardA8: return "A8";
27924+ case PictStandardA4: return "A4";
27925+ case PictStandardA1: return "A1";
27926+ default: return "none";
27927+ }
27928+}
27929+
27930+static char *glyph_iter_to_string(struct glyph_iter *gi,
27931+ const char *format,
27932+ ...)
27933+{
27934+ static char buf[100];
27935+ va_list ap;
27936+ int len;
27937+
27938+ len = sprintf(buf, "glyphs=%s, op=%d, dst=%08x, src=%08x, mask=%s",
27939+ stdformat_to_str(gi->glyph_format), gi->op,
27940+ xrender_color(&colors[gi->dst_color]),
27941+ xrender_color(&colors[gi->src_color]),
27942+ stdformat_to_str(gi->mask_format));
27943+
27944+ if (format) {
27945+ buf[len++] = ' ';
27946+ va_start(ap, format);
27947+ vsprintf(buf+len, format, ap);
27948+ va_end(ap);
27949+ }
27950+
27951+ return buf;
27952+}
27953+
27954+static void single(struct test *t, enum target target)
27955+{
27956+ struct glyph_iter gi;
27957+ int n;
27958+
27959+ printf("Testing single glyph (%s): ", test_target_name(target));
27960+ fflush(stdout);
27961+
27962+ glyph_iter_init(&gi, t, target);
27963+ while (glyph_iter_next(&gi)) {
27964+ XGlyphElt8 elt;
27965+ char id[N_GLYPHS];
27966+
27967+ for (n = 0; n < N_GLYPHS; n++) {
27968+ id[n] = n;
27969+
27970+ elt.chars = &id[n];
27971+ elt.nchars = 1;
27972+ elt.xOff = 0;
27973+ elt.yOff = 0;
27974+
27975+ clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]);
27976+ elt.glyphset = gi.out.glyphset;
27977+ XRenderCompositeText8 (gi.out.dpy->dpy, gi.op,
27978+ gi.out.src,
27979+ gi.out.tt.picture,
27980+ gi.out.mask_format,
27981+ 0, 0,
27982+ 0, 8,
27983+ &elt, 1);
27984+
27985+ clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]);
27986+ elt.glyphset = gi.ref.glyphset;
27987+ XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op,
27988+ gi.ref.src,
27989+ gi.ref.tt.picture,
27990+ gi.ref.mask_format,
27991+ 0, 0,
27992+ 0, 8,
27993+ &elt, 1);
27994+ test_compare(t,
27995+ gi.out.tt.draw, gi.out.tt.format,
27996+ gi.ref.tt.draw, gi.ref.tt.format,
27997+ 0, 0, gi.out.tt.width, gi.out.tt.height,
27998+ glyph_iter_to_string(&gi,
27999+ "glyph=%s",
28000+ glyph_name(n)));
28001+ }
28002+
28003+ elt.chars = &id[0];
28004+ elt.nchars = n;
28005+ clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]);
28006+ elt.glyphset = gi.out.glyphset;
28007+ XRenderCompositeText8 (gi.out.dpy->dpy, gi.op,
28008+ gi.out.src,
28009+ gi.out.tt.picture,
28010+ gi.out.mask_format,
28011+ 0, 0,
28012+ 0, 8,
28013+ &elt, 1);
28014+
28015+ clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]);
28016+ elt.glyphset = gi.ref.glyphset;
28017+ XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op,
28018+ gi.ref.src,
28019+ gi.ref.tt.picture,
28020+ gi.ref.mask_format,
28021+ 0, 0,
28022+ 0, 8,
28023+ &elt, 1);
28024+ test_compare(t,
28025+ gi.out.tt.draw, gi.out.tt.format,
28026+ gi.ref.tt.draw, gi.ref.tt.format,
28027+ 0, 0, gi.out.tt.width, gi.out.tt.height,
28028+ glyph_iter_to_string(&gi, "all"));
28029+ }
28030+ glyph_iter_fini(&gi);
28031+}
28032+
28033+int main(int argc, char **argv)
28034+{
28035+ struct test test;
28036+ int t;
28037+
28038+ test_init(&test, argc, argv);
28039+ XSetErrorHandler(_check_error_handler);
28040+
28041+ for (t = TARGET_FIRST; t <= TARGET_LAST; t++) {
28042+ single(&test, t);
28043+ //overlapping(&test, t);
28044+ //gap(&test, t);
28045+ //mixed(&test, t);
28046+ }
28047+
28048+ return 0;
28049+}
28050diff --git a/test/render-trapezoid.c b/test/render-trapezoid.c
28051index cd99014..f15a78e 100644
28052--- a/test/render-trapezoid.c
28053+++ b/test/render-trapezoid.c
28054@@ -403,16 +403,141 @@ static void trap_tests(struct test *t,
28055 free(traps);
28056 }
28057
28058+enum edge {
28059+ EDGE_SHARP = PolyEdgeSharp,
28060+ EDGE_SMOOTH,
28061+};
28062+
28063+static const char *edge_name(enum edge edge)
28064+{
28065+ switch (edge) {
28066+ default:
28067+ case EDGE_SHARP: return "sharp";
28068+ case EDGE_SMOOTH: return "smooth";
28069+ }
28070+}
28071+
28072+static void set_edge(Display *dpy, Picture p, enum edge edge)
28073+{
28074+ XRenderPictureAttributes a;
28075+
28076+ a.poly_edge = edge;
28077+ XRenderChangePicture(dpy, p, CPPolyEdge, &a);
28078+}
28079+
28080+static void edge_test(struct test *t,
28081+ enum mask mask,
28082+ enum edge edge,
28083+ enum target target)
28084+{
28085+ struct test_target out, ref;
28086+ XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
28087+ Picture src_ref, src_out;
28088+ XTrapezoid trap;
28089+ int left_or_right, p;
28090+
28091+ test_target_create_render(&t->out, target, &out);
28092+ set_edge(t->out.dpy, out.picture, edge);
28093+ src_out = XRenderCreateSolidFill(t->out.dpy, &white);
28094+
28095+ test_target_create_render(&t->ref, target, &ref);
28096+ set_edge(t->ref.dpy, ref.picture, edge);
28097+ src_ref = XRenderCreateSolidFill(t->ref.dpy, &white);
28098+
28099+ printf("Testing edges (with mask %s and %s edges) (%s): ",
28100+ mask_name(mask),
28101+ edge_name(edge),
28102+ test_target_name(target));
28103+ fflush(stdout);
28104+
28105+ for (left_or_right = 0; left_or_right <= 1; left_or_right++) {
28106+ for (p = -64; p <= out.width + 64; p++) {
28107+ char buf[80];
28108+
28109+ if (left_or_right) {
28110+ trap.left.p1.x = 0;
28111+ trap.left.p1.y = 0;
28112+ trap.left.p2.x = 0;
28113+ trap.left.p2.y = out.height << 16;
28114+
28115+ trap.right.p1.x = p << 16;
28116+ trap.right.p1.y = 0;
28117+ trap.right.p2.x = out.width << 16;
28118+ trap.right.p2.y = out.height << 16;
28119+ } else {
28120+ trap.right.p1.x = out.width << 16;
28121+ trap.right.p1.y = 0;
28122+ trap.right.p2.x = out.width << 16;
28123+ trap.right.p2.y = out.height << 16;
28124+
28125+ trap.left.p1.x = 0;
28126+ trap.left.p1.y = 0;
28127+ trap.left.p2.x = p << 16;
28128+ trap.left.p2.y = out.height << 16;
28129+ }
28130+
28131+ trap.top = 0;
28132+ trap.bottom = out.height << 16;
28133+
28134+ sprintf(buf,
28135+ "trap=((%d, %d), (%d, %d)), ((%d, %d), (%d, %d))\n",
28136+ trap.left.p1.x >> 16, trap.left.p1.y >> 16,
28137+ trap.left.p2.x >> 16, trap.left.p2.y >> 16,
28138+ trap.right.p1.x >> 16, trap.right.p1.y >> 16,
28139+ trap.right.p2.x >> 16, trap.right.p2.y >> 16);
28140+
28141+ clear(&t->out, &out);
28142+ XRenderCompositeTrapezoids(t->out.dpy,
28143+ PictOpSrc,
28144+ src_out,
28145+ out.picture,
28146+ mask_format(t->out.dpy, mask),
28147+ 0, 0,
28148+ &trap, 1);
28149+
28150+ clear(&t->ref, &ref);
28151+ XRenderCompositeTrapezoids(t->ref.dpy,
28152+ PictOpSrc,
28153+ src_ref,
28154+ ref.picture,
28155+ mask_format(t->ref.dpy, mask),
28156+ 0, 0,
28157+ &trap, 1);
28158+
28159+ test_compare(t,
28160+ out.draw, out.format,
28161+ ref.draw, ref.format,
28162+ 0, 0, out.width, out.height,
28163+ buf);
28164+ }
28165+ }
28166+
28167+ XRenderFreePicture(t->out.dpy, src_out);
28168+ test_target_destroy_render(&t->out, &out);
28169+
28170+ XRenderFreePicture(t->ref.dpy, src_ref);
28171+ test_target_destroy_render(&t->ref, &ref);
28172+
28173+ printf("pass\n");
28174+}
28175+
28176 int main(int argc, char **argv)
28177 {
28178 struct test test;
28179 int i, dx, dy;
28180 enum target target;
28181 enum mask mask;
28182+ enum edge edge;
28183 enum trapezoid trapezoid;
28184
28185 test_init(&test, argc, argv);
28186
28187+ for (target = TARGET_FIRST; target <= TARGET_LAST; target++) {
28188+ for (mask = MASK_NONE; mask <= MASK_A8; mask++)
28189+ for (edge = EDGE_SHARP; edge <= EDGE_SMOOTH; edge++)
28190+ edge_test(&test, mask, edge, target);
28191+ }
28192+
28193 for (i = 0; i <= DEFAULT_ITERATIONS; i++) {
28194 int reps = REPS(i), sets = SETS(i);
28195
28196diff --git a/test/render-triangle.c b/test/render-triangle.c
28197new file mode 100644
28198index 0000000..165834c
28199--- /dev/null
28200+++ b/test/render-triangle.c
28201@@ -0,0 +1,180 @@
28202+#include <stdint.h>
28203+#include <stdio.h>
28204+#include <stdlib.h>
28205+
28206+#include "test.h"
28207+
28208+enum edge {
28209+ EDGE_SHARP = PolyEdgeSharp,
28210+ EDGE_SMOOTH,
28211+};
28212+
28213+static void set_edge(Display *dpy, Picture p, enum edge edge)
28214+{
28215+ XRenderPictureAttributes a;
28216+
28217+ a.poly_edge = edge;
28218+ XRenderChangePicture(dpy, p, CPPolyEdge, &a);
28219+}
28220+
28221+static XRenderPictFormat *mask_format(Display *dpy, enum mask mask)
28222+{
28223+ switch (mask) {
28224+ default:
28225+ case MASK_NONE: return NULL;
28226+ case MASK_A1: return XRenderFindStandardFormat(dpy, PictStandardA1);
28227+ case MASK_A8: return XRenderFindStandardFormat(dpy, PictStandardA8);
28228+ }
28229+}
28230+
28231+static const char *mask_name(enum mask mask)
28232+{
28233+ switch (mask) {
28234+ default:
28235+ case MASK_NONE: return "none";
28236+ case MASK_A1: return "a1";
28237+ case MASK_A8: return "a8";
28238+ }
28239+}
28240+
28241+static const char *edge_name(enum edge edge)
28242+{
28243+ switch (edge) {
28244+ default:
28245+ case EDGE_SHARP: return "sharp";
28246+ case EDGE_SMOOTH: return "smooth";
28247+ }
28248+}
28249+
28250+static void clear(struct test_display *dpy, struct test_target *tt)
28251+{
28252+ XRenderColor render_color = {0};
28253+ XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color,
28254+ 0, 0, tt->width, tt->height);
28255+}
28256+
28257+static void step_to_point(int step, int width, int height, XPointFixed *p)
28258+{
28259+ do {
28260+ p->x = (step - 64) << 16;
28261+ p->y = -64 << 16;
28262+
28263+ step -= width - 128;
28264+ if (step <= 0)
28265+ return;
28266+
28267+ p->x = (width + 64) << 16;
28268+ p->y = (step - 64) << 16;
28269+ step -= height - 128;
28270+
28271+ if (step <= 0)
28272+ return;
28273+
28274+ p->x = (width + 64 - step) << 16;
28275+ p->y = (height + 64) << 16;
28276+ step -= width - 128;
28277+
28278+ if (step <= 0)
28279+ return;
28280+
28281+ p->x = -64 << 16;
28282+ p->y = (height + 64 - step) << 16;
28283+ step -= height - 128;
28284+ } while (step > 0);
28285+}
28286+
28287+static void edge_test(struct test *t,
28288+ enum mask mask,
28289+ enum edge edge,
28290+ enum target target)
28291+{
28292+ struct test_target out, ref;
28293+ XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
28294+ Picture src_ref, src_out;
28295+ XTriangle tri;
28296+ unsigned step, max;
28297+
28298+ test_target_create_render(&t->out, target, &out);
28299+ set_edge(t->out.dpy, out.picture, edge);
28300+ src_out = XRenderCreateSolidFill(t->out.dpy, &white);
28301+
28302+ test_target_create_render(&t->ref, target, &ref);
28303+ set_edge(t->ref.dpy, ref.picture, edge);
28304+ src_ref = XRenderCreateSolidFill(t->ref.dpy, &white);
28305+
28306+ printf("Testing edges (with mask %s and %s edges) (%s): ",
28307+ mask_name(mask),
28308+ edge_name(edge),
28309+ test_target_name(target));
28310+ fflush(stdout);
28311+
28312+ max = 2*(out.width + 128 + out.height+128);
28313+ step = 0;
28314+ for (step = 0; step <= max; step++) {
28315+ char buf[80];
28316+
28317+ step_to_point(step, out.width, out.height, &tri.p1);
28318+ step_to_point(step + out.width + 128,
28319+ out.width, out.height,
28320+ &tri.p2);
28321+ step_to_point(step + out.height + 128 + 2*(out.width + 128),
28322+ out.width, out.height,
28323+ &tri.p3);
28324+
28325+ sprintf(buf,
28326+ "tri=((%d, %d), (%d, %d), (%d, %d))\n",
28327+ tri.p1.x >> 16, tri.p1.y >> 16,
28328+ tri.p2.x >> 16, tri.p2.y >> 16,
28329+ tri.p3.x >> 16, tri.p3.y >> 16);
28330+
28331+ clear(&t->out, &out);
28332+ XRenderCompositeTriangles(t->out.dpy,
28333+ PictOpSrc,
28334+ src_out,
28335+ out.picture,
28336+ mask_format(t->out.dpy, mask),
28337+ 0, 0,
28338+ &tri, 1);
28339+
28340+ clear(&t->ref, &ref);
28341+ XRenderCompositeTriangles(t->ref.dpy,
28342+ PictOpSrc,
28343+ src_ref,
28344+ ref.picture,
28345+ mask_format(t->ref.dpy, mask),
28346+ 0, 0,
28347+ &tri, 1);
28348+
28349+ test_compare(t,
28350+ out.draw, out.format,
28351+ ref.draw, ref.format,
28352+ 0, 0, out.width, out.height,
28353+ buf);
28354+ }
28355+
28356+ XRenderFreePicture(t->out.dpy, src_out);
28357+ test_target_destroy_render(&t->out, &out);
28358+
28359+ XRenderFreePicture(t->ref.dpy, src_ref);
28360+ test_target_destroy_render(&t->ref, &ref);
28361+
28362+ printf("pass\n");
28363+}
28364+
28365+int main(int argc, char **argv)
28366+{
28367+ struct test test;
28368+ enum target target;
28369+ enum mask mask;
28370+ enum edge edge;
28371+
28372+ test_init(&test, argc, argv);
28373+
28374+ for (target = TARGET_FIRST; target <= TARGET_LAST; target++) {
28375+ for (mask = MASK_NONE; mask <= MASK_A8; mask++)
28376+ for (edge = EDGE_SHARP; edge <= EDGE_SMOOTH; edge++)
28377+ edge_test(&test, mask, edge, target);
28378+ }
28379+
28380+ return 0;
28381+}
28382diff --git a/test/test.h b/test/test.h
28383index a3ef979..9eec1cf 100644
28384--- a/test/test.h
28385+++ b/test/test.h
28386@@ -107,6 +107,15 @@ static inline uint32_t color(uint8_t red, uint8_t green, uint8_t blue, uint8_t a
28387 return alpha << 24 | ra >> 8 << 16 | ga >> 8 << 8 | ba >> 8;
28388 }
28389
28390+static inline uint32_t xrender_color(const XRenderColor *c)
28391+{
28392+ uint32_t ra = c->red * c->alpha;
28393+ uint32_t ga = c->green * c->alpha;
28394+ uint32_t ba = c->blue * c->alpha;
28395+
28396+ return c->alpha >> 8 << 24 | ra >> 24 << 16 | ga >> 24 << 8 | ba >> 24;
28397+}
28398+
28399 void test_timer_start(struct test_display *t, struct timespec *tv);
28400 double test_timer_stop(struct test_display *t, struct timespec *tv);
28401
28402diff --git a/test/test_image.c b/test/test_image.c
28403index d15a8af..1c07699 100644
28404--- a/test/test_image.c
28405+++ b/test/test_image.c
28406@@ -197,13 +197,10 @@ void test_compare(struct test *t,
28407 const char *info)
28408 {
28409 XImage out_image, ref_image;
28410- Pixmap tmp;
28411- char *out, *ref;
28412+ uint32_t *out, *ref;
28413 char buf[600];
28414 uint32_t mask;
28415 int i, j;
28416- XGCValues gcv;
28417- GC gc;
28418
28419 if (w * h * 4 > t->out.max_shm_size)
28420 return test_compare_fallback(t,
28421@@ -214,37 +211,24 @@ void test_compare(struct test *t,
28422 test_init_image(&out_image, &t->out.shm, out_format, w, h);
28423 test_init_image(&ref_image, &t->ref.shm, ref_format, w, h);
28424
28425- gcv.graphics_exposures = 0;
28426-
28427 die_unless(out_image.depth == ref_image.depth);
28428 die_unless(out_image.bits_per_pixel == ref_image.bits_per_pixel);
28429 die_unless(out_image.bits_per_pixel == 32);
28430
28431- mask = depth_mask(out_image.depth);
28432+ XShmGetImage(t->out.dpy, out_draw, &out_image, x, y, AllPlanes);
28433+ out = (uint32_t *)out_image.data;
28434
28435- tmp = XCreatePixmap(t->out.dpy, out_draw, w, h, out_image.depth);
28436- gc = XCreateGC(t->out.dpy, tmp, GCGraphicsExposures, &gcv);
28437- XCopyArea(t->out.dpy, out_draw, tmp, gc, x, y, w, h, 0, 0);
28438- XShmGetImage(t->out.dpy, tmp, &out_image, 0, 0, AllPlanes);
28439- XFreeGC(t->out.dpy, gc);
28440- XFreePixmap(t->out.dpy, tmp);
28441- out = out_image.data;
28442-
28443- tmp = XCreatePixmap(t->ref.dpy, ref_draw, w, h, ref_image.depth);
28444- gc = XCreateGC(t->ref.dpy, tmp, GCGraphicsExposures, &gcv);
28445- XCopyArea(t->ref.dpy, ref_draw, tmp, gc, x, y, w, h, 0, 0);
28446- XShmGetImage(t->ref.dpy, tmp, &ref_image, 0, 0, AllPlanes);
28447- XFreeGC(t->ref.dpy, gc);
28448- XFreePixmap(t->ref.dpy, tmp);
28449- ref = ref_image.data;
28450+ XShmGetImage(t->ref.dpy, ref_draw, &ref_image, x, y, AllPlanes);
28451+ ref = (uint32_t *)ref_image.data;
28452
28453 /* Start with an exact comparison. However, one quicky desires
28454 * a fuzzy comparator to hide hardware inaccuracies...
28455 */
28456+ mask = depth_mask(out_image.depth);
28457 for (j = 0; j < h; j++) {
28458 for (i = 0; i < w; i++) {
28459- uint32_t a = ((uint32_t *)out)[i] & mask;
28460- uint32_t b = ((uint32_t *)ref)[i] & mask;
28461+ uint32_t a = out[i] & mask;
28462+ uint32_t b = ref[i] & mask;
28463 if (a != b && pixel_difference(a, b) > MAX_DELTA) {
28464 show_pixels(buf,
28465 &out_image, &ref_image,
28466@@ -255,8 +239,8 @@ void test_compare(struct test *t,
28467 x,i, y,j, a, b, pixel_difference(a, b), buf, info);
28468 }
28469 }
28470- out += out_image.bytes_per_line;
28471- ref += ref_image.bytes_per_line;
28472+ out = (uint32_t *)((char *)out + out_image.bytes_per_line);
28473+ ref = (uint32_t *)((char *)ref + ref_image.bytes_per_line);
28474 }
28475 }
28476
28477diff --git a/tools/Makefile.am b/tools/Makefile.am
28478index b5de2c9..92df266 100644
28479--- a/tools/Makefile.am
28480+++ b/tools/Makefile.am
28481@@ -26,13 +26,30 @@ AM_CFLAGS = \
28482 drivermandir = $(DRIVER_MAN_DIR)
28483 policydir = $(datarootdir)/polkit-1/actions
28484
28485+bin_PROGRAMS =
28486+noinst_PROGRAMS =
28487+libexec_PROGRAMS =
28488+
28489 if BUILD_TOOLS
28490-bin_PROGRAMS = intel-virtual-output
28491+bin_PROGRAMS += intel-virtual-output
28492 driverman_DATA = intel-virtual-output.$(DRIVER_MAN_SUFFIX)
28493 endif
28494
28495+if BUILD_TOOL_CURSOR
28496+noinst_PROGRAMS += cursor
28497+cursor_CFLAGS = $(TOOL_CURSOR_CFLAGS)
28498+cursor_LDADD = $(TOOL_CURSOR_LIBS)
28499+endif
28500+
28501+if X11_DRI3
28502+noinst_PROGRAMS += dri3info
28503+dri3info_SOURCES = dri3info.c
28504+dri3info_CFLAGS = $(X11_DRI3_CFLAGS) $(DRI_CFLAGS)
28505+dri3info_LDADD = $(X11_DRI3_LIBS) $(DRI_LIBS)
28506+endif
28507+
28508 if BUILD_BACKLIGHT_HELPER
28509-libexec_PROGRAMS = xf86-video-intel-backlight-helper
28510+libexec_PROGRAMS += xf86-video-intel-backlight-helper
28511 nodist_policy_DATA = org.x.xf86-video-intel.backlight-helper.policy
28512
28513 backlight_helper = $(libexecdir)/xf86-video-intel-backlight-helper
28514diff --git a/tools/backlight_helper.c b/tools/backlight_helper.c
28515index 8b2667d..a00f0d6 100644
28516--- a/tools/backlight_helper.c
28517+++ b/tools/backlight_helper.c
28518@@ -9,6 +9,12 @@
28519 #include <sys/types.h>
28520 #include <sys/stat.h>
28521
28522+#if MAJOR_IN_MKDEV
28523+#include <sys/mkdev.h>
28524+#elif MAJOR_IN_SYSMACROS
28525+#include <sys/sysmacros.h>
28526+#endif
28527+
28528 #define DBG 0
28529
28530 #if defined(__GNUC__) && (__GNUC__ > 3)
28531diff --git a/tools/cursor.c b/tools/cursor.c
28532new file mode 100644
28533index 0000000..6f4e3f8
28534--- /dev/null
28535+++ b/tools/cursor.c
28536@@ -0,0 +1,111 @@
28537+/*
28538+ * Copyright © 2015 Intel Corporation
28539+ *
28540+ * Permission is hereby granted, free of charge, to any person obtaining a
28541+ * copy of this software and associated documentation files (the "Software"),
28542+ * to deal in the Software without restriction, including without limitation
28543+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
28544+ * and/or sell copies of the Software, and to permit persons to whom the
28545+ * Software is furnished to do so, subject to the following conditions:
28546+ *
28547+ * The above copyright notice and this permission notice (including the next
28548+ * paragraph) shall be included in all copies or substantial portions of the
28549+ * Software.
28550+ *
28551+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28552+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28553+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28554+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28555+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28556+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28557+ * IN THE SOFTWARE.
28558+ *
28559+ */
28560+
28561+#ifdef HAVE_CONFIG_H
28562+#include "config.h"
28563+#endif
28564+
28565+#include <X11/Xlib.h>
28566+#include <X11/extensions/Xfixes.h>
28567+
28568+#include <stdint.h>
28569+#include <stdio.h>
28570+#include <stdlib.h>
28571+#include <png.h>
28572+
28573+int main(int argc, char **argv)
28574+{
28575+ Display *dpy;
28576+ XFixesCursorImage *cur;
28577+ unsigned long *src; /* XXX deep sigh */
28578+ unsigned x, y;
28579+ png_struct *png;
28580+ png_info *info;
28581+ png_byte **rows;
28582+ FILE *file;
28583+
28584+ dpy = XOpenDisplay(NULL);
28585+ if (dpy == NULL)
28586+ return 1;
28587+
28588+ if (!XFixesQueryExtension(dpy, (int *)&x, (int *)&y))
28589+ return 1;
28590+
28591+ cur = XFixesGetCursorImage(dpy);
28592+ if (cur == NULL)
28593+ return 1;
28594+
28595+ printf("Cursor on display '%s': %dx%d, (hotspot %dx%d)\n",
28596+ DisplayString(dpy),
28597+ cur->width, cur->height,
28598+ cur->xhot, cur->yhot);
28599+
28600+ file = fopen("cursor.png", "wb");
28601+ if (file == NULL)
28602+ return 2;
28603+
28604+ png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
28605+ info = png_create_info_struct(png);
28606+ png_init_io(png, file);
28607+ png_set_IHDR(png, info,
28608+ cur->width, cur->height, 8,
28609+ PNG_COLOR_TYPE_RGB_ALPHA,
28610+ PNG_INTERLACE_NONE,
28611+ PNG_COMPRESSION_TYPE_DEFAULT,
28612+ PNG_FILTER_TYPE_DEFAULT);
28613+ png_write_info(png, info);
28614+
28615+ src = cur->pixels;
28616+ rows = malloc(cur->height*sizeof(png_byte*));
28617+ if (rows == NULL)
28618+ return 3;
28619+
28620+ for (y = 0; y < cur->height; y++) {
28621+ rows[y] = malloc(cur->width * 4);
28622+ for (x = 0; x < cur->width; x++) {
28623+ uint32_t p = *src++;
28624+ uint8_t r = p >> 0;
28625+ uint8_t g = p >> 8;
28626+ uint8_t b = p >> 16;
28627+ uint8_t a = p >> 24;
28628+
28629+ if (a > 0x00 && a < 0xff) {
28630+ r = (r * 0xff + a /2) / a;
28631+ g = (g * 0xff + a /2) / a;
28632+ b = (b * 0xff + a /2) / a;
28633+ }
28634+
28635+ rows[y][4*x + 0] = b;
28636+ rows[y][4*x + 1] = g;
28637+ rows[y][4*x + 2] = r;
28638+ rows[y][4*x + 3] = a;
28639+ }
28640+ }
28641+
28642+ png_write_image(png, rows);
28643+ png_write_end(png, NULL);
28644+ fclose(file);
28645+
28646+ return 0;
28647+}
28648diff --git a/tools/dri3info.c b/tools/dri3info.c
28649new file mode 100644
28650index 0000000..0c33fc5
28651--- /dev/null
28652+++ b/tools/dri3info.c
28653@@ -0,0 +1,329 @@
28654+/*
28655+ * Copyright (c) 2015 Intel Corporation
28656+ *
28657+ * Permission is hereby granted, free of charge, to any person obtaining a
28658+ * copy of this software and associated documentation files (the "Software"),
28659+ * to deal in the Software without restriction, including without limitation
28660+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
28661+ * and/or sell copies of the Software, and to permit persons to whom the
28662+ * Software is furnished to do so, subject to the following conditions:
28663+ *
28664+ * The above copyright notice and this permission notice (including the next
28665+ * paragraph) shall be included in all copies or substantial portions of the
28666+ * Software.
28667+ *
28668+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28669+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28670+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28671+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28672+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28673+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28674+ * SOFTWARE.
28675+ *
28676+ * To compile standalone: gcc -o dri3info dri3info.c `pkg-config --cflags --libs xcb-dri3 x11-xcb xrandr xxf86vm libdrm`
28677+ */
28678+
28679+#include <X11/Xlib.h>
28680+#include <X11/Xlib-xcb.h>
28681+#include <xcb/xcb.h>
28682+#include <xcb/dri3.h>
28683+#include <unistd.h>
28684+#include <stdio.h>
28685+#include <stdlib.h>
28686+#include <stdint.h>
28687+#include <string.h>
28688+#include <sys/stat.h>
28689+#include <drm.h>
28690+#include <xf86drm.h>
28691+
28692+#include <X11/extensions/Xrandr.h>
28693+#include <X11/extensions/xf86vmode.h>
28694+
28695+static int dri3_query_version(Display *dpy, int *major, int *minor)
28696+{
28697+ xcb_connection_t *c = XGetXCBConnection(dpy);
28698+ xcb_dri3_query_version_reply_t *reply;
28699+ xcb_generic_error_t *error;
28700+
28701+ *major = *minor = -1;
28702+
28703+ reply = xcb_dri3_query_version_reply(c,
28704+ xcb_dri3_query_version(c,
28705+ XCB_DRI3_MAJOR_VERSION,
28706+ XCB_DRI3_MINOR_VERSION),
28707+ &error);
28708+ free(error);
28709+ if (reply == NULL)
28710+ return -1;
28711+
28712+ *major = reply->major_version;
28713+ *minor = reply->minor_version;
28714+ free(reply);
28715+
28716+ return 0;
28717+}
28718+
28719+static int dri3_exists(Display *dpy)
28720+{
28721+ const xcb_query_extension_reply_t *ext;
28722+ int major, minor;
28723+
28724+ ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id);
28725+ if (ext == NULL || !ext->present)
28726+ return 0;
28727+
28728+ if (dri3_query_version(dpy, &major, &minor) < 0)
28729+ return 0;
28730+
28731+ return major >= 0;
28732+}
28733+
28734+static int dri3_open(Display *dpy)
28735+{
28736+ xcb_connection_t *c = XGetXCBConnection(dpy);
28737+ xcb_dri3_open_cookie_t cookie;
28738+ xcb_dri3_open_reply_t *reply;
28739+
28740+ if (!dri3_exists(dpy))
28741+ return -1;
28742+
28743+ cookie = xcb_dri3_open(c, RootWindow(dpy, DefaultScreen(dpy)), None);
28744+ reply = xcb_dri3_open_reply(c, cookie, NULL);
28745+
28746+ if (!reply)
28747+ return -1;
28748+
28749+ if (reply->nfd != 1)
28750+ return -1;
28751+
28752+ return xcb_dri3_open_reply_fds(c, reply)[0];
28753+}
28754+
28755+static void get_device_path(int fd, char *buf, int len)
28756+{
28757+ struct stat remote, local;
28758+ int i;
28759+
28760+ if (fstat(fd, &remote))
28761+ goto out;
28762+
28763+ for (i = 0; i < 16; i++) {
28764+ snprintf(buf, len, "/dev/dri/card%d", i);
28765+ if (stat(buf, &local))
28766+ continue;
28767+
28768+ if (local.st_mode == remote.st_mode &&
28769+ local.st_rdev == remote.st_rdev)
28770+ return;
28771+
28772+ snprintf(buf, len, "/dev/dri/renderD%d", i + 128);
28773+ if (stat(buf, &local))
28774+ continue;
28775+
28776+ if (local.st_mode == remote.st_mode &&
28777+ local.st_rdev == remote.st_rdev)
28778+ return;
28779+ }
28780+
28781+out:
28782+ strncpy(buf, "unknown path", len);
28783+}
28784+
28785+static void get_driver_name(int fd, char *name, int len)
28786+{
28787+ drm_version_t version;
28788+
28789+ memset(name, 0, len);
28790+ memset(&version, 0, sizeof(version));
28791+ version.name_len = len;
28792+ version.name = name;
28793+
28794+ (void)drmIoctl(fd, DRM_IOCTL_VERSION, &version);
28795+}
28796+
28797+static int compute_refresh_rate_from_mode(long n, long d, unsigned flags,
28798+ int32_t *numerator,
28799+ int32_t *denominator)
28800+{
28801+ int i;
28802+
28803+ /* The mode flags are only defined privately to the Xserver (in xf86str.h)
28804+ * but they at least bit compatible between VidMode, RandR and DRM.
28805+ */
28806+# define V_INTERLACE 0x010
28807+# define V_DBLSCAN 0x020
28808+
28809+ if (flags & V_INTERLACE)
28810+ n *= 2;
28811+ else if (flags & V_DBLSCAN)
28812+ d *= 2;
28813+
28814+ /* The OML_sync_control spec requires that if the refresh rate is a
28815+ * whole number, that the returned numerator be equal to the refresh
28816+ * rate and the denominator be 1.
28817+ */
28818+
28819+ if (n % d == 0) {
28820+ n /= d;
28821+ d = 1;
28822+ }
28823+ else {
28824+ static const unsigned f[] = { 13, 11, 7, 5, 3, 2, 0 };
28825+
28826+ /* This is a poor man's way to reduce a fraction. It's far from
28827+ * perfect, but it will work well enough for this situation.
28828+ */
28829+
28830+ for (i = 0; f[i] != 0; i++) {
28831+ while (n % f[i] == 0 && d % f[i] == 0) {
28832+ d /= f[i];
28833+ n /= f[i];
28834+ }
28835+ }
28836+ }
28837+
28838+ *numerator = n;
28839+ *denominator = d;
28840+ return 1;
28841+}
28842+
28843+static int RRGetMscRate(Display *dpy, int32_t *numerator, int32_t *denominator)
28844+{
28845+ int ret = 0;
28846+ Window root = RootWindow(dpy, DefaultScreen(dpy));
28847+ XRRScreenResources *res;
28848+ int rr_event, rr_error;
28849+ RROutput primary;
28850+ RRMode mode = 0;
28851+ int n;
28852+
28853+ if (!XRRQueryExtension(dpy, &rr_event, &rr_error))
28854+ return ret;
28855+
28856+ res = XRRGetScreenResourcesCurrent(dpy, root);
28857+ if (res == NULL)
28858+ return ret;
28859+
28860+ /* Use the primary output if specified, otherwise
28861+ * use the mode on the first enabled crtc.
28862+ */
28863+ primary = XRRGetOutputPrimary(dpy, root);
28864+ if (primary) {
28865+ XRROutputInfo *output;
28866+
28867+ output = XRRGetOutputInfo(dpy, res, primary);
28868+ if (output != NULL) {
28869+ if (output->crtc) {
28870+ XRRCrtcInfo *crtc;
28871+
28872+ crtc = XRRGetCrtcInfo(dpy, res, output->crtc);
28873+ if (crtc) {
28874+ mode = crtc->mode;
28875+ XRRFreeCrtcInfo(crtc);
28876+ }
28877+ }
28878+ XRRFreeOutputInfo(output);
28879+ }
28880+ }
28881+
28882+ for (n = 0; mode == 0 && n < res->ncrtc; n++) {
28883+ XRRCrtcInfo *crtc;
28884+
28885+ crtc = XRRGetCrtcInfo(dpy, res, res->crtcs[n]);
28886+ if (crtc) {
28887+ mode = crtc->mode;
28888+ XRRFreeCrtcInfo(crtc);
28889+ }
28890+ }
28891+
28892+ for (n = 0; n < res->nmode; n++) {
28893+ if (res->modes[n].id == mode) {
28894+ ret = compute_refresh_rate_from_mode(res->modes[n].dotClock,
28895+ res->modes[n].hTotal*res->modes[n].vTotal,
28896+ res->modes[n].modeFlags,
28897+ numerator, denominator);
28898+ break;
28899+ }
28900+ }
28901+
28902+ XRRFreeScreenResources(res);
28903+ return ret;
28904+}
28905+
28906+static int VMGetMscRate(Display *dpy, int32_t *numerator, int32_t *denominator)
28907+{
28908+ XF86VidModeModeLine mode_line;
28909+ int dot_clock;
28910+ int i;
28911+
28912+ if (XF86VidModeQueryVersion(dpy, &i, &i) &&
28913+ XF86VidModeGetModeLine(dpy, DefaultScreen(dpy), &dot_clock, &mode_line))
28914+ return compute_refresh_rate_from_mode(dot_clock * 1000,
28915+ mode_line.vtotal * mode_line.htotal,
28916+ mode_line.flags,
28917+ numerator, denominator);
28918+
28919+ return 0;
28920+}
28921+
28922+static int get_refresh_rate(Display *dpy,
28923+ int32_t *numerator,
28924+ int32_t *denominator)
28925+{
28926+ if (RRGetMscRate(dpy, numerator, denominator))
28927+ return 1;
28928+
28929+ if (VMGetMscRate(dpy, numerator, denominator))
28930+ return 1;
28931+
28932+ return 0;
28933+}
28934+
28935+static void info(const char *dpyname)
28936+{
28937+ Display *dpy;
28938+ int device;
28939+ int32_t numerator, denominator;
28940+
28941+ dpy = XOpenDisplay(dpyname);
28942+ if (dpy == NULL) {
28943+ printf("Unable to connect to display '%s'\n",
28944+ dpyname ?: getenv("DISPLAY") ?: "unset");
28945+ return;
28946+ }
28947+
28948+ printf("Display '%s'\n", DisplayString(dpy));
28949+ device = dri3_open(dpy);
28950+ if (device < 0) {
28951+ printf("\tUnable to connect to DRI3\n");
28952+ } else {
28953+ char device_path[1024];
28954+ char driver_name[1024];
28955+
28956+ get_device_path(device, device_path, sizeof(device_path));
28957+ get_driver_name(device, driver_name, sizeof(driver_name));
28958+
28959+ printf("Connected to DRI3, using fd %d which matches %s, driver %s\n",
28960+ device, device_path, driver_name);
28961+ close(device);
28962+ }
28963+
28964+ if (get_refresh_rate(dpy, &numerator, &denominator))
28965+ printf("\tPrimary refresh rate: %d/%d (%.1fHz)\n",
28966+ numerator, denominator, numerator/(float)denominator);
28967+
28968+ XCloseDisplay(dpy);
28969+}
28970+
28971+int main(int argc, char **argv)
28972+{
28973+ int i;
28974+
28975+ if (argc > 1) {
28976+ for (i = 1; i < argc; i++)
28977+ info(argv[i]);
28978+ } else
28979+ info(NULL);
28980+
28981+ return 0;
28982+}
28983diff --git a/tools/virtual.c b/tools/virtual.c
28984index 8e2b4a2..ffda54a 100644
28985--- a/tools/virtual.c
28986+++ b/tools/virtual.c
28987@@ -111,7 +111,7 @@ struct display {
28988 Cursor invisible_cursor;
28989 Cursor visible_cursor;
28990
28991- XcursorImage cursor_image;
28992+ XcursorImage cursor_image; /* first only */
28993 int cursor_serial;
28994 int cursor_x;
28995 int cursor_y;
28996@@ -145,6 +145,7 @@ struct output {
28997 XRenderPictFormat *use_render;
28998
28999 int x, y;
29000+ int width, height;
29001 XRRModeInfo mode;
29002 Rotation rotation;
29003 };
29004@@ -218,6 +219,13 @@ static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Wi
29005 static int _x_error_occurred;
29006
29007 static int
29008+_io_error_handler(Display *display)
29009+{
29010+ fprintf(stderr, "XIO error on display %s\n", DisplayString(display));
29011+ abort();
29012+}
29013+
29014+static int
29015 _check_error_handler(Display *display,
29016 XErrorEvent *event)
29017 {
29018@@ -243,6 +251,10 @@ can_use_shm(Display *dpy,
29019 XExtCodes *codes;
29020 int major, minor, has_shm, has_pixmap;
29021
29022+ *shm_event = 0;
29023+ *shm_opcode = 0;
29024+ *shm_pixmap = 0;
29025+
29026 if (!XShmQueryExtension(dpy))
29027 return 0;
29028
29029@@ -320,6 +332,7 @@ can_use_shm(Display *dpy,
29030 #include <X11/Xlib-xcb.h>
29031 #include <X11/xshmfence.h>
29032 #include <xcb/xcb.h>
29033+#include <xcb/xcbext.h>
29034 #include <xcb/dri3.h>
29035 #include <xcb/sync.h>
29036 static Pixmap dri3_create_pixmap(Display *dpy,
29037@@ -357,6 +370,7 @@ static int dri3_query_version(Display *dpy, int *major, int *minor)
29038 {
29039 xcb_connection_t *c = XGetXCBConnection(dpy);
29040 xcb_dri3_query_version_reply_t *reply;
29041+ xcb_generic_error_t *error;
29042
29043 *major = *minor = -1;
29044
29045@@ -364,7 +378,8 @@ static int dri3_query_version(Display *dpy, int *major, int *minor)
29046 xcb_dri3_query_version(c,
29047 XCB_DRI3_MAJOR_VERSION,
29048 XCB_DRI3_MINOR_VERSION),
29049- NULL);
29050+ &error);
29051+ free(error);
29052 if (reply == NULL)
29053 return -1;
29054
29055@@ -377,8 +392,13 @@ static int dri3_query_version(Display *dpy, int *major, int *minor)
29056
29057 static int dri3_exists(Display *dpy)
29058 {
29059+ const xcb_query_extension_reply_t *ext;
29060 int major, minor;
29061
29062+ ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id);
29063+ if (ext == NULL || !ext->present)
29064+ return 0;
29065+
29066 if (dri3_query_version(dpy, &major, &minor) < 0)
29067 return 0;
29068
29069@@ -809,6 +829,10 @@ static int clone_update_modes__fixed(struct clone *clone)
29070 RRMode id;
29071 int i, j, ret = ENOENT;
29072
29073+ DBG(X11, ("%s-%s cloning modes fixed %dx%d\n",
29074+ DisplayString(clone->dst.dpy), clone->dst.name,
29075+ clone->dst.width, clone->dst.height));
29076+
29077 assert(clone->src.rr_output);
29078
29079 res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window);
29080@@ -837,8 +861,8 @@ static int clone_update_modes__fixed(struct clone *clone)
29081
29082 /* Create matching mode for the real output on the virtual */
29083 memset(&mode, 0, sizeof(mode));
29084- mode.width = clone->width;
29085- mode.height = clone->height;
29086+ mode.width = clone->dst.width;
29087+ mode.height = clone->dst.height;
29088 mode.nameLength = sprintf(mode_name, "FAKE-%dx%d", mode.width, mode.height);
29089 mode.name = mode_name;
29090
29091@@ -1082,20 +1106,20 @@ static int clone_init_xfer(struct clone *clone)
29092 width = 0;
29093 height = 0;
29094 } else if (clone->dri3.xid) {
29095- width = clone->dst.display->width;
29096- height = clone->dst.display->height;
29097+ width = clone->dst.width;
29098+ height = clone->dst.height;
29099 } else {
29100 width = mode_width(&clone->src.mode, clone->src.rotation);
29101 height = mode_height(&clone->src.mode, clone->src.rotation);
29102 }
29103
29104+ DBG(DRAW, ("%s-%s create xfer, %dx%d (currently %dx%d)\n",
29105+ DisplayString(clone->dst.dpy), clone->dst.name,
29106+ width, height, clone->width, clone->height));
29107+
29108 if (width == clone->width && height == clone->height)
29109 return 0;
29110
29111- DBG(DRAW, ("%s-%s create xfer, %dx%d\n",
29112- DisplayString(clone->dst.dpy), clone->dst.name,
29113- width, height));
29114-
29115 if (clone->shm.shmaddr) {
29116 if (clone->src.use_shm)
29117 XShmDetach(clone->src.dpy, &clone->src.shm);
29118@@ -1325,8 +1349,19 @@ static int context_update(struct context *ctx)
29119 struct clone *clone;
29120 int x1, x2, y1, y2;
29121
29122- if (display->rr_active == 0)
29123+ if (display->rr_active == 0) {
29124+ for (clone = display->clone; clone; clone = clone->next) {
29125+ struct output *output = &clone->src;
29126+ if (output->mode.id) {
29127+ clone->dst.mode.id = -1;
29128+ clone->dst.rr_crtc = -1;
29129+ } else {
29130+ clone->dst.mode.id = 0;
29131+ clone->dst.rr_crtc = 0;
29132+ }
29133+ }
29134 continue;
29135+ }
29136
29137 x1 = y1 = INT_MAX;
29138 x2 = y2 = INT_MIN;
29139@@ -1599,14 +1634,17 @@ static Cursor display_load_invisible_cursor(struct display *display)
29140
29141 static Cursor display_get_visible_cursor(struct display *display)
29142 {
29143- if (display->cursor_serial != display->cursor_image.size) {
29144- DBG(CURSOR, ("%s updating cursor\n", DisplayString(display->dpy)));
29145+ struct display *first = display->ctx->display;
29146+
29147+ if (display->cursor_serial != first->cursor_serial) {
29148+ DBG(CURSOR, ("%s updating cursor %dx%d, serial %d\n",
29149+ DisplayString(display->dpy), first->cursor_image.width, first->cursor_image.height, first->cursor_serial));
29150
29151 if (display->visible_cursor)
29152 XFreeCursor(display->dpy, display->visible_cursor);
29153
29154- display->visible_cursor = XcursorImageLoadCursor(display->dpy, &display->cursor_image);
29155- display->cursor_serial = display->cursor_image.size;
29156+ display->visible_cursor = XcursorImageLoadCursor(display->dpy, &first->cursor_image);
29157+ display->cursor_serial = first->cursor_serial;
29158 }
29159
29160 return display->visible_cursor;
29161@@ -1629,7 +1667,7 @@ static void display_load_visible_cursor(struct display *display, XFixesCursorIma
29162 display->cursor_image.height = cur->height;
29163 display->cursor_image.xhot = cur->xhot;
29164 display->cursor_image.yhot = cur->yhot;
29165- display->cursor_image.size++;
29166+ display->cursor_serial++;
29167
29168 n = cur->width*cur->height;
29169 src = cur->pixels;
29170@@ -1637,11 +1675,24 @@ static void display_load_visible_cursor(struct display *display, XFixesCursorIma
29171 while (n--)
29172 *dst++ = *src++;
29173
29174- DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy)));
29175- display->cursor_moved++;
29176- if (display->cursor != display->invisible_cursor) {
29177- display->cursor_visible++;
29178- context_enable_timer(display->ctx);
29179+ if (verbose & CURSOR) {
29180+ int x, y;
29181+
29182+ printf("%s cursor image %dx%d, serial %d:\n",
29183+ DisplayString(display->dpy),
29184+ cur->width, cur->height,
29185+ display->cursor_serial);
29186+ dst = display->cursor_image.pixels;
29187+ for (y = 0; y < cur->height; y++) {
29188+ for (x = 0; x < cur->width; x++) {
29189+ if (x == cur->xhot && y == cur->yhot)
29190+ printf("+");
29191+ else
29192+ printf("%c", *dst ? *dst >> 24 >= 127 ? 'x' : '.' : ' ');
29193+ dst++;
29194+ }
29195+ printf("\n");
29196+ }
29197 }
29198 }
29199
29200@@ -1685,6 +1736,8 @@ static void display_flush_cursor(struct display *display)
29201 if (cursor == None)
29202 cursor = display->invisible_cursor;
29203 if (cursor != display->cursor) {
29204+ DBG(CURSOR, ("%s setting cursor shape %lx\n",
29205+ DisplayString(display->dpy), (long)cursor));
29206 XDefineCursor(display->dpy, display->root, cursor);
29207 display->cursor = cursor;
29208 }
29209@@ -1762,6 +1815,8 @@ static void get_src(struct clone *c, const XRectangle *clip)
29210 c->image.obdata = (char *)&c->src.shm;
29211
29212 if (c->src.use_render) {
29213+ DBG(DRAW, ("%s-%s get_src via XRender\n",
29214+ DisplayString(c->dst.dpy), c->dst.name));
29215 XRenderComposite(c->src.dpy, PictOpSrc,
29216 c->src.win_picture, 0, c->src.pix_picture,
29217 clip->x, clip->y,
29218@@ -1782,16 +1837,22 @@ static void get_src(struct clone *c, const XRectangle *clip)
29219 &c->image, 0, 0);
29220 }
29221 } else if (c->src.pixmap) {
29222+ DBG(DRAW, ("%s-%s get_src XCopyArea (SHM/DRI3)\n",
29223+ DisplayString(c->dst.dpy), c->dst.name));
29224 XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc,
29225 clip->x, clip->y,
29226 clip->width, clip->height,
29227 0, 0);
29228 XSync(c->src.dpy, False);
29229 } else if (c->src.use_shm) {
29230+ DBG(DRAW, ("%s-%s get_src XShmGetImage\n",
29231+ DisplayString(c->dst.dpy), c->dst.name));
29232 ximage_prepare(&c->image, clip->width, clip->height);
29233 XShmGetImage(c->src.dpy, c->src.window, &c->image,
29234 clip->x, clip->y, AllPlanes);
29235 } else {
29236+ DBG(DRAW, ("%s-%s get_src XGetSubImage (slow)\n",
29237+ DisplayString(c->dst.dpy), c->dst.name));
29238 ximage_prepare(&c->image, c->width, c->height);
29239 XGetSubImage(c->src.dpy, c->src.window,
29240 clip->x, clip->y, clip->width, clip->height,
29241@@ -1838,7 +1899,7 @@ static void put_dst(struct clone *c, const XRectangle *clip)
29242 clip->width, clip->height);
29243 c->dst.display->send |= c->dst.use_shm;
29244 } else if (c->dst.pixmap) {
29245- DBG(DRAW, ("%s-%s using SHM pixmap\n",
29246+ DBG(DRAW, ("%s-%s using SHM or DRI3 pixmap\n",
29247 DisplayString(c->dst.dpy), c->dst.name));
29248 c->dst.serial = NextRequest(c->dst.dpy);
29249 XCopyArea(c->dst.dpy, c->dst.pixmap, c->dst.window, c->dst.gc,
29250@@ -1870,6 +1931,9 @@ static int clone_paint(struct clone *c)
29251 {
29252 XRectangle clip;
29253
29254+ if (c->width == 0 || c->height == 0)
29255+ return 0;
29256+
29257 DBG(DRAW, ("%s-%s paint clone, damaged (%d, %d), (%d, %d) [(%d, %d), (%d, %d)]\n",
29258 DisplayString(c->dst.dpy), c->dst.name,
29259 c->damaged.x1, c->damaged.y1,
29260@@ -1944,6 +2008,10 @@ static int clone_paint(struct clone *c)
29261 clip.height = c->damaged.y2 - c->damaged.y1;
29262 get_src(c, &clip);
29263
29264+ DBG(DRAW, ("%s-%s target offset %dx%d\n",
29265+ DisplayString(c->dst.dpy), c->dst.name,
29266+ c->dst.x - c->src.x, c->dst.y - c->src.y));
29267+
29268 clip.x += c->dst.x - c->src.x;
29269 clip.y += c->dst.y - c->src.y;
29270 put_dst(c, &clip);
29271@@ -2252,6 +2320,8 @@ static int clone_init_depth(struct clone *clone)
29272 if (ret)
29273 return ret;
29274
29275+ clone->depth = depth;
29276+
29277 DBG(X11, ("%s-%s using depth %d, requires xrender for src? %d, for dst? %d\n",
29278 DisplayString(clone->dst.dpy), clone->dst.name,
29279 clone->depth,
29280@@ -2592,6 +2662,11 @@ static int last_display_add_clones__randr(struct context *ctx)
29281 return ret;
29282 }
29283
29284+ clone->dst.x = 0;
29285+ clone->dst.y = 0;
29286+ clone->dst.width = display->width;
29287+ clone->dst.height = display->height;
29288+
29289 ret = clone_update_modes__randr(clone);
29290 if (ret) {
29291 fprintf(stderr, "Failed to clone output \"%s\" from display \"%s\"\n",
29292@@ -2668,8 +2743,8 @@ static int last_display_add_clones__xinerama(struct context *ctx)
29293 }
29294
29295 /* Replace the modes on the local VIRTUAL output with the remote Screen */
29296- clone->width = xi[n].width;
29297- clone->height = xi[n].height;
29298+ clone->dst.width = xi[n].width;
29299+ clone->dst.height = xi[n].height;
29300 clone->dst.x = xi[n].x_org;
29301 clone->dst.y = xi[n].y_org;
29302 clone->dst.rr_crtc = -1;
29303@@ -2698,64 +2773,67 @@ static int last_display_add_clones__display(struct context *ctx)
29304 Display *dpy = display->dpy;
29305 struct clone *clone;
29306 Screen *scr;
29307+ int count, s;
29308 char buf[80];
29309 int ret;
29310 RROutput id;
29311
29312+ count = ScreenCount(dpy);
29313+ DBG(X11, ("%s(%s) - %d screens\n", __func__, DisplayString(dpy), count));
29314+ for (s = 0; s < count; s++) {
29315+ clone = add_clone(ctx);
29316+ if (clone == NULL)
29317+ return -ENOMEM;
29318
29319- DBG(X11, ("%s(%s)\n", __func__, DisplayString(dpy)));
29320- clone = add_clone(ctx);
29321- if (clone == NULL)
29322- return -ENOMEM;
29323+ clone->depth = 24;
29324+ clone->next = display->clone;
29325+ display->clone = clone;
29326
29327- clone->depth = 24;
29328- clone->next = display->clone;
29329- display->clone = clone;
29330+ id = claim_virtual(ctx->display, buf, ctx->nclone);
29331+ if (id == 0) {
29332+ fprintf(stderr, "Failed to find available VirtualHead \"%s\" for on display \"%s\"\n",
29333+ buf, DisplayString(dpy));
29334+ }
29335+ ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
29336+ if (ret) {
29337+ fprintf(stderr, "Failed to add display \"%s\"\n",
29338+ DisplayString(ctx->display->dpy));
29339+ return ret;
29340+ }
29341
29342- id = claim_virtual(ctx->display, buf, ctx->nclone);
29343- if (id == 0) {
29344- fprintf(stderr, "Failed to find available VirtualHead \"%s\" for on display \"%s\"\n",
29345- buf, DisplayString(dpy));
29346- }
29347- ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
29348- if (ret) {
29349- fprintf(stderr, "Failed to add display \"%s\"\n",
29350- DisplayString(ctx->display->dpy));
29351- return ret;
29352- }
29353+ sprintf(buf, "SCREEN%d", s);
29354+ ret = clone_output_init(clone, &clone->dst, display, buf, 0);
29355+ if (ret) {
29356+ fprintf(stderr, "Failed to add display \"%s\"\n",
29357+ DisplayString(dpy));
29358+ return ret;
29359+ }
29360
29361- sprintf(buf, "WHOLE");
29362- ret = clone_output_init(clone, &clone->dst, display, buf, 0);
29363- if (ret) {
29364- fprintf(stderr, "Failed to add display \"%s\"\n",
29365- DisplayString(dpy));
29366- return ret;
29367- }
29368+ ret = clone_init_depth(clone);
29369+ if (ret) {
29370+ fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
29371+ DisplayString(dpy));
29372+ return ret;
29373+ }
29374
29375- ret = clone_init_depth(clone);
29376- if (ret) {
29377- fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
29378- DisplayString(dpy));
29379- return ret;
29380- }
29381+ /* Replace the modes on the local VIRTUAL output with the remote Screen */
29382+ scr = ScreenOfDisplay(dpy, s);
29383+ clone->dst.width = scr->width;
29384+ clone->dst.height = scr->height;
29385+ clone->dst.x = 0;
29386+ clone->dst.y = 0;
29387+ clone->dst.rr_crtc = -1;
29388+ ret = clone_update_modes__fixed(clone);
29389+ if (ret) {
29390+ fprintf(stderr, "Failed to clone display \"%s\"\n",
29391+ DisplayString(dpy));
29392+ return ret;
29393+ }
29394
29395- /* Replace the modes on the local VIRTUAL output with the remote Screen */
29396- scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));
29397- clone->width = scr->width;
29398- clone->height = scr->height;
29399- clone->dst.x = 0;
29400- clone->dst.y = 0;
29401- clone->dst.rr_crtc = -1;
29402- ret = clone_update_modes__fixed(clone);
29403- if (ret) {
29404- fprintf(stderr, "Failed to clone display \"%s\"\n",
29405- DisplayString(dpy));
29406- return ret;
29407+ clone->active = ctx->active;
29408+ ctx->active = clone;
29409 }
29410
29411- clone->active = ctx->active;
29412- ctx->active = clone;
29413-
29414 return 0;
29415 }
29416
29417@@ -3168,6 +3246,33 @@ static void context_cleanup(struct context *ctx)
29418 XCloseDisplay(dpy);
29419 }
29420
29421+static void update_cursor_image(struct context *ctx)
29422+{
29423+ XFixesCursorImage *cur;
29424+ int i;
29425+
29426+ DBG(CURSOR, ("%s cursor changed\n",
29427+ DisplayString(ctx->display->dpy)));
29428+
29429+ cur = XFixesGetCursorImage(ctx->display->dpy);
29430+ if (cur == NULL)
29431+ return;
29432+
29433+ display_load_visible_cursor(&ctx->display[0], cur);
29434+ for (i = 1; i < ctx->ndisplay; i++) {
29435+ struct display *display = &ctx->display[i];
29436+
29437+ DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy)));
29438+ display->cursor_moved++;
29439+ if (display->cursor != display->invisible_cursor) {
29440+ display->cursor_visible++;
29441+ context_enable_timer(display->ctx);
29442+ }
29443+ }
29444+
29445+ XFree(cur);
29446+}
29447+
29448 static int done;
29449
29450 static void signal_handler(int sig)
29451@@ -3228,6 +3333,7 @@ int main(int argc, char **argv)
29452 return -ret;
29453
29454 XSetErrorHandler(_check_error_handler);
29455+ XSetIOErrorHandler(_io_error_handler);
29456
29457 ret = add_fd(&ctx, display_open(&ctx, src_name));
29458 if (ret) {
29459@@ -3348,6 +3454,7 @@ int main(int argc, char **argv)
29460 signal(SIGTERM, signal_handler);
29461
29462 ctx.command_continuation = 0;
29463+ update_cursor_image(&ctx);
29464 while (!done) {
29465 XEvent e;
29466 int reconfigure = 0;
29467@@ -3380,19 +3487,7 @@ int main(int argc, char **argv)
29468 if (ctx.active)
29469 context_enable_timer(&ctx);
29470 } else if (e.type == ctx.display->xfixes_event + XFixesCursorNotify) {
29471- XFixesCursorImage *cur;
29472-
29473- DBG(CURSOR, ("%s cursor changed\n",
29474- DisplayString(ctx.display->dpy)));
29475-
29476- cur = XFixesGetCursorImage(ctx.display->dpy);
29477- if (cur == NULL)
29478- continue;
29479-
29480- for (i = 1; i < ctx.ndisplay; i++)
29481- display_load_visible_cursor(&ctx.display[i], cur);
29482-
29483- XFree(cur);
29484+ update_cursor_image(&ctx);
29485 } else if (e.type == ctx.display->rr_event + RRScreenChangeNotify) {
29486 DBG(XRR, ("%s screen changed (reconfigure pending? %d)\n",
29487 DisplayString(ctx.display->dpy), reconfigure));
This page took 3.607698 seconds and 4 git commands to generate.