wok-next view xorg-xf86-video-intel/stuff/patches/git.patch @ rev 20905

Update packages from ISO and LFS backages (all but toolchain)
author Aleksej Bobylev <al.bobylev@gmail.com>
date Tue Aug 07 00:30:45 2018 +0300 (2018-08-07)
parents
children
line source
1 diff --git a/Makefile.am b/Makefile.am
2 index 418fdc92..de5fbe12 100644
3 --- a/Makefile.am
4 +++ b/Makefile.am
5 @@ -18,14 +18,16 @@
6 # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
7 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9 -ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4
10 +#Having problems passing through user flags as libtool complains
11 +#ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4
12 +ACLOCAL_AMFLAGS = -I m4
14 SUBDIRS = man libobj xvmc src tools
16 MAINTAINERCLEANFILES = ChangeLog INSTALL
18 if HAVE_X11
19 -SUBDIRS += test
20 +SUBDIRS += test benchmarks
21 endif
23 .PHONY: ChangeLog INSTALL
24 diff --git a/NEWS b/NEWS
25 index 604b9cce..0e200332 100644
26 --- a/NEWS
27 +++ b/NEWS
28 @@ -21,7 +21,7 @@ should make one more snapshot before an imminent release.
29 Before kernel 3.19, O_NONBLOCK support is broken and so we must avoid
30 reading if we are not expecting an event.
32 - * Backwards compatibilty fix for fake triple buffering with PRIME and
33 + * Backwards compatibility fix for fake triple buffering with PRIME and
34 Xorg-1.15
35 https://bugs.freedesktop.org/show_bug.cgi?id=85144#c12
37 @@ -51,7 +51,7 @@ should make one more snapshot before an imminent release.
38 Snapshot 2.99.916 (2014-09-08)
39 ==============================
40 Quick update for MST in UXA - we need to hook up the RandR outputs for
41 -dynamicaly added connectors.
42 +dynamically added connectors.
45 Snapshot 2.99.915 (2014-09-08)
46 @@ -503,7 +503,7 @@ release.
47 backlight property is queried whilst the connector is disabled
48 https://bugs.freedesktop.org/show_bug.cgi?id=70406
50 - * Pad GETCONNECTOR ioctl for compatability between 32/64-bit userspace
51 + * Pad GETCONNECTOR ioctl for compatibility between 32/64-bit userspace
52 and kernel
54 * Handle long glyph runs correctly
55 @@ -523,7 +523,7 @@ snapshot beforehand to push out the bug fixes from the last week.
57 * Fix video output using sprites when changing the image size
59 - * Apply more restrictive tile constaints for 915g class devices
60 + * Apply more restrictive tile constraints for 915g class devices
61 https://bugs.launchpad.net/ubuntu/+source/xserver-xorg-video-intel/+bug/1232546
63 * Ensure all overlapping rectangles are drawn for XRenderFillRectangles
64 @@ -1132,7 +1132,7 @@ operation.
65 * Explicitly prevent ring-switching for synchronized rendering to
66 scanouts (for vsync).
68 - * Clip dirty region to slave pixmaps (otherwise UDL is nigh unusuable)
69 + * Clip dirty region to slave pixmaps (otherwise UDL is nigh unusable)
70 https://bugs.freedesktop.org/show_bug.cgi?id=59539
73 @@ -1226,7 +1226,7 @@ Release 2.20.15 (2012-12-03)
74 ============================
75 And lo, enabling more of the common acceleration paths for gen4 revealed
76 another lurking bug - something is wrong with how we prepare Y-tiling
77 -surfaces for rendering. For the time being, we can surreptiously disable
78 +surfaces for rendering. For the time being, we can surreptitiously disable
79 them for gen4 and avoid hitting GPU hangs.
81 * Avoid clobbering the render state after failing to convert the
82 @@ -1515,7 +1515,7 @@ Release 2.20.5 (2012-08-26)
83 Another silly bug found, another small bugfix release. The goal was for
84 the driver to bind to all Intel devices supported by the kernel.
85 Unfortunately we were too successful and started claiming Pouslbo,
86 -Medfield and Cedarview devices which are still encumbered by propietary
87 +Medfield and Cedarview devices which are still encumbered by proprietary
88 IP and not supported by this driver.
90 Bugs fixed since 2.20.4:
91 diff --git a/README b/README
92 index cf4d88d8..348983b4 100644
93 --- a/README
94 +++ b/README
95 @@ -15,9 +15,9 @@ Intel graphics chipsets including:
96 G/Q33,G/Q35,G41,G/Q43,G/GM/Q45
97 PineView-M (Atom N400 series)
98 PineView-D (Atom D400/D500 series)
99 - Intel(R) HD Graphics: 2000-6000,
100 - Intel(R) Iris(TM) Graphics: 5100/6100, and
101 - Intel(R) Iris(TM) Pro Graphics: 5200/6200/P6300.
102 + Intel(R) HD Graphics,
103 + Intel(R) Iris(TM) Graphics,
104 + Intel(R) Iris(TM) Pro Graphics.
106 Where to get more information about the driver
107 ----------------------------------------------
108 diff --git a/benchmarks/.gitignore b/benchmarks/.gitignore
109 new file mode 100644
110 index 00000000..301c0129
111 --- /dev/null
112 +++ b/benchmarks/.gitignore
113 @@ -0,0 +1,2 @@
114 +dri2-swap
115 +dri3-swap
116 diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am
117 new file mode 100644
118 index 00000000..4976e8a3
119 --- /dev/null
120 +++ b/benchmarks/Makefile.am
121 @@ -0,0 +1,14 @@
122 +AM_CFLAGS = @CWARNFLAGS@ $(X11_CFLAGS) $(DRM_CFLAGS)
123 +LDADD = $(X11_LIBS) $(DRM_LIBS) $(CLOCK_GETTIME_LIBS)
124 +
125 +check_PROGRAMS =
126 +
127 +if DRI2
128 +check_PROGRAMS += dri2-swap
129 +endif
130 +
131 +if DRI3
132 +check_PROGRAMS += dri3-swap
133 +AM_CFLAGS += $(X11_DRI3_CFLAGS)
134 +LDADD += $(X11_DRI3_LIBS)
135 +endif
136 diff --git a/benchmarks/dri2-swap.c b/benchmarks/dri2-swap.c
137 new file mode 100644
138 index 00000000..3d9d30aa
139 --- /dev/null
140 +++ b/benchmarks/dri2-swap.c
141 @@ -0,0 +1,588 @@
142 +/*
143 + * Copyright (c) 2015 Intel Corporation
144 + *
145 + * Permission is hereby granted, free of charge, to any person obtaining a
146 + * copy of this software and associated documentation files (the "Software"),
147 + * to deal in the Software without restriction, including without limitation
148 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
149 + * and/or sell copies of the Software, and to permit persons to whom the
150 + * Software is furnished to do so, subject to the following conditions:
151 + *
152 + * The above copyright notice and this permission notice (including the next
153 + * paragraph) shall be included in all copies or substantial portions of the
154 + * Software.
155 + *
156 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
157 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
158 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
159 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
160 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
161 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
162 + * SOFTWARE.
163 + *
164 + */
165 +
166 +#ifdef HAVE_CONFIG_H
167 +#include "config.h"
168 +#endif
169 +
170 +#include <X11/Xlib.h>
171 +#include <X11/Xatom.h>
172 +#include <X11/Xlib-xcb.h>
173 +#include <X11/Xutil.h>
174 +#include <X11/Xlibint.h>
175 +#include <X11/extensions/dpms.h>
176 +#include <X11/extensions/randr.h>
177 +#include <X11/extensions/Xcomposite.h>
178 +#include <X11/extensions/Xdamage.h>
179 +#include <X11/extensions/Xrandr.h>
180 +#include <xcb/xcb.h>
181 +#include <xcb/dri2.h>
182 +#include <xf86drm.h>
183 +
184 +#include <stdio.h>
185 +#include <string.h>
186 +#include <fcntl.h>
187 +#include <unistd.h>
188 +#include <assert.h>
189 +#include <errno.h>
190 +#include <setjmp.h>
191 +#include <signal.h>
192 +
193 +#include <X11/Xlibint.h>
194 +#include <X11/extensions/Xext.h>
195 +#include <X11/extensions/extutil.h>
196 +#include <X11/extensions/dri2proto.h>
197 +#include <X11/extensions/dri2tokens.h>
198 +#include <X11/extensions/Xfixes.h>
199 +
200 +static char dri2ExtensionName[] = DRI2_NAME;
201 +static XExtensionInfo *dri2Info;
202 +static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info)
203 +
204 +static Bool
205 +DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire);
206 +static Status
207 +DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire);
208 +static int
209 +DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code);
210 +
211 +static /* const */ XExtensionHooks dri2ExtensionHooks = {
212 + NULL, /* create_gc */
213 + NULL, /* copy_gc */
214 + NULL, /* flush_gc */
215 + NULL, /* free_gc */
216 + NULL, /* create_font */
217 + NULL, /* free_font */
218 + DRI2CloseDisplay, /* close_display */
219 + DRI2WireToEvent, /* wire_to_event */
220 + DRI2EventToWire, /* event_to_wire */
221 + DRI2Error, /* error */
222 + NULL, /* error_string */
223 +};
224 +
225 +static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay,
226 + dri2Info,
227 + dri2ExtensionName,
228 + &dri2ExtensionHooks,
229 + 0, NULL)
230 +
231 +static Bool
232 +DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire)
233 +{
234 + XExtDisplayInfo *info = DRI2FindDisplay(dpy);
235 +
236 + XextCheckExtension(dpy, info, dri2ExtensionName, False);
237 +
238 + switch ((wire->u.u.type & 0x7f) - info->codes->first_event) {
239 +#ifdef X_DRI2SwapBuffers
240 + case DRI2_BufferSwapComplete:
241 + return False;
242 +#endif
243 +#ifdef DRI2_InvalidateBuffers
244 + case DRI2_InvalidateBuffers:
245 + return False;
246 +#endif
247 + default:
248 + /* client doesn't support server event */
249 + break;
250 + }
251 +
252 + return False;
253 +}
254 +
255 +/* We don't actually support this. It doesn't make sense for clients to
256 + * send each other DRI2 events.
257 + */
258 +static Status
259 +DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire)
260 +{
261 + XExtDisplayInfo *info = DRI2FindDisplay(dpy);
262 +
263 + XextCheckExtension(dpy, info, dri2ExtensionName, False);
264 +
265 + switch (event->type) {
266 + default:
267 + /* client doesn't support server event */
268 + break;
269 + }
270 +
271 + return Success;
272 +}
273 +
274 +static int
275 +DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code)
276 +{
277 + if (err->majorCode == codes->major_opcode &&
278 + err->errorCode == BadDrawable &&
279 + err->minorCode == X_DRI2CopyRegion)
280 + return True;
281 +
282 + /* If the X drawable was destroyed before the GLX drawable, the
283 + * DRI2 drawble will be gone by the time we call
284 + * DRI2DestroyDrawable. So just ignore BadDrawable here. */
285 + if (err->majorCode == codes->major_opcode &&
286 + err->errorCode == BadDrawable &&
287 + err->minorCode == X_DRI2DestroyDrawable)
288 + return True;
289 +
290 + /* If the server is non-local DRI2Connect will raise BadRequest.
291 + * Swallow this so that DRI2Connect can signal this in its return code */
292 + if (err->majorCode == codes->major_opcode &&
293 + err->minorCode == X_DRI2Connect &&
294 + err->errorCode == BadRequest) {
295 + *ret_code = False;
296 + return True;
297 + }
298 +
299 + return False;
300 +}
301 +
302 +static Bool
303 +DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase)
304 +{
305 + XExtDisplayInfo *info = DRI2FindDisplay(dpy);
306 +
307 + if (XextHasExtension(info)) {
308 + *eventBase = info->codes->first_event;
309 + *errorBase = info->codes->first_error;
310 + return True;
311 + }
312 +
313 + return False;
314 +}
315 +
316 +static Bool
317 +DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName)
318 +{
319 + XExtDisplayInfo *info = DRI2FindDisplay(dpy);
320 + xDRI2ConnectReply rep;
321 + xDRI2ConnectReq *req;
322 +
323 + XextCheckExtension(dpy, info, dri2ExtensionName, False);
324 +
325 + LockDisplay(dpy);
326 + GetReq(DRI2Connect, req);
327 + req->reqType = info->codes->major_opcode;
328 + req->dri2ReqType = X_DRI2Connect;
329 + req->window = window;
330 + req->driverType = DRI2DriverDRI;
331 + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
332 + UnlockDisplay(dpy);
333 + SyncHandle();
334 + return False;
335 + }
336 +
337 + if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) {
338 + UnlockDisplay(dpy);
339 + SyncHandle();
340 + return False;
341 + }
342 +
343 + *driverName = Xmalloc(rep.driverNameLength + 1);
344 + if (*driverName == NULL) {
345 + _XEatData(dpy,
346 + ((rep.driverNameLength + 3) & ~3) +
347 + ((rep.deviceNameLength + 3) & ~3));
348 + UnlockDisplay(dpy);
349 + SyncHandle();
350 + return False;
351 + }
352 + _XReadPad(dpy, *driverName, rep.driverNameLength);
353 + (*driverName)[rep.driverNameLength] = '\0';
354 +
355 + *deviceName = Xmalloc(rep.deviceNameLength + 1);
356 + if (*deviceName == NULL) {
357 + Xfree(*driverName);
358 + _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3));
359 + UnlockDisplay(dpy);
360 + SyncHandle();
361 + return False;
362 + }
363 + _XReadPad(dpy, *deviceName, rep.deviceNameLength);
364 + (*deviceName)[rep.deviceNameLength] = '\0';
365 +
366 + UnlockDisplay(dpy);
367 + SyncHandle();
368 +
369 + return True;
370 +}
371 +
372 +static Bool
373 +DRI2Authenticate(Display * dpy, XID window, unsigned int magic)
374 +{
375 + XExtDisplayInfo *info = DRI2FindDisplay(dpy);
376 + xDRI2AuthenticateReq *req;
377 + xDRI2AuthenticateReply rep;
378 +
379 + XextCheckExtension(dpy, info, dri2ExtensionName, False);
380 +
381 + LockDisplay(dpy);
382 + GetReq(DRI2Authenticate, req);
383 + req->reqType = info->codes->major_opcode;
384 + req->dri2ReqType = X_DRI2Authenticate;
385 + req->window = window;
386 + req->magic = magic;
387 +
388 + if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
389 + UnlockDisplay(dpy);
390 + SyncHandle();
391 + return False;
392 + }
393 +
394 + UnlockDisplay(dpy);
395 + SyncHandle();
396 +
397 + return rep.authenticated;
398 +}
399 +
400 +static void
401 +DRI2CreateDrawable(Display * dpy, XID drawable)
402 +{
403 + XExtDisplayInfo *info = DRI2FindDisplay(dpy);
404 + xDRI2CreateDrawableReq *req;
405 +
406 + XextSimpleCheckExtension(dpy, info, dri2ExtensionName);
407 +
408 + LockDisplay(dpy);
409 + GetReq(DRI2CreateDrawable, req);
410 + req->reqType = info->codes->major_opcode;
411 + req->dri2ReqType = X_DRI2CreateDrawable;
412 + req->drawable = drawable;
413 + UnlockDisplay(dpy);
414 + SyncHandle();
415 +}
416 +
417 +static void DRI2SwapInterval(Display *dpy, XID drawable, int interval)
418 +{
419 + XExtDisplayInfo *info = DRI2FindDisplay(dpy);
420 + xDRI2SwapIntervalReq *req;
421 +
422 + XextSimpleCheckExtension (dpy, info, dri2ExtensionName);
423 +
424 + LockDisplay(dpy);
425 + GetReq(DRI2SwapInterval, req);
426 + req->reqType = info->codes->major_opcode;
427 + req->dri2ReqType = X_DRI2SwapInterval;
428 + req->drawable = drawable;
429 + req->interval = interval;
430 + UnlockDisplay(dpy);
431 + SyncHandle();
432 +}
433 +
434 +static int _x_error_occurred;
435 +
436 +static int
437 +_check_error_handler(Display *display,
438 + XErrorEvent *event)
439 +{
440 + fprintf(stderr,
441 + "X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
442 + DisplayString(display),
443 + event->serial,
444 + event->error_code,
445 + event->request_code,
446 + event->minor_code);
447 + _x_error_occurred++;
448 + return False; /* ignored */
449 +}
450 +
451 +static double elapsed(const struct timespec *start,
452 + const struct timespec *end)
453 +{
454 + return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000;
455 +}
456 +
457 +static void run(Display *dpy, Window win)
458 +{
459 + xcb_connection_t *c = XGetXCBConnection(dpy);
460 + struct timespec start, end;
461 + int n, completed = 0;
462 +
463 + clock_gettime(CLOCK_MONOTONIC, &start);
464 + do {
465 + for (n = 0; n < 1000; n++) {
466 + unsigned int attachments[] = { DRI2BufferBackLeft };
467 + unsigned int seq[2];
468 +
469 + seq[0] = xcb_dri2_swap_buffers_unchecked(c, win,
470 + 0, 0, 0, 0, 0, 0).sequence;
471 +
472 +
473 + seq[1] = xcb_dri2_get_buffers_unchecked(c, win,
474 + 1, 1, attachments).sequence;
475 +
476 + xcb_flush(c);
477 + xcb_discard_reply(c, seq[0]);
478 + xcb_discard_reply(c, seq[1]);
479 + completed++;
480 + }
481 + clock_gettime(CLOCK_MONOTONIC, &end);
482 + } while (end.tv_sec < start.tv_sec + 10);
483 +
484 + printf("%f\n", completed / (elapsed(&start, &end) / 1000000));
485 +}
486 +
487 +static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
488 +{
489 + XRRScreenResources *res;
490 +
491 + res = XRRGetScreenResourcesCurrent(dpy, window);
492 + if (res == NULL)
493 + res = XRRGetScreenResources(dpy, window);
494 +
495 + return res;
496 +}
497 +
498 +static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
499 +{
500 + int i;
501 +
502 + for (i = 0; i < res->nmode; i++) {
503 + if (res->modes[i].id == id)
504 + return &res->modes[i];
505 + }
506 +
507 + return NULL;
508 +}
509 +
510 +static int dri2_open(Display *dpy)
511 +{
512 + drm_auth_t auth;
513 + char *driver, *device;
514 + int fd;
515 +
516 + if (!DRI2QueryExtension(dpy, &fd, &fd))
517 + return -1;
518 +
519 + if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device))
520 + return -1;
521 +
522 + fd = open(device, O_RDWR);
523 + if (fd < 0)
524 + return -1;
525 +
526 + if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
527 + return -1;
528 +
529 + if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic))
530 + return -1;
531 +
532 + return fd;
533 +}
534 +
535 +static void fullscreen(Display *dpy, Window win)
536 +{
537 + Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
538 + XChangeProperty(dpy, win,
539 + XInternAtom(dpy, "_NET_WM_STATE", False),
540 + XA_ATOM, 32, PropModeReplace,
541 + (unsigned char *)&atom, 1);
542 +}
543 +
544 +static int has_composite(Display *dpy)
545 +{
546 + int event, error;
547 + int major, minor;
548 +
549 + if (!XDamageQueryExtension (dpy, &event, &error))
550 + return 0;
551 +
552 + if (!XCompositeQueryExtension(dpy, &event, &error))
553 + return 0;
554 +
555 + XCompositeQueryVersion(dpy, &major, &minor);
556 +
557 + return major > 0 || minor >= 4;
558 +}
559 +
560 +int main(int argc, char **argv)
561 +{
562 + Display *dpy;
563 + Window root, win;
564 + XRRScreenResources *res;
565 + XRRCrtcInfo **original_crtc;
566 + XSetWindowAttributes attr;
567 + enum window { ROOT, FULLSCREEN, WINDOW } w = FULLSCREEN;
568 + enum visible {REDIRECTED, NORMAL } v = NORMAL;
569 + enum display { OFF, ON } d = OFF;
570 + int width, height;
571 + int i, fd;
572 + int c;
573 +
574 + while ((c = getopt(argc, argv, "d:v:w:")) != -1) {
575 + switch (c) {
576 + case 'd':
577 + if (strcmp(optarg, "off") == 0)
578 + d = OFF;
579 + else if (strcmp(optarg, "on") == 0)
580 + d = ON;
581 + else
582 + abort();
583 + break;
584 +
585 + case 'v':
586 + if (strcmp(optarg, "redirected") == 0)
587 + v = REDIRECTED;
588 + else if (strcmp(optarg, "normal") == 0)
589 + v = NORMAL;
590 + else
591 + abort();
592 + break;
593 +
594 + case 'w':
595 + if (strcmp(optarg, "fullscreen") == 0)
596 + w = FULLSCREEN;
597 + else if (strcmp(optarg, "window") == 0)
598 + w = WINDOW;
599 + else if (strcmp(optarg, "root") == 0)
600 + w = ROOT;
601 + else
602 + abort();
603 + break;
604 + }
605 + }
606 +
607 + attr.override_redirect = 1;
608 +
609 + dpy = XOpenDisplay(NULL);
610 + if (dpy == NULL)
611 + return 77;
612 +
613 + width = DisplayWidth(dpy, DefaultScreen(dpy));
614 + height = DisplayHeight(dpy, DefaultScreen(dpy));
615 +
616 + fd = dri2_open(dpy);
617 + if (fd < 0)
618 + return 77;
619 +
620 + if (DPMSQueryExtension(dpy, &i, &i))
621 + DPMSDisable(dpy);
622 +
623 + root = DefaultRootWindow(dpy);
624 +
625 + signal(SIGALRM, SIG_IGN);
626 + XSetErrorHandler(_check_error_handler);
627 +
628 + res = NULL;
629 + if (XRRQueryVersion(dpy, &i, &i))
630 + res = _XRRGetScreenResourcesCurrent(dpy, root);
631 + if (res == NULL)
632 + return 77;
633 +
634 + if (v == REDIRECTED && !has_composite(dpy))
635 + return 77;
636 +
637 + original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc);
638 + for (i = 0; i < res->ncrtc; i++)
639 + original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
640 +
641 + for (i = 0; i < res->ncrtc; i++)
642 + XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
643 + 0, 0, None, RR_Rotate_0, NULL, 0);
644 +
645 + DRI2CreateDrawable(dpy, root);
646 + DRI2SwapInterval(dpy, root, 0);
647 +
648 + if (d != OFF) {
649 + for (i = 0; i < res->noutput; i++) {
650 + XRROutputInfo *output;
651 + XRRModeInfo *mode;
652 +
653 + output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
654 + if (output == NULL)
655 + continue;
656 +
657 + mode = NULL;
658 + if (res->nmode)
659 + mode = lookup_mode(res, output->modes[0]);
660 + if (mode == NULL)
661 + continue;
662 +
663 + XRRSetCrtcConfig(dpy, res, output->crtcs[0], CurrentTime,
664 + 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1);
665 + width = mode->width;
666 + height = mode->height;
667 + break;
668 + }
669 + if (i == res->noutput) {
670 + _x_error_occurred = 77;
671 + goto restore;
672 + }
673 + }
674 +
675 + if (w == ROOT) {
676 + run(dpy, root);
677 + } else if (w == FULLSCREEN) {
678 + win = XCreateWindow(dpy, root,
679 + 0, 0, width, height, 0,
680 + DefaultDepth(dpy, DefaultScreen(dpy)),
681 + InputOutput,
682 + DefaultVisual(dpy, DefaultScreen(dpy)),
683 + CWOverrideRedirect, &attr);
684 + DRI2CreateDrawable(dpy, win);
685 + DRI2SwapInterval(dpy, win, 0);
686 + if (v == REDIRECTED) {
687 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
688 + XDamageCreate(dpy, win, XDamageReportRawRectangles);
689 + } else
690 + fullscreen(dpy, win);
691 + XMapWindow(dpy, win);
692 + run(dpy, win);
693 + } else if (w == WINDOW) {
694 + win = XCreateWindow(dpy, root,
695 + 0, 0, width/2, height/2, 0,
696 + DefaultDepth(dpy, DefaultScreen(dpy)),
697 + InputOutput,
698 + DefaultVisual(dpy, DefaultScreen(dpy)),
699 + CWOverrideRedirect, &attr);
700 + DRI2CreateDrawable(dpy, win);
701 + DRI2SwapInterval(dpy, win, 0);
702 + if (v == REDIRECTED) {
703 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
704 + XDamageCreate(dpy, win, XDamageReportRawRectangles);
705 + }
706 + XMapWindow(dpy, win);
707 + run(dpy, win);
708 + }
709 +
710 +restore:
711 + for (i = 0; i < res->ncrtc; i++)
712 + XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
713 + 0, 0, None, RR_Rotate_0, NULL, 0);
714 +
715 + for (i = 0; i < res->ncrtc; i++)
716 + XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
717 + original_crtc[i]->x,
718 + original_crtc[i]->y,
719 + original_crtc[i]->mode,
720 + original_crtc[i]->rotation,
721 + original_crtc[i]->outputs,
722 + original_crtc[i]->noutput);
723 +
724 + if (DPMSQueryExtension(dpy, &i, &i))
725 + DPMSEnable(dpy);
726 +
727 + XSync(dpy, True);
728 + return _x_error_occurred;
729 +}
730 diff --git a/benchmarks/dri3-swap.c b/benchmarks/dri3-swap.c
731 new file mode 100644
732 index 00000000..4dd423b3
733 --- /dev/null
734 +++ b/benchmarks/dri3-swap.c
735 @@ -0,0 +1,595 @@
736 +/*
737 + * Copyright (c) 2015 Intel Corporation
738 + *
739 + * Permission is hereby granted, free of charge, to any person obtaining a
740 + * copy of this software and associated documentation files (the "Software"),
741 + * to deal in the Software without restriction, including without limitation
742 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
743 + * and/or sell copies of the Software, and to permit persons to whom the
744 + * Software is furnished to do so, subject to the following conditions:
745 + *
746 + * The above copyright notice and this permission notice (including the next
747 + * paragraph) shall be included in all copies or substantial portions of the
748 + * Software.
749 + *
750 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
751 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
752 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
753 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
754 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
755 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
756 + * SOFTWARE.
757 + *
758 + */
759 +
760 +#ifdef HAVE_CONFIG_H
761 +#include "config.h"
762 +#endif
763 +
764 +#include <X11/Xlib.h>
765 +#include <X11/Xatom.h>
766 +#include <X11/Xlib-xcb.h>
767 +#include <X11/xshmfence.h>
768 +#include <X11/Xutil.h>
769 +#include <X11/Xlibint.h>
770 +#include <X11/extensions/Xcomposite.h>
771 +#include <X11/extensions/Xdamage.h>
772 +#include <X11/extensions/dpms.h>
773 +#include <X11/extensions/randr.h>
774 +#include <X11/extensions/Xrandr.h>
775 +#include <xcb/xcb.h>
776 +#include <xcb/present.h>
777 +#include <xcb/dri3.h>
778 +#include <xcb/xfixes.h>
779 +#include <xf86drm.h>
780 +#include <i915_drm.h>
781 +
782 +#include <stdio.h>
783 +#include <string.h>
784 +#include <fcntl.h>
785 +#include <unistd.h>
786 +#include <assert.h>
787 +#include <errno.h>
788 +#include <setjmp.h>
789 +#include <signal.h>
790 +
791 +struct dri3_fence {
792 + XID xid;
793 + void *addr;
794 +};
795 +
796 +static int _x_error_occurred;
797 +static uint32_t stamp;
798 +
799 +struct list {
800 + struct list *next, *prev;
801 +};
802 +
803 +static void
804 +list_init(struct list *list)
805 +{
806 + list->next = list->prev = list;
807 +}
808 +
809 +static inline void
810 +__list_add(struct list *entry,
811 + struct list *prev,
812 + struct list *next)
813 +{
814 + next->prev = entry;
815 + entry->next = next;
816 + entry->prev = prev;
817 + prev->next = entry;
818 +}
819 +
820 +static inline void
821 +list_add(struct list *entry, struct list *head)
822 +{
823 + __list_add(entry, head, head->next);
824 +}
825 +
826 +static inline void
827 +__list_del(struct list *prev, struct list *next)
828 +{
829 + next->prev = prev;
830 + prev->next = next;
831 +}
832 +
833 +static inline void
834 +_list_del(struct list *entry)
835 +{
836 + __list_del(entry->prev, entry->next);
837 +}
838 +
839 +static inline void
840 +list_move(struct list *list, struct list *head)
841 +{
842 + if (list->prev != head) {
843 + _list_del(list);
844 + list_add(list, head);
845 + }
846 +}
847 +
848 +#define __container_of(ptr, sample, member) \
849 + (void *)((char *)(ptr) - ((char *)&(sample)->member - (char *)(sample)))
850 +
851 +#define list_for_each_entry(pos, head, member) \
852 + for (pos = __container_of((head)->next, pos, member); \
853 + &pos->member != (head); \
854 + pos = __container_of(pos->member.next, pos, member))
855 +
856 +static int
857 +_check_error_handler(Display *display,
858 + XErrorEvent *event)
859 +{
860 + printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
861 + DisplayString(display),
862 + event->serial,
863 + event->error_code,
864 + event->request_code,
865 + event->minor_code);
866 + _x_error_occurred++;
867 + return False; /* ignored */
868 +}
869 +
870 +static int dri3_create_fence(Display *dpy,
871 + Pixmap pixmap,
872 + struct dri3_fence *fence)
873 +{
874 + xcb_connection_t *c = XGetXCBConnection(dpy);
875 + struct dri3_fence f;
876 + int fd;
877 +
878 + fd = xshmfence_alloc_shm();
879 + if (fd < 0)
880 + return -1;
881 +
882 + f.addr = xshmfence_map_shm(fd);
883 + if (f.addr == NULL) {
884 + close(fd);
885 + return -1;
886 + }
887 +
888 + f.xid = xcb_generate_id(c);
889 + xcb_dri3_fence_from_fd(c, pixmap, f.xid, 0, fd);
890 +
891 + *fence = f;
892 + return 0;
893 +}
894 +
895 +static double elapsed(const struct timespec *start,
896 + const struct timespec *end)
897 +{
898 + return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000;
899 +}
900 +
901 +struct buffer {
902 + struct list link;
903 + Pixmap pixmap;
904 + struct dri3_fence fence;
905 + int fd;
906 + int busy;
907 +};
908 +
909 +static void run(Display *dpy, Window win)
910 +{
911 + xcb_connection_t *c = XGetXCBConnection(dpy);
912 + struct timespec start, end;
913 +#define N_BACK 8
914 + struct buffer buffer[N_BACK];
915 + struct list mru;
916 + Window root;
917 + unsigned int width, height;
918 + unsigned border, depth;
919 + unsigned present_flags = XCB_PRESENT_OPTION_ASYNC;
920 + xcb_xfixes_region_t update = 0;
921 + int completed = 0;
922 + int queued = 0;
923 + uint32_t eid;
924 + void *Q;
925 + int i, n;
926 +
927 + list_init(&mru);
928 +
929 + XGetGeometry(dpy, win,
930 + &root, &i, &n, &width, &height, &border, &depth);
931 +
932 + _x_error_occurred = 0;
933 +
934 + for (n = 0; n < N_BACK; n++) {
935 + xcb_dri3_buffer_from_pixmap_reply_t *reply;
936 + int *fds;
937 +
938 + buffer[n].pixmap =
939 + XCreatePixmap(dpy, win, width, height, depth);
940 + buffer[n].fence.xid = 0;
941 + buffer[n].fd = -1;
942 +
943 + if (dri3_create_fence(dpy, win, &buffer[n].fence))
944 + return;
945 +
946 + reply = xcb_dri3_buffer_from_pixmap_reply (c,
947 + xcb_dri3_buffer_from_pixmap(c, buffer[n].pixmap),
948 + NULL);
949 + if (reply == NULL)
950 + return;
951 +
952 + fds = xcb_dri3_buffer_from_pixmap_reply_fds (c, reply);
953 + buffer[n].fd = fds[0];
954 + free(reply);
955 +
956 + /* start idle */
957 + xshmfence_trigger(buffer[n].fence.addr);
958 + buffer[n].busy = 0;
959 + list_add(&buffer[n].link, &mru);
960 + }
961 +
962 + eid = xcb_generate_id(c);
963 + xcb_present_select_input(c, eid, win,
964 + XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY |
965 + XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
966 + Q = xcb_register_for_special_xge(c, &xcb_present_id, eid, &stamp);
967 +
968 + clock_gettime(CLOCK_MONOTONIC, &start);
969 + do {
970 + for (n = 0; n < 1000; n++) {
971 + struct buffer *tmp, *b = NULL;
972 + list_for_each_entry(tmp, &mru, link) {
973 + if (!tmp->busy) {
974 + b = tmp;
975 + break;
976 + }
977 + }
978 + while (b == NULL) {
979 + xcb_present_generic_event_t *ev;
980 +
981 + ev = (xcb_present_generic_event_t *)
982 + xcb_wait_for_special_event(c, Q);
983 + if (ev == NULL)
984 + abort();
985 +
986 + do {
987 + switch (ev->evtype) {
988 + case XCB_PRESENT_COMPLETE_NOTIFY:
989 + completed++;
990 + queued--;
991 + break;
992 +
993 + case XCB_PRESENT_EVENT_IDLE_NOTIFY:
994 + {
995 + xcb_present_idle_notify_event_t *ie = (xcb_present_idle_notify_event_t *)ev;
996 + assert(ie->serial < N_BACK);
997 + buffer[ie->serial].busy = 0;
998 + if (b == NULL)
999 + b = &buffer[ie->serial];
1000 + break;
1001 + }
1002 + }
1003 + free(ev);
1004 + } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
1005 + }
1007 + b->busy = 1;
1008 + if (b->fence.xid) {
1009 + xshmfence_await(b->fence.addr);
1010 + xshmfence_reset(b->fence.addr);
1011 + }
1012 + xcb_present_pixmap(c, win, b->pixmap, b - buffer,
1013 + 0, /* valid */
1014 + update, /* update */
1015 + 0, /* x_off */
1016 + 0, /* y_off */
1017 + None,
1018 + None, /* wait fence */
1019 + b->fence.xid,
1020 + present_flags,
1021 + 0, /* target msc */
1022 + 0, /* divisor */
1023 + 0, /* remainder */
1024 + 0, NULL);
1025 + list_move(&b->link, &mru);
1026 + queued++;
1027 + xcb_flush(c);
1028 + }
1029 + clock_gettime(CLOCK_MONOTONIC, &end);
1030 + } while (end.tv_sec < start.tv_sec + 10);
1032 + while (queued) {
1033 + xcb_present_generic_event_t *ev;
1035 + ev = (xcb_present_generic_event_t *)
1036 + xcb_wait_for_special_event(c, Q);
1037 + if (ev == NULL)
1038 + abort();
1040 + do {
1041 + switch (ev->evtype) {
1042 + case XCB_PRESENT_COMPLETE_NOTIFY:
1043 + completed++;
1044 + queued--;
1045 + break;
1047 + case XCB_PRESENT_EVENT_IDLE_NOTIFY:
1048 + break;
1049 + }
1050 + free(ev);
1051 + } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
1052 + }
1053 + clock_gettime(CLOCK_MONOTONIC, &end);
1055 + printf("%f\n", completed / (elapsed(&start, &end) / 1000000));
1056 +}
1058 +static int has_present(Display *dpy)
1059 +{
1060 + xcb_connection_t *c = XGetXCBConnection(dpy);
1061 + xcb_generic_error_t *error = NULL;
1062 + void *reply;
1064 + reply = xcb_present_query_version_reply(c,
1065 + xcb_present_query_version(c,
1066 + XCB_PRESENT_MAJOR_VERSION,
1067 + XCB_PRESENT_MINOR_VERSION),
1068 + &error);
1070 + free(reply);
1071 + free(error);
1072 + if (reply == NULL) {
1073 + fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy));
1074 + return 0;
1075 + }
1077 + return 1;
1078 +}
1080 +static int has_composite(Display *dpy)
1081 +{
1082 + int event, error;
1083 + int major, minor;
1085 + if (!XDamageQueryExtension (dpy, &event, &error))
1086 + return 0;
1088 + if (!XCompositeQueryExtension(dpy, &event, &error))
1089 + return 0;
1091 + XCompositeQueryVersion(dpy, &major, &minor);
1093 + return major > 0 || minor >= 4;
1094 +}
1096 +static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
1097 +{
1098 + XRRScreenResources *res;
1100 + res = XRRGetScreenResourcesCurrent(dpy, window);
1101 + if (res == NULL)
1102 + res = XRRGetScreenResources(dpy, window);
1104 + return res;
1105 +}
1107 +static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
1108 +{
1109 + int i;
1111 + for (i = 0; i < res->nmode; i++) {
1112 + if (res->modes[i].id == id)
1113 + return &res->modes[i];
1114 + }
1116 + return NULL;
1117 +}
1119 +static void fullscreen(Display *dpy, Window win)
1120 +{
1121 + Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
1122 + XChangeProperty(dpy, win,
1123 + XInternAtom(dpy, "_NET_WM_STATE", False),
1124 + XA_ATOM, 32, PropModeReplace,
1125 + (unsigned char *)&atom, 1);
1126 +}
1128 +static int dri3_query_version(Display *dpy, int *major, int *minor)
1129 +{
1130 + xcb_connection_t *c = XGetXCBConnection(dpy);
1131 + xcb_dri3_query_version_reply_t *reply;
1132 + xcb_generic_error_t *error;
1134 + *major = *minor = -1;
1136 + reply = xcb_dri3_query_version_reply(c,
1137 + xcb_dri3_query_version(c,
1138 + XCB_DRI3_MAJOR_VERSION,
1139 + XCB_DRI3_MINOR_VERSION),
1140 + &error);
1141 + free(error);
1142 + if (reply == NULL)
1143 + return -1;
1145 + *major = reply->major_version;
1146 + *minor = reply->minor_version;
1147 + free(reply);
1149 + return 0;
1150 +}
1152 +static int has_dri3(Display *dpy)
1153 +{
1154 + const xcb_query_extension_reply_t *ext;
1155 + int major, minor;
1157 + ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id);
1158 + if (ext == NULL || !ext->present)
1159 + return 0;
1161 + if (dri3_query_version(dpy, &major, &minor) < 0)
1162 + return 0;
1164 + return major >= 0;
1165 +}
1167 +int main(int argc, char **argv)
1168 +{
1169 + Display *dpy;
1170 + Window root, win;
1171 + XRRScreenResources *res;
1172 + XRRCrtcInfo **original_crtc;
1173 + XSetWindowAttributes attr;
1174 + enum window { ROOT, FULLSCREEN, WINDOW } w = FULLSCREEN;
1175 + enum visible {REDIRECTED, NORMAL } v = NORMAL;
1176 + enum display { OFF, ON } d = OFF;
1177 + int width, height;
1178 + int i;
1180 + while ((i = getopt(argc, argv, "d:v:w:")) != -1) {
1181 + switch (i) {
1182 + case 'd':
1183 + if (strcmp(optarg, "off") == 0)
1184 + d = OFF;
1185 + else if (strcmp(optarg, "on") == 0)
1186 + d = ON;
1187 + else
1188 + abort();
1189 + break;
1191 + case 'v':
1192 + if (strcmp(optarg, "redirected") == 0)
1193 + v = REDIRECTED;
1194 + else if (strcmp(optarg, "normal") == 0)
1195 + v = NORMAL;
1196 + else
1197 + abort();
1198 + break;
1200 + case 'w':
1201 + if (strcmp(optarg, "fullscreen") == 0)
1202 + w = FULLSCREEN;
1203 + else if (strcmp(optarg, "window") == 0)
1204 + w = WINDOW;
1205 + else if (strcmp(optarg, "root") == 0)
1206 + w = ROOT;
1207 + else
1208 + abort();
1209 + break;
1210 + }
1211 + }
1213 + attr.override_redirect = 1;
1215 + dpy = XOpenDisplay(NULL);
1216 + if (dpy == NULL)
1217 + return 77;
1219 + width = DisplayWidth(dpy, DefaultScreen(dpy));
1220 + height = DisplayHeight(dpy, DefaultScreen(dpy));
1222 + if (!has_present(dpy))
1223 + return 77;
1225 + if (!has_dri3(dpy))
1226 + return 77;
1228 + if (DPMSQueryExtension(dpy, &i, &i))
1229 + DPMSDisable(dpy);
1231 + root = DefaultRootWindow(dpy);
1233 + signal(SIGALRM, SIG_IGN);
1234 + XSetErrorHandler(_check_error_handler);
1236 + res = NULL;
1237 + if (XRRQueryVersion(dpy, &i, &i))
1238 + res = _XRRGetScreenResourcesCurrent(dpy, root);
1239 + if (res == NULL)
1240 + return 77;
1242 + if (v == REDIRECTED && !has_composite(dpy))
1243 + return 77;
1245 + original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc);
1246 + for (i = 0; i < res->ncrtc; i++)
1247 + original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
1249 + for (i = 0; i < res->ncrtc; i++)
1250 + XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
1251 + 0, 0, None, RR_Rotate_0, NULL, 0);
1253 + if (d != OFF) {
1254 + for (i = 0; i < res->noutput; i++) {
1255 + XRROutputInfo *output;
1256 + XRRModeInfo *mode;
1258 + output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
1259 + if (output == NULL)
1260 + continue;
1262 + mode = NULL;
1263 + if (res->nmode)
1264 + mode = lookup_mode(res, output->modes[0]);
1265 + if (mode == NULL)
1266 + continue;
1268 + XRRSetCrtcConfig(dpy, res, output->crtcs[0], CurrentTime,
1269 + 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1);
1270 + width = mode->width;
1271 + height = mode->height;
1272 + break;
1273 + }
1274 + if (i == res->noutput) {
1275 + _x_error_occurred = 77;
1276 + goto restore;
1277 + }
1278 + }
1280 + if (w == ROOT) {
1281 + run(dpy, root);
1282 + } else if (w == FULLSCREEN) {
1283 + win = XCreateWindow(dpy, root,
1284 + 0, 0, width, height, 0,
1285 + DefaultDepth(dpy, DefaultScreen(dpy)),
1286 + InputOutput,
1287 + DefaultVisual(dpy, DefaultScreen(dpy)),
1288 + CWOverrideRedirect, &attr);
1289 + if (v == REDIRECTED) {
1290 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
1291 + XDamageCreate(dpy, win, XDamageReportRawRectangles);
1292 + } else
1293 + fullscreen(dpy, win);
1294 + XMapWindow(dpy, win);
1295 + run(dpy, win);
1296 + } else if (w == WINDOW) {
1297 + win = XCreateWindow(dpy, root,
1298 + 0, 0, width/2, height/2, 0,
1299 + DefaultDepth(dpy, DefaultScreen(dpy)),
1300 + InputOutput,
1301 + DefaultVisual(dpy, DefaultScreen(dpy)),
1302 + CWOverrideRedirect, &attr);
1303 + if (v == REDIRECTED) {
1304 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
1305 + XDamageCreate(dpy, win, XDamageReportRawRectangles);
1306 + }
1307 + XMapWindow(dpy, win);
1308 + run(dpy, win);
1309 + }
1311 +restore:
1312 + for (i = 0; i < res->ncrtc; i++)
1313 + XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
1314 + 0, 0, None, RR_Rotate_0, NULL, 0);
1316 + for (i = 0; i < res->ncrtc; i++)
1317 + XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
1318 + original_crtc[i]->x,
1319 + original_crtc[i]->y,
1320 + original_crtc[i]->mode,
1321 + original_crtc[i]->rotation,
1322 + original_crtc[i]->outputs,
1323 + original_crtc[i]->noutput);
1325 + if (DPMSQueryExtension(dpy, &i, &i))
1326 + DPMSEnable(dpy);
1328 + XSync(dpy, True);
1329 + return _x_error_occurred;
1330 +}
1331 diff --git a/configure.ac b/configure.ac
1332 index 61bea435..d13917ec 100644
1333 --- a/configure.ac
1334 +++ b/configure.ac
1335 @@ -195,18 +195,24 @@ AC_ARG_ENABLE(udev,
1336 [UDEV="$enableval"],
1337 [UDEV=auto])
1339 +udev_msg=" disabled"
1340 if test "x$UDEV" != "xno"; then
1341 PKG_CHECK_MODULES(UDEV, [libudev], [udev="yes"], [udev="no"])
1342 + AC_CHECK_HEADERS([sys/stat.h], [], [udev="no"])
1343 if test "x$UDEV" = "xyes" -a "x$udev" != "xyes"; then
1344 AC_MSG_ERROR([udev support requested but not found (libudev)])
1345 fi
1346 if test "x$udev" = "xyes"; then
1347 AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection])
1348 + udev_msg=" yes"
1349 + else
1350 + udev_msg=" no"
1351 fi
1352 fi
1354 -PKG_CHECK_MODULES(X11, [x11 xrender xrandr xext xfixes cairo cairo-xlib-xrender pixman-1 libpng], [x11="yes"], [x11="no"])
1355 +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"])
1356 AM_CONDITIONAL(HAVE_X11, test "x$x11" = "xyes")
1357 +echo X11_CLFAGS="$X11_CLFAGS" X11_LIBS="$X11_LIBS"
1359 cpuid="yes"
1360 AC_TRY_LINK([
1361 @@ -270,10 +276,13 @@ if test "x$shm" = "xyes"; then
1362 AC_DEFINE([HAVE_MIT_SHM], 1, [Define to 1 if MIT-SHM is available])
1363 fi
1365 -PKG_CHECK_MODULES(X11_DRI3, [xcb-dri3 xcb-sync xcb-present x11-xcb xshmfence x11 xrender xext libdrm], [x11_dri3="yes"], [x11_dri3="no"])
1366 +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"])
1367 AM_CONDITIONAL(X11_DRI3, test "x$x11_dri3" = "xyes" -a "x$shm" = "xyes")
1368 AM_CONDITIONAL(X11_SHM, test "x$shm" = "xyes")
1370 +PKG_CHECK_MODULES(X11_VM, [xxf86vm], [x11_vm="yes"], [x11_vm="no"])
1371 +AM_CONDITIONAL(X11_VM, test "x$x11_vm" = "xyes")
1373 AC_ARG_ENABLE(tools,
1374 AS_HELP_STRING([--disable-tools],
1375 [Enable building and installing the miscellaneous tools [default=auto]]),
1376 @@ -285,7 +294,7 @@ if test "x$shm" != "xyes"; then
1377 tools="no"
1378 fi
1379 if test "x$tools" != "xno"; then
1380 - ivo_requires="xrandr xdamage xfixes xcursor xtst xrender xext x11 pixman-1"
1381 + ivo_requires="xrandr xdamage xfixes xcursor xtst xrender xscrnsaver xext x11 pixman-1"
1382 extra_cflags=""
1384 ignore="xinerama"
1385 @@ -307,6 +316,8 @@ if test "x$tools" != "xno"; then
1386 tools="no"
1387 fi
1389 + PKG_CHECK_MODULES(TOOL_CURSOR, [xfixes x11 libpng], [cursor="yes"], [ivo="no"])
1391 IVO_CFLAGS="$IVO_CFLAGS $extra_cflags"
1392 fi
1393 if test "x$tools" != "xno"; then
1394 @@ -315,6 +326,7 @@ fi
1395 AC_MSG_CHECKING([whether to build additional tools])
1396 AC_MSG_RESULT([$tools])
1397 AM_CONDITIONAL(BUILD_TOOLS, test "x$tools" != "xno")
1398 +AM_CONDITIONAL(BUILD_TOOL_CURSOR, test "x$cursor" = "xyes")
1400 # Define a configure option for an alternate module directory
1401 AC_ARG_WITH(xorg-module-dir,
1402 @@ -339,10 +351,20 @@ AC_ARG_ENABLE(dri2,
1403 [DRI2=$enableval],
1404 [DRI2=yes])
1405 AC_ARG_ENABLE(dri3,
1406 - AS_HELP_STRING([--enable-dri3],
1407 - [Enable DRI3 support [[default=no]]]),
1408 + AS_HELP_STRING([--disable-dri3],
1409 + [Disable DRI3 support [[default=yes]]]),
1410 [DRI3=$enableval],
1411 - [DRI3=no])
1412 + [DRI3=yes])
1413 +AC_ARG_WITH(default-dri,
1414 + AS_HELP_STRING([--with-default-dri],
1415 + [Select the default maximum DRI level [default 2]]),
1416 + [DRI_DEFAULT=$withval],
1417 + [DRI_DEFAULT=2])
1418 +if test "x$DRI_DEFAULT" = "x0"; then
1419 + AC_DEFINE(DEFAULT_DRI_LEVEL, 0,[Default DRI level])
1420 +else
1421 + AC_DEFINE(DEFAULT_DRI_LEVEL, ~0, [Default DRI level])
1422 +fi
1424 AC_ARG_ENABLE(xvmc, AS_HELP_STRING([--disable-xvmc],
1425 [Disable XvMC support [[default=yes]]]),
1426 @@ -375,14 +397,12 @@ AC_ARG_ENABLE(ums-only,
1427 required_xorg_server_version=1.6
1428 required_pixman_version=0.16
1430 -if pkg-config --exists 'pixman-1 >= 0.27.1'; then
1431 - AC_DEFINE([HAS_PIXMAN_GLYPHS], 1, [Enable pixman glyph cache])
1432 -fi
1434 -if pkg-config --exists 'pixman-1 >= 0.24.0'; then
1435 - AC_DEFINE([HAS_PIXMAN_TRIANGLES], 1, [Enable pixman triangle rasterisation])
1436 -fi
1438 +PKG_CHECK_EXISTS([pixman-1 >= 0.24.0],
1439 + AC_DEFINE([HAS_PIXMAN_TRIANGLES], 1, [Enable pixman triangle rasterisation])
1440 + [])
1441 +PKG_CHECK_EXISTS([pixman-1 >= 0.27.1],
1442 + [AC_DEFINE([HAS_PIXMAN_GLYPHS], 1, [Enable pixman glyph cache])],
1443 + [])
1444 # Store the list of server defined optional extensions in REQUIRED_MODULES
1445 XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
1446 XORG_DRIVER_CHECK_EXT(RENDER, renderproto)
1447 @@ -398,24 +418,25 @@ AC_ARG_ENABLE(sna,
1448 [SNA="$enableval"],
1449 [SNA=auto])
1451 +AC_CHECK_HEADERS([dev/wscons/wsconsio.h])
1452 +AC_FUNC_ALLOCA
1453 +AC_HEADER_MAJOR
1455 if test "x$SNA" != "xno"; then
1456 AC_DEFINE(USE_SNA, 1, [Enable SNA support])
1457 AC_CHECK_HEADERS([sys/sysinfo.h], AC_CHECK_MEMBERS([struct sysinfo.totalram], [], [], [[#include <sys/sysinfo.h>]]))
1458 fi
1460 uxa_requires_libdrm=2.4.52
1461 +uxa_requires_pixman=0.24.0
1463 AC_ARG_ENABLE(uxa,
1464 AS_HELP_STRING([--enable-uxa],
1465 [Enable Unified Acceleration Architecture (UXA) [default=auto]]),
1466 [UXA="$enableval"],
1467 [UXA=auto])
1468 if test "x$UXA" = "xauto"; then
1469 - if ! pkg-config --exists "libdrm_intel >= $uxa_requires_libdrm"; then
1470 - UXA=no
1471 - fi
1472 - if ! pkg-config --exists 'pixman-1 >= 0.24.0'; then
1473 - UXA=no
1474 - fi
1475 + PKG_CHECK_EXISTS([libdrm_intel >= $uxa_requires_libdrm pixman-1 >= $uxa_requires_pixman], [], [UXA=no])
1476 fi
1477 if test "x$UXA" != "xno"; then
1478 AC_DEFINE(USE_UXA, 1, [Enable UXA support])
1479 @@ -424,8 +445,10 @@ if test "x$UXA" != "xno"; then
1480 UXA=yes
1481 fi
1483 -PKG_CHECK_MODULES(XORG, [xorg-server >= $required_xorg_server_version xproto fontsproto pixman-1 >= $required_pixman_version $REQUIRED_MODULES])
1484 +PKG_CHECK_MODULES(XORG, [xorg-server >= $required_xorg_server_version xproto fontsproto damageproto pixman-1 >= $required_pixman_version $REQUIRED_MODULES])
1485 ABI_VERSION=`$PKG_CONFIG --variable=abi_videodrv xorg-server`
1486 +XSERVER_VERSION=`$PKG_CONFIG --modversion xorg-server`
1487 +PIXMAN_VERSION=`$PKG_CONFIG --modversion pixman-1`
1489 if test "x$ONLY_UMS" = "xyes"; then
1490 UMS="yes"
1491 @@ -519,7 +542,12 @@ AC_MSG_RESULT([$have_dri1])
1492 AM_CONDITIONAL(DRI1, test "x$have_dri1" != "xno")
1493 if test "x$have_dri1" != "xno"; then
1494 AC_DEFINE(HAVE_DRI1,1,[Enable DRI1 driver support])
1495 - dri_msg="$dri_msg DRI1"
1496 + str="DRI1"
1497 + if test "x$DRI_DEFAULT" = "x1"; then
1498 + AC_DEFINE(DEFAULT_DRI_LEVEL,1,[Default DRI level])
1499 + str="*$str"
1500 + fi
1501 + dri_msg="$dri_msg $str"
1502 else
1503 DRI1_CFLAGS=""
1504 DRI1_LIBS=""
1505 @@ -576,7 +604,12 @@ AM_CONDITIONAL(DRI2, test "x$have_dri2" != "xno")
1506 AC_MSG_RESULT([$have_dri2])
1507 if test "x$have_dri2" != "xno"; then
1508 AC_DEFINE(HAVE_DRI2,1,[Enable DRI2 driver support])
1509 - dri_msg="$dri_msg DRI2"
1510 + str="DRI2"
1511 + if test "x$DRI_DEFAULT" = "x2"; then
1512 + AC_DEFINE(DEFAULT_DRI_LEVEL,2,[Default DRI level])
1513 + str="*$str"
1514 + fi
1515 + dri_msg="$dri_msg $str"
1516 else
1517 if test "x$DRI" = "xyes" -a "x$DRI2" != "xno" -a "x$KMS" = "xyes"; then
1518 AC_MSG_ERROR([DRI2 requested but prerequisites not found])
1519 @@ -591,13 +624,21 @@ AM_CONDITIONAL(DRI3, test "x$have_dri3" != "xno")
1520 AC_MSG_RESULT([$have_dri3])
1521 if test "x$have_dri3" != "xno"; then
1522 AC_DEFINE(HAVE_DRI3,1,[Enable DRI3 driver support])
1523 - dri_msg="$dri_msg DRI3"
1524 + str="DRI3"
1525 + if test "x$DRI_DEFAULT" = "x3"; then
1526 + AC_DEFINE(DEFAULT_DRI_LEVEL,3,[Default DRI level])
1527 + str="*$str"
1528 + fi
1529 + dri_msg="$dri_msg $str"
1530 else
1531 if test "x$DRI" = "xyes" -a "x$DRI3" != "xno" -a "x$KMS" = "xyes"; then
1532 AC_MSG_ERROR([DRI3 requested but prerequisites not found])
1533 fi
1534 fi
1536 +AC_MSG_CHECKING([default DRI support])
1537 +AC_MSG_RESULT([$DEFAULT_DRI_DEFAULT])
1539 AC_CHECK_HEADERS([X11/extensions/dpmsconst.h])
1541 PRESENT="no"
1542 @@ -711,27 +752,6 @@ if test "x$TEARFREE" = "xyes"; then
1543 xp_msg="$xp_msg TearFree"
1544 fi
1546 -AC_ARG_ENABLE(rendernode,
1547 - AS_HELP_STRING([--enable-rendernode],
1548 - [Enable use of render nodes (experimental) [default=no]]),
1549 - [RENDERNODE="$enableval"],
1550 - [RENDERNODE="no"])
1551 -AM_CONDITIONAL(USE_RENDERNODE, test "x$RENDERNODE" = "xyes")
1552 -if test "x$RENDERNODE" = "xyes"; then
1553 - AC_DEFINE(USE_RENDERNODE,1,[Assume "rendernode" support])
1554 - xp_msg="$xp_msg rendernode"
1555 -fi
1557 -AC_ARG_ENABLE(wc-mmap,
1558 - AS_HELP_STRING([--enable-wc-mmap],
1559 - [Enable use of WriteCombining mmaps [default=no]]),
1560 - [WC_MMAP="$enableval"],
1561 - [WC_MMAP="no"])
1562 -if test "x$WC_MMAP" = "xyes"; then
1563 - AC_DEFINE(USE_WC_MMAP,1,[Enable use of WriteCombining mmaps])
1564 - xp_msg="$xp_msg mmap(wc)"
1565 -fi
1567 AC_ARG_ENABLE(create2,
1568 AS_HELP_STRING([--enable-create2],
1569 [Enable use of create2 ioctl (experimental) [default=no]]),
1570 @@ -848,6 +868,7 @@ AC_CONFIG_FILES([
1571 xvmc/shader/mc/Makefile
1572 xvmc/shader/vld/Makefile
1573 test/Makefile
1574 + benchmarks/Makefile
1575 tools/Makefile
1576 tools/org.x.xf86-video-intel.backlight-helper.policy
1577 ])
1578 @@ -855,7 +876,7 @@ AC_OUTPUT
1580 echo ""
1581 echo ""
1582 -test -e `pwd $0`/README && cat `pwd $0`/README
1583 +cat $srcdir/README
1585 accel_msg=""
1586 if test "x$SNA" != "xno"; then
1587 @@ -895,13 +916,15 @@ fi
1589 echo ""
1590 echo "AC_PACKAGE_STRING will be compiled with:"
1591 -echo " Xorg Video ABI version: $ABI_VERSION"
1592 +echo " Xorg Video ABI version: $ABI_VERSION (xorg-server-$XSERVER_VERSION)"
1593 +echo " pixman version: pixman-1-$PIXMAN_VERSION"
1594 echo " Acceleration backends:$accel_msg"
1595 echo " Additional debugging support?$debug_msg"
1596 echo " Support for Kernel Mode Setting? $KMS"
1597 echo " Support for legacy User Mode Setting (for i810)? $UMS"
1598 echo " Support for Direct Rendering Infrastructure:$dri_msg"
1599 echo " Support for Xv motion compensation (XvMC and libXvMC):$xvmc_msg"
1600 +echo " Support for display hotplug notifications (udev):$udev_msg"
1601 echo " Build additional tools and utilities?$tools_msg"
1602 if test -n "$xp_msg"; then
1603 echo " Experimental support:$xp_msg"
1604 diff --git a/libobj/alloca.c b/libobj/alloca.c
1605 new file mode 100644
1606 index 00000000..883e1e9f
1607 --- /dev/null
1608 +++ b/libobj/alloca.c
1609 @@ -0,0 +1,4 @@
1610 +void *alloca(size_t sz)
1611 +{
1612 + return NULL;
1613 +}
1614 diff --git a/man/intel.man b/man/intel.man
1615 index 17515206..be398fbe 100644
1616 --- a/man/intel.man
1617 +++ b/man/intel.man
1618 @@ -27,9 +27,9 @@ supports the i810, i810-DC100, i810e, i815, i830M, 845G, 852GM, 855GM,
1619 865G, 915G, 915GM, 945G, 945GM, 965G, 965Q, 946GZ, 965GM, 945GME,
1620 G33, Q33, Q35, G35, GM45, G45, Q45, G43, G41 chipsets, Pineview-M in
1621 Atom N400 series, Pineview-D in Atom D400/D500 series,
1622 -Intel(R) HD Graphics: 2000-6000,
1623 -Intel(R) Iris(TM) Graphics: 5100/6100, and
1624 -Intel(R) Iris(TM) Pro Graphics: 5200/6200/P6300.
1625 +Intel(R) HD Graphics,
1626 +Intel(R) Iris(TM) Graphics,
1627 +Intel(R) Iris(TM) Pro Graphics.
1629 .SH CONFIGURATION DETAILS
1630 Please refer to __xconfigfile__(__filemansuffix__) for general configuration
1631 @@ -112,8 +112,8 @@ The default is 8192 if AGP allocable memory is < 128 MB, 16384 if < 192 MB,
1632 24576 if higher. DRI require at least a value of 16384. Higher values may give
1633 better 3D performance, at expense of available system memory.
1634 .TP
1635 -.BI "Option \*qNoAccel\*q \*q" boolean \*q
1636 -Disable or enable acceleration.
1637 +.BI "Option \*qAccel\*q \*q" boolean \*q
1638 +Enable or disable acceleration.
1639 .IP
1640 Default: acceleration is enabled.
1642 @@ -122,8 +122,8 @@ The following driver
1643 .B Options
1644 are supported for the 830M and later chipsets:
1645 .TP
1646 -.BI "Option \*qNoAccel\*q \*q" boolean \*q
1647 -Disable or enable acceleration.
1648 +.BI "Option \*qAccel\*q \*q" boolean \*q
1649 +Enable or disable acceleration.
1650 .IP
1651 Default: acceleration is enabled.
1652 .TP
1653 @@ -201,6 +201,16 @@ that choice by specifying the entry under /sys/class/backlight to use.
1654 .IP
1655 Default: Automatic selection.
1656 .TP
1657 +.BI "Option \*qCustomEDID\*q \*q" string \*q
1658 +Override the probed EDID on particular outputs. Sometimes the manufacturer
1659 +supplied EDID is corrupt or lacking a few usable modes and supplying a
1660 +corrected EDID may be easier than specifying every modeline. This option
1661 +allows to pass the path to load an EDID from per output. The format is a
1662 +comma separated string of output:path pairs, e.g.
1663 +DP1:/path/to/dp1.edid,DP2:/path/to/dp2.edid
1664 +.IP
1665 +Default: No override, use manufacturer supplied EDIDs.
1666 +.TP
1667 .BI "Option \*qFallbackDebug\*q \*q" boolean \*q
1668 Enable printing of debugging information on acceleration fallbacks to the
1669 server log.
1670 @@ -225,6 +235,15 @@ i.e. perform synchronous rendering.
1671 .IP
1672 Default: Disabled
1673 .TP
1674 +.BI "Option \*qHWRotation\*q \*q" boolean \*q
1675 +Override the use of native hardware rotation and force the use of software,
1676 +but GPU accelerated where possible, rotation. On some platforms the hardware
1677 +can scanout directly into a rotated output bypassing the intermediate rendering
1678 +and extra allocations required for software implemented rotation (i.e. native
1679 +rotation uses less resources, is quicker and uses less power). This allows you
1680 +to disable the native rotation in case of errors.
1681 +.IP
1682 +Default: Enabled (use hardware rotation)
1683 .TP
1684 .BI "Option \*qVSync\*q \*q" boolean \*q
1685 This option controls the use of commands to synchronise rendering with the
1686 @@ -324,13 +343,29 @@ Default: 0
1687 .BI "Option \*qZaphodHeads\*q \*q" string \*q
1688 .IP
1689 Specify the randr output(s) to use with zaphod mode for a particular driver
1690 -instance. If you this option you must use it with all instances of the
1691 -driver
1692 +instance. If you set this option you must use it with all instances of the
1693 +driver. By default, each head is assigned only one CRTC (which limits
1694 +using multiple outputs with that head to cloned mode). CRTC can be manually
1695 +assigned to individual heads by preceding the output names with a comma
1696 +delimited list of pipe numbers followed by a colon. Note that different pipes
1697 +may be limited in their functionality and some outputs may only work with
1698 +different pipes.
1699 .br
1700 For example:
1702 +.RS
1703 .B
1704 Option \*qZaphodHeads\*q \*qLVDS1,VGA1\*q
1705 -will assign xrandr outputs LVDS1 and VGA0 to this instance of the driver.
1707 +will assign xrandr outputs LVDS1 and VGA1 to this instance of the driver.
1708 +.RE
1710 +.RS
1711 +.B
1712 +Option \*qZaphodHeads\*q \*q0,2:HDMI1,DP2\*q
1714 +will assign xrandr outputs HDMI1 and DP2 and CRTCs 0 and 2 to this instance of the driver.
1715 +.RE
1717 .SH OUTPUT CONFIGURATION
1718 On 830M and better chipsets, the driver supports runtime configuration of
1719 @@ -431,11 +466,11 @@ First DVI SDVO output
1720 Second DVI SDVO output
1722 .SS "TMDS-1", "TMDS-2", "HDMI-1", "HDMI-2"
1723 -DVI/HDMI outputs. Avaliable common properties include:
1724 +DVI/HDMI outputs. Available common properties include:
1725 .TP
1726 \fBBROADCAST_RGB\fP - method used to set RGB color range
1727 Adjusting this property allows you to set RGB color range on each
1728 -channel in order to match HDTV requirment(default 0 for full
1729 +channel in order to match HDTV requirement(default 0 for full
1730 range). Setting 1 means RGB color range is 16-235, 0 means RGB color
1731 range is 0-255 on each channel. (Full range is 0-255, not 16-235)
1733 diff --git a/src/backlight.c b/src/backlight.c
1734 index 9f239867..fcbb279f 100644
1735 --- a/src/backlight.c
1736 +++ b/src/backlight.c
1737 @@ -34,6 +34,12 @@
1738 #include <sys/stat.h>
1739 #include <sys/ioctl.h>
1741 +#if MAJOR_IN_MKDEV
1742 +#include <sys/mkdev.h>
1743 +#elif MAJOR_IN_SYSMACROS
1744 +#include <sys/sysmacros.h>
1745 +#endif
1747 #include <stdio.h>
1748 #include <stdlib.h>
1749 #include <string.h>
1750 @@ -42,6 +48,7 @@
1751 #include <fcntl.h>
1752 #include <unistd.h>
1753 #include <dirent.h>
1754 +#include <errno.h>
1756 #include <xorg-server.h>
1757 #include <xf86.h>
1758 @@ -84,7 +91,7 @@ void backlight_init(struct backlight *b)
1759 b->has_power = 0;
1762 -#ifdef __OpenBSD__
1763 +#ifdef HAVE_DEV_WSCONS_WSCONSIO_H
1765 #include <dev/wscons/wsconsio.h>
1766 #include <xf86Priv.h>
1767 @@ -122,6 +129,11 @@ int backlight_get(struct backlight *b)
1768 return param.curval;
1771 +char *backlight_find_for_device(struct pci_device *pci)
1772 +{
1773 + return NULL;
1774 +}
1776 int backlight_open(struct backlight *b, char *iface)
1778 struct wsdisplay_param param;
1779 @@ -146,12 +158,9 @@ int backlight_open(struct backlight *b, char *iface)
1780 return param.curval;
1783 -enum backlight_type backlight_exists(const char *iface)
1784 +int backlight_exists(const char *iface)
1786 - if (iface != NULL)
1787 - return BL_NONE;
1789 - return BL_PLATFORM;
1790 + return iface == NULL;
1793 int backlight_on(struct backlight *b)
1794 @@ -163,6 +172,7 @@ int backlight_off(struct backlight *b)
1796 return 0;
1799 #else
1801 static int
1802 @@ -213,6 +223,24 @@ __backlight_read(const char *iface, const char *file)
1805 static int
1806 +writen(int fd, const char *value, int len)
1807 +{
1808 + int ret;
1810 + do {
1811 + ret = write(fd, value, len);
1812 + if (ret < 0) {
1813 + if (errno == EAGAIN || errno == EINTR)
1814 + continue;
1816 + return ret;
1817 + }
1818 + } while (value += ret, len -= ret);
1820 + return 0;
1821 +}
1823 +static int
1824 __backlight_write(const char *iface, const char *file, const char *value)
1826 int fd, ret;
1827 @@ -221,7 +249,7 @@ __backlight_write(const char *iface, const char *file, const char *value)
1828 if (fd < 0)
1829 return -1;
1831 - ret = write(fd, value, strlen(value)+1);
1832 + ret = writen(fd, value, strlen(value)+1);
1833 close(fd);
1835 return ret;
1836 @@ -244,10 +272,10 @@ static const char *known_interfaces[] = {
1837 "intel_backlight",
1838 };
1840 -static enum backlight_type __backlight_type(const char *iface)
1841 +static int __backlight_type(const char *iface)
1843 char buf[1024];
1844 - int fd, v;
1845 + int fd, v, i;
1847 v = -1;
1848 fd = __backlight_open(iface, "type", O_RDONLY);
1849 @@ -261,39 +289,41 @@ static enum backlight_type __backlight_type(const char *iface)
1850 buf[v] = '\0';
1852 if (strcmp(buf, "raw") == 0)
1853 - v = BL_RAW;
1854 + v = BL_RAW << 8;
1855 else if (strcmp(buf, "platform") == 0)
1856 - v = BL_PLATFORM;
1857 + v = BL_PLATFORM << 8;
1858 else if (strcmp(buf, "firmware") == 0)
1859 - v = BL_FIRMWARE;
1860 + v = BL_FIRMWARE << 8;
1861 else
1862 - v = BL_NAMED;
1863 + v = BL_NAMED << 8;
1864 } else
1865 - v = BL_NAMED;
1866 + v = BL_NAMED << 8;
1868 - if (v == BL_NAMED) {
1869 - int i;
1870 - for (i = 0; i < ARRAY_SIZE(known_interfaces); i++) {
1871 - if (strcmp(iface, known_interfaces[i]) == 0)
1872 - break;
1873 - }
1874 - v += i;
1875 + for (i = 0; i < ARRAY_SIZE(known_interfaces); i++) {
1876 + if (strcmp(iface, known_interfaces[i]) == 0)
1877 + break;
1879 + v += i;
1881 return v;
1884 -enum backlight_type backlight_exists(const char *iface)
1885 +static int __backlight_exists(const char *iface)
1887 if (__backlight_read(iface, "brightness") < 0)
1888 - return BL_NONE;
1889 + return -1;
1891 if (__backlight_read(iface, "max_brightness") <= 0)
1892 - return BL_NONE;
1893 + return -1;
1895 return __backlight_type(iface);
1898 +int backlight_exists(const char *iface)
1899 +{
1900 + return __backlight_exists(iface) != -1;
1901 +}
1903 static int __backlight_init(struct backlight *b, char *iface, int fd)
1905 b->fd = fd_move_cloexec(fd_set_nonblock(fd));
1906 @@ -399,7 +429,50 @@ __backlight_find(void)
1907 continue;
1909 /* Fallback to priority list of known iface for old kernels */
1910 - v = backlight_exists(de->d_name);
1911 + v = __backlight_exists(de->d_name);
1912 + if (v < 0)
1913 + continue;
1915 + if (v < best_type) {
1916 + char *copy = strdup(de->d_name);
1917 + if (copy) {
1918 + free(best_iface);
1919 + best_iface = copy;
1920 + best_type = v;
1921 + }
1922 + }
1923 + }
1924 + closedir(dir);
1926 + return best_iface;
1927 +}
1929 +char *backlight_find_for_device(struct pci_device *pci)
1930 +{
1931 + char path[200];
1932 + unsigned best_type = INT_MAX;
1933 + char *best_iface = NULL;
1934 + DIR *dir;
1935 + struct dirent *de;
1937 + snprintf(path, sizeof(path),
1938 + "/sys/bus/pci/devices/%04x:%02x:%02x.%d/backlight",
1939 + pci->domain, pci->bus, pci->dev, pci->func);
1941 + dir = opendir(path);
1942 + if (dir == NULL)
1943 + return NULL;
1945 + while ((de = readdir(dir))) {
1946 + int v;
1948 + if (*de->d_name == '.')
1949 + continue;
1951 + v = __backlight_exists(de->d_name);
1952 + if (v < 0)
1953 + continue;
1955 if (v < best_type) {
1956 char *copy = strdup(de->d_name);
1957 if (copy) {
1958 @@ -416,14 +489,17 @@ __backlight_find(void)
1960 int backlight_open(struct backlight *b, char *iface)
1962 - int level;
1963 + int level, type;
1965 if (iface == NULL)
1966 iface = __backlight_find();
1967 if (iface == NULL)
1968 goto err;
1970 - b->type = __backlight_type(iface);
1971 + type = __backlight_type(iface);
1972 + if (type < 0)
1973 + goto err;
1974 + b->type = type >> 8;
1976 b->max = __backlight_read(iface, "max_brightness");
1977 if (b->max <= 0)
1978 @@ -447,7 +523,7 @@ err:
1979 int backlight_set(struct backlight *b, int level)
1981 char val[BACKLIGHT_VALUE_LEN];
1982 - int len, ret = 0;
1983 + int len;
1985 if (b->iface == NULL)
1986 return 0;
1987 @@ -456,10 +532,7 @@ int backlight_set(struct backlight *b, int level)
1988 level = b->max;
1990 len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level);
1991 - if (write(b->fd, val, len) != len)
1992 - ret = -1;
1994 - return ret;
1995 + return writen(b->fd, val, len);
1998 int backlight_get(struct backlight *b)
1999 @@ -517,43 +590,6 @@ void backlight_disable(struct backlight *b)
2000 void backlight_close(struct backlight *b)
2002 backlight_disable(b);
2003 - if (b->pid)
2004 + if (b->pid > 0)
2005 waitpid(b->pid, NULL, 0);
2008 -char *backlight_find_for_device(struct pci_device *pci)
2009 -{
2010 - char path[200];
2011 - unsigned best_type = INT_MAX;
2012 - char *best_iface = NULL;
2013 - DIR *dir;
2014 - struct dirent *de;
2016 - snprintf(path, sizeof(path),
2017 - "/sys/bus/pci/devices/%04x:%02x:%02x.%d/backlight",
2018 - pci->domain, pci->bus, pci->dev, pci->func);
2020 - dir = opendir(path);
2021 - if (dir == NULL)
2022 - return NULL;
2024 - while ((de = readdir(dir))) {
2025 - int v;
2027 - if (*de->d_name == '.')
2028 - continue;
2030 - v = backlight_exists(de->d_name);
2031 - if (v < best_type) {
2032 - char *copy = strdup(de->d_name);
2033 - if (copy) {
2034 - free(best_iface);
2035 - best_iface = copy;
2036 - best_type = v;
2037 - }
2038 - }
2039 - }
2040 - closedir(dir);
2042 - return best_iface;
2043 -}
2044 diff --git a/src/backlight.h b/src/backlight.h
2045 index bb0e28bc..ba17755b 100644
2046 --- a/src/backlight.h
2047 +++ b/src/backlight.h
2048 @@ -43,7 +43,7 @@ struct backlight {
2049 int pid, fd;
2050 };
2052 -enum backlight_type backlight_exists(const char *iface);
2053 +int backlight_exists(const char *iface);
2055 void backlight_init(struct backlight *backlight);
2056 int backlight_open(struct backlight *backlight, char *iface);
2057 diff --git a/src/compat-api.h b/src/compat-api.h
2058 index d09e1fb3..05797a08 100644
2059 --- a/src/compat-api.h
2060 +++ b/src/compat-api.h
2061 @@ -30,6 +30,7 @@
2063 #include <xorg-server.h>
2064 #include <xorgVersion.h>
2065 +#include <xf86Module.h>
2067 #include <picturestr.h>
2068 #ifndef GLYPH_HAS_GLYPH_PICTURE_ACCESSOR
2069 @@ -39,7 +40,17 @@
2071 #ifndef XF86_HAS_SCRN_CONV
2072 #define xf86ScreenToScrn(s) xf86Screens[(s)->myNum]
2073 +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,1,0,0,0)
2074 #define xf86ScrnToScreen(s) screenInfo.screens[(s)->scrnIndex]
2075 +#else
2076 +#define xf86ScrnToScreen(s) ((s)->pScreen)
2077 +#endif
2078 +#else
2079 +#define xf86ScrnToScreen(s) ((s)->pScreen)
2080 +#endif
2082 +#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 22
2083 +#define HAVE_NOTIFY_FD 1
2084 #endif
2086 #ifndef XF86_SCRN_INTERFACE
2087 @@ -131,6 +142,17 @@ region_rects(const RegionRec *r)
2088 return r->data ? (const BoxRec *)(r->data + 1) : &r->extents;
2091 +inline static void
2092 +region_get_boxes(const RegionRec *r, const BoxRec **s, const BoxRec **e)
2093 +{
2094 + int n;
2095 + if (r->data)
2096 + *s = region_boxptr(r), n = r->data->numRects;
2097 + else
2098 + *s = &r->extents, n = 1;
2099 + *e = *s + n;
2100 +}
2102 #ifndef INCLUDE_LEGACY_REGION_DEFINES
2103 #define RegionCreate(r, s) REGION_CREATE(NULL, r, s)
2104 #define RegionBreak(r) REGION_BREAK(NULL, r)
2105 @@ -223,4 +245,19 @@ static inline void FreePixmap(PixmapPtr pixmap)
2106 dstx, dsty)
2107 #endif
2109 +#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
2110 +#define isGPU(S) (S)->is_gpu
2111 +#else
2112 +#define isGPU(S) 0
2113 +#endif
2115 +#if HAS_DIRTYTRACKING_ROTATION
2116 +#define PixmapSyncDirtyHelper(d, dd) PixmapSyncDirtyHelper(d)
2117 +#endif
2119 +#if !HAVE_NOTIFY_FD
2120 +#define SetNotifyFd(fd, cb, mode, data) AddGeneralSocket(fd);
2121 +#define RemoveNotifyFd(fd) RemoveGeneralSocket(fd)
2122 +#endif
2124 #endif
2125 diff --git a/src/i915_pciids.h b/src/i915_pciids.h
2126 index 180ad0e6..466c7159 100644
2127 --- a/src/i915_pciids.h
2128 +++ b/src/i915_pciids.h
2129 @@ -134,7 +134,7 @@
2130 #define INTEL_IVB_Q_IDS(info) \
2131 INTEL_QUANTA_VGA_DEVICE(info) /* Quanta transcode */
2133 -#define INTEL_HSW_D_IDS(info) \
2134 +#define INTEL_HSW_IDS(info) \
2135 INTEL_VGA_DEVICE(0x0402, info), /* GT1 desktop */ \
2136 INTEL_VGA_DEVICE(0x0412, info), /* GT2 desktop */ \
2137 INTEL_VGA_DEVICE(0x0422, info), /* GT3 desktop */ \
2138 @@ -179,9 +179,7 @@
2139 INTEL_VGA_DEVICE(0x0D2B, info), /* CRW GT3 reserved */ \
2140 INTEL_VGA_DEVICE(0x0D0E, info), /* CRW GT1 reserved */ \
2141 INTEL_VGA_DEVICE(0x0D1E, info), /* CRW GT2 reserved */ \
2142 - INTEL_VGA_DEVICE(0x0D2E, info) /* CRW GT3 reserved */ \
2144 -#define INTEL_HSW_M_IDS(info) \
2145 + INTEL_VGA_DEVICE(0x0D2E, info), /* CRW GT3 reserved */ \
2146 INTEL_VGA_DEVICE(0x0406, info), /* GT1 mobile */ \
2147 INTEL_VGA_DEVICE(0x0416, info), /* GT2 mobile */ \
2148 INTEL_VGA_DEVICE(0x0426, info), /* GT2 mobile */ \
2149 @@ -198,60 +196,48 @@
2150 INTEL_VGA_DEVICE(0x0D16, info), /* CRW GT2 mobile */ \
2151 INTEL_VGA_DEVICE(0x0D26, info) /* CRW GT3 mobile */
2153 -#define INTEL_VLV_M_IDS(info) \
2154 +#define INTEL_VLV_IDS(info) \
2155 INTEL_VGA_DEVICE(0x0f30, info), \
2156 INTEL_VGA_DEVICE(0x0f31, info), \
2157 INTEL_VGA_DEVICE(0x0f32, info), \
2158 INTEL_VGA_DEVICE(0x0f33, info), \
2159 - INTEL_VGA_DEVICE(0x0157, info)
2161 -#define INTEL_VLV_D_IDS(info) \
2162 + INTEL_VGA_DEVICE(0x0157, info), \
2163 INTEL_VGA_DEVICE(0x0155, info)
2165 -#define _INTEL_BDW_M(gt, id, info) \
2166 - INTEL_VGA_DEVICE((((gt) - 1) << 4) | (id), info)
2167 -#define _INTEL_BDW_D(gt, id, info) \
2168 - INTEL_VGA_DEVICE((((gt) - 1) << 4) | (id), info)
2170 -#define _INTEL_BDW_M_IDS(gt, info) \
2171 - _INTEL_BDW_M(gt, 0x1602, info), /* ULT */ \
2172 - _INTEL_BDW_M(gt, 0x1606, info), /* ULT */ \
2173 - _INTEL_BDW_M(gt, 0x160B, info), /* Iris */ \
2174 - _INTEL_BDW_M(gt, 0x160E, info) /* ULX */
2176 -#define _INTEL_BDW_D_IDS(gt, info) \
2177 - _INTEL_BDW_D(gt, 0x160A, info), /* Server */ \
2178 - _INTEL_BDW_D(gt, 0x160D, info) /* Workstation */
2180 -#define INTEL_BDW_GT12M_IDS(info) \
2181 - _INTEL_BDW_M_IDS(1, info), \
2182 - _INTEL_BDW_M_IDS(2, info)
2184 -#define INTEL_BDW_GT12D_IDS(info) \
2185 - _INTEL_BDW_D_IDS(1, info), \
2186 - _INTEL_BDW_D_IDS(2, info)
2188 -#define INTEL_BDW_GT3M_IDS(info) \
2189 - _INTEL_BDW_M_IDS(3, info)
2191 -#define INTEL_BDW_GT3D_IDS(info) \
2192 - _INTEL_BDW_D_IDS(3, info)
2194 -#define INTEL_BDW_RSVDM_IDS(info) \
2195 - _INTEL_BDW_M_IDS(4, info)
2197 -#define INTEL_BDW_RSVDD_IDS(info) \
2198 - _INTEL_BDW_D_IDS(4, info)
2200 -#define INTEL_BDW_M_IDS(info) \
2201 - INTEL_BDW_GT12M_IDS(info), \
2202 - INTEL_BDW_GT3M_IDS(info), \
2203 - INTEL_BDW_RSVDM_IDS(info)
2205 -#define INTEL_BDW_D_IDS(info) \
2206 - INTEL_BDW_GT12D_IDS(info), \
2207 - INTEL_BDW_GT3D_IDS(info), \
2208 - INTEL_BDW_RSVDD_IDS(info)
2209 +#define INTEL_BDW_GT12_IDS(info) \
2210 + INTEL_VGA_DEVICE(0x1602, info), /* GT1 ULT */ \
2211 + INTEL_VGA_DEVICE(0x1606, info), /* GT1 ULT */ \
2212 + INTEL_VGA_DEVICE(0x160B, info), /* GT1 Iris */ \
2213 + INTEL_VGA_DEVICE(0x160E, info), /* GT1 ULX */ \
2214 + INTEL_VGA_DEVICE(0x1612, info), /* GT2 Halo */ \
2215 + INTEL_VGA_DEVICE(0x1616, info), /* GT2 ULT */ \
2216 + INTEL_VGA_DEVICE(0x161B, info), /* GT2 ULT */ \
2217 + INTEL_VGA_DEVICE(0x161E, info), /* GT2 ULX */ \
2218 + INTEL_VGA_DEVICE(0x160A, info), /* GT1 Server */ \
2219 + INTEL_VGA_DEVICE(0x160D, info), /* GT1 Workstation */ \
2220 + INTEL_VGA_DEVICE(0x161A, info), /* GT2 Server */ \
2221 + INTEL_VGA_DEVICE(0x161D, info) /* GT2 Workstation */
2223 +#define INTEL_BDW_GT3_IDS(info) \
2224 + INTEL_VGA_DEVICE(0x1622, info), /* ULT */ \
2225 + INTEL_VGA_DEVICE(0x1626, info), /* ULT */ \
2226 + INTEL_VGA_DEVICE(0x162B, info), /* Iris */ \
2227 + INTEL_VGA_DEVICE(0x162E, info), /* ULX */\
2228 + INTEL_VGA_DEVICE(0x162A, info), /* Server */ \
2229 + INTEL_VGA_DEVICE(0x162D, info) /* Workstation */
2231 +#define INTEL_BDW_RSVD_IDS(info) \
2232 + INTEL_VGA_DEVICE(0x1632, info), /* ULT */ \
2233 + INTEL_VGA_DEVICE(0x1636, info), /* ULT */ \
2234 + INTEL_VGA_DEVICE(0x163B, info), /* Iris */ \
2235 + INTEL_VGA_DEVICE(0x163E, info), /* ULX */ \
2236 + INTEL_VGA_DEVICE(0x163A, info), /* Server */ \
2237 + INTEL_VGA_DEVICE(0x163D, info) /* Workstation */
2239 +#define INTEL_BDW_IDS(info) \
2240 + INTEL_BDW_GT12_IDS(info), \
2241 + INTEL_BDW_GT3_IDS(info), \
2242 + INTEL_BDW_RSVD_IDS(info)
2244 #define INTEL_CHV_IDS(info) \
2245 INTEL_VGA_DEVICE(0x22b0, info), \
2246 @@ -259,21 +245,85 @@
2247 INTEL_VGA_DEVICE(0x22b2, info), \
2248 INTEL_VGA_DEVICE(0x22b3, info)
2250 -#define INTEL_SKL_IDS(info) \
2251 - INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \
2252 +#define INTEL_SKL_GT1_IDS(info) \
2253 INTEL_VGA_DEVICE(0x1906, info), /* ULT GT1 */ \
2254 - INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \
2255 - INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \
2256 INTEL_VGA_DEVICE(0x190E, info), /* ULX GT1 */ \
2257 + INTEL_VGA_DEVICE(0x1902, info), /* DT GT1 */ \
2258 + INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \
2259 + INTEL_VGA_DEVICE(0x190A, info) /* SRV GT1 */
2261 +#define INTEL_SKL_GT2_IDS(info) \
2262 + INTEL_VGA_DEVICE(0x1916, info), /* ULT GT2 */ \
2263 + INTEL_VGA_DEVICE(0x1921, info), /* ULT GT2F */ \
2264 INTEL_VGA_DEVICE(0x191E, info), /* ULX GT2 */ \
2265 INTEL_VGA_DEVICE(0x1912, info), /* DT GT2 */ \
2266 - INTEL_VGA_DEVICE(0x1902, info), /* DT GT1 */ \
2267 INTEL_VGA_DEVICE(0x191B, info), /* Halo GT2 */ \
2268 - INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \
2269 - INTEL_VGA_DEVICE(0x190B, info), /* Halo GT1 */ \
2270 INTEL_VGA_DEVICE(0x191A, info), /* SRV GT2 */ \
2271 - INTEL_VGA_DEVICE(0x192A, info), /* SRV GT3 */ \
2272 - INTEL_VGA_DEVICE(0x190A, info), /* SRV GT1 */ \
2273 INTEL_VGA_DEVICE(0x191D, info) /* WKS GT2 */
2275 +#define INTEL_SKL_GT3_IDS(info) \
2276 + INTEL_VGA_DEVICE(0x1923, info), /* ULT GT3 */ \
2277 + INTEL_VGA_DEVICE(0x1926, info), /* ULT GT3 */ \
2278 + INTEL_VGA_DEVICE(0x1927, info), /* ULT GT3 */ \
2279 + INTEL_VGA_DEVICE(0x192B, info), /* Halo GT3 */ \
2280 + INTEL_VGA_DEVICE(0x192D, info) /* SRV GT3 */
2282 +#define INTEL_SKL_GT4_IDS(info) \
2283 + INTEL_VGA_DEVICE(0x1932, info), /* DT GT4 */ \
2284 + INTEL_VGA_DEVICE(0x193B, info), /* Halo GT4 */ \
2285 + INTEL_VGA_DEVICE(0x193D, info), /* WKS GT4 */ \
2286 + INTEL_VGA_DEVICE(0x192A, info), /* SRV GT4 */ \
2287 + INTEL_VGA_DEVICE(0x193A, info) /* SRV GT4e */
2289 +#define INTEL_SKL_IDS(info) \
2290 + INTEL_SKL_GT1_IDS(info), \
2291 + INTEL_SKL_GT2_IDS(info), \
2292 + INTEL_SKL_GT3_IDS(info), \
2293 + INTEL_SKL_GT4_IDS(info)
2295 +#define INTEL_BXT_IDS(info) \
2296 + INTEL_VGA_DEVICE(0x0A84, info), \
2297 + INTEL_VGA_DEVICE(0x1A84, info), \
2298 + INTEL_VGA_DEVICE(0x1A85, info), \
2299 + INTEL_VGA_DEVICE(0x5A84, info), /* APL HD Graphics 505 */ \
2300 + INTEL_VGA_DEVICE(0x5A85, info) /* APL HD Graphics 500 */
2302 +#define INTEL_GLK_IDS(info) \
2303 + INTEL_VGA_DEVICE(0x3184, info), \
2304 + INTEL_VGA_DEVICE(0x3185, info)
2306 +#define INTEL_KBL_GT1_IDS(info) \
2307 + INTEL_VGA_DEVICE(0x5913, info), /* ULT GT1.5 */ \
2308 + INTEL_VGA_DEVICE(0x5915, info), /* ULX GT1.5 */ \
2309 + INTEL_VGA_DEVICE(0x5917, info), /* DT GT1.5 */ \
2310 + INTEL_VGA_DEVICE(0x5906, info), /* ULT GT1 */ \
2311 + INTEL_VGA_DEVICE(0x590E, info), /* ULX GT1 */ \
2312 + INTEL_VGA_DEVICE(0x5902, info), /* DT GT1 */ \
2313 + INTEL_VGA_DEVICE(0x5908, info), /* Halo GT1 */ \
2314 + INTEL_VGA_DEVICE(0x590B, info), /* Halo GT1 */ \
2315 + INTEL_VGA_DEVICE(0x590A, info) /* SRV GT1 */
2317 +#define INTEL_KBL_GT2_IDS(info) \
2318 + INTEL_VGA_DEVICE(0x5916, info), /* ULT GT2 */ \
2319 + INTEL_VGA_DEVICE(0x5921, info), /* ULT GT2F */ \
2320 + INTEL_VGA_DEVICE(0x591E, info), /* ULX GT2 */ \
2321 + INTEL_VGA_DEVICE(0x5912, info), /* DT GT2 */ \
2322 + INTEL_VGA_DEVICE(0x591B, info), /* Halo GT2 */ \
2323 + INTEL_VGA_DEVICE(0x591A, info), /* SRV GT2 */ \
2324 + INTEL_VGA_DEVICE(0x591D, info) /* WKS GT2 */
2326 +#define INTEL_KBL_GT3_IDS(info) \
2327 + INTEL_VGA_DEVICE(0x5923, info), /* ULT GT3 */ \
2328 + INTEL_VGA_DEVICE(0x5926, info), /* ULT GT3 */ \
2329 + INTEL_VGA_DEVICE(0x5927, info) /* ULT GT3 */
2331 +#define INTEL_KBL_GT4_IDS(info) \
2332 + INTEL_VGA_DEVICE(0x593B, info) /* Halo GT4 */
2334 +#define INTEL_KBL_IDS(info) \
2335 + INTEL_KBL_GT1_IDS(info), \
2336 + INTEL_KBL_GT2_IDS(info), \
2337 + INTEL_KBL_GT3_IDS(info), \
2338 + INTEL_KBL_GT4_IDS(info)
2340 #endif /* _I915_PCIIDS_H */
2341 diff --git a/src/intel_device.c b/src/intel_device.c
2342 index 140e1536..c4910cd8 100644
2343 --- a/src/intel_device.c
2344 +++ b/src/intel_device.c
2345 @@ -38,6 +38,12 @@
2346 #include <dirent.h>
2347 #include <errno.h>
2349 +#if MAJOR_IN_MKDEV
2350 +#include <sys/mkdev.h>
2351 +#elif MAJOR_IN_SYSMACROS
2352 +#include <sys/sysmacros.h>
2353 +#endif
2355 #include <pciaccess.h>
2357 #include <xorg-server.h>
2358 @@ -197,9 +203,15 @@ static inline struct intel_device *intel_device(ScrnInfoPtr scrn)
2359 return xf86GetEntityPrivate(scrn->entityList[0], intel_device_key)->ptr;
2362 +static const char *kernel_module_names[] ={
2363 + "i915",
2364 + NULL,
2365 +};
2367 static int is_i915_device(int fd)
2369 drm_version_t version;
2370 + const char **kn;
2371 char name[5] = "";
2373 memset(&version, 0, sizeof(version));
2374 @@ -209,7 +221,22 @@ static int is_i915_device(int fd)
2375 if (drmIoctl(fd, DRM_IOCTL_VERSION, &version))
2376 return 0;
2378 - return strcmp("i915", name) == 0;
2379 + for (kn = kernel_module_names; *kn; kn++)
2380 + if (strcmp(*kn, name) == 0)
2381 + return 1;
2383 + return 0;
2384 +}
2386 +static int load_i915_kernel_module(void)
2387 +{
2388 + const char **kn;
2390 + for (kn = kernel_module_names; *kn; kn++)
2391 + if (xf86LoadKernelModule(*kn))
2392 + return 0;
2394 + return -1;
2397 static int is_i915_gem(int fd)
2398 @@ -336,7 +363,7 @@ static int __intel_open_device__pci(const struct pci_device *pci)
2400 sprintf(path + base, "driver");
2401 if (stat(path, &st)) {
2402 - if (xf86LoadKernelModule("i915"))
2403 + if (load_i915_kernel_module())
2404 return -1;
2405 (void)xf86LoadKernelModule("fbcon");
2407 @@ -399,7 +426,7 @@ static int __intel_open_device__legacy(const struct pci_device *pci)
2409 ret = drmCheckModesettingSupported(id);
2410 if (ret) {
2411 - if (xf86LoadKernelModule("i915"))
2412 + if (load_i915_kernel_module() == 0)
2413 ret = drmCheckModesettingSupported(id);
2414 if (ret)
2415 return -1;
2416 @@ -461,9 +488,9 @@ static int is_render_node(int fd, struct stat *st)
2418 static char *find_render_node(int fd)
2420 -#if defined(USE_RENDERNODE)
2421 struct stat master, render;
2422 char buf[128];
2423 + int i;
2425 /* Are we a render-node ourselves? */
2426 if (is_render_node(fd, &master))
2427 @@ -472,9 +499,17 @@ static char *find_render_node(int fd)
2428 sprintf(buf, "/dev/dri/renderD%d", (int)((master.st_rdev | 0x80) & 0xbf));
2429 if (stat(buf, &render) == 0 &&
2430 master.st_mode == render.st_mode &&
2431 - render.st_rdev == ((master.st_rdev | 0x80) & 0xbf))
2432 + render.st_rdev == (master.st_rdev | 0x80))
2433 return strdup(buf);
2434 -#endif
2436 + /* Misaligned card <-> renderD, do a full search */
2437 + for (i = 0; i < 16; i++) {
2438 + sprintf(buf, "/dev/dri/renderD%d", i + 128);
2439 + if (stat(buf, &render) == 0 &&
2440 + master.st_mode == render.st_mode &&
2441 + render.st_rdev == (master.st_rdev | 0x80))
2442 + return strdup(buf);
2443 + }
2445 return NULL;
2447 @@ -608,6 +643,27 @@ err_path:
2448 return -1;
2451 +void intel_close_device(int entity_num)
2452 +{
2453 + struct intel_device *dev;
2455 + if (intel_device_key == -1)
2456 + return;
2458 + dev = xf86GetEntityPrivate(entity_num, intel_device_key)->ptr;
2459 + xf86GetEntityPrivate(entity_num, intel_device_key)->ptr = NULL;
2460 + if (!dev)
2461 + return;
2463 + if (dev->master_count == 0) /* Don't close server-fds */
2464 + close(dev->fd);
2466 + if (dev->render_node != dev->master_node)
2467 + free(dev->render_node);
2468 + free(dev->master_node);
2469 + free(dev);
2470 +}
2472 int __intel_peek_fd(ScrnInfoPtr scrn)
2474 struct intel_device *dev;
2475 @@ -672,6 +728,12 @@ struct intel_device *intel_get_device(ScrnInfoPtr scrn, int *fd)
2476 return dev;
2479 +const char *intel_get_master_name(struct intel_device *dev)
2480 +{
2481 + assert(dev && dev->master_node);
2482 + return dev->master_node;
2483 +}
2485 const char *intel_get_client_name(struct intel_device *dev)
2487 assert(dev && dev->render_node);
2488 diff --git a/src/intel_driver.h b/src/intel_driver.h
2489 index 28ed1a0e..bece88a0 100644
2490 --- a/src/intel_driver.h
2491 +++ b/src/intel_driver.h
2492 @@ -124,9 +124,11 @@ int intel_entity_get_devid(int index);
2493 int intel_open_device(int entity_num,
2494 const struct pci_device *pci,
2495 struct xf86_platform_device *dev);
2496 +void intel_close_device(int entity_num);
2497 int __intel_peek_fd(ScrnInfoPtr scrn);
2498 struct intel_device *intel_get_device(ScrnInfoPtr scrn, int *fd);
2499 int intel_has_render_node(struct intel_device *dev);
2500 +const char *intel_get_master_name(struct intel_device *dev);
2501 const char *intel_get_client_name(struct intel_device *dev);
2502 int intel_get_client_fd(struct intel_device *dev);
2503 int intel_get_device_id(struct intel_device *dev);
2504 diff --git a/src/intel_list.h b/src/intel_list.h
2505 index 51af825d..c8a3187a 100644
2506 --- a/src/intel_list.h
2507 +++ b/src/intel_list.h
2508 @@ -306,8 +306,7 @@ list_is_empty(const struct list *head)
2509 list_entry((ptr)->prev, type, member)
2511 #define __container_of(ptr, sample, member) \
2512 - (void *)((char *)(ptr) \
2513 - - ((char *)&(sample)->member - (char *)(sample)))
2514 + (void *)((char *)(ptr) - ((char *)&(sample)->member - (char *)(sample)))
2515 /**
2516 * Loop through the list given by head and set pos to struct in the list.
2518 @@ -392,17 +391,50 @@ static inline void list_move_tail(struct list *list, struct list *head)
2519 #define list_last_entry(ptr, type, member) \
2520 list_entry((ptr)->prev, type, member)
2522 -#define list_for_each_entry_reverse(pos, head, member) \
2523 +#define list_for_each_entry_reverse(pos, head, member) \
2524 for (pos = __container_of((head)->prev, pos, member); \
2525 &pos->member != (head); \
2526 pos = __container_of(pos->member.prev, pos, member))
2528 #endif
2530 +#define list_for_each_entry_safe_from(pos, tmp, head, member) \
2531 + for (tmp = __container_of(pos->member.next, pos, member); \
2532 + &pos->member != (head); \
2533 + pos = tmp, tmp = __container_of(tmp->member.next, tmp, member))
2535 #undef container_of
2536 #define container_of(ptr, type, member) \
2537 ((type *)((char *)(ptr) - (char *) &((type *)0)->member))
2539 +static inline void __list_splice(const struct list *list,
2540 + struct list *prev,
2541 + struct list *next)
2542 +{
2543 + struct list *first = list->next;
2544 + struct list *last = list->prev;
2546 + first->prev = prev;
2547 + prev->next = first;
2549 + last->next = next;
2550 + next->prev = last;
2551 +}
2553 +static inline void list_splice(const struct list *list,
2554 + struct list *head)
2555 +{
2556 + if (!list_is_empty(list))
2557 + __list_splice(list, head, head->next);
2558 +}
2560 +static inline void list_splice_tail(const struct list *list,
2561 + struct list *head)
2562 +{
2563 + if (!list_is_empty(list))
2564 + __list_splice(list, head->prev, head);
2565 +}
2567 static inline int list_is_singular(const struct list *list)
2569 return list->next == list->prev;
2570 diff --git a/src/intel_module.c b/src/intel_module.c
2571 index 102d52aa..2e97b5ea 100644
2572 --- a/src/intel_module.c
2573 +++ b/src/intel_module.c
2574 @@ -126,6 +126,17 @@ static const struct intel_device_info intel_skylake_info = {
2575 .gen = 0110,
2576 };
2578 +static const struct intel_device_info intel_broxton_info = {
2579 + .gen = 0111,
2580 +};
2582 +static const struct intel_device_info intel_kabylake_info = {
2583 + .gen = 0112,
2584 +};
2586 +static const struct intel_device_info intel_geminilake_info = {
2587 + .gen = 0113,
2588 +};
2590 static const SymTabRec intel_chipsets[] = {
2591 {PCI_CHIP_I810, "i810"},
2592 @@ -234,30 +245,63 @@ static const SymTabRec intel_chipsets[] = {
2593 {0x0157, "HD Graphics"},
2595 /* Broadwell Marketing names */
2596 - {0x1602, "HD graphics"},
2597 - {0x1606, "HD graphics"},
2598 - {0x160B, "HD graphics"},
2599 - {0x160A, "HD graphics"},
2600 - {0x160D, "HD graphics"},
2601 - {0x160E, "HD graphics"},
2602 - {0x1612, "HD graphics 5600"},
2603 - {0x1616, "HD graphics 5500"},
2604 - {0x161B, "HD graphics"},
2605 - {0x161A, "HD graphics"},
2606 - {0x161D, "HD graphics"},
2607 - {0x161E, "HD graphics 5300"},
2608 - {0x1622, "Iris Pro graphics 6200"},
2609 - {0x1626, "HD graphics 6000"},
2610 - {0x162B, "Iris graphics 6100"},
2611 - {0x162A, "Iris Pro graphics P6300"},
2612 - {0x162D, "HD graphics"},
2613 - {0x162E, "HD graphics"},
2614 - {0x1632, "HD graphics"},
2615 - {0x1636, "HD graphics"},
2616 - {0x163B, "HD graphics"},
2617 - {0x163A, "HD graphics"},
2618 - {0x163D, "HD graphics"},
2619 - {0x163E, "HD graphics"},
2620 + {0x1602, "HD Graphics"},
2621 + {0x1606, "HD Graphics"},
2622 + {0x160B, "HD Graphics"},
2623 + {0x160A, "HD Graphics"},
2624 + {0x160D, "HD Graphics"},
2625 + {0x160E, "HD Graphics"},
2626 + {0x1612, "HD Graphics 5600"},
2627 + {0x1616, "HD Graphics 5500"},
2628 + {0x161B, "HD Graphics"},
2629 + {0x161A, "HD Graphics"},
2630 + {0x161D, "HD Graphics"},
2631 + {0x161E, "HD Graphics 5300"},
2632 + {0x1622, "Iris Pro Graphics 6200"},
2633 + {0x1626, "HD Graphics 6000"},
2634 + {0x162B, "Iris Graphics 6100"},
2635 + {0x162A, "Iris Pro Graphics P6300"},
2636 + {0x162D, "HD Graphics"},
2637 + {0x162E, "HD Graphics"},
2638 + {0x1632, "HD Graphics"},
2639 + {0x1636, "HD Graphics"},
2640 + {0x163B, "HD Graphics"},
2641 + {0x163A, "HD Graphics"},
2642 + {0x163D, "HD Graphics"},
2643 + {0x163E, "HD Graphics"},
2645 + /* Cherryview (Cherrytrail/Braswell) */
2646 + {0x22b0, "HD Graphics"},
2647 + {0x22b1, "HD Graphics"},
2648 + {0x22b2, "HD Graphics"},
2649 + {0x22b3, "HD Graphics"},
2651 + /* Skylake */
2652 + {0x1902, "HD Graphics 510"},
2653 + {0x1906, "HD Graphics 510"},
2654 + {0x190B, "HD Graphics 510"},
2655 + {0x1912, "HD Graphics 530"},
2656 + {0x1916, "HD Graphics 520"},
2657 + {0x191B, "HD Graphics 530"},
2658 + {0x191D, "HD Graphics P530"},
2659 + {0x191E, "HD Graphics 515"},
2660 + {0x1921, "HD Graphics 520"},
2661 + {0x1926, "Iris Graphics 540"},
2662 + {0x1927, "Iris Graphics 550"},
2663 + {0x192B, "Iris Graphics 555"},
2664 + {0x192D, "Iris Graphics P555"},
2665 + {0x1932, "Iris Pro Graphics 580"},
2666 + {0x193A, "Iris Pro Graphics P580"},
2667 + {0x193B, "Iris Pro Graphics 580"},
2668 + {0x193D, "Iris Pro Graphics P580"},
2670 + /* Broxton (Apollolake) */
2671 + {0x5A84, "HD Graphics 505"},
2672 + {0x5A85, "HD Graphics 500"},
2674 + /* Kabylake */
2675 + {0x5916, "HD Graphics 620"},
2676 + {0x591E, "HD Graphics 615"},
2678 /* When adding new identifiers, also update:
2679 * 1. intel_identify()
2680 @@ -305,18 +349,14 @@ static const struct pci_id_match intel_device_match[] = {
2681 INTEL_IVB_D_IDS(&intel_ivybridge_info),
2682 INTEL_IVB_M_IDS(&intel_ivybridge_info),
2684 - INTEL_HSW_D_IDS(&intel_haswell_info),
2685 - INTEL_HSW_M_IDS(&intel_haswell_info),
2687 - INTEL_VLV_D_IDS(&intel_valleyview_info),
2688 - INTEL_VLV_M_IDS(&intel_valleyview_info),
2690 - INTEL_BDW_D_IDS(&intel_broadwell_info),
2691 - INTEL_BDW_M_IDS(&intel_broadwell_info),
2693 + INTEL_HSW_IDS(&intel_haswell_info),
2694 + INTEL_VLV_IDS(&intel_valleyview_info),
2695 + INTEL_BDW_IDS(&intel_broadwell_info),
2696 INTEL_CHV_IDS(&intel_cherryview_info),
2698 INTEL_SKL_IDS(&intel_skylake_info),
2699 + INTEL_BXT_IDS(&intel_broxton_info),
2700 + INTEL_KBL_IDS(&intel_kabylake_info),
2701 + INTEL_GLK_IDS(&intel_geminilake_info),
2703 INTEL_VGA_DEVICE(PCI_MATCH_ANY, &intel_generic_info),
2704 #endif
2705 @@ -448,9 +488,9 @@ static void intel_identify(int flags)
2706 if (unique != stack)
2707 free(unique);
2709 - xf86Msg(X_INFO, INTEL_NAME ": Driver for Intel(R) HD Graphics: 2000-6000\n");
2710 - xf86Msg(X_INFO, INTEL_NAME ": Driver for Intel(R) Iris(TM) Graphics: 5100, 6100\n");
2711 - xf86Msg(X_INFO, INTEL_NAME ": Driver for Intel(R) Iris(TM) Pro Graphics: 5200, 6200, P6300\n");
2712 + xf86Msg(X_INFO, INTEL_NAME ": Driver for Intel(R) HD Graphics\n");
2713 + xf86Msg(X_INFO, INTEL_NAME ": Driver for Intel(R) Iris(TM) Graphics\n");
2714 + xf86Msg(X_INFO, INTEL_NAME ": Driver for Intel(R) Iris(TM) Pro Graphics\n");
2717 static Bool intel_driver_func(ScrnInfoPtr pScrn,
2718 @@ -508,6 +548,9 @@ static enum accel_method { NOACCEL, SNA, UXA } get_accel_method(void)
2719 if (hosted())
2720 return SNA;
2722 + if (xf86configptr == NULL) /* X -configure */
2723 + return SNA;
2725 dev = _xf86findDriver("intel", xf86configptr->conf_device_lst);
2726 if (dev && dev->dev_option_lst) {
2727 const char *s;
2728 @@ -582,10 +625,17 @@ intel_scrn_create(DriverPtr driver,
2729 case NOACCEL:
2730 #endif
2731 case UXA:
2732 - return intel_init_scrn(scrn);
2733 + return intel_init_scrn(scrn);
2734 #endif
2736 - default: break;
2737 + default:
2738 +#if USE_SNA
2739 + return sna_init_scrn(scrn, entity_num);
2740 +#elif USE_UXA
2741 + return intel_init_scrn(scrn);
2742 +#else
2743 + break;
2744 +#endif
2746 #endif
2748 @@ -604,6 +654,8 @@ static Bool intel_pci_probe(DriverPtr driver,
2749 struct pci_device *pci,
2750 intptr_t match_data)
2752 + Bool ret;
2754 if (intel_open_device(entity_num, pci, NULL) == -1) {
2755 #if UMS
2756 switch (pci->device_id) {
2757 @@ -621,7 +673,11 @@ static Bool intel_pci_probe(DriverPtr driver,
2758 #endif
2761 - return intel_scrn_create(driver, entity_num, match_data, 0);
2762 + ret = intel_scrn_create(driver, entity_num, match_data, 0);
2763 + if (!ret)
2764 + intel_close_device(entity_num);
2766 + return ret;
2769 #ifdef XSERVER_PLATFORM_BUS
2770 @@ -644,9 +700,16 @@ intel_platform_probe(DriverPtr driver,
2772 /* if we get any flags we don't understand fail to probe for now */
2773 if (flags)
2774 - return FALSE;
2775 + goto err;
2777 + if (!intel_scrn_create(driver, entity_num, match_data, scrn_flags))
2778 + goto err;
2780 - return intel_scrn_create(driver, entity_num, match_data, scrn_flags);
2781 + return TRUE;
2783 +err:
2784 + intel_close_device(entity_num);
2785 + return FALSE;
2787 #endif
2789 diff --git a/src/intel_options.c b/src/intel_options.c
2790 index ff8541a4..7f253ac1 100644
2791 --- a/src/intel_options.c
2792 +++ b/src/intel_options.c
2793 @@ -2,18 +2,24 @@
2794 #include "config.h"
2795 #endif
2797 +#include <xorg-server.h>
2798 +#include <xorgVersion.h>
2799 +#include <xf86Parser.h>
2801 #include "intel_options.h"
2803 const OptionInfoRec intel_options[] = {
2804 - {OPTION_ACCEL_DISABLE, "NoAccel", OPTV_BOOLEAN, {0}, 0},
2805 + {OPTION_ACCEL_ENABLE, "Accel", OPTV_BOOLEAN, {0}, 0},
2806 {OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, 0},
2807 {OPTION_BACKLIGHT, "Backlight", OPTV_STRING, {0}, 0},
2808 + {OPTION_EDID, "CustomEDID", OPTV_STRING, {0}, 0},
2809 {OPTION_DRI, "DRI", OPTV_STRING, {0}, 0},
2810 {OPTION_PRESENT, "Present", OPTV_BOOLEAN, {0}, 1},
2811 {OPTION_COLOR_KEY, "ColorKey", OPTV_INTEGER, {0}, 0},
2812 {OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, 0},
2813 {OPTION_TILING_2D, "Tiling", OPTV_BOOLEAN, {0}, 1},
2814 {OPTION_TILING_FB, "LinearFramebuffer", OPTV_BOOLEAN, {0}, 0},
2815 + {OPTION_ROTATION, "HWRotation", OPTV_BOOLEAN, {0}, 1},
2816 {OPTION_VSYNC, "VSync", OPTV_BOOLEAN, {0}, 1},
2817 {OPTION_PAGEFLIP, "PageFlip", OPTV_BOOLEAN, {0}, 1},
2818 {OPTION_SWAPBUFFERS_WAIT, "SwapbuffersWait", OPTV_BOOLEAN, {0}, 1},
2819 @@ -21,7 +27,6 @@ const OptionInfoRec intel_options[] = {
2820 {OPTION_PREFER_OVERLAY, "XvPreferOverlay", OPTV_BOOLEAN, {0}, 0},
2821 {OPTION_HOTPLUG, "HotPlug", OPTV_BOOLEAN, {0}, 1},
2822 {OPTION_REPROBE, "ReprobeOutputs", OPTV_BOOLEAN, {0}, 0},
2823 - {OPTION_DELETE_DP12, "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, 0},
2824 #ifdef INTEL_XVMC
2825 {OPTION_XVMC, "XvMC", OPTV_BOOLEAN, {0}, 1},
2826 #endif
2827 @@ -54,3 +59,85 @@ OptionInfoPtr intel_options_get(ScrnInfoPtr scrn)
2829 return options;
2832 +Bool intel_option_cast_to_bool(OptionInfoPtr options, int id, Bool val)
2833 +{
2834 +#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
2835 + xf86getBoolValue(&val, xf86GetOptValString(options, id));
2836 +#endif
2837 + return val;
2838 +}
2840 +static int
2841 +namecmp(const char *s1, const char *s2)
2842 +{
2843 + char c1, c2;
2845 + if (!s1 || *s1 == 0) {
2846 + if (!s2 || *s2 == 0)
2847 + return 0;
2848 + else
2849 + return 1;
2850 + }
2852 + while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
2853 + s1++;
2855 + while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
2856 + s2++;
2858 + c1 = isupper(*s1) ? tolower(*s1) : *s1;
2859 + c2 = isupper(*s2) ? tolower(*s2) : *s2;
2860 + while (c1 == c2) {
2861 + if (c1 == '\0')
2862 + return 0;
2864 + s1++;
2865 + while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
2866 + s1++;
2868 + s2++;
2869 + while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
2870 + s2++;
2872 + c1 = isupper(*s1) ? tolower(*s1) : *s1;
2873 + c2 = isupper(*s2) ? tolower(*s2) : *s2;
2874 + }
2876 + return c1 - c2;
2877 +}
2879 +unsigned intel_option_cast_to_unsigned(OptionInfoPtr options, int id, unsigned val)
2880 +{
2881 +#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
2882 + const char *str = xf86GetOptValString(options, id);
2883 +#else
2884 + const char *str = NULL;
2885 +#endif
2886 + unsigned v;
2888 + if (str == NULL || *str == '\0')
2889 + return val;
2891 + if (namecmp(str, "on") == 0)
2892 + return val;
2893 + if (namecmp(str, "true") == 0)
2894 + return val;
2895 + if (namecmp(str, "yes") == 0)
2896 + return val;
2898 + if (namecmp(str, "0") == 0)
2899 + return 0;
2900 + if (namecmp(str, "off") == 0)
2901 + return 0;
2902 + if (namecmp(str, "false") == 0)
2903 + return 0;
2904 + if (namecmp(str, "no") == 0)
2905 + return 0;
2907 + v = atoi(str);
2908 + if (v)
2909 + return v;
2911 + return val;
2912 +}
2913 diff --git a/src/intel_options.h b/src/intel_options.h
2914 index 7e2cbd9b..43635f1f 100644
2915 --- a/src/intel_options.h
2916 +++ b/src/intel_options.h
2917 @@ -12,15 +12,17 @@
2918 */
2920 enum intel_options {
2921 - OPTION_ACCEL_DISABLE,
2922 + OPTION_ACCEL_ENABLE,
2923 OPTION_ACCEL_METHOD,
2924 OPTION_BACKLIGHT,
2925 + OPTION_EDID,
2926 OPTION_DRI,
2927 OPTION_PRESENT,
2928 OPTION_VIDEO_KEY,
2929 OPTION_COLOR_KEY,
2930 OPTION_TILING_2D,
2931 OPTION_TILING_FB,
2932 + OPTION_ROTATION,
2933 OPTION_VSYNC,
2934 OPTION_PAGEFLIP,
2935 OPTION_SWAPBUFFERS_WAIT,
2936 @@ -28,7 +30,6 @@ enum intel_options {
2937 OPTION_PREFER_OVERLAY,
2938 OPTION_HOTPLUG,
2939 OPTION_REPROBE,
2940 - OPTION_DELETE_DP12,
2941 #if defined(XvMCExtension) && defined(ENABLE_XVMC)
2942 OPTION_XVMC,
2943 #define INTEL_XVMC 1
2944 @@ -51,5 +52,7 @@ enum intel_options {
2946 extern const OptionInfoRec intel_options[];
2947 OptionInfoPtr intel_options_get(ScrnInfoPtr scrn);
2948 +unsigned intel_option_cast_to_unsigned(OptionInfoPtr, int id, unsigned val);
2949 +Bool intel_option_cast_to_bool(OptionInfoPtr, int id, Bool val);
2951 #endif /* INTEL_OPTIONS_H */
2952 diff --git a/src/legacy/i810/i810_common.h b/src/legacy/i810/i810_common.h
2953 index 4cc10e8b..8355708c 100644
2954 --- a/src/legacy/i810/i810_common.h
2955 +++ b/src/legacy/i810/i810_common.h
2956 @@ -52,7 +52,7 @@
2958 #define ALIGN(i,m) (((i) + (m) - 1) & ~((m) - 1))
2960 -/* Using usleep() makes things noticably slow. */
2961 +/* Using usleep() makes things noticeably slow. */
2962 #if 0
2963 #define DELAY(x) usleep(x)
2964 #else
2965 @@ -185,7 +185,7 @@ enum {
2966 * - zbuffer linear offset and pitch -- also invarient
2967 * - drawing origin in back and depth buffers.
2969 - * Keep the depth/back buffer state here to acommodate private buffers
2970 + * Keep the depth/back buffer state here to accommodate private buffers
2971 * in the future.
2972 */
2973 #define I810_DESTREG_DI0 0 /* CMD_OP_DESTBUFFER_INFO (2 dwords) */
2974 diff --git a/src/legacy/i810/i810_hwmc.c b/src/legacy/i810/i810_hwmc.c
2975 index 7cb9c1ab..58661b0a 100644
2976 --- a/src/legacy/i810/i810_hwmc.c
2977 +++ b/src/legacy/i810/i810_hwmc.c
2978 @@ -171,7 +171,7 @@ static XF86MCAdaptorPtr ppAdapt[1] =
2980 * I810InitMC
2982 - * Initialize the hardware motion compenstation extention for this
2983 + * Initialize the hardware motion compensation extension for this
2984 * hardware. The initialization routines want the address of the pointers
2985 * to the structures, not the address of the structures. This means we
2986 * allocate (or create static?) the pointer memory and pass that
2987 diff --git a/src/legacy/i810/i810_memory.c b/src/legacy/i810/i810_memory.c
2988 index c3de2777..6f274836 100644
2989 --- a/src/legacy/i810/i810_memory.c
2990 +++ b/src/legacy/i810/i810_memory.c
2991 @@ -76,7 +76,7 @@ I810AllocateGARTMemory(ScrnInfoPtr pScrn)
2992 unsigned long size = pScrn->videoRam * 1024UL;
2993 I810Ptr pI810 = I810PTR(pScrn);
2994 int key;
2995 - long tom = 0;
2996 + unsigned long tom = 0;
2997 unsigned long physical;
2999 if (!xf86AgpGARTSupported() || !xf86AcquireGART(pScrn->scrnIndex)) {
3000 @@ -132,8 +132,8 @@ I810AllocateGARTMemory(ScrnInfoPtr pScrn)
3001 * Keep it 512K aligned for the sake of tiled regions.
3002 */
3004 - tom += 0x7ffff;
3005 - tom &= ~0x7ffff;
3006 + tom += 0x7ffffUL;
3007 + tom &= ~0x7ffffUL;
3009 if ((key = xf86AllocateGARTMemory(pScrn->scrnIndex, size, 1, NULL)) != -1) {
3010 pI810->DcacheOffset = tom;
3011 diff --git a/src/legacy/i810/i810_reg.h b/src/legacy/i810/i810_reg.h
3012 index 54faeb3d..fa091c5b 100644
3013 --- a/src/legacy/i810/i810_reg.h
3014 +++ b/src/legacy/i810/i810_reg.h
3015 @@ -245,7 +245,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
3016 * not sure they refer to local (graphics) memory.
3018 * These details are for the local memory control registers,
3019 - * (pp301-310). The test machines are not equiped with local memory,
3020 + * (pp301-310). The test machines are not equipped with local memory,
3021 * so nothing is tested. Only a single row seems to be supported.
3022 */
3023 #define DRAM_ROW_TYPE 0x3000
3024 diff --git a/src/legacy/i810/i810_video.c b/src/legacy/i810/i810_video.c
3025 index be49b91d..af683c81 100644
3026 --- a/src/legacy/i810/i810_video.c
3027 +++ b/src/legacy/i810/i810_video.c
3028 @@ -77,7 +77,11 @@ static int I810PutImage( ScrnInfoPtr,
3029 static int I810QueryImageAttributes(ScrnInfoPtr,
3030 int, unsigned short *, unsigned short *, int *, int *);
3032 +#if !HAVE_NOTIFY_FD
3033 static void I810BlockHandler(BLOCKHANDLER_ARGS_DECL);
3034 +#else
3035 +static void I810BlockHandler(void *data, void *_timeout);
3036 +#endif
3038 #define MAKE_ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
3040 @@ -418,8 +422,14 @@ I810SetupImageVideo(ScreenPtr screen)
3042 pI810->adaptor = adapt;
3044 +#if !HAVE_NOTIFY_FD
3045 pI810->BlockHandler = screen->BlockHandler;
3046 screen->BlockHandler = I810BlockHandler;
3047 +#else
3048 + RegisterBlockAndWakeupHandlers(I810BlockHandler,
3049 + (ServerWakeupHandlerProcPtr)NoopDDA,
3050 + pScrn);
3051 +#endif
3053 xvBrightness = MAKE_ATOM("XV_BRIGHTNESS");
3054 xvContrast = MAKE_ATOM("XV_CONTRAST");
3055 @@ -1135,6 +1145,7 @@ I810QueryImageAttributes(
3056 return size;
3059 +#if !HAVE_NOTIFY_FD
3060 static void
3061 I810BlockHandler (BLOCKHANDLER_ARGS_DECL)
3063 @@ -1172,6 +1183,38 @@ I810BlockHandler (BLOCKHANDLER_ARGS_DECL)
3067 +#else
3068 +static void
3069 +I810BlockHandler(void *data, void *_timeout)
3070 +{
3071 + ScrnInfoPtr pScrn = data;
3072 + I810Ptr pI810 = I810PTR(pScrn);
3073 + I810PortPrivPtr pPriv = GET_PORT_PRIVATE(pScrn);
3074 + I810OverlayRegPtr overlay = (I810OverlayRegPtr) (pI810->FbBase + pI810->OverlayStart);
3076 + if(pPriv->videoStatus & TIMER_MASK) {
3077 + UpdateCurrentTime();
3078 + if(pPriv->videoStatus & OFF_TIMER) {
3079 + if(pPriv->offTime < currentTime.milliseconds) {
3080 + /* Turn off the overlay */
3081 + overlay->OV0CMD &= 0xFFFFFFFE;
3082 + OVERLAY_UPDATE(pI810->OverlayPhysical);
3084 + pPriv->videoStatus = FREE_TIMER;
3085 + pPriv->freeTime = currentTime.milliseconds + FREE_DELAY;
3086 + }
3087 + } else { /* FREE_TIMER */
3088 + if(pPriv->freeTime < currentTime.milliseconds) {
3089 + if(pPriv->linear) {
3090 + xf86FreeOffscreenLinear(pPriv->linear);
3091 + pPriv->linear = NULL;
3092 + }
3093 + pPriv->videoStatus = 0;
3094 + }
3095 + }
3096 + }
3097 +}
3098 +#endif
3101 /***************************************************************************
3102 @@ -1373,7 +1416,6 @@ I810DisplaySurface(
3103 UpdateCurrentTime();
3104 pI810Priv->videoStatus = FREE_TIMER;
3105 pI810Priv->freeTime = currentTime.milliseconds + FREE_DELAY;
3106 - pScrn->pScreen->BlockHandler = I810BlockHandler;
3109 return Success;
3110 diff --git a/src/legacy/i810/xvmc/I810XvMC.c b/src/legacy/i810/xvmc/I810XvMC.c
3111 index e6b63d30..a538e999 100644
3112 --- a/src/legacy/i810/xvmc/I810XvMC.c
3113 +++ b/src/legacy/i810/xvmc/I810XvMC.c
3114 @@ -61,7 +61,7 @@ static int event_base;
3115 // Arguments: pI810XvMC private data structure from the current context.
3116 // Notes: We faked the drmMapBufs for the i810's security so now we have
3117 // to insert an allocated page into the correct spot in the faked
3118 -// list to keep up appearences.
3119 +// list to keep up appearances.
3120 // Concept for this function was taken from Mesa sources.
3121 // Returns: drmBufPtr containing the information about the allocated page.
3122 ***************************************************************************/
3123 @@ -188,7 +188,7 @@ _X_EXPORT Status XvMCCreateContext(Display *display, XvPortID port,
3125 /* Check for drm */
3126 if(! drmAvailable()) {
3127 - printf("Direct Rendering is not avilable on this system!\n");
3128 + printf("Direct Rendering is not available on this system!\n");
3129 return BadAlloc;
3132 @@ -3279,7 +3279,7 @@ _X_EXPORT Status XvMCSyncSurface(Display *display,XvMCSurface *surface) {
3133 // display - Connection to X server
3134 // surface - Surface to flush
3135 // Info:
3136 -// This command is a noop for i810 becuase we always dispatch buffers in
3137 +// This command is a noop for i810 because we always dispatch buffers in
3138 // render. There is little gain to be had with 4k buffers.
3139 // Returns: Status
3140 ***************************************************************************/
3141 diff --git a/src/render_program/exa_wm.g4i b/src/render_program/exa_wm.g4i
3142 index 5d3d45b1..587b581c 100644
3143 --- a/src/render_program/exa_wm.g4i
3144 +++ b/src/render_program/exa_wm.g4i
3145 @@ -57,7 +57,7 @@ define(`mask_dw_dy', `g6.4<0,1,0>F')
3146 define(`mask_wo', `g6.12<0,1,0>F')
3148 /*
3149 - * Local variables. Pairs must be aligned on even reg boundry
3150 + * Local variables. Pairs must be aligned on even reg boundary
3151 */
3153 /* this holds the X dest coordinates */
3154 diff --git a/src/render_program/exa_wm_yuv_rgb.g8a b/src/render_program/exa_wm_yuv_rgb.g8a
3155 index 7def0930..34973ba8 100644
3156 --- a/src/render_program/exa_wm_yuv_rgb.g8a
3157 +++ b/src/render_program/exa_wm_yuv_rgb.g8a
3158 @@ -76,7 +76,7 @@ add (16) Cbn<1>F Cb<8,8,1>F -0.501961F { compr align1 };
3159 /*
3160 * R = Y + Cr * 1.596
3161 */
3162 -mov (8) acc0<1>F Yn<8,8,1>F { compr align1 };
3163 +mov (8) acc0<1>F Yn_01<8,8,1>F { compr align1 };
3164 mac.sat(8) src_sample_r_01<1>F Crn_01<8,8,1>F 1.596F { compr align1 };
3166 mov (8) acc0<1>F Yn_23<8,8,1>F { compr align1 };
3167 @@ -84,7 +84,7 @@ mac.sat(8) src_sample_r_23<1>F Crn_23<8,8,1>F 1.596F { compr align1 };
3168 /*
3169 * G = Crn * -0.813 + Cbn * -0.392 + Y
3170 */
3171 -mov (8) acc0<1>F Yn_23<8,8,1>F { compr align1 };
3172 +mov (8) acc0<1>F Yn_01<8,8,1>F { compr align1 };
3173 mac (8) acc0<1>F Crn_01<8,8,1>F -0.813F { compr align1 };
3174 mac.sat(8) src_sample_g_01<1>F Cbn_01<8,8,1>F -0.392F { compr align1 };
3176 diff --git a/src/render_program/exa_wm_yuv_rgb.g8b b/src/render_program/exa_wm_yuv_rgb.g8b
3177 index 44949538..2cd6fc44 100644
3178 --- a/src/render_program/exa_wm_yuv_rgb.g8b
3179 +++ b/src/render_program/exa_wm_yuv_rgb.g8b
3180 @@ -6,7 +6,7 @@
3181 { 0x80600048, 0x21c03ae8, 0x3e8d02c0, 0x3fcc49ba },
3182 { 0x00600001, 0x24003ae0, 0x008d0320, 0x00000000 },
3183 { 0x80600048, 0x21e03ae8, 0x3e8d02e0, 0x3fcc49ba },
3184 - { 0x00600001, 0x24003ae0, 0x008d0320, 0x00000000 },
3185 + { 0x00600001, 0x24003ae0, 0x008d0300, 0x00000000 },
3186 { 0x00600048, 0x24003ae0, 0x3e8d02c0, 0xbf5020c5 },
3187 { 0x80600048, 0x22003ae8, 0x3e8d0340, 0xbec8b439 },
3188 { 0x00600001, 0x24003ae0, 0x008d0320, 0x00000000 },
3189 diff --git a/src/sna/Makefile.am b/src/sna/Makefile.am
3190 index e09a8d49..adf13963 100644
3191 --- a/src/sna/Makefile.am
3192 +++ b/src/sna/Makefile.am
3193 @@ -107,6 +107,8 @@ libsna_la_SOURCES = \
3194 gen8_render.h \
3195 gen8_vertex.c \
3196 gen8_vertex.h \
3197 + gen9_render.c \
3198 + gen9_render.h \
3199 xassert.h \
3200 $(NULL)
3202 diff --git a/src/sna/blt.c b/src/sna/blt.c
3203 index b5bfee69..cb90437a 100644
3204 --- a/src/sna/blt.c
3205 +++ b/src/sna/blt.c
3206 @@ -30,112 +30,608 @@
3207 #endif
3209 #include "sna.h"
3210 +#include <pixman.h>
3212 -#if __x86_64__
3213 -#define USE_SSE2 1
3214 -#endif
3216 -#if USE_SSE2
3217 +#if defined(sse2)
3218 +#pragma GCC push_options
3219 +#pragma GCC target("sse2,inline-all-stringops,fpmath=sse")
3220 +#pragma GCC optimize("Ofast")
3221 #include <xmmintrin.h>
3223 #if __x86_64__
3224 #define have_sse2() 1
3225 #else
3226 -enum {
3227 - MMX = 0x1,
3228 - MMX_EXTENSIONS = 0x2,
3229 - SSE = 0x6,
3230 - SSE2 = 0x8,
3231 - CMOV = 0x10
3232 -};
3234 -#ifdef __GNUC__
3235 -static unsigned int
3236 -detect_cpu_features(void)
3237 -{
3238 - unsigned int features;
3239 - unsigned int result = 0;
3241 - char vendor[13];
3242 - vendor[0] = 0;
3243 - vendor[12] = 0;
3245 - asm (
3246 - "pushf\n"
3247 - "pop %%eax\n"
3248 - "mov %%eax, %%ecx\n"
3249 - "xor $0x00200000, %%eax\n"
3250 - "push %%eax\n"
3251 - "popf\n"
3252 - "pushf\n"
3253 - "pop %%eax\n"
3254 - "mov $0x0, %%edx\n"
3255 - "xor %%ecx, %%eax\n"
3256 - "jz 1f\n"
3258 - "mov $0x00000000, %%eax\n"
3259 - "push %%ebx\n"
3260 - "cpuid\n"
3261 - "mov %%ebx, %%eax\n"
3262 - "pop %%ebx\n"
3263 - "mov %%eax, %1\n"
3264 - "mov %%edx, %2\n"
3265 - "mov %%ecx, %3\n"
3266 - "mov $0x00000001, %%eax\n"
3267 - "push %%ebx\n"
3268 - "cpuid\n"
3269 - "pop %%ebx\n"
3270 - "1:\n"
3271 - "mov %%edx, %0\n"
3272 - : "=r" (result), "=m" (vendor[0]), "=m" (vendor[4]), "=m" (vendor[8])
3273 - :: "%eax", "%ecx", "%edx");
3275 - features = 0;
3276 - if (result) {
3277 - /* result now contains the standard feature bits */
3278 - if (result & (1 << 15))
3279 - features |= CMOV;
3280 - if (result & (1 << 23))
3281 - features |= MMX;
3282 - if (result & (1 << 25))
3283 - features |= SSE;
3284 - if (result & (1 << 26))
3285 - features |= SSE2;
3286 - }
3287 - return features;
3288 -}
3289 -#else
3290 -static unsigned int detect_cpu_features(void) { return 0; }
3291 -#endif
3293 static bool have_sse2(void)
3295 static int sse2_present = -1;
3297 if (sse2_present == -1)
3298 - sse2_present = detect_cpu_features() & SSE2;
3299 + sse2_present = sna_cpu_detect() & SSE2;
3301 return sse2_present;
3303 #endif
3305 -static inline __m128i
3306 +static force_inline __m128i
3307 xmm_create_mask_32(uint32_t mask)
3309 return _mm_set_epi32(mask, mask, mask, mask);
3312 -static inline __m128i
3313 +static force_inline __m128i
3314 +xmm_load_128(const __m128i *src)
3315 +{
3316 + return _mm_load_si128(src);
3317 +}
3319 +static force_inline __m128i
3320 xmm_load_128u(const __m128i *src)
3322 return _mm_loadu_si128(src);
3325 -static inline void
3326 +static force_inline void
3327 xmm_save_128(__m128i *dst, __m128i data)
3329 _mm_store_si128(dst, data);
3332 +static force_inline void
3333 +xmm_save_128u(__m128i *dst, __m128i data)
3334 +{
3335 + _mm_storeu_si128(dst, data);
3336 +}
3338 +static force_inline void
3339 +to_sse128xN(uint8_t *dst, const uint8_t *src, int bytes)
3340 +{
3341 + int i;
3343 + for (i = 0; i < bytes / 128; i++) {
3344 + __m128i xmm0, xmm1, xmm2, xmm3;
3345 + __m128i xmm4, xmm5, xmm6, xmm7;
3347 + xmm0 = xmm_load_128u((const __m128i*)src + 0);
3348 + xmm1 = xmm_load_128u((const __m128i*)src + 1);
3349 + xmm2 = xmm_load_128u((const __m128i*)src + 2);
3350 + xmm3 = xmm_load_128u((const __m128i*)src + 3);
3351 + xmm4 = xmm_load_128u((const __m128i*)src + 4);
3352 + xmm5 = xmm_load_128u((const __m128i*)src + 5);
3353 + xmm6 = xmm_load_128u((const __m128i*)src + 6);
3354 + xmm7 = xmm_load_128u((const __m128i*)src + 7);
3356 + xmm_save_128((__m128i*)dst + 0, xmm0);
3357 + xmm_save_128((__m128i*)dst + 1, xmm1);
3358 + xmm_save_128((__m128i*)dst + 2, xmm2);
3359 + xmm_save_128((__m128i*)dst + 3, xmm3);
3360 + xmm_save_128((__m128i*)dst + 4, xmm4);
3361 + xmm_save_128((__m128i*)dst + 5, xmm5);
3362 + xmm_save_128((__m128i*)dst + 6, xmm6);
3363 + xmm_save_128((__m128i*)dst + 7, xmm7);
3365 + dst += 128;
3366 + src += 128;
3367 + }
3368 +}
3370 +static force_inline void
3371 +to_sse64(uint8_t *dst, const uint8_t *src)
3372 +{
3373 + __m128i xmm1, xmm2, xmm3, xmm4;
3375 + xmm1 = xmm_load_128u((const __m128i*)src + 0);
3376 + xmm2 = xmm_load_128u((const __m128i*)src + 1);
3377 + xmm3 = xmm_load_128u((const __m128i*)src + 2);
3378 + xmm4 = xmm_load_128u((const __m128i*)src + 3);
3380 + xmm_save_128((__m128i*)dst + 0, xmm1);
3381 + xmm_save_128((__m128i*)dst + 1, xmm2);
3382 + xmm_save_128((__m128i*)dst + 2, xmm3);
3383 + xmm_save_128((__m128i*)dst + 3, xmm4);
3384 +}
3386 +static force_inline void
3387 +to_sse32(uint8_t *dst, const uint8_t *src)
3388 +{
3389 + __m128i xmm1, xmm2;
3391 + xmm1 = xmm_load_128u((const __m128i*)src + 0);
3392 + xmm2 = xmm_load_128u((const __m128i*)src + 1);
3394 + xmm_save_128((__m128i*)dst + 0, xmm1);
3395 + xmm_save_128((__m128i*)dst + 1, xmm2);
3396 +}
3398 +static force_inline void
3399 +to_sse16(uint8_t *dst, const uint8_t *src)
3400 +{
3401 + xmm_save_128((__m128i*)dst, xmm_load_128u((const __m128i*)src));
3402 +}
3404 +static void to_memcpy(uint8_t *dst, const uint8_t *src, unsigned len)
3405 +{
3406 + assert(len);
3407 + if ((uintptr_t)dst & 15) {
3408 + if (len <= 16 - ((uintptr_t)dst & 15)) {
3409 + memcpy(dst, src, len);
3410 + return;
3411 + }
3413 + if ((uintptr_t)dst & 1) {
3414 + assert(len >= 1);
3415 + *dst++ = *src++;
3416 + len--;
3417 + }
3418 + if ((uintptr_t)dst & 2) {
3419 + assert(((uintptr_t)dst & 1) == 0);
3420 + assert(len >= 2);
3421 + *(uint16_t *)dst = *(const uint16_t *)src;
3422 + dst += 2;
3423 + src += 2;
3424 + len -= 2;
3425 + }
3426 + if ((uintptr_t)dst & 4) {
3427 + assert(((uintptr_t)dst & 3) == 0);
3428 + assert(len >= 4);
3429 + *(uint32_t *)dst = *(const uint32_t *)src;
3430 + dst += 4;
3431 + src += 4;
3432 + len -= 4;
3433 + }
3434 + if ((uintptr_t)dst & 8) {
3435 + assert(((uintptr_t)dst & 7) == 0);
3436 + assert(len >= 8);
3437 + *(uint64_t *)dst = *(const uint64_t *)src;
3438 + dst += 8;
3439 + src += 8;
3440 + len -= 8;
3441 + }
3442 + }
3444 + assert(((uintptr_t)dst & 15) == 0);
3445 + while (len >= 64) {
3446 + to_sse64(dst, src);
3447 + dst += 64;
3448 + src += 64;
3449 + len -= 64;
3450 + }
3451 + if (len == 0)
3452 + return;
3454 + if (len & 32) {
3455 + to_sse32(dst, src);
3456 + dst += 32;
3457 + src += 32;
3458 + }
3459 + if (len & 16) {
3460 + to_sse16(dst, src);
3461 + dst += 16;
3462 + src += 16;
3463 + }
3464 + if (len & 8) {
3465 + *(uint64_t *)dst = *(uint64_t *)src;
3466 + dst += 8;
3467 + src += 8;
3468 + }
3469 + if (len & 4) {
3470 + *(uint32_t *)dst = *(uint32_t *)src;
3471 + dst += 4;
3472 + src += 4;
3473 + }
3474 + memcpy(dst, src, len & 3);
3475 +}
3477 +static void
3478 +memcpy_to_tiled_x__swizzle_0__sse2(const void *src, void *dst, int bpp,
3479 + int32_t src_stride, int32_t dst_stride,
3480 + int16_t src_x, int16_t src_y,
3481 + int16_t dst_x, int16_t dst_y,
3482 + uint16_t width, uint16_t height)
3483 +{
3484 + const unsigned tile_width = 512;
3485 + const unsigned tile_height = 8;
3486 + const unsigned tile_size = 4096;
3488 + const unsigned cpp = bpp / 8;
3489 + const unsigned tile_pixels = tile_width / cpp;
3490 + const unsigned tile_shift = ffs(tile_pixels) - 1;
3491 + const unsigned tile_mask = tile_pixels - 1;
3493 + unsigned offset_x, length_x;
3495 + DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
3496 + __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
3497 + assert(src != dst);
3499 + if (src_x | src_y)
3500 + src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
3501 + width *= cpp;
3502 + assert(src_stride >= width);
3504 + if (dst_x & tile_mask) {
3505 + offset_x = (dst_x & tile_mask) * cpp;
3506 + length_x = min(tile_width - offset_x, width);
3507 + } else
3508 + length_x = 0;
3509 + dst = (uint8_t *)dst + (dst_x >> tile_shift) * tile_size;
3511 + while (height--) {
3512 + unsigned w = width;
3513 + const uint8_t *src_row = src;
3514 + uint8_t *tile_row = dst;
3516 + src = (const uint8_t *)src + src_stride;
3518 + tile_row += dst_y / tile_height * dst_stride * tile_height;
3519 + tile_row += (dst_y & (tile_height-1)) * tile_width;
3520 + dst_y++;
3522 + if (length_x) {
3523 + to_memcpy(tile_row + offset_x, src_row, length_x);
3525 + tile_row += tile_size;
3526 + src_row = (const uint8_t *)src_row + length_x;
3527 + w -= length_x;
3528 + }
3529 + while (w >= tile_width) {
3530 + assert(((uintptr_t)tile_row & (tile_width - 1)) == 0);
3531 + to_sse128xN(assume_aligned(tile_row, tile_width),
3532 + src_row, tile_width);
3533 + tile_row += tile_size;
3534 + src_row = (const uint8_t *)src_row + tile_width;
3535 + w -= tile_width;
3536 + }
3537 + if (w) {
3538 + assert(((uintptr_t)tile_row & (tile_width - 1)) == 0);
3539 + to_memcpy(assume_aligned(tile_row, tile_width),
3540 + src_row, w);
3541 + }
3542 + }
3543 +}
3545 +static force_inline void
3546 +from_sse128xNu(uint8_t *dst, const uint8_t *src, int bytes)
3547 +{
3548 + int i;
3550 + assert(((uintptr_t)src & 15) == 0);
3552 + for (i = 0; i < bytes / 128; i++) {
3553 + __m128i xmm0, xmm1, xmm2, xmm3;
3554 + __m128i xmm4, xmm5, xmm6, xmm7;
3556 + xmm0 = xmm_load_128((const __m128i*)src + 0);
3557 + xmm1 = xmm_load_128((const __m128i*)src + 1);
3558 + xmm2 = xmm_load_128((const __m128i*)src + 2);
3559 + xmm3 = xmm_load_128((const __m128i*)src + 3);
3560 + xmm4 = xmm_load_128((const __m128i*)src + 4);
3561 + xmm5 = xmm_load_128((const __m128i*)src + 5);
3562 + xmm6 = xmm_load_128((const __m128i*)src + 6);
3563 + xmm7 = xmm_load_128((const __m128i*)src + 7);
3565 + xmm_save_128u((__m128i*)dst + 0, xmm0);
3566 + xmm_save_128u((__m128i*)dst + 1, xmm1);
3567 + xmm_save_128u((__m128i*)dst + 2, xmm2);
3568 + xmm_save_128u((__m128i*)dst + 3, xmm3);
3569 + xmm_save_128u((__m128i*)dst + 4, xmm4);
3570 + xmm_save_128u((__m128i*)dst + 5, xmm5);
3571 + xmm_save_128u((__m128i*)dst + 6, xmm6);
3572 + xmm_save_128u((__m128i*)dst + 7, xmm7);
3574 + dst += 128;
3575 + src += 128;
3576 + }
3577 +}
3579 +static force_inline void
3580 +from_sse128xNa(uint8_t *dst, const uint8_t *src, int bytes)
3581 +{
3582 + int i;
3584 + assert(((uintptr_t)dst & 15) == 0);
3585 + assert(((uintptr_t)src & 15) == 0);
3587 + for (i = 0; i < bytes / 128; i++) {
3588 + __m128i xmm0, xmm1, xmm2, xmm3;
3589 + __m128i xmm4, xmm5, xmm6, xmm7;
3591 + xmm0 = xmm_load_128((const __m128i*)src + 0);
3592 + xmm1 = xmm_load_128((const __m128i*)src + 1);
3593 + xmm2 = xmm_load_128((const __m128i*)src + 2);
3594 + xmm3 = xmm_load_128((const __m128i*)src + 3);
3595 + xmm4 = xmm_load_128((const __m128i*)src + 4);
3596 + xmm5 = xmm_load_128((const __m128i*)src + 5);
3597 + xmm6 = xmm_load_128((const __m128i*)src + 6);
3598 + xmm7 = xmm_load_128((const __m128i*)src + 7);
3600 + xmm_save_128((__m128i*)dst + 0, xmm0);
3601 + xmm_save_128((__m128i*)dst + 1, xmm1);
3602 + xmm_save_128((__m128i*)dst + 2, xmm2);
3603 + xmm_save_128((__m128i*)dst + 3, xmm3);
3604 + xmm_save_128((__m128i*)dst + 4, xmm4);
3605 + xmm_save_128((__m128i*)dst + 5, xmm5);
3606 + xmm_save_128((__m128i*)dst + 6, xmm6);
3607 + xmm_save_128((__m128i*)dst + 7, xmm7);
3609 + dst += 128;
3610 + src += 128;
3611 + }
3612 +}
3614 +static force_inline void
3615 +from_sse64u(uint8_t *dst, const uint8_t *src)
3616 +{
3617 + __m128i xmm1, xmm2, xmm3, xmm4;
3619 + assert(((uintptr_t)src & 15) == 0);
3621 + xmm1 = xmm_load_128((const __m128i*)src + 0);
3622 + xmm2 = xmm_load_128((const __m128i*)src + 1);
3623 + xmm3 = xmm_load_128((const __m128i*)src + 2);
3624 + xmm4 = xmm_load_128((const __m128i*)src + 3);
3626 + xmm_save_128u((__m128i*)dst + 0, xmm1);
3627 + xmm_save_128u((__m128i*)dst + 1, xmm2);
3628 + xmm_save_128u((__m128i*)dst + 2, xmm3);
3629 + xmm_save_128u((__m128i*)dst + 3, xmm4);
3630 +}
3632 +static force_inline void
3633 +from_sse64a(uint8_t *dst, const uint8_t *src)
3634 +{
3635 + __m128i xmm1, xmm2, xmm3, xmm4;
3637 + assert(((uintptr_t)dst & 15) == 0);
3638 + assert(((uintptr_t)src & 15) == 0);
3640 + xmm1 = xmm_load_128((const __m128i*)src + 0);
3641 + xmm2 = xmm_load_128((const __m128i*)src + 1);
3642 + xmm3 = xmm_load_128((const __m128i*)src + 2);
3643 + xmm4 = xmm_load_128((const __m128i*)src + 3);
3645 + xmm_save_128((__m128i*)dst + 0, xmm1);
3646 + xmm_save_128((__m128i*)dst + 1, xmm2);
3647 + xmm_save_128((__m128i*)dst + 2, xmm3);
3648 + xmm_save_128((__m128i*)dst + 3, xmm4);
3649 +}
3651 +static force_inline void
3652 +from_sse32u(uint8_t *dst, const uint8_t *src)
3653 +{
3654 + __m128i xmm1, xmm2;
3656 + xmm1 = xmm_load_128((const __m128i*)src + 0);
3657 + xmm2 = xmm_load_128((const __m128i*)src + 1);
3659 + xmm_save_128u((__m128i*)dst + 0, xmm1);
3660 + xmm_save_128u((__m128i*)dst + 1, xmm2);
3661 +}
3663 +static force_inline void
3664 +from_sse32a(uint8_t *dst, const uint8_t *src)
3665 +{
3666 + __m128i xmm1, xmm2;
3668 + assert(((uintptr_t)dst & 15) == 0);
3669 + assert(((uintptr_t)src & 15) == 0);
3671 + xmm1 = xmm_load_128((const __m128i*)src + 0);
3672 + xmm2 = xmm_load_128((const __m128i*)src + 1);
3674 + xmm_save_128((__m128i*)dst + 0, xmm1);
3675 + xmm_save_128((__m128i*)dst + 1, xmm2);
3676 +}
3678 +static force_inline void
3679 +from_sse16u(uint8_t *dst, const uint8_t *src)
3680 +{
3681 + assert(((uintptr_t)src & 15) == 0);
3683 + xmm_save_128u((__m128i*)dst, xmm_load_128((const __m128i*)src));
3684 +}
3686 +static force_inline void
3687 +from_sse16a(uint8_t *dst, const uint8_t *src)
3688 +{
3689 + assert(((uintptr_t)dst & 15) == 0);
3690 + assert(((uintptr_t)src & 15) == 0);
3692 + xmm_save_128((__m128i*)dst, xmm_load_128((const __m128i*)src));
3693 +}
3695 +static void
3696 +memcpy_from_tiled_x__swizzle_0__sse2(const void *src, void *dst, int bpp,
3697 + int32_t src_stride, int32_t dst_stride,
3698 + int16_t src_x, int16_t src_y,
3699 + int16_t dst_x, int16_t dst_y,
3700 + uint16_t width, uint16_t height)
3701 +{
3702 + const unsigned tile_width = 512;
3703 + const unsigned tile_height = 8;
3704 + const unsigned tile_size = 4096;
3706 + const unsigned cpp = bpp / 8;
3707 + const unsigned tile_pixels = tile_width / cpp;
3708 + const unsigned tile_shift = ffs(tile_pixels) - 1;
3709 + const unsigned tile_mask = tile_pixels - 1;
3711 + unsigned length_x, offset_x;
3713 + DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
3714 + __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
3715 + assert(src != dst);
3717 + if (dst_x | dst_y)
3718 + dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
3719 + width *= cpp;
3720 + assert(dst_stride >= width);
3721 + if (src_x & tile_mask) {
3722 + offset_x = (src_x & tile_mask) * cpp;
3723 + length_x = min(tile_width - offset_x, width);
3724 + dst_stride -= width;
3725 + dst_stride += (width - length_x) & 15;
3726 + } else {
3727 + offset_x = 0;
3728 + dst_stride -= width & ~15;
3729 + }
3730 + assert(dst_stride >= 0);
3731 + src = (const uint8_t *)src + (src_x >> tile_shift) * tile_size;
3733 + while (height--) {
3734 + unsigned w = width;
3735 + const uint8_t *tile_row = src;
3737 + tile_row += src_y / tile_height * src_stride * tile_height;
3738 + tile_row += (src_y & (tile_height-1)) * tile_width;
3739 + src_y++;
3741 + if (offset_x) {
3742 + memcpy(dst, tile_row + offset_x, length_x);
3743 + tile_row += tile_size;
3744 + dst = (uint8_t *)dst + length_x;
3745 + w -= length_x;
3746 + }
3748 + if ((uintptr_t)dst & 15) {
3749 + while (w >= tile_width) {
3750 + from_sse128xNu(dst,
3751 + assume_aligned(tile_row, tile_width),
3752 + tile_width);
3753 + tile_row += tile_size;
3754 + dst = (uint8_t *)dst + tile_width;
3755 + w -= tile_width;
3756 + }
3757 + while (w >= 64) {
3758 + from_sse64u(dst, tile_row);
3759 + tile_row += 64;
3760 + dst = (uint8_t *)dst + 64;
3761 + w -= 64;
3762 + }
3763 + if (w & 32) {
3764 + from_sse32u(dst, tile_row);
3765 + tile_row += 32;
3766 + dst = (uint8_t *)dst + 32;
3767 + }
3768 + if (w & 16) {
3769 + from_sse16u(dst, tile_row);
3770 + tile_row += 16;
3771 + dst = (uint8_t *)dst + 16;
3772 + }
3773 + memcpy(dst, assume_aligned(tile_row, 16), w & 15);
3774 + } else {
3775 + while (w >= tile_width) {
3776 + from_sse128xNa(assume_aligned(dst, 16),
3777 + assume_aligned(tile_row, tile_width),
3778 + tile_width);
3779 + tile_row += tile_size;
3780 + dst = (uint8_t *)dst + tile_width;
3781 + w -= tile_width;
3782 + }
3783 + while (w >= 64) {
3784 + from_sse64a(dst, tile_row);
3785 + tile_row += 64;
3786 + dst = (uint8_t *)dst + 64;
3787 + w -= 64;
3788 + }
3789 + if (w & 32) {
3790 + from_sse32a(dst, tile_row);
3791 + tile_row += 32;
3792 + dst = (uint8_t *)dst + 32;
3793 + }
3794 + if (w & 16) {
3795 + from_sse16a(dst, tile_row);
3796 + tile_row += 16;
3797 + dst = (uint8_t *)dst + 16;
3798 + }
3799 + memcpy(assume_aligned(dst, 16),
3800 + assume_aligned(tile_row, 16),
3801 + w & 15);
3802 + }
3803 + dst = (uint8_t *)dst + dst_stride;
3804 + }
3805 +}
3807 +static void
3808 +memcpy_between_tiled_x__swizzle_0__sse2(const void *src, void *dst, int bpp,
3809 + int32_t src_stride, int32_t dst_stride,
3810 + int16_t src_x, int16_t src_y,
3811 + int16_t dst_x, int16_t dst_y,
3812 + uint16_t width, uint16_t height)
3813 +{
3814 + const unsigned tile_width = 512;
3815 + const unsigned tile_height = 8;
3816 + const unsigned tile_size = 4096;
3818 + const unsigned cpp = bpp / 8;
3819 + const unsigned tile_pixels = tile_width / cpp;
3820 + const unsigned tile_shift = ffs(tile_pixels) - 1;
3821 + const unsigned tile_mask = tile_pixels - 1;
3823 + unsigned ox, lx;
3825 + DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
3826 + __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
3827 + assert(src != dst);
3829 + width *= cpp;
3830 + dst_stride *= tile_height;
3831 + src_stride *= tile_height;
3833 + assert((dst_x & tile_mask) == (src_x & tile_mask));
3834 + if (dst_x & tile_mask) {
3835 + ox = (dst_x & tile_mask) * cpp;
3836 + lx = min(tile_width - ox, width);
3837 + assert(lx != 0);
3838 + } else
3839 + lx = 0;
3841 + if (dst_x)
3842 + dst = (uint8_t *)dst + (dst_x >> tile_shift) * tile_size;
3843 + if (src_x)
3844 + src = (const uint8_t *)src + (src_x >> tile_shift) * tile_size;
3846 + while (height--) {
3847 + const uint8_t *src_row;
3848 + uint8_t *dst_row;
3849 + unsigned w = width;
3851 + dst_row = dst;
3852 + dst_row += dst_y / tile_height * dst_stride;
3853 + dst_row += (dst_y & (tile_height-1)) * tile_width;
3854 + dst_y++;
3856 + src_row = src;
3857 + src_row += src_y / tile_height * src_stride;
3858 + src_row += (src_y & (tile_height-1)) * tile_width;
3859 + src_y++;
3861 + if (lx) {
3862 + to_memcpy(dst_row + ox, src_row + ox, lx);
3863 + dst_row += tile_size;
3864 + src_row += tile_size;
3865 + w -= lx;
3866 + }
3867 + while (w >= tile_width) {
3868 + assert(((uintptr_t)dst_row & (tile_width - 1)) == 0);
3869 + assert(((uintptr_t)src_row & (tile_width - 1)) == 0);
3870 + to_sse128xN(assume_aligned(dst_row, tile_width),
3871 + assume_aligned(src_row, tile_width),
3872 + tile_width);
3873 + dst_row += tile_size;
3874 + src_row += tile_size;
3875 + w -= tile_width;
3876 + }
3877 + if (w) {
3878 + assert(((uintptr_t)dst_row & (tile_width - 1)) == 0);
3879 + assert(((uintptr_t)src_row & (tile_width - 1)) == 0);
3880 + to_memcpy(assume_aligned(dst_row, tile_width),
3881 + assume_aligned(src_row, tile_width),
3882 + w);
3883 + }
3884 + }
3885 +}
3887 +#pragma GCC push_options
3888 #endif
3890 fast void
3891 @@ -257,7 +753,8 @@ memcpy_to_tiled_x__swizzle_0(const void *src, void *dst, int bpp,
3892 if (dst_x & tile_mask) {
3893 const unsigned x = (dst_x & tile_mask) * cpp;
3894 const unsigned len = min(tile_width - x, w);
3895 - memcpy(tile_row + x, src, len);
3896 + memcpy(assume_misaligned(tile_row + x, tile_width, x),
3897 + src, len);
3899 tile_row += tile_size;
3900 src = (const uint8_t *)src + len;
3901 @@ -265,13 +762,13 @@ memcpy_to_tiled_x__swizzle_0(const void *src, void *dst, int bpp,
3904 while (w >= tile_width) {
3905 - memcpy(tile_row, src, tile_width);
3907 + memcpy(assume_aligned(tile_row, tile_width),
3908 + src, tile_width);
3909 tile_row += tile_size;
3910 src = (const uint8_t *)src + tile_width;
3911 w -= tile_width;
3913 - memcpy(tile_row, src, w);
3914 + memcpy(assume_aligned(tile_row, tile_width), src, w);
3915 src = (const uint8_t *)src + src_stride + w;
3916 dst_y++;
3918 @@ -313,7 +810,7 @@ memcpy_from_tiled_x__swizzle_0(const void *src, void *dst, int bpp,
3919 if (src_x & tile_mask) {
3920 const unsigned x = (src_x & tile_mask) * cpp;
3921 const unsigned len = min(tile_width - x, w);
3922 - memcpy(dst, tile_row + x, len);
3923 + memcpy(dst, assume_misaligned(tile_row + x, tile_width, x), len);
3925 tile_row += tile_size;
3926 dst = (uint8_t *)dst + len;
3927 @@ -321,440 +818,371 @@ memcpy_from_tiled_x__swizzle_0(const void *src, void *dst, int bpp,
3930 while (w >= tile_width) {
3931 - memcpy(dst, tile_row, tile_width);
3932 + memcpy(dst,
3933 + assume_aligned(tile_row, tile_width),
3934 + tile_width);
3936 tile_row += tile_size;
3937 dst = (uint8_t *)dst + tile_width;
3938 w -= tile_width;
3940 - memcpy(dst, tile_row, w);
3941 + memcpy(dst, assume_aligned(tile_row, tile_width), w);
3942 dst = (uint8_t *)dst + dst_stride + w;
3943 src_y++;
3947 -fast_memcpy static void
3948 -memcpy_to_tiled_x__swizzle_9(const void *src, void *dst, int bpp,
3949 - int32_t src_stride, int32_t dst_stride,
3950 - int16_t src_x, int16_t src_y,
3951 - int16_t dst_x, int16_t dst_y,
3952 - uint16_t width, uint16_t height)
3953 +static fast_memcpy void
3954 +memcpy_between_tiled_x__swizzle_0(const void *src, void *dst, int bpp,
3955 + int32_t src_stride, int32_t dst_stride,
3956 + int16_t src_x, int16_t src_y,
3957 + int16_t dst_x, int16_t dst_y,
3958 + uint16_t width, uint16_t height)
3960 const unsigned tile_width = 512;
3961 const unsigned tile_height = 8;
3962 const unsigned tile_size = 4096;
3964 const unsigned cpp = bpp / 8;
3965 - const unsigned stride_tiles = dst_stride / tile_width;
3966 - const unsigned swizzle_pixels = 64 / cpp;
3967 - const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
3968 - const unsigned tile_mask = (1 << tile_pixels) - 1;
3970 - unsigned x, y;
3971 + const unsigned tile_pixels = tile_width / cpp;
3972 + const unsigned tile_shift = ffs(tile_pixels) - 1;
3973 + const unsigned tile_mask = tile_pixels - 1;
3975 DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
3976 __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
3977 + assert(src != dst);
3978 + assert((dst_x & tile_mask) == (src_x & tile_mask));
3980 - src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
3982 - for (y = 0; y < height; ++y) {
3983 - const uint32_t dy = y + dst_y;
3984 - const uint32_t tile_row =
3985 - (dy / tile_height * stride_tiles * tile_size +
3986 - (dy & (tile_height-1)) * tile_width);
3987 - const uint8_t *src_row = (const uint8_t *)src + src_stride * y;
3988 - uint32_t dx = dst_x, offset;
3990 - x = width * cpp;
3991 - if (dx & (swizzle_pixels - 1)) {
3992 - const uint32_t swizzle_bound_pixels = ALIGN(dx + 1, swizzle_pixels);
3993 - const uint32_t length = min(dst_x + width, swizzle_bound_pixels) - dx;
3994 - offset = tile_row +
3995 - (dx >> tile_pixels) * tile_size +
3996 - (dx & tile_mask) * cpp;
3997 - offset ^= (offset >> 3) & 64;
3999 - memcpy((char *)dst + offset, src_row, length * cpp);
4001 - src_row += length * cpp;
4002 - x -= length * cpp;
4003 - dx += length;
4004 - }
4005 - while (x >= 64) {
4006 - offset = tile_row +
4007 - (dx >> tile_pixels) * tile_size +
4008 - (dx & tile_mask) * cpp;
4009 - offset ^= (offset >> 3) & 64;
4011 - memcpy((char *)dst + offset, src_row, 64);
4013 - src_row += 64;
4014 - x -= 64;
4015 - dx += swizzle_pixels;
4016 - }
4017 - if (x) {
4018 - offset = tile_row +
4019 - (dx >> tile_pixels) * tile_size +
4020 - (dx & tile_mask) * cpp;
4021 - offset ^= (offset >> 3) & 64;
4022 - memcpy((char *)dst + offset, src_row, x);
4023 - }
4024 - }
4025 -}
4026 + while (height--) {
4027 + unsigned w = width * cpp;
4028 + uint8_t *dst_row = dst;
4029 + const uint8_t *src_row = src;
4031 -fast_memcpy static void
4032 -memcpy_from_tiled_x__swizzle_9(const void *src, void *dst, int bpp,
4033 - int32_t src_stride, int32_t dst_stride,
4034 - int16_t src_x, int16_t src_y,
4035 - int16_t dst_x, int16_t dst_y,
4036 - uint16_t width, uint16_t height)
4037 -{
4038 - const unsigned tile_width = 512;
4039 - const unsigned tile_height = 8;
4040 - const unsigned tile_size = 4096;
4041 + dst_row += dst_y / tile_height * dst_stride * tile_height;
4042 + dst_row += (dst_y & (tile_height-1)) * tile_width;
4043 + if (dst_x)
4044 + dst_row += (dst_x >> tile_shift) * tile_size;
4045 + dst_y++;
4047 - const unsigned cpp = bpp / 8;
4048 - const unsigned stride_tiles = src_stride / tile_width;
4049 - const unsigned swizzle_pixels = 64 / cpp;
4050 - const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
4051 - const unsigned tile_mask = (1 << tile_pixels) - 1;
4052 + src_row += src_y / tile_height * src_stride * tile_height;
4053 + src_row += (src_y & (tile_height-1)) * tile_width;
4054 + if (src_x)
4055 + src_row += (src_x >> tile_shift) * tile_size;
4056 + src_y++;
4058 - unsigned x, y;
4059 + if (dst_x & tile_mask) {
4060 + const unsigned x = (dst_x & tile_mask) * cpp;
4061 + const unsigned len = min(tile_width - x, w);
4063 - DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
4064 - __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
4065 + memcpy(assume_misaligned(dst_row + x, tile_width, x),
4066 + assume_misaligned(src_row + x, tile_width, x),
4067 + len);
4069 - dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
4071 - for (y = 0; y < height; ++y) {
4072 - const uint32_t sy = y + src_y;
4073 - const uint32_t tile_row =
4074 - (sy / tile_height * stride_tiles * tile_size +
4075 - (sy & (tile_height-1)) * tile_width);
4076 - uint8_t *dst_row = (uint8_t *)dst + dst_stride * y;
4077 - uint32_t sx = src_x, offset;
4079 - x = width * cpp;
4080 - if (sx & (swizzle_pixels - 1)) {
4081 - const uint32_t swizzle_bound_pixels = ALIGN(sx + 1, swizzle_pixels);
4082 - const uint32_t length = min(src_x + width, swizzle_bound_pixels) - sx;
4083 - offset = tile_row +
4084 - (sx >> tile_pixels) * tile_size +
4085 - (sx & tile_mask) * cpp;
4086 - offset ^= (offset >> 3) & 64;
4088 - memcpy(dst_row, (const char *)src + offset, length * cpp);
4090 - dst_row += length * cpp;
4091 - x -= length * cpp;
4092 - sx += length;
4093 + dst_row += tile_size;
4094 + src_row += tile_size;
4095 + w -= len;
4097 - while (x >= 64) {
4098 - offset = tile_row +
4099 - (sx >> tile_pixels) * tile_size +
4100 - (sx & tile_mask) * cpp;
4101 - offset ^= (offset >> 3) & 64;
4103 - memcpy(dst_row, (const char *)src + offset, 64);
4105 - dst_row += 64;
4106 - x -= 64;
4107 - sx += swizzle_pixels;
4108 - }
4109 - if (x) {
4110 - offset = tile_row +
4111 - (sx >> tile_pixels) * tile_size +
4112 - (sx & tile_mask) * cpp;
4113 - offset ^= (offset >> 3) & 64;
4114 - memcpy(dst_row, (const char *)src + offset, x);
4115 + while (w >= tile_width) {
4116 + memcpy(assume_aligned(dst_row, tile_width),
4117 + assume_aligned(src_row, tile_width),
4118 + tile_width);
4119 + dst_row += tile_size;
4120 + src_row += tile_size;
4121 + w -= tile_width;
4123 + memcpy(assume_aligned(dst_row, tile_width),
4124 + assume_aligned(src_row, tile_width),
4125 + w);
4129 -fast_memcpy static void
4130 -memcpy_to_tiled_x__swizzle_9_10(const void *src, void *dst, int bpp,
4131 - int32_t src_stride, int32_t dst_stride,
4132 - int16_t src_x, int16_t src_y,
4133 - int16_t dst_x, int16_t dst_y,
4134 - uint16_t width, uint16_t height)
4135 -{
4136 - const unsigned tile_width = 512;
4137 - const unsigned tile_height = 8;
4138 - const unsigned tile_size = 4096;
4140 - const unsigned cpp = bpp / 8;
4141 - const unsigned stride_tiles = dst_stride / tile_width;
4142 - const unsigned swizzle_pixels = 64 / cpp;
4143 - const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
4144 - const unsigned tile_mask = (1 << tile_pixels) - 1;
4145 +#define memcpy_to_tiled_x(swizzle) \
4146 +fast_memcpy static void \
4147 +memcpy_to_tiled_x__##swizzle (const void *src, void *dst, int bpp, \
4148 + int32_t src_stride, int32_t dst_stride, \
4149 + int16_t src_x, int16_t src_y, \
4150 + int16_t dst_x, int16_t dst_y, \
4151 + uint16_t width, uint16_t height) \
4152 +{ \
4153 + const unsigned tile_width = 512; \
4154 + const unsigned tile_height = 8; \
4155 + const unsigned tile_size = 4096; \
4156 + const unsigned cpp = bpp / 8; \
4157 + const unsigned stride_tiles = dst_stride / tile_width; \
4158 + const unsigned swizzle_pixels = 64 / cpp; \
4159 + const unsigned tile_pixels = ffs(tile_width / cpp) - 1; \
4160 + const unsigned tile_mask = (1 << tile_pixels) - 1; \
4161 + unsigned x, y; \
4162 + DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n", \
4163 + __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride)); \
4164 + src = (const uint8_t *)src + src_y * src_stride + src_x * cpp; \
4165 + for (y = 0; y < height; ++y) { \
4166 + const uint32_t dy = y + dst_y; \
4167 + const uint32_t tile_row = \
4168 + (dy / tile_height * stride_tiles * tile_size + \
4169 + (dy & (tile_height-1)) * tile_width); \
4170 + const uint8_t *src_row = (const uint8_t *)src + src_stride * y; \
4171 + uint32_t dx = dst_x; \
4172 + x = width * cpp; \
4173 + if (dx & (swizzle_pixels - 1)) { \
4174 + const uint32_t swizzle_bound_pixels = ALIGN(dx + 1, swizzle_pixels); \
4175 + const uint32_t length = min(dst_x + width, swizzle_bound_pixels) - dx; \
4176 + uint32_t offset = \
4177 + tile_row + \
4178 + (dx >> tile_pixels) * tile_size + \
4179 + (dx & tile_mask) * cpp; \
4180 + memcpy((char *)dst + swizzle(offset), src_row, length * cpp); \
4181 + src_row += length * cpp; \
4182 + x -= length * cpp; \
4183 + dx += length; \
4184 + } \
4185 + while (x >= 64) { \
4186 + uint32_t offset = \
4187 + tile_row + \
4188 + (dx >> tile_pixels) * tile_size + \
4189 + (dx & tile_mask) * cpp; \
4190 + memcpy(assume_aligned((char *)dst+swizzle(offset),64), \
4191 + src_row, 64); \
4192 + src_row += 64; \
4193 + x -= 64; \
4194 + dx += swizzle_pixels; \
4195 + } \
4196 + if (x) { \
4197 + uint32_t offset = \
4198 + tile_row + \
4199 + (dx >> tile_pixels) * tile_size + \
4200 + (dx & tile_mask) * cpp; \
4201 + memcpy(assume_aligned((char *)dst + swizzle(offset), 64), src_row, x); \
4202 + } \
4203 + } \
4204 +}
4206 - unsigned x, y;
4207 +#define memcpy_from_tiled_x(swizzle) \
4208 +fast_memcpy static void \
4209 +memcpy_from_tiled_x__##swizzle (const void *src, void *dst, int bpp, \
4210 + int32_t src_stride, int32_t dst_stride, \
4211 + int16_t src_x, int16_t src_y, \
4212 + int16_t dst_x, int16_t dst_y, \
4213 + uint16_t width, uint16_t height) \
4214 +{ \
4215 + const unsigned tile_width = 512; \
4216 + const unsigned tile_height = 8; \
4217 + const unsigned tile_size = 4096; \
4218 + const unsigned cpp = bpp / 8; \
4219 + const unsigned stride_tiles = src_stride / tile_width; \
4220 + const unsigned swizzle_pixels = 64 / cpp; \
4221 + const unsigned tile_pixels = ffs(tile_width / cpp) - 1; \
4222 + const unsigned tile_mask = (1 << tile_pixels) - 1; \
4223 + unsigned x, y; \
4224 + DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n", \
4225 + __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride)); \
4226 + dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp; \
4227 + for (y = 0; y < height; ++y) { \
4228 + const uint32_t sy = y + src_y; \
4229 + const uint32_t tile_row = \
4230 + (sy / tile_height * stride_tiles * tile_size + \
4231 + (sy & (tile_height-1)) * tile_width); \
4232 + uint8_t *dst_row = (uint8_t *)dst + dst_stride * y; \
4233 + uint32_t sx = src_x; \
4234 + x = width * cpp; \
4235 + if (sx & (swizzle_pixels - 1)) { \
4236 + const uint32_t swizzle_bound_pixels = ALIGN(sx + 1, swizzle_pixels); \
4237 + const uint32_t length = min(src_x + width, swizzle_bound_pixels) - sx; \
4238 + uint32_t offset = \
4239 + tile_row + \
4240 + (sx >> tile_pixels) * tile_size + \
4241 + (sx & tile_mask) * cpp; \
4242 + memcpy(dst_row, (const char *)src + swizzle(offset), length * cpp); \
4243 + dst_row += length * cpp; \
4244 + x -= length * cpp; \
4245 + sx += length; \
4246 + } \
4247 + while (x >= 64) { \
4248 + uint32_t offset = \
4249 + tile_row + \
4250 + (sx >> tile_pixels) * tile_size + \
4251 + (sx & tile_mask) * cpp; \
4252 + memcpy(dst_row, assume_aligned((const char *)src + swizzle(offset), 64), 64); \
4253 + dst_row += 64; \
4254 + x -= 64; \
4255 + sx += swizzle_pixels; \
4256 + } \
4257 + if (x) { \
4258 + uint32_t offset = \
4259 + tile_row + \
4260 + (sx >> tile_pixels) * tile_size + \
4261 + (sx & tile_mask) * cpp; \
4262 + memcpy(dst_row, assume_aligned((const char *)src + swizzle(offset), 64), x); \
4263 + } \
4264 + } \
4265 +}
4267 - DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
4268 - __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
4269 +#define swizzle_9(X) ((X) ^ (((X) >> 3) & 64))
4270 +memcpy_to_tiled_x(swizzle_9)
4271 +memcpy_from_tiled_x(swizzle_9)
4272 +#undef swizzle_9
4274 - src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
4276 - for (y = 0; y < height; ++y) {
4277 - const uint32_t dy = y + dst_y;
4278 - const uint32_t tile_row =
4279 - (dy / tile_height * stride_tiles * tile_size +
4280 - (dy & (tile_height-1)) * tile_width);
4281 - const uint8_t *src_row = (const uint8_t *)src + src_stride * y;
4282 - uint32_t dx = dst_x, offset;
4284 - x = width * cpp;
4285 - if (dx & (swizzle_pixels - 1)) {
4286 - const uint32_t swizzle_bound_pixels = ALIGN(dx + 1, swizzle_pixels);
4287 - const uint32_t length = min(dst_x + width, swizzle_bound_pixels) - dx;
4288 - offset = tile_row +
4289 - (dx >> tile_pixels) * tile_size +
4290 - (dx & tile_mask) * cpp;
4291 - offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
4293 - memcpy((char *)dst + offset, src_row, length * cpp);
4295 - src_row += length * cpp;
4296 - x -= length * cpp;
4297 - dx += length;
4298 - }
4299 - while (x >= 64) {
4300 - offset = tile_row +
4301 - (dx >> tile_pixels) * tile_size +
4302 - (dx & tile_mask) * cpp;
4303 - offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
4304 +#define swizzle_9_10(X) ((X) ^ ((((X) ^ ((X) >> 1)) >> 3) & 64))
4305 +memcpy_to_tiled_x(swizzle_9_10)
4306 +memcpy_from_tiled_x(swizzle_9_10)
4307 +#undef swizzle_9_10
4309 - memcpy((char *)dst + offset, src_row, 64);
4310 +#define swizzle_9_11(X) ((X) ^ ((((X) ^ ((X) >> 2)) >> 3) & 64))
4311 +memcpy_to_tiled_x(swizzle_9_11)
4312 +memcpy_from_tiled_x(swizzle_9_11)
4313 +#undef swizzle_9_11
4315 - src_row += 64;
4316 - x -= 64;
4317 - dx += swizzle_pixels;
4318 - }
4319 - if (x) {
4320 - offset = tile_row +
4321 - (dx >> tile_pixels) * tile_size +
4322 - (dx & tile_mask) * cpp;
4323 - offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
4324 - memcpy((char *)dst + offset, src_row, x);
4325 - }
4326 - }
4327 -}
4328 +#define swizzle_9_10_11(X) ((X) ^ ((((X) ^ ((X) >> 1) ^ ((X) >> 2)) >> 3) & 64))
4329 +memcpy_to_tiled_x(swizzle_9_10_11)
4330 +memcpy_from_tiled_x(swizzle_9_10_11)
4331 +#undef swizzle_9_10_11
4333 -fast_memcpy static void
4334 -memcpy_from_tiled_x__swizzle_9_10(const void *src, void *dst, int bpp,
4335 - int32_t src_stride, int32_t dst_stride,
4336 - int16_t src_x, int16_t src_y,
4337 - int16_t dst_x, int16_t dst_y,
4338 - uint16_t width, uint16_t height)
4339 +static fast_memcpy void
4340 +memcpy_to_tiled_x__gen2(const void *src, void *dst, int bpp,
4341 + int32_t src_stride, int32_t dst_stride,
4342 + int16_t src_x, int16_t src_y,
4343 + int16_t dst_x, int16_t dst_y,
4344 + uint16_t width, uint16_t height)
4346 - const unsigned tile_width = 512;
4347 - const unsigned tile_height = 8;
4348 - const unsigned tile_size = 4096;
4349 + const unsigned tile_width = 128;
4350 + const unsigned tile_height = 16;
4351 + const unsigned tile_size = 2048;
4353 const unsigned cpp = bpp / 8;
4354 - const unsigned stride_tiles = src_stride / tile_width;
4355 - const unsigned swizzle_pixels = 64 / cpp;
4356 - const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
4357 - const unsigned tile_mask = (1 << tile_pixels) - 1;
4359 - unsigned x, y;
4360 + const unsigned tile_pixels = tile_width / cpp;
4361 + const unsigned tile_shift = ffs(tile_pixels) - 1;
4362 + const unsigned tile_mask = tile_pixels - 1;
4364 DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
4365 __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
4366 + assert(src != dst);
4368 - dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
4370 - for (y = 0; y < height; ++y) {
4371 - const uint32_t sy = y + src_y;
4372 - const uint32_t tile_row =
4373 - (sy / tile_height * stride_tiles * tile_size +
4374 - (sy & (tile_height-1)) * tile_width);
4375 - uint8_t *dst_row = (uint8_t *)dst + dst_stride * y;
4376 - uint32_t sx = src_x, offset;
4378 - x = width * cpp;
4379 - if (sx & (swizzle_pixels - 1)) {
4380 - const uint32_t swizzle_bound_pixels = ALIGN(sx + 1, swizzle_pixels);
4381 - const uint32_t length = min(src_x + width, swizzle_bound_pixels) - sx;
4382 - offset = tile_row +
4383 - (sx >> tile_pixels) * tile_size +
4384 - (sx & tile_mask) * cpp;
4385 - offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
4387 - memcpy(dst_row, (const char *)src + offset, length * cpp);
4389 - dst_row += length * cpp;
4390 - x -= length * cpp;
4391 - sx += length;
4392 - }
4393 - while (x >= 64) {
4394 - offset = tile_row +
4395 - (sx >> tile_pixels) * tile_size +
4396 - (sx & tile_mask) * cpp;
4397 - offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
4399 - memcpy(dst_row, (const char *)src + offset, 64);
4401 - dst_row += 64;
4402 - x -= 64;
4403 - sx += swizzle_pixels;
4404 - }
4405 - if (x) {
4406 - offset = tile_row +
4407 - (sx >> tile_pixels) * tile_size +
4408 - (sx & tile_mask) * cpp;
4409 - offset ^= ((offset ^ (offset >> 1)) >> 3) & 64;
4410 - memcpy(dst_row, (const char *)src + offset, x);
4411 - }
4412 - }
4413 -}
4415 -fast_memcpy static void
4416 -memcpy_to_tiled_x__swizzle_9_11(const void *src, void *dst, int bpp,
4417 - int32_t src_stride, int32_t dst_stride,
4418 - int16_t src_x, int16_t src_y,
4419 - int16_t dst_x, int16_t dst_y,
4420 - uint16_t width, uint16_t height)
4421 -{
4422 - const unsigned tile_width = 512;
4423 - const unsigned tile_height = 8;
4424 - const unsigned tile_size = 4096;
4426 - const unsigned cpp = bpp / 8;
4427 - const unsigned stride_tiles = dst_stride / tile_width;
4428 - const unsigned swizzle_pixels = 64 / cpp;
4429 - const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
4430 - const unsigned tile_mask = (1 << tile_pixels) - 1;
4431 + if (src_x | src_y)
4432 + src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
4433 + assert(src_stride >= width * cpp);
4434 + src_stride -= width * cpp;
4436 - unsigned x, y;
4437 + while (height--) {
4438 + unsigned w = width * cpp;
4439 + uint8_t *tile_row = dst;
4441 - DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
4442 - __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
4443 + tile_row += dst_y / tile_height * dst_stride * tile_height;
4444 + tile_row += (dst_y & (tile_height-1)) * tile_width;
4445 + if (dst_x) {
4446 + tile_row += (dst_x >> tile_shift) * tile_size;
4447 + if (dst_x & tile_mask) {
4448 + const unsigned x = (dst_x & tile_mask) * cpp;
4449 + const unsigned len = min(tile_width - x, w);
4450 + memcpy(assume_misaligned(tile_row + x, tile_width, x), src, len);
4452 - src = (const uint8_t *)src + src_y * src_stride + src_x * cpp;
4454 - for (y = 0; y < height; ++y) {
4455 - const uint32_t dy = y + dst_y;
4456 - const uint32_t tile_row =
4457 - (dy / tile_height * stride_tiles * tile_size +
4458 - (dy & (tile_height-1)) * tile_width);
4459 - const uint8_t *src_row = (const uint8_t *)src + src_stride * y;
4460 - uint32_t dx = dst_x, offset;
4462 - x = width * cpp;
4463 - if (dx & (swizzle_pixels - 1)) {
4464 - const uint32_t swizzle_bound_pixels = ALIGN(dx + 1, swizzle_pixels);
4465 - const uint32_t length = min(dst_x + width, swizzle_bound_pixels) - dx;
4466 - offset = tile_row +
4467 - (dx >> tile_pixels) * tile_size +
4468 - (dx & tile_mask) * cpp;
4469 - offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
4470 - memcpy((char *)dst + offset, src_row, length * cpp);
4472 - src_row += length * cpp;
4473 - x -= length * cpp;
4474 - dx += length;
4475 + tile_row += tile_size;
4476 + src = (const uint8_t *)src + len;
4477 + w -= len;
4478 + }
4480 - while (x >= 64) {
4481 - offset = tile_row +
4482 - (dx >> tile_pixels) * tile_size +
4483 - (dx & tile_mask) * cpp;
4484 - offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
4486 - memcpy((char *)dst + offset, src_row, 64);
4487 + while (w >= tile_width) {
4488 + memcpy(assume_aligned(tile_row, tile_width),
4489 + src, tile_width);
4491 - src_row += 64;
4492 - x -= 64;
4493 - dx += swizzle_pixels;
4494 - }
4495 - if (x) {
4496 - offset = tile_row +
4497 - (dx >> tile_pixels) * tile_size +
4498 - (dx & tile_mask) * cpp;
4499 - offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
4500 - memcpy((char *)dst + offset, src_row, x);
4501 + tile_row += tile_size;
4502 + src = (const uint8_t *)src + tile_width;
4503 + w -= tile_width;
4505 + memcpy(assume_aligned(tile_row, tile_width), src, w);
4506 + src = (const uint8_t *)src + src_stride + w;
4507 + dst_y++;
4511 -fast_memcpy static void
4512 -memcpy_from_tiled_x__swizzle_9_11(const void *src, void *dst, int bpp,
4513 - int32_t src_stride, int32_t dst_stride,
4514 - int16_t src_x, int16_t src_y,
4515 - int16_t dst_x, int16_t dst_y,
4516 - uint16_t width, uint16_t height)
4517 +static fast_memcpy void
4518 +memcpy_from_tiled_x__gen2(const void *src, void *dst, int bpp,
4519 + int32_t src_stride, int32_t dst_stride,
4520 + int16_t src_x, int16_t src_y,
4521 + int16_t dst_x, int16_t dst_y,
4522 + uint16_t width, uint16_t height)
4524 - const unsigned tile_width = 512;
4525 - const unsigned tile_height = 8;
4526 - const unsigned tile_size = 4096;
4527 + const unsigned tile_width = 128;
4528 + const unsigned tile_height = 16;
4529 + const unsigned tile_size = 2048;
4531 const unsigned cpp = bpp / 8;
4532 - const unsigned stride_tiles = src_stride / tile_width;
4533 - const unsigned swizzle_pixels = 64 / cpp;
4534 - const unsigned tile_pixels = ffs(tile_width / cpp) - 1;
4535 - const unsigned tile_mask = (1 << tile_pixels) - 1;
4537 - unsigned x, y;
4538 + const unsigned tile_pixels = tile_width / cpp;
4539 + const unsigned tile_shift = ffs(tile_pixels) - 1;
4540 + const unsigned tile_mask = tile_pixels - 1;
4542 DBG(("%s(bpp=%d): src=(%d, %d), dst=(%d, %d), size=%dx%d, pitch=%d/%d\n",
4543 __FUNCTION__, bpp, src_x, src_y, dst_x, dst_y, width, height, src_stride, dst_stride));
4544 + assert(src != dst);
4546 - dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
4548 - for (y = 0; y < height; ++y) {
4549 - const uint32_t sy = y + src_y;
4550 - const uint32_t tile_row =
4551 - (sy / tile_height * stride_tiles * tile_size +
4552 - (sy & (tile_height-1)) * tile_width);
4553 - uint8_t *dst_row = (uint8_t *)dst + dst_stride * y;
4554 - uint32_t sx = src_x, offset;
4556 - x = width * cpp;
4557 - if (sx & (swizzle_pixels - 1)) {
4558 - const uint32_t swizzle_bound_pixels = ALIGN(sx + 1, swizzle_pixels);
4559 - const uint32_t length = min(src_x + width, swizzle_bound_pixels) - sx;
4560 - offset = tile_row +
4561 - (sx >> tile_pixels) * tile_size +
4562 - (sx & tile_mask) * cpp;
4563 - offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
4564 - memcpy(dst_row, (const char *)src + offset, length * cpp);
4566 - dst_row += length * cpp;
4567 - x -= length * cpp;
4568 - sx += length;
4569 - }
4570 - while (x >= 64) {
4571 - offset = tile_row +
4572 - (sx >> tile_pixels) * tile_size +
4573 - (sx & tile_mask) * cpp;
4574 - offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
4575 + if (dst_x | dst_y)
4576 + dst = (uint8_t *)dst + dst_y * dst_stride + dst_x * cpp;
4577 + assert(dst_stride >= width * cpp);
4578 + dst_stride -= width * cpp;
4580 + while (height--) {
4581 + unsigned w = width * cpp;
4582 + const uint8_t *tile_row = src;
4584 - memcpy(dst_row, (const char *)src + offset, 64);
4585 + tile_row += src_y / tile_height * src_stride * tile_height;
4586 + tile_row += (src_y & (tile_height-1)) * tile_width;
4587 + if (src_x) {
4588 + tile_row += (src_x >> tile_shift) * tile_size;
4589 + if (src_x & tile_mask) {
4590 + const unsigned x = (src_x & tile_mask) * cpp;
4591 + const unsigned len = min(tile_width - x, w);
4592 + memcpy(dst, assume_misaligned(tile_row + x, tile_width, x), len);
4594 - dst_row += 64;
4595 - x -= 64;
4596 - sx += swizzle_pixels;
4597 + tile_row += tile_size;
4598 + dst = (uint8_t *)dst + len;
4599 + w -= len;
4600 + }
4602 - if (x) {
4603 - offset = tile_row +
4604 - (sx >> tile_pixels) * tile_size +
4605 - (sx & tile_mask) * cpp;
4606 - offset ^= ((offset ^ (offset >> 2)) >> 3) & 64;
4607 - memcpy(dst_row, (const char *)src + offset, x);
4608 + while (w >= tile_width) {
4609 + memcpy(dst,
4610 + assume_aligned(tile_row, tile_width),
4611 + tile_width);
4613 + tile_row += tile_size;
4614 + dst = (uint8_t *)dst + tile_width;
4615 + w -= tile_width;
4617 + memcpy(dst, assume_aligned(tile_row, tile_width), w);
4618 + dst = (uint8_t *)dst + dst_stride + w;
4619 + src_y++;
4623 -void choose_memcpy_tiled_x(struct kgem *kgem, int swizzling)
4624 +void choose_memcpy_tiled_x(struct kgem *kgem, int swizzling, unsigned cpu)
4626 + if (kgem->gen < 030) {
4627 + if (swizzling == I915_BIT_6_SWIZZLE_NONE) {
4628 + DBG(("%s: gen2, no swizzling\n", __FUNCTION__));
4629 + kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__gen2;
4630 + kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__gen2;
4631 + } else
4632 + DBG(("%s: no detiling with swizzle functions for gen2\n", __FUNCTION__));
4633 + return;
4634 + }
4636 switch (swizzling) {
4637 default:
4638 DBG(("%s: unknown swizzling, %d\n", __FUNCTION__, swizzling));
4639 break;
4640 case I915_BIT_6_SWIZZLE_NONE:
4641 DBG(("%s: no swizzling\n", __FUNCTION__));
4642 - kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__swizzle_0;
4643 - kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__swizzle_0;
4644 +#if defined(sse2)
4645 + if (cpu & SSE2) {
4646 + kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__swizzle_0__sse2;
4647 + kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__swizzle_0__sse2;
4648 + kgem->memcpy_between_tiled_x = memcpy_between_tiled_x__swizzle_0__sse2;
4649 + } else
4650 +#endif
4651 + {
4652 + kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__swizzle_0;
4653 + kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__swizzle_0;
4654 + kgem->memcpy_between_tiled_x = memcpy_between_tiled_x__swizzle_0;
4655 + }
4656 break;
4657 case I915_BIT_6_SWIZZLE_9:
4658 DBG(("%s: 6^9 swizzling\n", __FUNCTION__));
4659 @@ -771,6 +1199,11 @@ void choose_memcpy_tiled_x(struct kgem *kgem, int swizzling)
4660 kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__swizzle_9_11;
4661 kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__swizzle_9_11;
4662 break;
4663 + case I915_BIT_6_SWIZZLE_9_10_11:
4664 + DBG(("%s: 6^9^10^11 swizzling\n", __FUNCTION__));
4665 + kgem->memcpy_to_tiled_x = memcpy_to_tiled_x__swizzle_9_10_11;
4666 + kgem->memcpy_from_tiled_x = memcpy_from_tiled_x__swizzle_9_10_11;
4667 + break;
4671 @@ -995,7 +1428,7 @@ memcpy_xor(const void *src, void *dst, int bpp,
4672 height = 1;
4675 -#if USE_SSE2
4676 +#if defined(sse2) && __x86_64__
4677 if (have_sse2()) {
4678 do {
4679 uint32_t *d = (uint32_t *)dst_bytes;
4680 @@ -1118,3 +1551,241 @@ memcpy_xor(const void *src, void *dst, int bpp,
4685 +#define BILINEAR_INTERPOLATION_BITS 4
4686 +static inline int
4687 +bilinear_weight(pixman_fixed_t x)
4688 +{
4689 + return (x >> (16 - BILINEAR_INTERPOLATION_BITS)) &
4690 + ((1 << BILINEAR_INTERPOLATION_BITS) - 1);
4691 +}
4693 +#if BILINEAR_INTERPOLATION_BITS <= 4
4694 +/* Inspired by Filter_32_opaque from Skia */
4695 +static inline uint32_t
4696 +bilinear_interpolation(uint32_t tl, uint32_t tr,
4697 + uint32_t bl, uint32_t br,
4698 + int distx, int disty)
4699 +{
4700 + int distxy, distxiy, distixy, distixiy;
4701 + uint32_t lo, hi;
4703 + distx <<= (4 - BILINEAR_INTERPOLATION_BITS);
4704 + disty <<= (4 - BILINEAR_INTERPOLATION_BITS);
4706 + distxy = distx * disty;
4707 + distxiy = (distx << 4) - distxy; /* distx * (16 - disty) */
4708 + distixy = (disty << 4) - distxy; /* disty * (16 - distx) */
4709 + distixiy =
4710 + 16 * 16 - (disty << 4) -
4711 + (distx << 4) + distxy; /* (16 - distx) * (16 - disty) */
4713 + lo = (tl & 0xff00ff) * distixiy;
4714 + hi = ((tl >> 8) & 0xff00ff) * distixiy;
4716 + lo += (tr & 0xff00ff) * distxiy;
4717 + hi += ((tr >> 8) & 0xff00ff) * distxiy;
4719 + lo += (bl & 0xff00ff) * distixy;
4720 + hi += ((bl >> 8) & 0xff00ff) * distixy;
4722 + lo += (br & 0xff00ff) * distxy;
4723 + hi += ((br >> 8) & 0xff00ff) * distxy;
4725 + return ((lo >> 8) & 0xff00ff) | (hi & ~0xff00ff);
4726 +}
4727 +#elif SIZEOF_LONG > 4
4728 +static inline uint32_t
4729 +bilinear_interpolation(uint32_t tl, uint32_t tr,
4730 + uint32_t bl, uint32_t br,
4731 + int distx, int disty)
4732 +{
4733 + uint64_t distxy, distxiy, distixy, distixiy;
4734 + uint64_t tl64, tr64, bl64, br64;
4735 + uint64_t f, r;
4737 + distx <<= (8 - BILINEAR_INTERPOLATION_BITS);
4738 + disty <<= (8 - BILINEAR_INTERPOLATION_BITS);
4740 + distxy = distx * disty;
4741 + distxiy = distx * (256 - disty);
4742 + distixy = (256 - distx) * disty;
4743 + distixiy = (256 - distx) * (256 - disty);
4745 + /* Alpha and Blue */
4746 + tl64 = tl & 0xff0000ff;
4747 + tr64 = tr & 0xff0000ff;
4748 + bl64 = bl & 0xff0000ff;
4749 + br64 = br & 0xff0000ff;
4751 + f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
4752 + r = f & 0x0000ff0000ff0000ull;
4754 + /* Red and Green */
4755 + tl64 = tl;
4756 + tl64 = ((tl64 << 16) & 0x000000ff00000000ull) | (tl64 & 0x0000ff00ull);
4758 + tr64 = tr;
4759 + tr64 = ((tr64 << 16) & 0x000000ff00000000ull) | (tr64 & 0x0000ff00ull);
4761 + bl64 = bl;
4762 + bl64 = ((bl64 << 16) & 0x000000ff00000000ull) | (bl64 & 0x0000ff00ull);
4764 + br64 = br;
4765 + br64 = ((br64 << 16) & 0x000000ff00000000ull) | (br64 & 0x0000ff00ull);
4767 + f = tl64 * distixiy + tr64 * distxiy + bl64 * distixy + br64 * distxy;
4768 + r |= ((f >> 16) & 0x000000ff00000000ull) | (f & 0xff000000ull);
4770 + return (uint32_t)(r >> 16);
4771 +}
4772 +#else
4773 +static inline uint32_t
4774 +bilinear_interpolation(uint32_t tl, uint32_t tr,
4775 + uint32_t bl, uint32_t br,
4776 + int distx, int disty)
4777 +{
4778 + int distxy, distxiy, distixy, distixiy;
4779 + uint32_t f, r;
4781 + distx <<= (8 - BILINEAR_INTERPOLATION_BITS);
4782 + disty <<= (8 - BILINEAR_INTERPOLATION_BITS);
4784 + distxy = distx * disty;
4785 + distxiy = (distx << 8) - distxy; /* distx * (256 - disty) */
4786 + distixy = (disty << 8) - distxy; /* disty * (256 - distx) */
4787 + distixiy =
4788 + 256 * 256 - (disty << 8) -
4789 + (distx << 8) + distxy; /* (256 - distx) * (256 - disty) */
4791 + /* Blue */
4792 + r = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy +
4793 + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy);
4795 + /* Green */
4796 + f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy +
4797 + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy);
4798 + r |= f & 0xff000000;
4800 + tl >>= 16;
4801 + tr >>= 16;
4802 + bl >>= 16;
4803 + br >>= 16;
4804 + r >>= 16;
4806 + /* Red */
4807 + f = ((tl & 0x000000ff) * distixiy + (tr & 0x000000ff) * distxiy +
4808 + (bl & 0x000000ff) * distixy + (br & 0x000000ff) * distxy);
4809 + r |= f & 0x00ff0000;
4811 + /* Alpha */
4812 + f = ((tl & 0x0000ff00) * distixiy + (tr & 0x0000ff00) * distxiy +
4813 + (bl & 0x0000ff00) * distixy + (br & 0x0000ff00) * distxy);
4814 + r |= f & 0xff000000;
4816 + return r;
4817 +}
4818 +#endif
4820 +static inline uint32_t convert_pixel(const uint8_t *p, int x)
4821 +{
4822 + return ((uint32_t *)p)[x];
4823 +}
4825 +fast void
4826 +affine_blt(const void *src, void *dst, int bpp,
4827 + int16_t src_x, int16_t src_y,
4828 + int16_t src_width, int16_t src_height,
4829 + int32_t src_stride,
4830 + int16_t dst_x, int16_t dst_y,
4831 + uint16_t dst_width, uint16_t dst_height,
4832 + int32_t dst_stride,
4833 + const struct pixman_f_transform *t)
4834 +{
4835 + static const uint8_t zero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
4836 + const pixman_fixed_t ux = pixman_double_to_fixed(t->m[0][0]);
4837 + const pixman_fixed_t uy = pixman_double_to_fixed(t->m[1][0]);
4838 + int i, j;
4840 + assert(bpp == 32);
4842 + for (j = 0; j < dst_height; j++) {
4843 + pixman_fixed_t x, y;
4844 + struct pixman_f_vector v;
4845 + uint32_t *b;
4847 + /* reference point is the center of the pixel */
4848 + v.v[0] = dst_x + 0.5;
4849 + v.v[1] = dst_y + j + 0.5;
4850 + v.v[2] = 1.0;
4852 + pixman_f_transform_point_3d(t, &v);
4854 + x = pixman_double_to_fixed(v.v[0]);
4855 + x += pixman_int_to_fixed(src_x - dst_x);
4856 + y = pixman_double_to_fixed(v.v[1]);
4857 + y += pixman_int_to_fixed(src_y - dst_y);
4859 + b = (uint32_t*)((uint8_t *)dst + (dst_y + j) * dst_stride + dst_x * bpp / 8);
4860 + for (i = 0; i < dst_width; i++) {
4861 + const uint8_t *row1;
4862 + const uint8_t *row2;
4863 + int x1, y1, x2, y2;
4864 + uint32_t tl, tr, bl, br;
4865 + int32_t fx, fy;
4867 + x1 = x - pixman_fixed_1/2;
4868 + y1 = y - pixman_fixed_1/2;
4870 + fx = bilinear_weight(x1);
4871 + fy = bilinear_weight(y1);
4873 + x1 = pixman_fixed_to_int(x1);
4874 + x2 = x1 + 1;
4875 + y1 = pixman_fixed_to_int(y1);
4876 + y2 = y1 + 1;
4878 + if (x1 >= src_width || x2 < 0 ||
4879 + y1 >= src_height || y2 < 0) {
4880 + b[i] = 0;
4881 + goto next;
4882 + }
4884 + if (y2 == 0) {
4885 + row1 = zero;
4886 + } else {
4887 + row1 = (uint8_t *)src + src_stride * y1;
4888 + row1 += bpp / 8 * x1;
4889 + }
4891 + if (y1 == src_height - 1) {
4892 + row2 = zero;
4893 + } else {
4894 + row2 = (uint8_t *)src + src_stride * y2;
4895 + row2 += bpp / 8 * x1;
4896 + }
4898 + if (x2 == 0) {
4899 + tl = 0;
4900 + bl = 0;
4901 + } else {
4902 + tl = convert_pixel(row1, 0);
4903 + bl = convert_pixel(row2, 0);
4904 + }
4906 + if (x1 == src_width - 1) {
4907 + tr = 0;
4908 + br = 0;
4909 + } else {
4910 + tr = convert_pixel(row1, 1);
4911 + br = convert_pixel(row2, 1);
4912 + }
4914 + b[i] = bilinear_interpolation(tl, tr, bl, br, fx, fy);
4916 +next:
4917 + x += ux;
4918 + y += uy;
4919 + }
4920 + }
4921 +}
4922 diff --git a/src/sna/brw/brw_eu_emit.c b/src/sna/brw/brw_eu_emit.c
4923 index 00c984d9..154f939a 100644
4924 --- a/src/sna/brw/brw_eu_emit.c
4925 +++ b/src/sna/brw/brw_eu_emit.c
4926 @@ -178,7 +178,7 @@ validate_reg(struct brw_instruction *insn, struct brw_reg reg)
4929 if (reg.file == BRW_ARCHITECTURE_REGISTER_FILE &&
4930 - reg.file == BRW_ARF_NULL)
4931 + reg.nr == BRW_ARF_NULL)
4932 return;
4934 assert(reg.hstride >= 0 && reg.hstride < ARRAY_SIZE(hstride_for_reg));
4935 @@ -700,7 +700,7 @@ push_if_stack(struct brw_compile *p, struct brw_instruction *inst)
4937 * When the matching 'else' instruction is reached (presumably by
4938 * countdown of the instruction count patched in by our ELSE/ENDIF
4939 - * functions), the relevent flags are inverted.
4940 + * functions), the relevant flags are inverted.
4942 * When the matching 'endif' instruction is reached, the flags are
4943 * popped off. If the stack is now empty, normal execution resumes.
4944 diff --git a/src/sna/compiler.h b/src/sna/compiler.h
4945 index ff412179..0f3775ec 100644
4946 --- a/src/sna/compiler.h
4947 +++ b/src/sna/compiler.h
4948 @@ -39,6 +39,7 @@
4949 #define pure __attribute__((pure))
4950 #define tightly_packed __attribute__((__packed__))
4951 #define flatten __attribute__((flatten))
4952 +#define nonnull __attribute__((nonnull))
4953 #define page_aligned __attribute__((aligned(4096)))
4954 #else
4955 #define likely(expr) (expr)
4956 @@ -51,18 +52,15 @@
4957 #define pure
4958 #define tighly_packed
4959 #define flatten
4960 +#define nonnull
4961 #define page_aligned
4962 #endif
4964 #define HAS_GCC(major, minor) defined(__GNUC__) && (__GNUC__ > (major) || __GNUC__ == (major) && __GNUC_MINOR__ >= (minor))
4966 #if HAS_GCC(4, 5)
4967 -#define sse2 __attribute__((target("sse2,fpmath=sse")))
4968 -#define sse4_2 __attribute__((target("sse4.2,sse2,fpmath=sse")))
4969 -#endif
4971 -#if HAS_GCC(4, 7)
4972 -#define avx2 __attribute__((target("avx2,sse4.2,sse2,fpmath=sse")))
4973 +#define sse2 fast __attribute__((target("sse2,fpmath=sse")))
4974 +#define sse4_2 fast __attribute__((target("sse4.2,sse2,fpmath=sse")))
4975 #endif
4977 #if HAS_GCC(4, 6) && defined(__OPTIMIZE__)
4978 @@ -71,10 +69,17 @@
4979 #define fast
4980 #endif
4982 -#if HAS_GCC(4, 6) && defined(__OPTIMIZE__)
4983 -#define fast_memcpy __attribute__((optimize("Ofast"))) __attribute__((target("inline-all-stringops")))
4984 -#elif HAS_GCC(4, 5) && defined(__OPTIMIZE__)
4985 -#define fast_memcpy __attribute__((target("inline-all-stringops")))
4986 +#if HAS_GCC(4, 7)
4987 +#define avx2 fast __attribute__((target("avx2,avx,sse4.2,sse2,fpmath=sse")))
4988 +#define assume_aligned(ptr, align) __builtin_assume_aligned((ptr), (align))
4989 +#define assume_misaligned(ptr, align, offset) __builtin_assume_aligned((ptr), (align), (offset))
4990 +#else
4991 +#define assume_aligned(ptr, align) (ptr)
4992 +#define assume_misaligned(ptr, align, offset) (ptr)
4993 +#endif
4995 +#if HAS_GCC(4, 5) && defined(__OPTIMIZE__)
4996 +#define fast_memcpy fast __attribute__((target("inline-all-stringops")))
4997 #else
4998 #define fast_memcpy
4999 #endif
5000 diff --git a/src/sna/fb/fb.h b/src/sna/fb/fb.h
5001 index 8bf9008a..90431747 100644
5002 --- a/src/sna/fb/fb.h
5003 +++ b/src/sna/fb/fb.h
5004 @@ -24,10 +24,6 @@
5005 #ifndef FB_H
5006 #define FB_H
5008 -#ifdef HAVE_CONFIG_H
5009 -#include "config.h"
5010 -#endif
5012 #include <xorg-server.h>
5013 #include <servermd.h>
5014 #include <gcstruct.h>
5015 diff --git a/src/sna/fb/fbimage.c b/src/sna/fb/fbimage.c
5016 index 5af23890..cc81c85b 100644
5017 --- a/src/sna/fb/fbimage.c
5018 +++ b/src/sna/fb/fbimage.c
5019 @@ -229,13 +229,19 @@ fbGetImage(DrawablePtr drawable,
5020 FbBits pm;
5022 pm = fbReplicatePixel(planeMask, srcBpp);
5024 dstStride = PixmapBytePad(w, drawable->depth);
5025 - if (pm != FB_ALLONES)
5026 - memset(d, 0, dstStride * h);
5027 dstStride /= sizeof(FbStip);
5029 fbBltStip((FbStip *)(src + (y + srcYoff) * srcStride), srcStride,
5030 (x + srcXoff) * srcBpp,
5031 - dst, dstStride, 0, w * srcBpp, h, GXcopy, pm, srcBpp);
5032 + dst, dstStride, 0, w * srcBpp, h, GXcopy, FB_ALLONES, srcBpp);
5034 + if (pm != FB_ALLONES) {
5035 + int i = dstStride * h;
5036 + while (i--)
5037 + *dst++ &= pm;
5038 + }
5039 } else {
5040 dstStride = BitmapBytePad(w) / sizeof(FbStip);
5041 fbBltPlane(src + (y + srcYoff) * srcStride,
5042 diff --git a/src/sna/fb/fbpict.h b/src/sna/fb/fbpict.h
5043 index 932032f9..20877777 100644
5044 --- a/src/sna/fb/fbpict.h
5045 +++ b/src/sna/fb/fbpict.h
5046 @@ -24,10 +24,6 @@
5047 #ifndef FBPICT_H
5048 #define FBPICT_H
5050 -#ifdef HAVE_CONFIG_H
5051 -#include "config.h"
5052 -#endif
5054 #include <xorg-server.h>
5055 #include <picturestr.h>
5057 diff --git a/src/sna/gen2_render.c b/src/sna/gen2_render.c
5058 index 1104f462..49ad16a3 100644
5059 --- a/src/sna/gen2_render.c
5060 +++ b/src/sna/gen2_render.c
5061 @@ -35,6 +35,7 @@
5062 #include "sna_reg.h"
5063 #include "sna_render.h"
5064 #include "sna_render_inline.h"
5065 +#include "sna_video.h"
5067 #include "gen2_render.h"
5069 @@ -48,6 +49,7 @@
5071 #define MAX_3D_SIZE 2048
5072 #define MAX_3D_PITCH 8192
5073 +#define MAX_INLINE (1 << 18)
5075 #define BATCH(v) batch_emit(sna, v)
5076 #define BATCH_F(v) batch_emit_float(sna, v)
5077 @@ -596,39 +598,43 @@ gen2_get_batch(struct sna *sna, const struct sna_composite_op *op)
5078 gen2_emit_invariant(sna);
5081 -static void gen2_emit_target(struct sna *sna, const struct sna_composite_op *op)
5082 +static void gen2_emit_target(struct sna *sna,
5083 + struct kgem_bo *bo,
5084 + int width,
5085 + int height,
5086 + int format)
5088 - assert(!too_large(op->dst.width, op->dst.height));
5089 - assert(op->dst.bo->pitch >= 8 && op->dst.bo->pitch <= MAX_3D_PITCH);
5090 + assert(!too_large(width, height));
5091 + assert(bo->pitch >= 8 && bo->pitch <= MAX_3D_PITCH);
5092 assert(sna->render.vertex_offset == 0);
5094 - assert(op->dst.bo->unique_id);
5095 - if (sna->render_state.gen2.target == op->dst.bo->unique_id) {
5096 - kgem_bo_mark_dirty(op->dst.bo);
5097 + assert(bo->unique_id);
5098 + if (sna->render_state.gen2.target == bo->unique_id) {
5099 + kgem_bo_mark_dirty(bo);
5100 return;
5103 BATCH(_3DSTATE_BUF_INFO_CMD);
5104 BATCH(BUF_3D_ID_COLOR_BACK |
5105 - gen2_buf_tiling(op->dst.bo->tiling) |
5106 - BUF_3D_PITCH(op->dst.bo->pitch));
5107 + gen2_buf_tiling(bo->tiling) |
5108 + BUF_3D_PITCH(bo->pitch));
5109 BATCH(kgem_add_reloc(&sna->kgem, sna->kgem.nbatch,
5110 - op->dst.bo,
5111 + bo,
5112 I915_GEM_DOMAIN_RENDER << 16 |
5113 I915_GEM_DOMAIN_RENDER,
5114 0));
5116 BATCH(_3DSTATE_DST_BUF_VARS_CMD);
5117 - BATCH(gen2_get_dst_format(op->dst.format));
5118 + BATCH(gen2_get_dst_format(format));
5120 BATCH(_3DSTATE_DRAW_RECT_CMD);
5121 BATCH(0);
5122 BATCH(0); /* ymin, xmin */
5123 - BATCH(DRAW_YMAX(op->dst.height - 1) |
5124 - DRAW_XMAX(op->dst.width - 1));
5125 + BATCH(DRAW_YMAX(height - 1) |
5126 + DRAW_XMAX(width - 1));
5127 BATCH(0); /* yorig, xorig */
5129 - sna->render_state.gen2.target = op->dst.bo->unique_id;
5130 + sna->render_state.gen2.target = bo->unique_id;
5133 static void gen2_disable_logic_op(struct sna *sna)
5134 @@ -701,7 +707,11 @@ static void gen2_emit_composite_state(struct sna *sna,
5135 kgem_clear_dirty(&sna->kgem);
5138 - gen2_emit_target(sna, op);
5139 + gen2_emit_target(sna,
5140 + op->dst.bo,
5141 + op->dst.width,
5142 + op->dst.height,
5143 + op->dst.format);
5145 unwind = sna->kgem.nbatch;
5146 BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
5147 @@ -1190,7 +1200,13 @@ inline static int gen2_get_rectangles(struct sna *sna,
5148 sna->render.vertex_offset = sna->kgem.nbatch;
5149 BATCH(PRIM3D_INLINE | PRIM3D_RECTLIST);
5151 - }
5153 + need = 0;
5154 + } else
5155 + need = sna->kgem.nbatch - sna->render.vertex_offset;
5157 + if (rem > MAX_INLINE - need)
5158 + rem = MAX_INLINE -need;
5160 if (want > 1 && want * size > rem)
5161 want = rem / size;
5162 @@ -1572,12 +1588,12 @@ gen2_composite_picture(struct sna *sna,
5163 if (channel->repeat &&
5164 (x >= 0 &&
5165 y >= 0 &&
5166 - x + w < pixmap->drawable.width &&
5167 - y + h < pixmap->drawable.height)) {
5168 + x + w <= pixmap->drawable.width &&
5169 + y + h <= pixmap->drawable.height)) {
5170 struct sna_pixmap *priv = sna_pixmap(pixmap);
5171 if (priv && priv->clear) {
5172 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
5173 - return gen2_composite_solid_init(sna, channel, priv->clear_color);
5174 + return gen2_composite_solid_init(sna, channel, solid_color(picture->format, priv->clear_color));
5177 } else
5178 @@ -1619,7 +1635,9 @@ gen2_composite_set_target(struct sna *sna,
5179 } else
5180 sna_render_picture_extents(dst, &box);
5182 - hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
5183 + hint = PREFER_GPU | RENDER_GPU;
5184 + if (!need_tiling(sna, op->dst.width, op->dst.height))
5185 + hint |= FORCE_GPU;
5186 if (!partial) {
5187 hint |= IGNORE_DAMAGE;
5188 if (w == op->dst.width && h == op->dst.height)
5189 @@ -2423,7 +2441,11 @@ static void gen2_emit_composite_spans_state(struct sna *sna,
5190 uint32_t unwind;
5192 gen2_get_batch(sna, &op->base);
5193 - gen2_emit_target(sna, &op->base);
5194 + gen2_emit_target(sna,
5195 + op->base.dst.bo,
5196 + op->base.dst.width,
5197 + op->base.dst.height,
5198 + op->base.dst.format);
5200 unwind = sna->kgem.nbatch;
5201 BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
5202 @@ -2706,7 +2728,11 @@ static void gen2_emit_fill_composite_state(struct sna *sna,
5203 uint32_t ls1;
5205 gen2_get_batch(sna, op);
5206 - gen2_emit_target(sna, op);
5207 + gen2_emit_target(sna,
5208 + op->dst.bo,
5209 + op->dst.width,
5210 + op->dst.height,
5211 + op->dst.format);
5213 ls1 = sna->kgem.nbatch;
5214 BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
5215 @@ -2868,7 +2894,11 @@ static void gen2_emit_fill_state(struct sna *sna,
5216 uint32_t ls1;
5218 gen2_get_batch(sna, op);
5219 - gen2_emit_target(sna, op);
5220 + gen2_emit_target(sna,
5221 + op->dst.bo,
5222 + op->dst.width,
5223 + op->dst.height,
5224 + op->dst.format);
5226 ls1 = sna->kgem.nbatch;
5227 BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
5228 @@ -3102,6 +3132,276 @@ gen2_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
5231 static void
5232 +gen2_emit_video_state(struct sna *sna,
5233 + struct sna_video *video,
5234 + struct sna_video_frame *frame,
5235 + PixmapPtr pixmap,
5236 + struct kgem_bo *dst_bo,
5237 + int width, int height,
5238 + bool bilinear)
5239 +{
5240 + uint32_t ms1, v, unwind;
5242 + gen2_emit_target(sna, dst_bo, width, height,
5243 + sna_format_for_depth(pixmap->drawable.depth));
5245 + unwind = sna->kgem.nbatch;
5246 + BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
5247 + I1_LOAD_S(2) | I1_LOAD_S(3) | I1_LOAD_S(8) | 2);
5248 + BATCH(1 << 12);
5249 + BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY);
5250 + BATCH(S8_ENABLE_COLOR_BUFFER_WRITE);
5251 + if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls1 + 1,
5252 + sna->kgem.batch + unwind + 1,
5253 + 3 * sizeof(uint32_t)) == 0)
5254 + sna->kgem.nbatch = unwind;
5255 + else
5256 + sna->render_state.gen2.ls1 = unwind;
5258 + gen2_disable_logic_op(sna);
5260 + unwind = sna->kgem.nbatch;
5261 + BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
5262 + LOAD_TEXTURE_BLEND_STAGE(0) | 1);
5263 + BATCH(TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OUTPUT_WRITE_CURRENT |
5264 + TB0C_OP_ARG1 | TB0C_ARG1_SEL_TEXEL0);
5265 + BATCH(TB0A_RESULT_SCALE_1X | TB0A_OUTPUT_WRITE_CURRENT |
5266 + TB0A_OP_ARG1 | TB0A_ARG1_SEL_ONE);
5267 + if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls2 + 1,
5268 + sna->kgem.batch + unwind + 1,
5269 + 2 * sizeof(uint32_t)) == 0)
5270 + sna->kgem.nbatch = unwind;
5271 + else
5272 + sna->render_state.gen2.ls2 = unwind;
5274 + BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 | LOAD_TEXTURE_MAP(0) | 4);
5275 + BATCH(kgem_add_reloc(&sna->kgem, sna->kgem.nbatch,
5276 + frame->bo,
5277 + I915_GEM_DOMAIN_SAMPLER << 16,
5278 + 0));
5279 + ms1 = MAPSURF_422 | TM0S1_COLORSPACE_CONVERSION;
5280 + switch (frame->id) {
5281 + case FOURCC_YUY2:
5282 + ms1 |= MT_422_YCRCB_NORMAL;
5283 + break;
5284 + case FOURCC_UYVY:
5285 + ms1 |= MT_422_YCRCB_SWAPY;
5286 + break;
5287 + }
5288 + BATCH(((frame->height - 1) << TM0S1_HEIGHT_SHIFT) |
5289 + ((frame->width - 1) << TM0S1_WIDTH_SHIFT) |
5290 + ms1 |
5291 + gen2_sampler_tiling_bits(frame->bo->tiling));
5292 + BATCH((frame->pitch[0] / 4 - 1) << TM0S2_PITCH_SHIFT | TM0S2_MAP_2D);
5293 + if (bilinear)
5294 + BATCH(FILTER_LINEAR << TM0S3_MAG_FILTER_SHIFT |
5295 + FILTER_LINEAR << TM0S3_MIN_FILTER_SHIFT |
5296 + MIPFILTER_NONE << TM0S3_MIP_FILTER_SHIFT);
5297 + else
5298 + BATCH(FILTER_NEAREST << TM0S3_MAG_FILTER_SHIFT |
5299 + FILTER_NEAREST << TM0S3_MIN_FILTER_SHIFT |
5300 + MIPFILTER_NONE << TM0S3_MIP_FILTER_SHIFT);
5301 + BATCH(0); /* default color */
5303 + BATCH(_3DSTATE_MAP_COORD_SET_CMD | TEXCOORD_SET(0) |
5304 + ENABLE_TEXCOORD_PARAMS | TEXCOORDS_ARE_NORMAL | TEXCOORDTYPE_CARTESIAN |
5305 + ENABLE_ADDR_V_CNTL | TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_CLAMP) |
5306 + ENABLE_ADDR_U_CNTL | TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_CLAMP));
5308 + v = _3DSTATE_VERTEX_FORMAT_2_CMD | TEXCOORDFMT_2D;
5309 + if (sna->render_state.gen2.vft != v) {
5310 + BATCH(v);
5311 + sna->render_state.gen2.vft = v;
5312 + }
5313 +}
5315 +static void
5316 +gen2_video_get_batch(struct sna *sna, struct kgem_bo *bo)
5317 +{
5318 + kgem_set_mode(&sna->kgem, KGEM_RENDER, bo);
5320 + if (!kgem_check_batch(&sna->kgem, 120) ||
5321 + !kgem_check_reloc(&sna->kgem, 4) ||
5322 + !kgem_check_exec(&sna->kgem, 2)) {
5323 + _kgem_submit(&sna->kgem);
5324 + _kgem_set_mode(&sna->kgem, KGEM_RENDER);
5325 + }
5327 + if (sna->render_state.gen2.need_invariant)
5328 + gen2_emit_invariant(sna);
5329 +}
5331 +static int
5332 +gen2_get_inline_rectangles(struct sna *sna, int want, int floats_per_vertex)
5333 +{
5334 + int size = floats_per_vertex * 3;
5335 + int rem = batch_space(sna) - 1;
5337 + if (rem > MAX_INLINE)
5338 + rem = MAX_INLINE;
5340 + if (size * want > rem)
5341 + want = rem / size;
5343 + return want;
5344 +}
5346 +static bool
5347 +gen2_render_video(struct sna *sna,
5348 + struct sna_video *video,
5349 + struct sna_video_frame *frame,
5350 + RegionPtr dstRegion,
5351 + PixmapPtr pixmap)
5352 +{
5353 + struct sna_pixmap *priv = sna_pixmap(pixmap);
5354 + const BoxRec *pbox = region_rects(dstRegion);
5355 + int nbox = region_num_rects(dstRegion);
5356 + int dst_width = dstRegion->extents.x2 - dstRegion->extents.x1;
5357 + int dst_height = dstRegion->extents.y2 - dstRegion->extents.y1;
5358 + int src_width = frame->src.x2 - frame->src.x1;
5359 + int src_height = frame->src.y2 - frame->src.y1;
5360 + float src_offset_x, src_offset_y;
5361 + float src_scale_x, src_scale_y;
5362 + int pix_xoff, pix_yoff;
5363 + struct kgem_bo *dst_bo;
5364 + bool bilinear;
5365 + int copy = 0;
5367 + DBG(("%s: src:%dx%d (frame:%dx%d) -> dst:%dx%d\n", __FUNCTION__,
5368 + src_width, src_height, frame->width, frame->height, dst_width, dst_height));
5370 + assert(priv->gpu_bo);
5371 + dst_bo = priv->gpu_bo;
5373 + bilinear = src_width != dst_width || src_height != dst_height;
5375 + src_scale_x = (float)src_width / dst_width / frame->width;
5376 + src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
5378 + src_scale_y = (float)src_height / dst_height / frame->height;
5379 + src_offset_y = (float)frame->src.y1 / frame->height - dstRegion->extents.y1 * src_scale_y;
5380 + DBG(("%s: src offset (%f, %f), scale (%f, %f)\n",
5381 + __FUNCTION__, src_offset_x, src_offset_y, src_scale_x, src_scale_y));
5383 + if (too_large(pixmap->drawable.width, pixmap->drawable.height) ||
5384 + dst_bo->pitch > MAX_3D_PITCH) {
5385 + int bpp = pixmap->drawable.bitsPerPixel;
5387 + if (too_large(dst_width, dst_height))
5388 + return false;
5390 + dst_bo = kgem_create_2d(&sna->kgem,
5391 + dst_width, dst_height, bpp,
5392 + kgem_choose_tiling(&sna->kgem,
5393 + I915_TILING_X,
5394 + dst_width, dst_height, bpp),
5395 + 0);
5396 + if (!dst_bo)
5397 + return false;
5399 + pix_xoff = -dstRegion->extents.x1;
5400 + pix_yoff = -dstRegion->extents.y1;
5401 + copy = 1;
5402 + } else {
5403 + /* Set up the offset for translating from the given region
5404 + * (in screen coordinates) to the backing pixmap.
5405 + */
5406 +#ifdef COMPOSITE
5407 + pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
5408 + pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
5409 +#else
5410 + pix_xoff = 0;
5411 + pix_yoff = 0;
5412 +#endif
5414 + dst_width = pixmap->drawable.width;
5415 + dst_height = pixmap->drawable.height;
5416 + }
5418 + gen2_video_get_batch(sna, dst_bo);
5419 + gen2_emit_video_state(sna, video, frame, pixmap,
5420 + dst_bo, dst_width, dst_height, bilinear);
5421 + do {
5422 + int nbox_this_time = gen2_get_inline_rectangles(sna, nbox, 4);
5423 + if (nbox_this_time == 0) {
5424 + gen2_video_get_batch(sna, dst_bo);
5425 + gen2_emit_video_state(sna, video, frame, pixmap,
5426 + dst_bo, dst_width, dst_height, bilinear);
5427 + nbox_this_time = gen2_get_inline_rectangles(sna, nbox, 4);
5428 + assert(nbox_this_time);
5429 + }
5430 + nbox -= nbox_this_time;
5432 + BATCH(PRIM3D_INLINE | PRIM3D_RECTLIST |
5433 + ((12 * nbox_this_time) - 1));
5434 + do {
5435 + int box_x1 = pbox->x1;
5436 + int box_y1 = pbox->y1;
5437 + int box_x2 = pbox->x2;
5438 + int box_y2 = pbox->y2;
5440 + pbox++;
5442 + DBG(("%s: dst (%d, %d), (%d, %d) + (%d, %d); src (%f, %f), (%f, %f)\n",
5443 + __FUNCTION__, box_x1, box_y1, box_x2, box_y2, pix_xoff, pix_yoff,
5444 + box_x1 * src_scale_x + src_offset_x,
5445 + box_y1 * src_scale_y + src_offset_y,
5446 + box_x2 * src_scale_x + src_offset_x,
5447 + box_y2 * src_scale_y + src_offset_y));
5449 + /* bottom right */
5450 + BATCH_F(box_x2 + pix_xoff);
5451 + BATCH_F(box_y2 + pix_yoff);
5452 + BATCH_F(box_x2 * src_scale_x + src_offset_x);
5453 + BATCH_F(box_y2 * src_scale_y + src_offset_y);
5455 + /* bottom left */
5456 + BATCH_F(box_x1 + pix_xoff);
5457 + BATCH_F(box_y2 + pix_yoff);
5458 + BATCH_F(box_x1 * src_scale_x + src_offset_x);
5459 + BATCH_F(box_y2 * src_scale_y + src_offset_y);
5461 + /* top left */
5462 + BATCH_F(box_x1 + pix_xoff);
5463 + BATCH_F(box_y1 + pix_yoff);
5464 + BATCH_F(box_x1 * src_scale_x + src_offset_x);
5465 + BATCH_F(box_y1 * src_scale_y + src_offset_y);
5466 + } while (--nbox_this_time);
5467 + } while (nbox);
5469 + if (copy) {
5470 +#ifdef COMPOSITE
5471 + pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
5472 + pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
5473 +#else
5474 + pix_xoff = 0;
5475 + pix_yoff = 0;
5476 +#endif
5477 + sna_blt_copy_boxes(sna, GXcopy,
5478 + dst_bo, -dstRegion->extents.x1, -dstRegion->extents.y1,
5479 + priv->gpu_bo, pix_xoff, pix_yoff,
5480 + pixmap->drawable.bitsPerPixel,
5481 + region_rects(dstRegion),
5482 + region_num_rects(dstRegion));
5484 + kgem_bo_destroy(&sna->kgem, dst_bo);
5485 + }
5487 + if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
5488 + if ((pix_xoff | pix_yoff) == 0) {
5489 + sna_damage_add(&priv->gpu_damage, dstRegion);
5490 + } else {
5491 + sna_damage_add_boxes(&priv->gpu_damage,
5492 + region_rects(dstRegion),
5493 + region_num_rects(dstRegion),
5494 + pix_xoff, pix_yoff);
5495 + }
5496 + }
5498 + return true;
5499 +}
5501 +static void
5502 gen2_render_copy_setup_source(struct sna_composite_channel *channel,
5503 const DrawableRec *draw,
5504 struct kgem_bo *bo)
5505 @@ -3176,7 +3476,11 @@ static void gen2_emit_copy_state(struct sna *sna, const struct sna_composite_op
5506 PIPELINE_FLUSH_TEXTURE_CACHE);
5507 kgem_clear_dirty(&sna->kgem);
5509 - gen2_emit_target(sna, op);
5510 + gen2_emit_target(sna,
5511 + op->dst.bo,
5512 + op->dst.width,
5513 + op->dst.height,
5514 + op->dst.format);
5516 ls1 = sna->kgem.nbatch;
5517 BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
5518 @@ -3511,7 +3815,7 @@ const char *gen2_render_init(struct sna *sna, const char *backend)
5519 render->copy = gen2_render_copy;
5520 render->copy_boxes = gen2_render_copy_boxes;
5522 - /* XXX YUV color space conversion for video? */
5523 + render->video = gen2_render_video;
5525 render->reset = gen2_render_reset;
5526 render->flush = gen2_render_flush;
5527 diff --git a/src/sna/gen3_render.c b/src/sna/gen3_render.c
5528 index 78289f00..4459a562 100644
5529 --- a/src/sna/gen3_render.c
5530 +++ b/src/sna/gen3_render.c
5531 @@ -448,14 +448,14 @@ gen3_emit_composite_boxes_constant(const struct sna_composite_op *op,
5532 float *v)
5534 do {
5535 - v[0] = box->x2;
5536 - v[1] = box->y2;
5537 + v[0] = box->x2 + op->dst.x;
5538 + v[1] = box->y2 + op->dst.y;
5540 - v[2] = box->x1;
5541 - v[3] = box->y2;
5542 + v[2] = box->x1 + op->dst.x;
5543 + v[3] = box->y2 + op->dst.y;
5545 - v[4] = box->x1;
5546 - v[5] = box->y1;
5547 + v[4] = box->x1 + op->dst.x;
5548 + v[5] = box->y1 + op->dst.y;
5550 box++;
5551 v += 6;
5552 @@ -494,18 +494,18 @@ gen3_emit_composite_boxes_identity_gradient(const struct sna_composite_op *op,
5553 float *v)
5555 do {
5556 - v[0] = box->x2;
5557 - v[1] = box->y2;
5558 + v[0] = box->x2 + op->dst.x;
5559 + v[1] = box->y2 + op->dst.y;
5560 v[2] = box->x2 + op->src.offset[0];
5561 v[3] = box->y2 + op->src.offset[1];
5563 - v[4] = box->x1;
5564 - v[5] = box->y2;
5565 + v[4] = box->x1 + op->dst.x;
5566 + v[5] = box->y2 + op->dst.y;
5567 v[6] = box->x1 + op->src.offset[0];
5568 v[7] = box->y2 + op->src.offset[1];
5570 - v[8] = box->x1;
5571 - v[9] = box->y1;
5572 + v[8] = box->x1 + op->dst.x;
5573 + v[9] = box->y1 + op->dst.y;
5574 v[10] = box->x1 + op->src.offset[0];
5575 v[11] = box->y1 + op->src.offset[1];
5577 @@ -531,6 +531,7 @@ gen3_emit_composite_primitive_affine_gradient(struct sna *sna,
5579 v = sna->render.vertices + sna->render.vertex_used;
5580 sna->render.vertex_used += 12;
5581 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5583 v[0] = dst_x + r->width;
5584 v[1] = dst_y + r->height;
5585 @@ -559,22 +560,22 @@ gen3_emit_composite_boxes_affine_gradient(const struct sna_composite_op *op,
5586 const PictTransform *transform = op->src.transform;
5588 do {
5589 - v[0] = box->x2;
5590 - v[1] = box->y2;
5591 + v[0] = box->x2 + op->dst.x;
5592 + v[1] = box->y2 + op->dst.y;
5593 _sna_get_transformed_scaled(box->x2 + op->src.offset[0],
5594 box->y2 + op->src.offset[1],
5595 transform, op->src.scale,
5596 &v[2], &v[3]);
5598 - v[4] = box->x1;
5599 - v[5] = box->y2;
5600 + v[4] = box->x1 + op->dst.x;
5601 + v[5] = box->y2 + op->dst.y;
5602 _sna_get_transformed_scaled(box->x1 + op->src.offset[0],
5603 box->y2 + op->src.offset[1],
5604 transform, op->src.scale,
5605 &v[6], &v[7]);
5607 - v[8] = box->x1;
5608 - v[9] = box->y1;
5609 + v[8] = box->x1 + op->dst.x;
5610 + v[9] = box->y1 + op->dst.y;
5611 _sna_get_transformed_scaled(box->x1 + op->src.offset[0],
5612 box->y1 + op->src.offset[1],
5613 transform, op->src.scale,
5614 @@ -596,6 +597,7 @@ gen3_emit_composite_primitive_identity_source(struct sna *sna,
5616 v = sna->render.vertices + sna->render.vertex_used;
5617 sna->render.vertex_used += 12;
5618 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5620 v[8] = v[4] = r->dst.x + op->dst.x;
5621 v[0] = v[4] + w;
5622 @@ -643,6 +645,7 @@ gen3_emit_composite_primitive_identity_source_no_offset(struct sna *sna,
5624 v = sna->render.vertices + sna->render.vertex_used;
5625 sna->render.vertex_used += 12;
5626 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5628 v[8] = v[4] = r->dst.x;
5629 v[9] = r->dst.y;
5630 @@ -693,6 +696,7 @@ gen3_emit_composite_primitive_affine_source(struct sna *sna,
5632 v = sna->render.vertices + sna->render.vertex_used;
5633 sna->render.vertex_used += 12;
5634 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5636 v[0] = dst_x + r->width;
5637 v[5] = v[1] = dst_y + r->height;
5638 @@ -720,10 +724,10 @@ gen3_emit_composite_boxes_affine_source(const struct sna_composite_op *op,
5639 const PictTransform *transform = op->src.transform;
5641 do {
5642 - v[0] = box->x2;
5643 - v[5] = v[1] = box->y2;
5644 - v[8] = v[4] = box->x1;
5645 - v[9] = box->y1;
5646 + v[0] = box->x2 + op->dst.x;
5647 + v[5] = v[1] = box->y2 + op->dst.y;
5648 + v[8] = v[4] = box->x1 + op->dst.x;
5649 + v[9] = box->y1 + op->dst.y;
5651 _sna_get_transformed_scaled(box->x2 + op->src.offset[0],
5652 box->y2 + op->src.offset[1],
5653 @@ -756,6 +760,7 @@ gen3_emit_composite_primitive_constant_identity_mask(struct sna *sna,
5655 v = sna->render.vertices + sna->render.vertex_used;
5656 sna->render.vertex_used += 12;
5657 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5659 v[8] = v[4] = r->dst.x + op->dst.x;
5660 v[0] = v[4] + w;
5661 @@ -781,6 +786,7 @@ gen3_emit_composite_primitive_constant_identity_mask_no_offset(struct sna *sna,
5663 v = sna->render.vertices + sna->render.vertex_used;
5664 sna->render.vertex_used += 12;
5665 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5667 v[8] = v[4] = r->dst.x;
5668 v[9] = r->dst.y;
5669 @@ -817,6 +823,7 @@ gen3_emit_composite_primitive_identity_source_mask(struct sna *sna,
5671 v = sna->render.vertices + sna->render.vertex_used;
5672 sna->render.vertex_used += 18;
5673 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5675 v[0] = dst_x + w;
5676 v[1] = dst_y + h;
5677 @@ -862,6 +869,7 @@ gen3_emit_composite_primitive_affine_source_mask(struct sna *sna,
5679 v = sna->render.vertices + sna->render.vertex_used;
5680 sna->render.vertex_used += 18;
5681 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5683 v[0] = dst_x + w;
5684 v[1] = dst_y + h;
5685 @@ -978,6 +986,7 @@ gen3_emit_composite_primitive_constant__sse2(struct sna *sna,
5687 v = sna->render.vertices + sna->render.vertex_used;
5688 sna->render.vertex_used += 6;
5689 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5691 v[4] = v[2] = r->dst.x + op->dst.x;
5692 v[5] = r->dst.y + op->dst.y;
5693 @@ -993,10 +1002,10 @@ gen3_emit_composite_boxes_constant__sse2(const struct sna_composite_op *op,
5694 float *v)
5696 do {
5697 - v[0] = box->x2;
5698 - v[3] = v[1] = box->y2;
5699 - v[4] = v[2] = box->x1;
5700 - v[5] = box->y1;
5701 + v[0] = box->x2 + op->dst.x;
5702 + v[3] = v[1] = box->y2 + op->dst.y;
5703 + v[4] = v[2] = box->x1 + op->dst.x;
5704 + v[5] = box->y1 + op->dst.y;
5706 box++;
5707 v += 6;
5708 @@ -1013,6 +1022,7 @@ gen3_emit_composite_primitive_identity_gradient__sse2(struct sna *sna,
5710 v = sna->render.vertices + sna->render.vertex_used;
5711 sna->render.vertex_used += 12;
5712 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5714 x = r->dst.x + op->dst.x;
5715 y = r->dst.y + op->dst.y;
5716 @@ -1035,10 +1045,10 @@ gen3_emit_composite_boxes_identity_gradient__sse2(const struct sna_composite_op
5717 float *v)
5719 do {
5720 - v[0] = box->x2;
5721 - v[5] = v[1] = box->y2;
5722 - v[8] = v[4] = box->x1;
5723 - v[9] = box->y1;
5724 + v[0] = box->x2 + op->dst.x;
5725 + v[5] = v[1] = box->y2 + op->dst.y;
5726 + v[8] = v[4] = box->x1 + op->dst.x;
5727 + v[9] = box->y1 + op->dst.y;
5729 v[2] = box->x2 + op->src.offset[0];
5730 v[7] = v[3] = box->y2 + op->src.offset[1];
5731 @@ -1067,6 +1077,7 @@ gen3_emit_composite_primitive_affine_gradient__sse2(struct sna *sna,
5733 v = sna->render.vertices + sna->render.vertex_used;
5734 sna->render.vertex_used += 12;
5735 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5737 v[0] = dst_x + r->width;
5738 v[1] = dst_y + r->height;
5739 @@ -1095,22 +1106,22 @@ gen3_emit_composite_boxes_affine_gradient__sse2(const struct sna_composite_op *o
5740 const PictTransform *transform = op->src.transform;
5742 do {
5743 - v[0] = box->x2;
5744 - v[1] = box->y2;
5745 + v[0] = box->x2 + op->dst.x;
5746 + v[1] = box->y2 + op->dst.y;
5747 _sna_get_transformed_scaled(box->x2 + op->src.offset[0],
5748 box->y2 + op->src.offset[1],
5749 transform, op->src.scale,
5750 &v[2], &v[3]);
5752 - v[4] = box->x1;
5753 - v[5] = box->y2;
5754 + v[4] = box->x1 + op->dst.x;
5755 + v[5] = box->y2 + op->dst.y;
5756 _sna_get_transformed_scaled(box->x1 + op->src.offset[0],
5757 box->y2 + op->src.offset[1],
5758 transform, op->src.scale,
5759 &v[6], &v[7]);
5761 - v[8] = box->x1;
5762 - v[9] = box->y1;
5763 + v[8] = box->x1 + op->dst.x;
5764 + v[9] = box->y1 + op->dst.y;
5765 _sna_get_transformed_scaled(box->x1 + op->src.offset[0],
5766 box->y1 + op->src.offset[1],
5767 transform, op->src.scale,
5768 @@ -1132,6 +1143,7 @@ gen3_emit_composite_primitive_identity_source__sse2(struct sna *sna,
5770 v = sna->render.vertices + sna->render.vertex_used;
5771 sna->render.vertex_used += 12;
5772 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5774 v[8] = v[4] = r->dst.x + op->dst.x;
5775 v[0] = v[4] + w;
5776 @@ -1179,6 +1191,7 @@ gen3_emit_composite_primitive_identity_source_no_offset__sse2(struct sna *sna,
5778 v = sna->render.vertices + sna->render.vertex_used;
5779 sna->render.vertex_used += 12;
5780 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5782 v[8] = v[4] = r->dst.x;
5783 v[9] = r->dst.y;
5784 @@ -1227,8 +1240,12 @@ gen3_emit_composite_primitive_affine_source__sse2(struct sna *sna,
5785 int src_y = r->src.y + (int)op->src.offset[1];
5786 float *v;
5788 + DBG(("%s: src=(%d, %d), dst=(%d, %d), size=%dx%d\n",
5789 + __FUNCTION__, src_x, src_y, dst_x, dst_y, r->width, r->height));
5791 v = sna->render.vertices + sna->render.vertex_used;
5792 sna->render.vertex_used += 12;
5793 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5795 v[0] = dst_x + r->width;
5796 v[5] = v[1] = dst_y + r->height;
5797 @@ -1256,10 +1273,13 @@ gen3_emit_composite_boxes_affine_source__sse2(const struct sna_composite_op *op,
5798 const PictTransform *transform = op->src.transform;
5800 do {
5801 - v[0] = box->x2;
5802 - v[5] = v[1] = box->y2;
5803 - v[8] = v[4] = box->x1;
5804 - v[9] = box->y1;
5805 + DBG(("%s: box=(%d, %d), (%d, %d), src.offset=(%d, %d)\n",
5806 + __FUNCTION__, box->x1, box->y1, box->x2, box->y2, op->src.offset[0], op->src.offset[1]));
5808 + v[0] = box->x2 + op->dst.x;
5809 + v[5] = v[1] = box->y2 + op->dst.y;
5810 + v[8] = v[4] = box->x1 + op->dst.x;
5811 + v[9] = box->y1 + op->dst.y;
5813 _sna_get_transformed_scaled(box->x2 + op->src.offset[0],
5814 box->y2 + op->src.offset[1],
5815 @@ -1292,6 +1312,7 @@ gen3_emit_composite_primitive_constant_identity_mask__sse2(struct sna *sna,
5817 v = sna->render.vertices + sna->render.vertex_used;
5818 sna->render.vertex_used += 12;
5819 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5821 v[8] = v[4] = r->dst.x + op->dst.x;
5822 v[0] = v[4] + w;
5823 @@ -1317,6 +1338,7 @@ gen3_emit_composite_primitive_constant_identity_mask_no_offset__sse2(struct sna
5825 v = sna->render.vertices + sna->render.vertex_used;
5826 sna->render.vertex_used += 12;
5827 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5829 v[8] = v[4] = r->dst.x;
5830 v[9] = r->dst.y;
5831 @@ -1353,6 +1375,7 @@ gen3_emit_composite_primitive_identity_source_mask__sse2(struct sna *sna,
5833 v = sna->render.vertices + sna->render.vertex_used;
5834 sna->render.vertex_used += 18;
5835 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5837 v[0] = dst_x + w;
5838 v[1] = dst_y + h;
5839 @@ -1398,6 +1421,7 @@ gen3_emit_composite_primitive_affine_source_mask__sse2(struct sna *sna,
5841 v = sna->render.vertices + sna->render.vertex_used;
5842 sna->render.vertex_used += 18;
5843 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5845 v[0] = dst_x + w;
5846 v[1] = dst_y + h;
5847 @@ -2233,6 +2257,7 @@ static void gen3_vertex_flush(struct sna *sna)
5848 static int gen3_vertex_finish(struct sna *sna)
5850 struct kgem_bo *bo;
5851 + unsigned hint, size;
5853 DBG(("%s: used=%d/%d, vbo active? %d\n",
5854 __FUNCTION__, sna->render.vertex_used, sna->render.vertex_size,
5855 @@ -2243,6 +2268,7 @@ static int gen3_vertex_finish(struct sna *sna)
5857 sna_vertex_wait__locked(&sna->render);
5859 + hint = CREATE_GTT_MAP;
5860 bo = sna->render.vbo;
5861 if (bo) {
5862 DBG(("%s: reloc = %d\n", __FUNCTION__,
5863 @@ -2251,7 +2277,7 @@ static int gen3_vertex_finish(struct sna *sna)
5864 if (sna->render.vertex_reloc[0]) {
5865 sna->kgem.batch[sna->render.vertex_reloc[0]] =
5866 kgem_add_reloc(&sna->kgem, sna->render.vertex_reloc[0],
5867 - bo, I915_GEM_DOMAIN_VERTEX << 16, 0);
5868 + bo, I915_GEM_DOMAIN_VERTEX << 16 | KGEM_RELOC_FENCED, 0);
5870 sna->render.vertex_reloc[0] = 0;
5872 @@ -2260,17 +2286,29 @@ static int gen3_vertex_finish(struct sna *sna)
5873 sna->render.vbo = NULL;
5875 kgem_bo_destroy(&sna->kgem, bo);
5876 + hint |= CREATE_CACHED | CREATE_NO_THROTTLE;
5879 + size = 256*1024;
5880 sna->render.vertices = NULL;
5881 - sna->render.vbo = kgem_create_linear(&sna->kgem,
5882 - 256*1024, CREATE_GTT_MAP);
5883 - if (sna->render.vbo)
5884 + sna->render.vbo = kgem_create_linear(&sna->kgem, size, hint);
5885 + while (sna->render.vbo == NULL && size > sizeof(sna->render.vertex_data)) {
5886 + size /= 2;
5887 + sna->render.vbo = kgem_create_linear(&sna->kgem, size, hint);
5888 + }
5889 + if (sna->render.vbo == NULL)
5890 + sna->render.vbo = kgem_create_linear(&sna->kgem,
5891 + 256*1024, CREATE_GTT_MAP);
5892 + if (sna->render.vbo &&
5893 + kgem_check_bo(&sna->kgem, sna->render.vbo, NULL))
5894 sna->render.vertices = kgem_bo_map(&sna->kgem, sna->render.vbo);
5895 if (sna->render.vertices == NULL) {
5896 - if (sna->render.vbo)
5897 + if (sna->render.vbo) {
5898 kgem_bo_destroy(&sna->kgem, sna->render.vbo);
5899 - sna->render.vbo = NULL;
5900 + sna->render.vbo = NULL;
5901 + }
5902 + sna->render.vertices = sna->render.vertex_data;
5903 + sna->render.vertex_size = ARRAY_SIZE(sna->render.vertex_data);
5904 return 0;
5906 assert(sna->render.vbo->snoop == false);
5907 @@ -2280,8 +2318,14 @@ static int gen3_vertex_finish(struct sna *sna)
5908 sna->render.vertex_data,
5909 sizeof(float)*sna->render.vertex_used);
5911 - sna->render.vertex_size = 64 * 1024 - 1;
5912 - return sna->render.vertex_size - sna->render.vertex_used;
5914 + size = __kgem_bo_size(sna->render.vbo)/4;
5915 + if (size >= UINT16_MAX)
5916 + size = UINT16_MAX - 1;
5917 + assert(size > sna->render.vertex_used);
5919 + sna->render.vertex_size = size;
5920 + return size - sna->render.vertex_used;
5923 static void gen3_vertex_close(struct sna *sna)
5924 @@ -2345,7 +2389,7 @@ static void gen3_vertex_close(struct sna *sna)
5925 DBG(("%s: reloc = %d\n", __FUNCTION__, sna->render.vertex_reloc[0]));
5926 sna->kgem.batch[sna->render.vertex_reloc[0]] =
5927 kgem_add_reloc(&sna->kgem, sna->render.vertex_reloc[0],
5928 - bo, I915_GEM_DOMAIN_VERTEX << 16, delta);
5929 + bo, I915_GEM_DOMAIN_VERTEX << 16 | KGEM_RELOC_FENCED, delta);
5930 sna->render.vertex_reloc[0] = 0;
5932 if (sna->render.vbo == NULL) {
5933 @@ -2580,6 +2624,7 @@ gen3_render_composite_boxes(struct sna *sna,
5935 v = sna->render.vertices + sna->render.vertex_used;
5936 sna->render.vertex_used += nbox_this_time * op->floats_per_rect;
5937 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5939 op->emit_boxes(op, box, nbox_this_time, v);
5940 box += nbox_this_time;
5941 @@ -2604,6 +2649,7 @@ gen3_render_composite_boxes__thread(struct sna *sna,
5943 v = sna->render.vertices + sna->render.vertex_used;
5944 sna->render.vertex_used += nbox_this_time * op->floats_per_rect;
5945 + assert(sna->render.vertex_used <= sna->render.vertex_size);
5947 sna_vertex_acquire__locked(&sna->render);
5948 sna_vertex_unlock(&sna->render);
5949 @@ -3065,7 +3111,7 @@ gen3_composite_picture(struct sna *sna,
5951 if (sna_picture_is_clear(picture, x, y, w, h, &color)) {
5952 DBG(("%s: clear drawable [%08x]\n", __FUNCTION__, color));
5953 - return gen3_init_solid(channel, color_convert(color, picture->format, PICT_a8r8g8b8));
5954 + return gen3_init_solid(channel, solid_color(picture->format, color));
5957 if (!gen3_check_repeat(picture))
5958 @@ -3097,12 +3143,12 @@ gen3_composite_picture(struct sna *sna,
5959 if (channel->repeat ||
5960 (x >= 0 &&
5961 y >= 0 &&
5962 - x + w < pixmap->drawable.width &&
5963 - y + h < pixmap->drawable.height)) {
5964 + x + w <= pixmap->drawable.width &&
5965 + y + h <= pixmap->drawable.height)) {
5966 struct sna_pixmap *priv = sna_pixmap(pixmap);
5967 if (priv && priv->clear) {
5968 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
5969 - return gen3_init_solid(channel, priv->clear_color);
5970 + return gen3_init_solid(channel, solid_color(picture->format, priv->clear_color));
5973 } else {
5974 @@ -3182,7 +3228,9 @@ gen3_composite_set_target(struct sna *sna,
5975 } else
5976 sna_render_picture_extents(dst, &box);
5978 - hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
5979 + hint = PREFER_GPU | RENDER_GPU;
5980 + if (!need_tiling(sna, op->dst.width, op->dst.height))
5981 + hint |= FORCE_GPU;
5982 if (!partial) {
5983 hint |= IGNORE_DAMAGE;
5984 if (w == op->dst.width && h == op->dst.height)
5985 @@ -3645,8 +3693,11 @@ gen3_render_composite(struct sna *sna,
5989 - DBG(("%s: final src/mask type=%d/%d, affine=%d/%d\n", __FUNCTION__,
5990 + DBG(("%s: final src/mask type=%d/%d [constant? %d/%d], transform? %d/%d, affine=%d/%d\n", __FUNCTION__,
5991 tmp->src.u.gen3.type, tmp->mask.u.gen3.type,
5992 + is_constant_ps(tmp->src.u.gen3.type),
5993 + is_constant_ps(tmp->mask.u.gen3.type),
5994 + !!tmp->src.transform, !!tmp->mask.transform,
5995 tmp->src.is_affine, tmp->mask.is_affine));
5997 tmp->prim_emit = gen3_emit_composite_primitive;
5998 @@ -3862,6 +3913,7 @@ gen3_emit_composite_spans_primitive_zero(struct sna *sna,
6000 float *v = sna->render.vertices + sna->render.vertex_used;
6001 sna->render.vertex_used += 6;
6002 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6004 v[0] = op->base.dst.x + box->x2;
6005 v[1] = op->base.dst.y + box->y2;
6006 @@ -3901,6 +3953,7 @@ gen3_emit_composite_spans_primitive_zero_no_offset(struct sna *sna,
6008 float *v = sna->render.vertices + sna->render.vertex_used;
6009 sna->render.vertex_used += 6;
6010 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6012 v[0] = box->x2;
6013 v[3] = v[1] = box->y2;
6014 @@ -3932,6 +3985,7 @@ gen3_emit_composite_spans_primitive_constant(struct sna *sna,
6016 float *v = sna->render.vertices + sna->render.vertex_used;
6017 sna->render.vertex_used += 9;
6018 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6020 v[0] = op->base.dst.x + box->x2;
6021 v[6] = v[3] = op->base.dst.x + box->x1;
6022 @@ -3966,6 +4020,7 @@ gen3_emit_composite_spans_primitive_constant_no_offset(struct sna *sna,
6024 float *v = sna->render.vertices + sna->render.vertex_used;
6025 sna->render.vertex_used += 9;
6026 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6028 v[0] = box->x2;
6029 v[6] = v[3] = box->x1;
6030 @@ -3999,6 +4054,7 @@ gen3_emit_composite_spans_primitive_identity_source(struct sna *sna,
6032 float *v = sna->render.vertices + sna->render.vertex_used;
6033 sna->render.vertex_used += 15;
6034 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6036 v[0] = op->base.dst.x + box->x2;
6037 v[1] = op->base.dst.y + box->y2;
6038 @@ -4060,6 +4116,7 @@ gen3_emit_composite_spans_primitive_affine_source(struct sna *sna,
6040 v = sna->render.vertices + sna->render.vertex_used;
6041 sna->render.vertex_used += 15;
6042 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6044 v[0] = op->base.dst.x + box->x2;
6045 v[6] = v[1] = op->base.dst.y + box->y2;
6046 @@ -4125,6 +4182,7 @@ gen3_emit_composite_spans_primitive_identity_gradient(struct sna *sna,
6048 float *v = sna->render.vertices + sna->render.vertex_used;
6049 sna->render.vertex_used += 15;
6050 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6052 v[0] = op->base.dst.x + box->x2;
6053 v[1] = op->base.dst.y + box->y2;
6054 @@ -4184,6 +4242,7 @@ gen3_emit_composite_spans_primitive_constant__sse2(struct sna *sna,
6056 float *v = sna->render.vertices + sna->render.vertex_used;
6057 sna->render.vertex_used += 9;
6058 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6060 v[0] = op->base.dst.x + box->x2;
6061 v[6] = v[3] = op->base.dst.x + box->x1;
6062 @@ -4229,6 +4288,7 @@ gen3_render_composite_spans_constant_box__sse2(struct sna *sna,
6064 v = sna->render.vertices + sna->render.vertex_used;
6065 sna->render.vertex_used += 9;
6066 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6068 v[0] = box->x2;
6069 v[6] = v[3] = box->x1;
6070 @@ -4259,6 +4319,7 @@ gen3_render_composite_spans_constant_thread__sse2__boxes(struct sna *sna,
6072 v = sna->render.vertices + sna->render.vertex_used;
6073 sna->render.vertex_used += nbox_this_time * 9;
6074 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6076 sna_vertex_acquire__locked(&sna->render);
6077 sna_vertex_unlock(&sna->render);
6078 @@ -4287,6 +4348,7 @@ gen3_emit_composite_spans_primitive_constant__sse2__no_offset(struct sna *sna,
6080 float *v = sna->render.vertices + sna->render.vertex_used;
6081 sna->render.vertex_used += 9;
6082 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6084 v[0] = box->x2;
6085 v[6] = v[3] = box->x1;
6086 @@ -4320,6 +4382,7 @@ gen3_emit_composite_spans_primitive_identity_source__sse2(struct sna *sna,
6088 float *v = sna->render.vertices + sna->render.vertex_used;
6089 sna->render.vertex_used += 15;
6090 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6092 v[0] = op->base.dst.x + box->x2;
6093 v[1] = op->base.dst.y + box->y2;
6094 @@ -4380,6 +4443,7 @@ gen3_emit_composite_spans_primitive_affine_source__sse2(struct sna *sna,
6096 v = sna->render.vertices + sna->render.vertex_used;
6097 sna->render.vertex_used += 15;
6098 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6100 v[0] = op->base.dst.x + box->x2;
6101 v[6] = v[1] = op->base.dst.y + box->y2;
6102 @@ -4445,6 +4509,7 @@ gen3_emit_composite_spans_primitive_identity_gradient__sse2(struct sna *sna,
6104 float *v = sna->render.vertices + sna->render.vertex_used;
6105 sna->render.vertex_used += 15;
6106 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6108 v[0] = op->base.dst.x + box->x2;
6109 v[1] = op->base.dst.y + box->y2;
6110 @@ -4504,6 +4569,7 @@ gen3_emit_composite_spans_primitive_affine_gradient__sse2(struct sna *sna,
6111 PictTransform *transform = op->base.src.transform;
6112 float *v = sna->render.vertices + sna->render.vertex_used;
6113 sna->render.vertex_used += 15;
6114 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6116 v[0] = op->base.dst.x + box->x2;
6117 v[1] = op->base.dst.y + box->y2;
6118 @@ -4577,6 +4643,7 @@ gen3_emit_composite_spans_primitive_affine_gradient(struct sna *sna,
6119 PictTransform *transform = op->base.src.transform;
6120 float *v = sna->render.vertices + sna->render.vertex_used;
6121 sna->render.vertex_used += 15;
6122 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6124 v[0] = op->base.dst.x + box->x2;
6125 v[1] = op->base.dst.y + box->y2;
6126 @@ -4676,6 +4743,7 @@ gen3_render_composite_spans_constant_box(struct sna *sna,
6128 v = sna->render.vertices + sna->render.vertex_used;
6129 sna->render.vertex_used += 9;
6130 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6132 v[0] = box->x2;
6133 v[6] = v[3] = box->x1;
6134 @@ -4706,6 +4774,7 @@ gen3_render_composite_spans_constant_thread_boxes(struct sna *sna,
6136 v = sna->render.vertices + sna->render.vertex_used;
6137 sna->render.vertex_used += nbox_this_time * 9;
6138 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6140 sna_vertex_acquire__locked(&sna->render);
6141 sna_vertex_unlock(&sna->render);
6142 @@ -4795,6 +4864,7 @@ gen3_render_composite_spans_boxes__thread(struct sna *sna,
6144 v = sna->render.vertices + sna->render.vertex_used;
6145 sna->render.vertex_used += nbox_this_time * op->base.floats_per_rect;
6146 + assert(sna->render.vertex_used <= sna->render.vertex_size);
6148 sna_vertex_acquire__locked(&sna->render);
6149 sna_vertex_unlock(&sna->render);
6150 @@ -5436,17 +5506,7 @@ gen3_render_video(struct sna *sna,
6151 pix_yoff = -dstRegion->extents.y1;
6152 copy = 1;
6153 } else {
6154 - /* Set up the offset for translating from the given region
6155 - * (in screen coordinates) to the backing pixmap.
6156 - */
6157 -#ifdef COMPOSITE
6158 - pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
6159 - pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
6160 -#else
6161 - pix_xoff = 0;
6162 - pix_yoff = 0;
6163 -#endif
6165 + pix_xoff = pix_yoff = 0;
6166 dst_width = pixmap->drawable.width;
6167 dst_height = pixmap->drawable.height;
6169 @@ -5502,16 +5562,9 @@ gen3_render_video(struct sna *sna,
6170 } while (nbox);
6172 if (copy) {
6173 -#ifdef COMPOSITE
6174 - pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
6175 - pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
6176 -#else
6177 - pix_xoff = 0;
6178 - pix_yoff = 0;
6179 -#endif
6180 sna_blt_copy_boxes(sna, GXcopy,
6181 dst_bo, -dstRegion->extents.x1, -dstRegion->extents.y1,
6182 - priv->gpu_bo, pix_xoff, pix_yoff,
6183 + priv->gpu_bo, 0, 0,
6184 pixmap->drawable.bitsPerPixel,
6185 region_rects(dstRegion),
6186 region_num_rects(dstRegion));
6187 @@ -5519,21 +5572,8 @@ gen3_render_video(struct sna *sna,
6188 kgem_bo_destroy(&sna->kgem, dst_bo);
6191 - if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
6192 - if ((pix_xoff | pix_yoff) == 0) {
6193 - sna_damage_add(&priv->gpu_damage, dstRegion);
6194 - sna_damage_subtract(&priv->cpu_damage, dstRegion);
6195 - } else {
6196 - sna_damage_add_boxes(&priv->gpu_damage,
6197 - region_rects(dstRegion),
6198 - region_num_rects(dstRegion),
6199 - pix_xoff, pix_yoff);
6200 - sna_damage_subtract_boxes(&priv->cpu_damage,
6201 - region_rects(dstRegion),
6202 - region_num_rects(dstRegion),
6203 - pix_xoff, pix_yoff);
6204 - }
6205 - }
6206 + if (!DAMAGE_IS_ALL(priv->gpu_damage))
6207 + sna_damage_add(&priv->gpu_damage, dstRegion);
6209 return true;
6211 diff --git a/src/sna/gen4_render.c b/src/sna/gen4_render.c
6212 index 6c2d3808..72a98aee 100644
6213 --- a/src/sna/gen4_render.c
6214 +++ b/src/sna/gen4_render.c
6215 @@ -1405,8 +1405,8 @@ gen4_render_video(struct sna *sna,
6216 int src_height = frame->src.y2 - frame->src.y1;
6217 float src_offset_x, src_offset_y;
6218 float src_scale_x, src_scale_y;
6219 - int nbox, pix_xoff, pix_yoff;
6220 const BoxRec *box;
6221 + int nbox;
6223 DBG(("%s: %dx%d -> %dx%d\n", __FUNCTION__,
6224 src_width, src_height, dst_width, dst_height));
6225 @@ -1445,17 +1445,6 @@ gen4_render_video(struct sna *sna,
6226 gen4_align_vertex(sna, &tmp);
6227 gen4_video_bind_surfaces(sna, &tmp);
6229 - /* Set up the offset for translating from the given region (in screen
6230 - * coordinates) to the backing pixmap.
6231 - */
6232 -#ifdef COMPOSITE
6233 - pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
6234 - pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
6235 -#else
6236 - pix_xoff = 0;
6237 - pix_yoff = 0;
6238 -#endif
6240 src_scale_x = (float)src_width / dst_width / frame->width;
6241 src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
6243 @@ -1473,34 +1462,26 @@ gen4_render_video(struct sna *sna,
6244 nbox -= n;
6246 do {
6247 - BoxRec r;
6249 - r.x1 = box->x1 + pix_xoff;
6250 - r.x2 = box->x2 + pix_xoff;
6251 - r.y1 = box->y1 + pix_yoff;
6252 - r.y2 = box->y2 + pix_yoff;
6254 - OUT_VERTEX(r.x2, r.y2);
6255 + OUT_VERTEX(box->x2, box->y2);
6256 OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
6257 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
6259 - OUT_VERTEX(r.x1, r.y2);
6260 + OUT_VERTEX(box->x1, box->y2);
6261 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
6262 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
6264 - OUT_VERTEX(r.x1, r.y1);
6265 + OUT_VERTEX(box->x1, box->y1);
6266 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
6267 OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
6269 - if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
6270 - sna_damage_add_box(&priv->gpu_damage, &r);
6271 - sna_damage_subtract_box(&priv->cpu_damage, &r);
6272 - }
6273 box++;
6274 } while (--n);
6275 } while (nbox);
6276 gen4_vertex_flush(sna);
6278 + if (!DAMAGE_IS_ALL(priv->gpu_damage))
6279 + sna_damage_add(&priv->gpu_damage, dstRegion);
6281 return true;
6284 @@ -1585,12 +1566,14 @@ gen4_composite_picture(struct sna *sna,
6285 if (channel->repeat &&
6286 (x >= 0 &&
6287 y >= 0 &&
6288 - x + w < pixmap->drawable.width &&
6289 - y + h < pixmap->drawable.height)) {
6290 + x + w <= pixmap->drawable.width &&
6291 + y + h <= pixmap->drawable.height)) {
6292 struct sna_pixmap *priv = sna_pixmap(pixmap);
6293 if (priv && priv->clear) {
6294 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
6295 - return gen4_channel_init_solid(sna, channel, priv->clear_color);
6296 + return gen4_channel_init_solid(sna, channel,
6297 + solid_color(picture->format,
6298 + priv->clear_color));
6301 } else
6302 @@ -1664,7 +1647,9 @@ gen4_composite_set_target(struct sna *sna,
6303 } else
6304 sna_render_picture_extents(dst, &box);
6306 - hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
6307 + hint = PREFER_GPU | RENDER_GPU;
6308 + if (!need_tiling(sna, op->dst.width, op->dst.height))
6309 + hint |= FORCE_GPU;
6310 if (!partial) {
6311 hint |= IGNORE_DAMAGE;
6312 if (w == op->dst.width && h == op->dst.height)
6313 @@ -2738,6 +2723,20 @@ gen4_render_fill_boxes(struct sna *sna,
6314 tmp.dst.format = format;
6315 tmp.dst.bo = dst_bo;
6317 + sna_render_composite_redirect_init(&tmp);
6318 + if (too_large(dst->width, dst->height)) {
6319 + BoxRec extents;
6321 + boxes_extents(box, n, &extents);
6322 + if (!sna_render_composite_redirect(sna, &tmp,
6323 + extents.x1, extents.y1,
6324 + extents.x2 - extents.x1,
6325 + extents.y2 - extents.y1,
6326 + n > 1))
6327 + return sna_tiling_fill_boxes(sna, op, format, color,
6328 + dst, dst_bo, box, n);
6329 + }
6331 gen4_channel_init_solid(sna, &tmp.src, pixel);
6333 tmp.is_affine = true;
6334 @@ -2748,8 +2747,10 @@ gen4_render_fill_boxes(struct sna *sna,
6336 if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
6337 kgem_submit(&sna->kgem);
6338 - if (!kgem_check_bo(&sna->kgem, dst_bo, NULL))
6339 + if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
6340 + kgem_bo_destroy(&sna->kgem, tmp.src.bo);
6341 return false;
6342 + }
6345 gen4_align_vertex(sna, &tmp);
6346 @@ -2765,6 +2766,7 @@ gen4_render_fill_boxes(struct sna *sna,
6348 gen4_vertex_flush(sna);
6349 kgem_bo_destroy(&sna->kgem, tmp.src.bo);
6350 + sna_render_composite_redirect_done(sna, &tmp);
6351 return true;
6354 diff --git a/src/sna/gen5_render.c b/src/sna/gen5_render.c
6355 index 37cf1ff9..fb3e79bf 100644
6356 --- a/src/sna/gen5_render.c
6357 +++ b/src/sna/gen5_render.c
6358 @@ -1355,8 +1355,8 @@ gen5_render_video(struct sna *sna,
6359 int src_height = frame->src.y2 - frame->src.y1;
6360 float src_offset_x, src_offset_y;
6361 float src_scale_x, src_scale_y;
6362 - int nbox, pix_xoff, pix_yoff;
6363 const BoxRec *box;
6364 + int nbox;
6366 DBG(("%s: %dx%d -> %dx%d\n", __FUNCTION__,
6367 src_width, src_height, dst_width, dst_height));
6368 @@ -1395,17 +1395,6 @@ gen5_render_video(struct sna *sna,
6369 gen5_align_vertex(sna, &tmp);
6370 gen5_video_bind_surfaces(sna, &tmp);
6372 - /* Set up the offset for translating from the given region (in screen
6373 - * coordinates) to the backing pixmap.
6374 - */
6375 -#ifdef COMPOSITE
6376 - pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
6377 - pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
6378 -#else
6379 - pix_xoff = 0;
6380 - pix_yoff = 0;
6381 -#endif
6383 src_scale_x = (float)src_width / dst_width / frame->width;
6384 src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
6386 @@ -1415,35 +1404,27 @@ gen5_render_video(struct sna *sna,
6387 box = region_rects(dstRegion);
6388 nbox = region_num_rects(dstRegion);
6389 while (nbox--) {
6390 - BoxRec r;
6392 - r.x1 = box->x1 + pix_xoff;
6393 - r.x2 = box->x2 + pix_xoff;
6394 - r.y1 = box->y1 + pix_yoff;
6395 - r.y2 = box->y2 + pix_yoff;
6397 gen5_get_rectangles(sna, &tmp, 1, gen5_video_bind_surfaces);
6399 - OUT_VERTEX(r.x2, r.y2);
6400 + OUT_VERTEX(box->x2, box->y2);
6401 OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
6402 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
6404 - OUT_VERTEX(r.x1, r.y2);
6405 + OUT_VERTEX(box->x1, box->y2);
6406 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
6407 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
6409 - OUT_VERTEX(r.x1, r.y1);
6410 + OUT_VERTEX(box->x1, box->y1);
6411 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
6412 OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
6414 - if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
6415 - sna_damage_add_box(&priv->gpu_damage, &r);
6416 - sna_damage_subtract_box(&priv->cpu_damage, &r);
6417 - }
6418 box++;
6421 gen4_vertex_flush(sna);
6423 + if (!DAMAGE_IS_ALL(priv->gpu_damage))
6424 + sna_damage_add(&priv->gpu_damage, dstRegion);
6426 return true;
6429 @@ -1524,12 +1505,12 @@ gen5_composite_picture(struct sna *sna,
6430 if (channel->repeat ||
6431 (x >= 0 &&
6432 y >= 0 &&
6433 - x + w < pixmap->drawable.width &&
6434 - y + h < pixmap->drawable.height)) {
6435 + x + w <= pixmap->drawable.width &&
6436 + y + h <= pixmap->drawable.height)) {
6437 struct sna_pixmap *priv = sna_pixmap(pixmap);
6438 if (priv && priv->clear) {
6439 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
6440 - return gen4_channel_init_solid(sna, channel, priv->clear_color);
6441 + return gen4_channel_init_solid(sna, channel, solid_color(picture->format, priv->clear_color));
6444 } else
6445 @@ -1618,7 +1599,9 @@ gen5_composite_set_target(struct sna *sna,
6446 } else
6447 sna_render_picture_extents(dst, &box);
6449 - hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
6450 + hint = PREFER_GPU | RENDER_GPU;
6451 + if (!need_tiling(sna, op->dst.width, op->dst.height))
6452 + hint |= FORCE_GPU;
6453 if (!partial) {
6454 hint |= IGNORE_DAMAGE;
6455 if (w == op->dst.width && h == op->dst.height)
6456 @@ -2734,6 +2717,19 @@ gen5_render_fill_boxes(struct sna *sna,
6457 tmp.dst.format = format;
6458 tmp.dst.bo = dst_bo;
6460 + if (too_large(dst->width, dst->height)) {
6461 + BoxRec extents;
6463 + boxes_extents(box, n, &extents);
6464 + if (!sna_render_composite_redirect(sna, &tmp,
6465 + extents.x1, extents.y1,
6466 + extents.x2 - extents.x1,
6467 + extents.y2 - extents.y1,
6468 + n > 1))
6469 + return sna_tiling_fill_boxes(sna, op, format, color,
6470 + dst, dst_bo, box, n);
6471 + }
6473 tmp.src.bo = sna_render_get_solid(sna, pixel);
6474 tmp.src.filter = SAMPLER_FILTER_NEAREST;
6475 tmp.src.repeat = SAMPLER_EXTEND_REPEAT;
6476 @@ -2780,6 +2776,7 @@ gen5_render_fill_boxes(struct sna *sna,
6478 gen4_vertex_flush(sna);
6479 kgem_bo_destroy(&sna->kgem, tmp.src.bo);
6480 + sna_render_composite_redirect_done(sna, &tmp);
6481 return true;
6484 diff --git a/src/sna/gen6_common.h b/src/sna/gen6_common.h
6485 index 6668620b..b53ec0c9 100644
6486 --- a/src/sna/gen6_common.h
6487 +++ b/src/sna/gen6_common.h
6488 @@ -30,8 +30,8 @@
6490 #include "sna.h"
6492 -#define NO_RING_SWITCH 0
6493 -#define PREFER_RENDER 0
6494 +#define NO_RING_SWITCH(sna) (!(sna)->kgem.has_semaphores)
6495 +#define PREFER_RENDER 0 /* -1 -> BLT, 1 -> RENDER */
6497 static inline bool is_uncached(struct sna *sna,
6498 struct kgem_bo *bo)
6499 @@ -46,40 +46,28 @@ inline static bool can_switch_to_blt(struct sna *sna,
6500 if (sna->kgem.ring != KGEM_RENDER)
6501 return true;
6503 - if (NO_RING_SWITCH)
6504 - return false;
6506 - if (!sna->kgem.has_semaphores)
6507 - return false;
6509 - if (flags & COPY_LAST)
6510 - return true;
6512 if (bo && RQ_IS_BLT(bo->rq))
6513 return true;
6515 - if (sna->render_state.gt < 2)
6516 - return true;
6517 + if (bo && bo->tiling == I915_TILING_Y)
6518 + return false;
6520 - return kgem_ring_is_idle(&sna->kgem, KGEM_BLT);
6521 -}
6522 + if (bo && !kgem_bo_can_blt(&sna->kgem, bo))
6523 + return false;
6525 -inline static bool can_switch_to_render(struct sna *sna,
6526 - struct kgem_bo *bo)
6527 -{
6528 - if (sna->kgem.ring == KGEM_RENDER)
6529 + if (sna->render_state.gt < 2)
6530 return true;
6532 - if (NO_RING_SWITCH)
6533 + if (bo && RQ_IS_RENDER(bo->rq))
6534 return false;
6536 - if (!sna->kgem.has_semaphores)
6537 + if (NO_RING_SWITCH(sna))
6538 return false;
6540 - if (bo && !RQ_IS_BLT(bo->rq) && !is_uncached(sna, bo))
6541 + if (flags & COPY_LAST)
6542 return true;
6544 - return !kgem_ring_is_idle(&sna->kgem, KGEM_RENDER);
6545 + return kgem_ring_is_idle(&sna->kgem, KGEM_BLT);
6548 static inline bool untiled_tlb_miss(struct kgem_bo *bo)
6549 @@ -90,57 +78,95 @@ static inline bool untiled_tlb_miss(struct kgem_bo *bo)
6550 return bo->tiling == I915_TILING_NONE && bo->pitch >= 4096;
6553 -static int prefer_blt_bo(struct sna *sna, struct kgem_bo *bo)
6554 +static int prefer_blt_bo(struct sna *sna,
6555 + struct kgem_bo *src,
6556 + struct kgem_bo *dst)
6558 + assert(dst != NULL);
6560 if (PREFER_RENDER)
6561 return PREFER_RENDER < 0;
6563 - if (bo->rq)
6564 - return RQ_IS_BLT(bo->rq);
6565 + if (dst->rq)
6566 + return RQ_IS_BLT(dst->rq);
6568 if (sna->flags & SNA_POWERSAVE)
6569 return true;
6571 - return bo->tiling == I915_TILING_NONE || is_uncached(sna, bo);
6572 -}
6573 + if (src) {
6574 + if (sna->render_state.gt > 1)
6575 + return false;
6577 -inline static bool force_blt_ring(struct sna *sna)
6578 -{
6579 - if (sna->flags & SNA_POWERSAVE)
6580 + if (src->rq)
6581 + return RQ_IS_BLT(src->rq);
6583 + if (src->tiling == I915_TILING_Y)
6584 + return false;
6585 + } else {
6586 + if (sna->render_state.gt > 2)
6587 + return false;
6588 + }
6590 + if (sna->render_state.gt < 2)
6591 return true;
6593 + return dst->tiling == I915_TILING_NONE || is_uncached(sna, dst);
6594 +}
6596 +inline static bool force_blt_ring(struct sna *sna, struct kgem_bo *bo)
6597 +{
6598 if (sna->kgem.mode == KGEM_RENDER)
6599 return false;
6601 + if (NO_RING_SWITCH(sna))
6602 + return sna->kgem.ring == KGEM_BLT;
6604 + if (bo->tiling == I915_TILING_Y)
6605 + return false;
6607 + if (sna->flags & SNA_POWERSAVE)
6608 + return true;
6610 if (sna->render_state.gt < 2)
6611 return true;
6613 return false;
6616 -inline static bool prefer_blt_ring(struct sna *sna,
6617 - struct kgem_bo *bo,
6618 - unsigned flags)
6619 +nonnull inline static bool
6620 +prefer_blt_ring(struct sna *sna, struct kgem_bo *bo, unsigned flags)
6622 if (PREFER_RENDER)
6623 return PREFER_RENDER < 0;
6625 - assert(!force_blt_ring(sna));
6626 - assert(!kgem_bo_is_render(bo));
6627 + assert(!force_blt_ring(sna, bo));
6628 + assert(!kgem_bo_is_render(bo) || NO_RING_SWITCH(sna));
6630 + if (kgem_bo_is_blt(bo))
6631 + return true;
6633 return can_switch_to_blt(sna, bo, flags);
6636 -inline static bool prefer_render_ring(struct sna *sna,
6637 - struct kgem_bo *bo)
6638 +nonnull inline static bool
6639 +prefer_render_ring(struct sna *sna, struct kgem_bo *bo)
6641 + if (sna->kgem.ring == KGEM_RENDER)
6642 + return true;
6644 + if (sna->kgem.ring != KGEM_NONE && NO_RING_SWITCH(sna))
6645 + return false;
6647 + if (kgem_bo_is_render(bo))
6648 + return true;
6650 if (sna->flags & SNA_POWERSAVE)
6651 return false;
6653 - if (sna->render_state.gt < 2)
6654 - return false;
6655 + if (!prefer_blt_bo(sna, NULL, bo))
6656 + return true;
6658 - return can_switch_to_render(sna, bo);
6659 + return !kgem_ring_is_idle(&sna->kgem, KGEM_RENDER);
6662 inline static bool
6663 @@ -153,25 +179,20 @@ prefer_blt_composite(struct sna *sna, struct sna_composite_op *tmp)
6664 untiled_tlb_miss(tmp->src.bo))
6665 return true;
6667 - if (force_blt_ring(sna))
6668 + if (force_blt_ring(sna, tmp->dst.bo))
6669 return true;
6671 - if (kgem_bo_is_render(tmp->dst.bo) ||
6672 - kgem_bo_is_render(tmp->src.bo))
6673 - return false;
6675 if (prefer_render_ring(sna, tmp->dst.bo))
6676 return false;
6678 if (!prefer_blt_ring(sna, tmp->dst.bo, 0))
6679 return false;
6681 - return prefer_blt_bo(sna, tmp->dst.bo) || prefer_blt_bo(sna, tmp->src.bo);
6682 + return prefer_blt_bo(sna, tmp->src.bo, tmp->dst.bo);
6685 -static inline bool prefer_blt_fill(struct sna *sna,
6686 - struct kgem_bo *bo,
6687 - unsigned flags)
6688 +nonnull static inline bool
6689 +prefer_blt_fill(struct sna *sna, struct kgem_bo *bo, unsigned flags)
6691 if (PREFER_RENDER)
6692 return PREFER_RENDER < 0;
6693 @@ -179,24 +200,21 @@ static inline bool prefer_blt_fill(struct sna *sna,
6694 if (untiled_tlb_miss(bo))
6695 return true;
6697 - if (force_blt_ring(sna))
6698 + if (force_blt_ring(sna, bo))
6699 return true;
6701 if ((flags & (FILL_POINTS | FILL_SPANS)) == 0) {
6702 - if (kgem_bo_is_render(bo))
6703 - return false;
6705 if (prefer_render_ring(sna, bo))
6706 return false;
6708 if (!prefer_blt_ring(sna, bo, 0))
6709 return false;
6710 } else {
6711 - if (can_switch_to_blt(sna, bo, 0))
6712 + if (can_switch_to_blt(sna, bo, COPY_LAST))
6713 return true;
6716 - return prefer_blt_bo(sna, bo);
6717 + return prefer_blt_bo(sna, NULL, bo);
6720 void gen6_render_context_switch(struct kgem *kgem, int new_mode);
6721 diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c
6722 index 25044685..6b69f216 100644
6723 --- a/src/sna/gen6_render.c
6724 +++ b/src/sna/gen6_render.c
6725 @@ -1633,9 +1633,9 @@ gen6_render_video(struct sna *sna,
6726 int src_height = frame->src.y2 - frame->src.y1;
6727 float src_offset_x, src_offset_y;
6728 float src_scale_x, src_scale_y;
6729 - int nbox, pix_xoff, pix_yoff;
6730 unsigned filter;
6731 const BoxRec *box;
6732 + int nbox;
6734 DBG(("%s: src=(%d, %d), dst=(%d, %d), %dx[(%d, %d), (%d, %d)...]\n",
6735 __FUNCTION__,
6736 @@ -1686,17 +1686,6 @@ gen6_render_video(struct sna *sna,
6737 gen6_align_vertex(sna, &tmp);
6738 gen6_emit_video_state(sna, &tmp);
6740 - /* Set up the offset for translating from the given region (in screen
6741 - * coordinates) to the backing pixmap.
6742 - */
6743 -#ifdef COMPOSITE
6744 - pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
6745 - pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
6746 -#else
6747 - pix_xoff = 0;
6748 - pix_yoff = 0;
6749 -#endif
6751 src_scale_x = (float)src_width / dst_width / frame->width;
6752 src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
6754 @@ -1706,35 +1695,27 @@ gen6_render_video(struct sna *sna,
6755 box = region_rects(dstRegion);
6756 nbox = region_num_rects(dstRegion);
6757 while (nbox--) {
6758 - BoxRec r;
6760 - r.x1 = box->x1 + pix_xoff;
6761 - r.x2 = box->x2 + pix_xoff;
6762 - r.y1 = box->y1 + pix_yoff;
6763 - r.y2 = box->y2 + pix_yoff;
6765 gen6_get_rectangles(sna, &tmp, 1, gen6_emit_video_state);
6767 - OUT_VERTEX(r.x2, r.y2);
6768 + OUT_VERTEX(box->x2, box->y2);
6769 OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
6770 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
6772 - OUT_VERTEX(r.x1, r.y2);
6773 + OUT_VERTEX(box->x1, box->y2);
6774 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
6775 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
6777 - OUT_VERTEX(r.x1, r.y1);
6778 + OUT_VERTEX(box->x1, box->y1);
6779 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
6780 OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
6782 - if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
6783 - sna_damage_add_box(&priv->gpu_damage, &r);
6784 - sna_damage_subtract_box(&priv->cpu_damage, &r);
6785 - }
6786 box++;
6789 gen4_vertex_flush(sna);
6791 + if (!DAMAGE_IS_ALL(priv->gpu_damage))
6792 + sna_damage_add(&priv->gpu_damage, dstRegion);
6794 return true;
6797 @@ -1815,12 +1796,12 @@ gen6_composite_picture(struct sna *sna,
6798 if (channel->repeat &&
6799 (x >= 0 &&
6800 y >= 0 &&
6801 - x + w < pixmap->drawable.width &&
6802 - y + h < pixmap->drawable.height)) {
6803 + x + w <= pixmap->drawable.width &&
6804 + y + h <= pixmap->drawable.height)) {
6805 struct sna_pixmap *priv = sna_pixmap(pixmap);
6806 if (priv && priv->clear) {
6807 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
6808 - return gen4_channel_init_solid(sna, channel, priv->clear_color);
6809 + return gen4_channel_init_solid(sna, channel, solid_color(picture->format, priv->clear_color));
6812 } else
6813 @@ -1927,7 +1908,9 @@ gen6_composite_set_target(struct sna *sna,
6814 } else
6815 sna_render_picture_extents(dst, &box);
6817 - hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
6818 + hint = PREFER_GPU | RENDER_GPU;
6819 + if (!need_tiling(sna, op->dst.width, op->dst.height))
6820 + hint |= FORCE_GPU;
6821 if (!partial) {
6822 hint |= IGNORE_DAMAGE;
6823 if (w == op->dst.width && h == op->dst.height)
6824 @@ -1965,46 +1948,77 @@ gen6_composite_set_target(struct sna *sna,
6826 static bool
6827 try_blt(struct sna *sna,
6828 - PicturePtr dst, PicturePtr src,
6829 - int width, int height)
6830 + uint8_t op,
6831 + PicturePtr src,
6832 + PicturePtr mask,
6833 + PicturePtr dst,
6834 + int16_t src_x, int16_t src_y,
6835 + int16_t msk_x, int16_t msk_y,
6836 + int16_t dst_x, int16_t dst_y,
6837 + int16_t width, int16_t height,
6838 + unsigned flags,
6839 + struct sna_composite_op *tmp)
6841 struct kgem_bo *bo;
6843 if (sna->kgem.mode == KGEM_BLT) {
6844 DBG(("%s: already performing BLT\n", __FUNCTION__));
6845 - return true;
6846 + goto execute;
6849 if (too_large(width, height)) {
6850 DBG(("%s: operation too large for 3D pipe (%d, %d)\n",
6851 __FUNCTION__, width, height));
6852 - return true;
6853 + goto execute;
6856 bo = __sna_drawable_peek_bo(dst->pDrawable);
6857 if (bo == NULL)
6858 - return true;
6859 - if (bo->rq)
6860 - return RQ_IS_BLT(bo->rq);
6861 + goto execute;
6863 + if (untiled_tlb_miss(bo))
6864 + goto execute;
6866 + if (bo->rq) {
6867 + if (RQ_IS_BLT(bo->rq))
6868 + goto execute;
6870 + return false;
6871 + }
6873 + if (bo->tiling == I915_TILING_Y)
6874 + goto upload;
6876 + if (src->pDrawable == dst->pDrawable &&
6877 + can_switch_to_blt(sna, bo, 0))
6878 + goto execute;
6880 if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0))
6881 - return true;
6882 + goto execute;
6884 if (src->pDrawable) {
6885 - bo = __sna_drawable_peek_bo(src->pDrawable);
6886 - if (bo == NULL)
6887 - return true;
6888 + struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable);
6889 + if (s == NULL)
6890 + goto execute;
6892 - if (prefer_blt_bo(sna, bo))
6893 - return true;
6894 + if (prefer_blt_bo(sna, s, bo))
6895 + goto execute;
6898 if (sna->kgem.ring == KGEM_BLT) {
6899 DBG(("%s: already performing BLT\n", __FUNCTION__));
6900 - return true;
6901 + goto execute;
6904 - return false;
6905 +upload:
6906 + flags |= COMPOSITE_UPLOAD;
6907 +execute:
6908 + return sna_blt_composite(sna, op,
6909 + src, dst,
6910 + src_x, src_y,
6911 + dst_x, dst_y,
6912 + width, height,
6913 + flags, tmp);
6916 static bool
6917 @@ -2234,13 +2248,13 @@ gen6_render_composite(struct sna *sna,
6918 width, height, sna->kgem.ring));
6920 if (mask == NULL &&
6921 - try_blt(sna, dst, src, width, height) &&
6922 - sna_blt_composite(sna, op,
6923 - src, dst,
6924 - src_x, src_y,
6925 - dst_x, dst_y,
6926 - width, height,
6927 - flags, tmp))
6928 + try_blt(sna, op,
6929 + src, mask, dst,
6930 + src_x, src_y,
6931 + msk_x, msk_y,
6932 + dst_x, dst_y,
6933 + width, height,
6934 + flags, tmp))
6935 return true;
6937 if (gen6_composite_fallback(sna, src, mask, dst))
6938 @@ -2676,27 +2690,35 @@ static inline bool prefer_blt_copy(struct sna *sna,
6939 if (sna->kgem.ring == KGEM_BLT)
6940 return true;
6942 - if (src_bo == dst_bo && can_switch_to_blt(sna, dst_bo, flags))
6943 + if (flags & COPY_DRI && !sna->kgem.has_semaphores)
6944 + return false;
6946 + if ((flags & COPY_SMALL || src_bo == dst_bo) &&
6947 + can_switch_to_blt(sna, dst_bo, flags))
6948 return true;
6950 if (untiled_tlb_miss(src_bo) ||
6951 untiled_tlb_miss(dst_bo))
6952 return true;
6954 - if (force_blt_ring(sna))
6955 + if (force_blt_ring(sna, dst_bo))
6956 return true;
6958 if (kgem_bo_is_render(dst_bo) ||
6959 kgem_bo_is_render(src_bo))
6960 return false;
6962 + if (flags & COPY_LAST &&
6963 + can_switch_to_blt(sna, dst_bo, flags))
6964 + return true;
6966 if (prefer_render_ring(sna, dst_bo))
6967 return false;
6969 if (!prefer_blt_ring(sna, dst_bo, flags))
6970 return false;
6972 - return prefer_blt_bo(sna, src_bo) || prefer_blt_bo(sna, dst_bo);
6973 + return prefer_blt_bo(sna, src_bo, dst_bo);
6976 static bool
6977 @@ -2758,8 +2780,7 @@ fallback_blt:
6978 assert(src->depth == dst->depth);
6979 assert(src->width == dst->width);
6980 assert(src->height == dst->height);
6981 - return sna_render_copy_boxes__overlap(sna, alu,
6982 - src, src_bo,
6983 + return sna_render_copy_boxes__overlap(sna, alu, dst, dst_bo,
6984 src_dx, src_dy,
6985 dst_dx, dst_dy,
6986 box, n, &extents);
6987 diff --git a/src/sna/gen7_render.c b/src/sna/gen7_render.c
6988 index 2ecfd641..aabb8693 100644
6989 --- a/src/sna/gen7_render.c
6990 +++ b/src/sna/gen7_render.c
6991 @@ -60,8 +60,6 @@
6992 #define NO_FILL_ONE 0
6993 #define NO_FILL_CLEAR 0
6995 -#define NO_RING_SWITCH 0
6997 #define USE_8_PIXEL_DISPATCH 1
6998 #define USE_16_PIXEL_DISPATCH 1
6999 #define USE_32_PIXEL_DISPATCH 0
7000 @@ -149,7 +147,7 @@ static const struct gt_info hsw_gt1_info = {
7001 .max_vs_threads = 70,
7002 .max_gs_threads = 70,
7003 .max_wm_threads =
7004 - (102 - 1) << HSW_PS_MAX_THREADS_SHIFT |
7005 + (70 - 1) << HSW_PS_MAX_THREADS_SHIFT |
7006 1 << HSW_PS_SAMPLE_MASK_SHIFT,
7007 .urb = { 128, 640, 256, 8 },
7008 .gt = 1,
7009 @@ -209,6 +207,12 @@ static const uint32_t ps_kernel_planar[][4] = {
7010 #include "exa_wm_write.g7b"
7011 };
7013 +static const uint32_t ps_kernel_rgb[][4] = {
7014 +#include "exa_wm_src_affine.g7b"
7015 +#include "exa_wm_src_sample_argb.g7b"
7016 +#include "exa_wm_write.g7b"
7017 +};
7019 #define KERNEL(kernel_enum, kernel, num_surfaces) \
7020 [GEN7_WM_KERNEL_##kernel_enum] = {#kernel_enum, kernel, sizeof(kernel), num_surfaces}
7021 #define NOKERNEL(kernel_enum, func, num_surfaces) \
7022 @@ -218,7 +222,7 @@ static const struct wm_kernel_info {
7023 const void *data;
7024 unsigned int size;
7025 int num_surfaces;
7026 -} wm_kernels[] = {
7027 +} wm_kernels[GEN7_WM_KERNEL_COUNT] = {
7028 NOKERNEL(NOMASK, brw_wm_kernel__affine, 2),
7029 NOKERNEL(NOMASK_P, brw_wm_kernel__projective, 2),
7031 @@ -236,6 +240,7 @@ static const struct wm_kernel_info {
7033 KERNEL(VIDEO_PLANAR, ps_kernel_planar, 7),
7034 KERNEL(VIDEO_PACKED, ps_kernel_packed, 2),
7035 + KERNEL(VIDEO_RGB, ps_kernel_rgb, 2),
7036 };
7037 #undef KERNEL
7039 @@ -810,7 +815,7 @@ gen7_emit_cc(struct sna *sna, uint32_t blend_offset)
7041 DBG(("%s: blend = %x\n", __FUNCTION__, blend_offset));
7043 - /* XXX can have upto 8 blend states preload, selectable via
7044 + /* XXX can have up to 8 blend states preload, selectable via
7045 * Render Target Index. What other side-effects of Render Target Index?
7046 */
7048 @@ -1792,7 +1797,9 @@ static void gen7_emit_video_state(struct sna *sna,
7049 frame->pitch[0];
7050 n_src = 6;
7051 } else {
7052 - if (frame->id == FOURCC_UYVY)
7053 + if (frame->id == FOURCC_RGB888)
7054 + src_surf_format = GEN7_SURFACEFORMAT_B8G8R8X8_UNORM;
7055 + else if (frame->id == FOURCC_UYVY)
7056 src_surf_format = GEN7_SURFACEFORMAT_YCRCB_SWAPY;
7057 else
7058 src_surf_format = GEN7_SURFACEFORMAT_YCRCB_NORMAL;
7059 @@ -1826,6 +1833,23 @@ static void gen7_emit_video_state(struct sna *sna,
7060 gen7_emit_state(sna, op, offset | dirty);
7063 +static unsigned select_video_kernel(const struct sna_video_frame *frame)
7064 +{
7065 + switch (frame->id) {
7066 + case FOURCC_YV12:
7067 + case FOURCC_I420:
7068 + case FOURCC_XVMC:
7069 + return GEN7_WM_KERNEL_VIDEO_PLANAR;
7071 + case FOURCC_RGB888:
7072 + case FOURCC_RGB565:
7073 + return GEN7_WM_KERNEL_VIDEO_RGB;
7075 + default:
7076 + return GEN7_WM_KERNEL_VIDEO_PACKED;
7077 + }
7078 +}
7080 static bool
7081 gen7_render_video(struct sna *sna,
7082 struct sna_video *video,
7083 @@ -1841,9 +1865,9 @@ gen7_render_video(struct sna *sna,
7084 int src_height = frame->src.y2 - frame->src.y1;
7085 float src_offset_x, src_offset_y;
7086 float src_scale_x, src_scale_y;
7087 - int nbox, pix_xoff, pix_yoff;
7088 unsigned filter;
7089 const BoxRec *box;
7090 + int nbox;
7092 DBG(("%s: src=(%d, %d), dst=(%d, %d), %dx[(%d, %d), (%d, %d)...]\n",
7093 __FUNCTION__,
7094 @@ -1878,9 +1902,7 @@ gen7_render_video(struct sna *sna,
7095 GEN7_SET_FLAGS(SAMPLER_OFFSET(filter, SAMPLER_EXTEND_PAD,
7096 SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE),
7097 NO_BLEND,
7098 - is_planar_fourcc(frame->id) ?
7099 - GEN7_WM_KERNEL_VIDEO_PLANAR :
7100 - GEN7_WM_KERNEL_VIDEO_PACKED,
7101 + select_video_kernel(frame),
7102 2);
7103 tmp.priv = frame;
7105 @@ -1896,17 +1918,6 @@ gen7_render_video(struct sna *sna,
7106 gen7_align_vertex(sna, &tmp);
7107 gen7_emit_video_state(sna, &tmp);
7109 - /* Set up the offset for translating from the given region (in screen
7110 - * coordinates) to the backing pixmap.
7111 - */
7112 -#ifdef COMPOSITE
7113 - pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
7114 - pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
7115 -#else
7116 - pix_xoff = 0;
7117 - pix_yoff = 0;
7118 -#endif
7120 DBG(("%s: src=(%d, %d)x(%d, %d); frame=(%dx%d), dst=(%dx%d)\n",
7121 __FUNCTION__,
7122 frame->src.x1, frame->src.y1,
7123 @@ -1928,45 +1939,36 @@ gen7_render_video(struct sna *sna,
7124 box = region_rects(dstRegion);
7125 nbox = region_num_rects(dstRegion);
7126 while (nbox--) {
7127 - BoxRec r;
7129 - DBG(("%s: dst=(%d, %d), (%d, %d) + (%d, %d); src=(%f, %f), (%f, %f)\n",
7130 + DBG(("%s: dst=(%d, %d), (%d, %d); src=(%f, %f), (%f, %f)\n",
7131 __FUNCTION__,
7132 box->x1, box->y1,
7133 box->x2, box->y2,
7134 - pix_xoff, pix_yoff,
7135 box->x1 * src_scale_x + src_offset_x,
7136 box->y1 * src_scale_y + src_offset_y,
7137 box->x2 * src_scale_x + src_offset_x,
7138 box->y2 * src_scale_y + src_offset_y));
7140 - r.x1 = box->x1 + pix_xoff;
7141 - r.x2 = box->x2 + pix_xoff;
7142 - r.y1 = box->y1 + pix_yoff;
7143 - r.y2 = box->y2 + pix_yoff;
7145 gen7_get_rectangles(sna, &tmp, 1, gen7_emit_video_state);
7147 - OUT_VERTEX(r.x2, r.y2);
7148 + OUT_VERTEX(box->x2, box->y2);
7149 OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
7150 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
7152 - OUT_VERTEX(r.x1, r.y2);
7153 + OUT_VERTEX(box->x1, box->y2);
7154 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
7155 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
7157 - OUT_VERTEX(r.x1, r.y1);
7158 + OUT_VERTEX(box->x1, box->y1);
7159 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
7160 OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
7162 - if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
7163 - sna_damage_add_box(&priv->gpu_damage, &r);
7164 - sna_damage_subtract_box(&priv->cpu_damage, &r);
7165 - }
7166 box++;
7169 gen4_vertex_flush(sna);
7171 + if (!DAMAGE_IS_ALL(priv->gpu_damage))
7172 + sna_damage_add(&priv->gpu_damage, dstRegion);
7174 return true;
7177 @@ -2048,12 +2050,13 @@ gen7_composite_picture(struct sna *sna,
7178 if (channel->repeat ||
7179 (x >= 0 &&
7180 y >= 0 &&
7181 - x + w < pixmap->drawable.width &&
7182 - y + h < pixmap->drawable.height)) {
7183 + x + w <= pixmap->drawable.width &&
7184 + y + h <= pixmap->drawable.height)) {
7185 struct sna_pixmap *priv = sna_pixmap(pixmap);
7186 if (priv && priv->clear) {
7187 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
7188 - return gen4_channel_init_solid(sna, channel, priv->clear_color);
7189 + return gen4_channel_init_solid(sna, channel,
7190 + solid_color(picture->format, priv->clear_color));
7193 } else
7194 @@ -2147,7 +2150,9 @@ gen7_composite_set_target(struct sna *sna,
7195 } else
7196 sna_render_picture_extents(dst, &box);
7198 - hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
7199 + hint = PREFER_GPU | RENDER_GPU;
7200 + if (!need_tiling(sna, op->dst.width, op->dst.height))
7201 + hint |= FORCE_GPU;
7202 if (!partial) {
7203 hint |= IGNORE_DAMAGE;
7204 if (w == op->dst.width && h == op->dst.height)
7205 @@ -2185,46 +2190,78 @@ gen7_composite_set_target(struct sna *sna,
7207 static bool
7208 try_blt(struct sna *sna,
7209 - PicturePtr dst, PicturePtr src,
7210 - int width, int height)
7211 + uint8_t op,
7212 + PicturePtr src,
7213 + PicturePtr mask,
7214 + PicturePtr dst,
7215 + int16_t src_x, int16_t src_y,
7216 + int16_t msk_x, int16_t msk_y,
7217 + int16_t dst_x, int16_t dst_y,
7218 + int16_t width, int16_t height,
7219 + unsigned flags,
7220 + struct sna_composite_op *tmp)
7222 struct kgem_bo *bo;
7224 if (sna->kgem.mode == KGEM_BLT) {
7225 DBG(("%s: already performing BLT\n", __FUNCTION__));
7226 - return true;
7227 + goto execute;
7230 if (too_large(width, height)) {
7231 DBG(("%s: operation too large for 3D pipe (%d, %d)\n",
7232 __FUNCTION__, width, height));
7233 - return true;
7234 + goto execute;
7237 bo = __sna_drawable_peek_bo(dst->pDrawable);
7238 if (bo == NULL)
7239 - return true;
7240 - if (bo->rq)
7241 - return RQ_IS_BLT(bo->rq);
7242 + goto execute;
7244 + if (untiled_tlb_miss(bo))
7245 + goto execute;
7247 + if (bo->rq) {
7248 + if (RQ_IS_BLT(bo->rq))
7249 + goto execute;
7251 + return false;
7252 + }
7254 + if (bo->tiling == I915_TILING_Y)
7255 + goto upload;
7257 + if (src->pDrawable == dst->pDrawable &&
7258 + (sna->render_state.gt < 3 || width*height < 1024) &&
7259 + can_switch_to_blt(sna, bo, 0))
7260 + goto execute;
7262 if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0))
7263 - return true;
7264 + goto execute;
7266 if (src->pDrawable) {
7267 - bo = __sna_drawable_peek_bo(src->pDrawable);
7268 - if (bo == NULL)
7269 - return true;
7270 + struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable);
7271 + if (s == NULL)
7272 + goto upload;
7274 - if (prefer_blt_bo(sna, bo))
7275 - return true;
7276 + if (prefer_blt_bo(sna, s, bo))
7277 + goto execute;
7280 if (sna->kgem.ring == KGEM_BLT) {
7281 DBG(("%s: already performing BLT\n", __FUNCTION__));
7282 - return true;
7283 + goto execute;
7286 - return false;
7287 +upload:
7288 + flags |= COMPOSITE_UPLOAD;
7289 +execute:
7290 + return sna_blt_composite(sna, op,
7291 + src, dst,
7292 + src_x, src_y,
7293 + dst_x, dst_y,
7294 + width, height,
7295 + flags, tmp);
7298 static bool
7299 @@ -2454,13 +2491,13 @@ gen7_render_composite(struct sna *sna,
7300 width, height, sna->kgem.mode, sna->kgem.ring));
7302 if (mask == NULL &&
7303 - try_blt(sna, dst, src, width, height) &&
7304 - sna_blt_composite(sna, op,
7305 - src, dst,
7306 - src_x, src_y,
7307 - dst_x, dst_y,
7308 - width, height,
7309 - flags, tmp))
7310 + try_blt(sna, op,
7311 + src, mask, dst,
7312 + src_x, src_y,
7313 + msk_x, msk_y,
7314 + dst_x, dst_y,
7315 + width, height,
7316 + flags, tmp))
7317 return true;
7319 if (gen7_composite_fallback(sna, src, mask, dst))
7320 @@ -2878,27 +2915,37 @@ prefer_blt_copy(struct sna *sna,
7322 assert((flags & COPY_SYNC) == 0);
7324 - if (src_bo == dst_bo && can_switch_to_blt(sna, dst_bo, flags))
7325 - return true;
7327 if (untiled_tlb_miss(src_bo) ||
7328 untiled_tlb_miss(dst_bo))
7329 return true;
7331 - if (force_blt_ring(sna))
7332 + if (flags & COPY_DRI && !sna->kgem.has_semaphores)
7333 + return false;
7335 + if (force_blt_ring(sna, dst_bo))
7336 + return true;
7338 + if ((flags & COPY_SMALL ||
7339 + (sna->render_state.gt < 3 && src_bo == dst_bo)) &&
7340 + can_switch_to_blt(sna, dst_bo, flags))
7341 return true;
7343 if (kgem_bo_is_render(dst_bo) ||
7344 kgem_bo_is_render(src_bo))
7345 return false;
7347 + if (flags & COPY_LAST &&
7348 + sna->render_state.gt < 3 &&
7349 + can_switch_to_blt(sna, dst_bo, flags))
7350 + return true;
7352 if (prefer_render_ring(sna, dst_bo))
7353 return false;
7355 if (!prefer_blt_ring(sna, dst_bo, flags))
7356 return false;
7358 - return prefer_blt_bo(sna, src_bo) || prefer_blt_bo(sna, dst_bo);
7359 + return prefer_blt_bo(sna, src_bo, dst_bo);
7362 static bool
7363 @@ -2946,7 +2993,7 @@ fallback_blt:
7364 &extents)) {
7365 bool big = too_large(extents.x2-extents.x1, extents.y2-extents.y1);
7367 - if ((big || can_switch_to_blt(sna, dst_bo, flags)) &&
7368 + if ((big || !prefer_render_ring(sna, dst_bo)) &&
7369 sna_blt_copy_boxes(sna, alu,
7370 src_bo, src_dx, src_dy,
7371 dst_bo, dst_dx, dst_dy,
7372 @@ -2961,8 +3008,7 @@ fallback_blt:
7373 assert(src->depth == dst->depth);
7374 assert(src->width == dst->width);
7375 assert(src->height == dst->height);
7376 - return sna_render_copy_boxes__overlap(sna, alu,
7377 - src, src_bo,
7378 + return sna_render_copy_boxes__overlap(sna, alu, dst, dst_bo,
7379 src_dx, src_dy,
7380 dst_dx, dst_dy,
7381 box, n, &extents);
7382 diff --git a/src/sna/gen8_render.c b/src/sna/gen8_render.c
7383 index 6eb11452..445983b1 100644
7384 --- a/src/sna/gen8_render.c
7385 +++ b/src/sna/gen8_render.c
7386 @@ -106,6 +106,12 @@ static const uint32_t ps_kernel_planar[][4] = {
7387 #include "exa_wm_yuv_rgb.g8b"
7388 #include "exa_wm_write.g8b"
7389 };
7391 +static const uint32_t ps_kernel_rgb[][4] = {
7392 +#include "exa_wm_src_affine.g8b"
7393 +#include "exa_wm_src_sample_argb.g8b"
7394 +#include "exa_wm_write.g8b"
7395 +};
7396 #endif
7398 #define SURFACE_DW (64 / sizeof(uint32_t));
7399 @@ -119,7 +125,7 @@ static const struct wm_kernel_info {
7400 const void *data;
7401 unsigned int size;
7402 int num_surfaces;
7403 -} wm_kernels[] = {
7404 +} wm_kernels[GEN8_WM_KERNEL_COUNT] = {
7405 NOKERNEL(NOMASK, gen8_wm_kernel__affine, 2),
7406 NOKERNEL(NOMASK_P, gen8_wm_kernel__projective, 2),
7408 @@ -138,6 +144,7 @@ static const struct wm_kernel_info {
7409 #if !NO_VIDEO
7410 KERNEL(VIDEO_PLANAR, ps_kernel_planar, 7),
7411 KERNEL(VIDEO_PACKED, ps_kernel_packed, 2),
7412 + KERNEL(VIDEO_RGB, ps_kernel_rgb, 2),
7413 #endif
7414 };
7415 #undef KERNEL
7416 @@ -205,6 +212,33 @@ static const struct blendinfo {
7417 #define OUT_VERTEX(x,y) vertex_emit_2s(sna, x,y)
7418 #define OUT_VERTEX_F(v) vertex_emit(sna, v)
7420 +struct gt_info {
7421 + const char *name;
7422 + struct {
7423 + int max_vs_entries;
7424 + } urb;
7425 +};
7427 +static const struct gt_info bdw_gt_info = {
7428 + .name = "Broadwell (gen8)",
7429 + .urb = { .max_vs_entries = 960 },
7430 +};
7432 +static bool is_bdw(struct sna *sna)
7433 +{
7434 + return sna->kgem.gen == 0100;
7435 +}
7437 +static const struct gt_info chv_gt_info = {
7438 + .name = "Cherryview (gen8)",
7439 + .urb = { .max_vs_entries = 640 },
7440 +};
7442 +static bool is_chv(struct sna *sna)
7443 +{
7444 + return sna->kgem.gen == 0101;
7445 +}
7447 static inline bool too_large(int width, int height)
7449 return width > GEN8_MAX_SIZE || height > GEN8_MAX_SIZE;
7450 @@ -462,7 +496,7 @@ gen8_emit_urb(struct sna *sna)
7452 /* num of VS entries must be divisible by 8 if size < 9 */
7453 OUT_BATCH(GEN8_3DSTATE_URB_VS | (2 - 2));
7454 - OUT_BATCH(960 << URB_ENTRY_NUMBER_SHIFT |
7455 + OUT_BATCH(sna->render_state.gen8.info->urb.max_vs_entries << URB_ENTRY_NUMBER_SHIFT |
7456 (2 - 1) << URB_ENTRY_SIZE_SHIFT |
7457 4 << URB_STARTING_ADDRESS_SHIFT);
7459 @@ -873,7 +907,7 @@ gen8_emit_cc(struct sna *sna, uint32_t blend)
7460 assert(blend / GEN8_BLENDFACTOR_COUNT > 0);
7461 assert(blend % GEN8_BLENDFACTOR_COUNT > 0);
7463 - /* XXX can have upto 8 blend states preload, selectable via
7464 + /* XXX can have up to 8 blend states preload, selectable via
7465 * Render Target Index. What other side-effects of Render Target Index?
7466 */
7468 @@ -1167,6 +1201,7 @@ gen8_emit_pipe_stall(struct sna *sna)
7470 OUT_BATCH(GEN8_PIPE_CONTROL | (6 - 2));
7471 OUT_BATCH(PIPE_CONTROL_CS_STALL |
7472 + PIPE_CONTROL_FLUSH |
7473 PIPE_CONTROL_STALL_AT_SCOREBOARD);
7474 OUT_BATCH64(0);
7475 OUT_BATCH64(0);
7476 @@ -1876,12 +1911,12 @@ gen8_composite_picture(struct sna *sna,
7477 if (channel->repeat ||
7478 (x >= 0 &&
7479 y >= 0 &&
7480 - x + w < pixmap->drawable.width &&
7481 - y + h < pixmap->drawable.height)) {
7482 + x + w <= pixmap->drawable.width &&
7483 + y + h <= pixmap->drawable.height)) {
7484 struct sna_pixmap *priv = sna_pixmap(pixmap);
7485 if (priv && priv->clear) {
7486 DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
7487 - return gen4_channel_init_solid(sna, channel, priv->clear_color);
7488 + return gen4_channel_init_solid(sna, channel, solid_color(picture->format, priv->clear_color));
7491 } else
7492 @@ -1961,7 +1996,9 @@ gen8_composite_set_target(struct sna *sna,
7493 } else
7494 sna_render_picture_extents(dst, &box);
7496 - hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
7497 + hint = PREFER_GPU | RENDER_GPU;
7498 + if (!need_tiling(sna, op->dst.width, op->dst.height))
7499 + hint |= FORCE_GPU;
7500 if (!partial) {
7501 hint |= IGNORE_DAMAGE;
7502 if (w == op->dst.width && h == op->dst.height)
7503 @@ -2002,46 +2039,78 @@ gen8_composite_set_target(struct sna *sna,
7505 static bool
7506 try_blt(struct sna *sna,
7507 - PicturePtr dst, PicturePtr src,
7508 - int width, int height)
7509 + uint8_t op,
7510 + PicturePtr src,
7511 + PicturePtr mask,
7512 + PicturePtr dst,
7513 + int16_t src_x, int16_t src_y,
7514 + int16_t msk_x, int16_t msk_y,
7515 + int16_t dst_x, int16_t dst_y,
7516 + int16_t width, int16_t height,
7517 + unsigned flags,
7518 + struct sna_composite_op *tmp)
7520 struct kgem_bo *bo;
7522 if (sna->kgem.mode == KGEM_BLT) {
7523 DBG(("%s: already performing BLT\n", __FUNCTION__));
7524 - return true;
7525 + goto execute;
7528 if (too_large(width, height)) {
7529 DBG(("%s: operation too large for 3D pipe (%d, %d)\n",
7530 __FUNCTION__, width, height));
7531 - return true;
7532 + goto execute;
7535 bo = __sna_drawable_peek_bo(dst->pDrawable);
7536 if (bo == NULL)
7537 - return true;
7538 - if (bo->rq)
7539 - return RQ_IS_BLT(bo->rq);
7540 + goto execute;
7542 + if (untiled_tlb_miss(bo))
7543 + goto execute;
7545 + if (bo->rq) {
7546 + if (RQ_IS_BLT(bo->rq))
7547 + goto execute;
7549 + return false;
7550 + }
7552 + if (bo->tiling == I915_TILING_Y)
7553 + goto upload;
7555 if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0))
7556 - return true;
7557 + goto execute;
7559 + if (src->pDrawable == dst->pDrawable &&
7560 + (sna->render_state.gt < 3 || width*height < 1024) &&
7561 + can_switch_to_blt(sna, bo, 0))
7562 + goto execute;
7564 if (src->pDrawable) {
7565 - bo = __sna_drawable_peek_bo(src->pDrawable);
7566 - if (bo == NULL)
7567 - return true;
7568 + struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable);
7569 + if (s == NULL)
7570 + goto upload;
7572 - if (prefer_blt_bo(sna, bo))
7573 - return RQ_IS_BLT(bo->rq);
7574 + if (prefer_blt_bo(sna, s, bo))
7575 + goto execute;
7578 if (sna->kgem.ring == KGEM_BLT) {
7579 DBG(("%s: already performing BLT\n", __FUNCTION__));
7580 - return true;
7581 + goto execute;
7584 - return false;
7585 +upload:
7586 + flags |= COMPOSITE_UPLOAD;
7587 +execute:
7588 + return sna_blt_composite(sna, op,
7589 + src, dst,
7590 + src_x, src_y,
7591 + dst_x, dst_y,
7592 + width, height,
7593 + flags, tmp);
7596 static bool
7597 @@ -2271,13 +2340,13 @@ gen8_render_composite(struct sna *sna,
7598 width, height, sna->kgem.mode, sna->kgem.ring));
7600 if (mask == NULL &&
7601 - try_blt(sna, dst, src, width, height) &&
7602 - sna_blt_composite(sna, op,
7603 - src, dst,
7604 - src_x, src_y,
7605 - dst_x, dst_y,
7606 - width, height,
7607 - flags, tmp))
7608 + try_blt(sna, op,
7609 + src, mask, dst,
7610 + src_x, src_y,
7611 + msk_x, msk_y,
7612 + dst_x, dst_y,
7613 + width, height,
7614 + flags, tmp))
7615 return true;
7617 if (gen8_composite_fallback(sna, src, mask, dst))
7618 @@ -2700,27 +2769,37 @@ prefer_blt_copy(struct sna *sna,
7620 assert((flags & COPY_SYNC) == 0);
7622 - if (src_bo == dst_bo && can_switch_to_blt(sna, dst_bo, flags))
7623 - return true;
7625 if (untiled_tlb_miss(src_bo) ||
7626 untiled_tlb_miss(dst_bo))
7627 return true;
7629 - if (force_blt_ring(sna))
7630 + if (flags & COPY_DRI && !sna->kgem.has_semaphores)
7631 + return false;
7633 + if (force_blt_ring(sna, dst_bo))
7634 + return true;
7636 + if ((flags & COPY_SMALL ||
7637 + (sna->render_state.gt < 3 && src_bo == dst_bo)) &&
7638 + can_switch_to_blt(sna, dst_bo, flags))
7639 return true;
7641 if (kgem_bo_is_render(dst_bo) ||
7642 kgem_bo_is_render(src_bo))
7643 return false;
7645 + if (flags & COPY_LAST &&
7646 + sna->render_state.gt < 3 &&
7647 + can_switch_to_blt(sna, dst_bo, flags))
7648 + return true;
7650 if (prefer_render_ring(sna, dst_bo))
7651 return false;
7653 if (!prefer_blt_ring(sna, dst_bo, flags))
7654 return false;
7656 - return prefer_blt_bo(sna, src_bo) || prefer_blt_bo(sna, dst_bo);
7657 + return prefer_blt_bo(sna, src_bo, dst_bo);
7660 static bool
7661 @@ -2770,7 +2849,7 @@ fallback_blt:
7662 &extents)) {
7663 bool big = too_large(extents.x2-extents.x1, extents.y2-extents.y1);
7665 - if ((big || can_switch_to_blt(sna, dst_bo, flags)) &&
7666 + if ((big || !prefer_render_ring(sna, dst_bo)) &&
7667 sna_blt_copy_boxes(sna, alu,
7668 src_bo, src_dx, src_dy,
7669 dst_bo, dst_dx, dst_dy,
7670 @@ -2785,8 +2864,7 @@ fallback_blt:
7671 assert(src->depth == dst->depth);
7672 assert(src->width == dst->width);
7673 assert(src->height == dst->height);
7674 - return sna_render_copy_boxes__overlap(sna, alu,
7675 - src, src_bo,
7676 + return sna_render_copy_boxes__overlap(sna, alu, dst, dst_bo,
7677 src_dx, src_dy,
7678 dst_dx, dst_dy,
7679 box, n, &extents);
7680 @@ -3665,7 +3743,9 @@ static void gen8_emit_video_state(struct sna *sna,
7681 frame->pitch[0];
7682 n_src = 6;
7683 } else {
7684 - if (frame->id == FOURCC_UYVY)
7685 + if (frame->id == FOURCC_RGB888)
7686 + src_surf_format = SURFACEFORMAT_B8G8R8X8_UNORM;
7687 + else if (frame->id == FOURCC_UYVY)
7688 src_surf_format = SURFACEFORMAT_YCRCB_SWAPY;
7689 else
7690 src_surf_format = SURFACEFORMAT_YCRCB_NORMAL;
7691 @@ -3697,6 +3777,23 @@ static void gen8_emit_video_state(struct sna *sna,
7692 gen8_emit_state(sna, op, offset);
7695 +static unsigned select_video_kernel(const struct sna_video_frame *frame)
7696 +{
7697 + switch (frame->id) {
7698 + case FOURCC_YV12:
7699 + case FOURCC_I420:
7700 + case FOURCC_XVMC:
7701 + return GEN8_WM_KERNEL_VIDEO_PLANAR;
7703 + case FOURCC_RGB888:
7704 + case FOURCC_RGB565:
7705 + return GEN8_WM_KERNEL_VIDEO_RGB;
7707 + default:
7708 + return GEN8_WM_KERNEL_VIDEO_PACKED;
7709 + }
7710 +}
7712 static bool
7713 gen8_render_video(struct sna *sna,
7714 struct sna_video *video,
7715 @@ -3712,9 +3809,9 @@ gen8_render_video(struct sna *sna,
7716 int src_height = frame->src.y2 - frame->src.y1;
7717 float src_offset_x, src_offset_y;
7718 float src_scale_x, src_scale_y;
7719 - int nbox, pix_xoff, pix_yoff;
7720 unsigned filter;
7721 const BoxRec *box;
7722 + int nbox;
7724 DBG(("%s: src=(%d, %d), dst=(%d, %d), %dx[(%d, %d), (%d, %d)...]\n",
7725 __FUNCTION__,
7726 @@ -3743,6 +3840,11 @@ gen8_render_video(struct sna *sna,
7727 tmp.floats_per_vertex = 3;
7728 tmp.floats_per_rect = 9;
7730 + DBG(("%s: scaling?=%d, planar?=%d [%x]\n",
7731 + __FUNCTION__,
7732 + src_width != dst_width || src_height != dst_height,
7733 + is_planar_fourcc(frame->id), frame->id));
7735 if (src_width == dst_width && src_height == dst_height)
7736 filter = SAMPLER_FILTER_NEAREST;
7737 else
7738 @@ -3752,9 +3854,7 @@ gen8_render_video(struct sna *sna,
7739 GEN8_SET_FLAGS(SAMPLER_OFFSET(filter, SAMPLER_EXTEND_PAD,
7740 SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE),
7741 NO_BLEND,
7742 - is_planar_fourcc(frame->id) ?
7743 - GEN8_WM_KERNEL_VIDEO_PLANAR :
7744 - GEN8_WM_KERNEL_VIDEO_PACKED,
7745 + select_video_kernel(frame),
7746 2);
7747 tmp.priv = frame;
7749 @@ -3770,17 +3870,6 @@ gen8_render_video(struct sna *sna,
7750 gen8_align_vertex(sna, &tmp);
7751 gen8_emit_video_state(sna, &tmp);
7753 - /* Set up the offset for translating from the given region (in screen
7754 - * coordinates) to the backing pixmap.
7755 - */
7756 -#ifdef COMPOSITE
7757 - pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
7758 - pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
7759 -#else
7760 - pix_xoff = 0;
7761 - pix_yoff = 0;
7762 -#endif
7764 DBG(("%s: src=(%d, %d)x(%d, %d); frame=(%dx%d), dst=(%dx%d)\n",
7765 __FUNCTION__,
7766 frame->src.x1, frame->src.y1,
7767 @@ -3802,45 +3891,36 @@ gen8_render_video(struct sna *sna,
7768 box = region_rects(dstRegion);
7769 nbox = region_num_rects(dstRegion);
7770 while (nbox--) {
7771 - BoxRec r;
7773 DBG(("%s: dst=(%d, %d), (%d, %d) + (%d, %d); src=(%f, %f), (%f, %f)\n",
7774 __FUNCTION__,
7775 box->x1, box->y1,
7776 box->x2, box->y2,
7777 - pix_xoff, pix_yoff,
7778 box->x1 * src_scale_x + src_offset_x,
7779 box->y1 * src_scale_y + src_offset_y,
7780 box->x2 * src_scale_x + src_offset_x,
7781 box->y2 * src_scale_y + src_offset_y));
7783 - r.x1 = box->x1 + pix_xoff;
7784 - r.x2 = box->x2 + pix_xoff;
7785 - r.y1 = box->y1 + pix_yoff;
7786 - r.y2 = box->y2 + pix_yoff;
7788 gen8_get_rectangles(sna, &tmp, 1, gen8_emit_video_state);
7790 - OUT_VERTEX(r.x2, r.y2);
7791 + OUT_VERTEX(box->x2, box->y2);
7792 OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
7793 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
7795 - OUT_VERTEX(r.x1, r.y2);
7796 + OUT_VERTEX(box->x1, box->y2);
7797 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
7798 OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
7800 - OUT_VERTEX(r.x1, r.y1);
7801 + OUT_VERTEX(box->x1, box->y1);
7802 OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
7803 OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
7805 - if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
7806 - sna_damage_add_box(&priv->gpu_damage, &r);
7807 - sna_damage_subtract_box(&priv->cpu_damage, &r);
7808 - }
7809 box++;
7812 gen8_vertex_flush(sna);
7814 + if (!DAMAGE_IS_ALL(priv->gpu_damage))
7815 + sna_damage_add(&priv->gpu_damage, dstRegion);
7817 return true;
7819 #endif
7820 @@ -3896,6 +3976,13 @@ static bool gen8_render_setup(struct sna *sna)
7821 state->gt = ((devid >> 4) & 0xf) + 1;
7822 DBG(("%s: gt=%d\n", __FUNCTION__, state->gt));
7824 + if (is_bdw(sna))
7825 + state->info = &bdw_gt_info;
7826 + else if (is_chv(sna))
7827 + state->info = &chv_gt_info;
7828 + else
7829 + return false;
7831 sna_static_stream_init(&general);
7833 /* Zero pad the start. If you see an offset of 0x0 in the batchbuffer
7834 @@ -4007,5 +4094,5 @@ const char *gen8_render_init(struct sna *sna, const char *backend)
7836 sna->render.max_3d_size = GEN8_MAX_SIZE;
7837 sna->render.max_3d_pitch = 1 << 18;
7838 - return "Broadwell";
7839 + return sna->render_state.gen8.info->name;
7841 diff --git a/src/sna/gen8_render.h b/src/sna/gen8_render.h
7842 index eb4928e7..e6a8dc55 100644
7843 --- a/src/sna/gen8_render.h
7844 +++ b/src/sna/gen8_render.h
7845 @@ -335,6 +335,7 @@
7846 #define PIPE_CONTROL_IS_FLUSH (1 << 11)
7847 #define PIPE_CONTROL_TC_FLUSH (1 << 10)
7848 #define PIPE_CONTROL_NOTIFY_ENABLE (1 << 8)
7849 +#define PIPE_CONTROL_FLUSH (1 << 7)
7850 #define PIPE_CONTROL_GLOBAL_GTT (1 << 2)
7851 #define PIPE_CONTROL_LOCAL_PGTT (0 << 2)
7852 #define PIPE_CONTROL_STALL_AT_SCOREBOARD (1 << 1)
7853 diff --git a/src/sna/gen9_render.c b/src/sna/gen9_render.c
7854 new file mode 100644
7855 index 00000000..e5f12c72
7856 --- /dev/null
7857 +++ b/src/sna/gen9_render.c
7858 @@ -0,0 +1,4156 @@
7859 +/*
7860 + * Copyright © 2012,2013 Intel Corporation
7861 + *
7862 + * Permission is hereby granted, free of charge, to any person obtaining a
7863 + * copy of this software and associated documentation files (the "Software"),
7864 + * to deal in the Software without restriction, including without limitation
7865 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
7866 + * and/or sell copies of the Software, and to permit persons to whom the
7867 + * Software is furnished to do so, subject to the following conditions:
7868 + *
7869 + * The above copyright notice and this permission notice (including the next
7870 + * paragraph) shall be included in all copies or substantial portions of the
7871 + * Software.
7872 + *
7873 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7874 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7875 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
7876 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7877 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7878 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
7879 + * SOFTWARE.
7880 + *
7881 + * Authors:
7882 + * Chris Wilson <chris@chris-wilson.co.uk>
7883 + *
7884 + */
7886 +#ifdef HAVE_CONFIG_H
7887 +#include "config.h"
7888 +#endif
7890 +#include "sna.h"
7891 +#include "sna_reg.h"
7892 +#include "sna_render.h"
7893 +#include "sna_render_inline.h"
7894 +#include "sna_video.h"
7896 +#include "gen9_render.h"
7897 +#include "gen8_eu.h"
7898 +#include "gen4_common.h"
7899 +#include "gen4_source.h"
7900 +#include "gen4_vertex.h"
7901 +#include "gen6_common.h"
7902 +#include "gen8_vertex.h"
7904 +#define SIM 1
7906 +#define ALWAYS_INVALIDATE 0
7907 +#define ALWAYS_FLUSH 0
7908 +#define ALWAYS_STALL 0
7910 +#define NO_COMPOSITE 0
7911 +#define NO_COMPOSITE_SPANS 0
7912 +#define NO_COPY 0
7913 +#define NO_COPY_BOXES 0
7914 +#define NO_FILL 0
7915 +#define NO_FILL_BOXES 0
7916 +#define NO_FILL_ONE 0
7917 +#define NO_FILL_CLEAR 0
7918 +#define NO_VIDEO 0
7920 +#define USE_8_PIXEL_DISPATCH 1
7921 +#define USE_16_PIXEL_DISPATCH 1
7922 +#define USE_32_PIXEL_DISPATCH 0
7924 +#if !USE_8_PIXEL_DISPATCH && !USE_16_PIXEL_DISPATCH && !USE_32_PIXEL_DISPATCH
7925 +#error "Must select at least 8, 16 or 32 pixel dispatch"
7926 +#endif
7928 +#define GEN9_MAX_SIZE 16384
7929 +#define GEN9_GT_BIAS 1 /* Each GT is bigger than previous gen */
7931 +/* XXX Todo
7932 + *
7933 + * STR (software tiled rendering) mode. No, really.
7934 + * 64x32 pixel blocks align with the rendering cache. Worth considering.
7935 + */
7937 +#define is_aligned(x, y) (((x) & ((y) - 1)) == 0)
7939 +/* Pipeline stages:
7940 + * 1. Command Streamer (CS)
7941 + * 2. Vertex Fetch (VF)
7942 + * 3. Vertex Shader (VS)
7943 + * 4. Hull Shader (HS)
7944 + * 5. Tesselation Engine (TE)
7945 + * 6. Domain Shader (DS)
7946 + * 7. Geometry Shader (GS)
7947 + * 8. Stream Output Logic (SOL)
7948 + * 9. Clipper (CLIP)
7949 + * 10. Strip/Fan (SF)
7950 + * 11. Windower/Masker (WM)
7951 + * 12. Color Calculator (CC)
7952 + */
7954 +#if !NO_VIDEO
7955 +static const uint32_t ps_kernel_packed[][4] = {
7956 +#include "exa_wm_src_affine.g8b"
7957 +#include "exa_wm_src_sample_argb.g8b"
7958 +#include "exa_wm_yuv_rgb.g8b"
7959 +#include "exa_wm_write.g8b"
7960 +};
7962 +static const uint32_t ps_kernel_planar[][4] = {
7963 +#include "exa_wm_src_affine.g8b"
7964 +#include "exa_wm_src_sample_planar.g8b"
7965 +#include "exa_wm_yuv_rgb.g8b"
7966 +#include "exa_wm_write.g8b"
7967 +};
7969 +static const uint32_t ps_kernel_rgb[][4] = {
7970 +#include "exa_wm_src_affine.g8b"
7971 +#include "exa_wm_src_sample_argb.g8b"
7972 +#include "exa_wm_write.g8b"
7973 +};
7974 +#endif
7976 +#define SURFACE_DW (64 / sizeof(uint32_t));
7978 +#define KERNEL(kernel_enum, kernel, num_surfaces) \
7979 + [GEN9_WM_KERNEL_##kernel_enum] = {#kernel_enum, kernel, sizeof(kernel), num_surfaces}
7980 +#define NOKERNEL(kernel_enum, func, num_surfaces) \
7981 + [GEN9_WM_KERNEL_##kernel_enum] = {#kernel_enum, (void *)func, 0, num_surfaces}
7982 +static const struct wm_kernel_info {
7983 + const char *name;
7984 + const void *data;
7985 + unsigned int size;
7986 + int num_surfaces;
7987 +} wm_kernels[] = {
7988 + NOKERNEL(NOMASK, gen8_wm_kernel__affine, 2),
7989 + NOKERNEL(NOMASK_P, gen8_wm_kernel__projective, 2),
7991 + NOKERNEL(MASK, gen8_wm_kernel__affine_mask, 3),
7992 + NOKERNEL(MASK_P, gen8_wm_kernel__projective_mask, 3),
7994 + NOKERNEL(MASKCA, gen8_wm_kernel__affine_mask_ca, 3),
7995 + NOKERNEL(MASKCA_P, gen8_wm_kernel__projective_mask_ca, 3),
7997 + NOKERNEL(MASKSA, gen8_wm_kernel__affine_mask_sa, 3),
7998 + NOKERNEL(MASKSA_P, gen8_wm_kernel__projective_mask_sa, 3),
8000 + NOKERNEL(OPACITY, gen8_wm_kernel__affine_opacity, 2),
8001 + NOKERNEL(OPACITY_P, gen8_wm_kernel__projective_opacity, 2),
8003 +#if !NO_VIDEO
8004 + KERNEL(VIDEO_PLANAR, ps_kernel_planar, 7),
8005 + KERNEL(VIDEO_PACKED, ps_kernel_packed, 2),
8006 + KERNEL(VIDEO_RGB, ps_kernel_rgb, 2),
8007 +#endif
8008 +};
8009 +#undef KERNEL
8011 +static const struct blendinfo {
8012 + uint8_t src_alpha;
8013 + uint8_t src_blend;
8014 + uint8_t dst_blend;
8015 +} gen9_blend_op[] = {
8016 + /* Clear */ {0, BLENDFACTOR_ZERO, BLENDFACTOR_ZERO},
8017 + /* Src */ {0, BLENDFACTOR_ONE, BLENDFACTOR_ZERO},
8018 + /* Dst */ {0, BLENDFACTOR_ZERO, BLENDFACTOR_ONE},
8019 + /* Over */ {1, BLENDFACTOR_ONE, BLENDFACTOR_INV_SRC_ALPHA},
8020 + /* OverReverse */ {0, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_ONE},
8021 + /* In */ {0, BLENDFACTOR_DST_ALPHA, BLENDFACTOR_ZERO},
8022 + /* InReverse */ {1, BLENDFACTOR_ZERO, BLENDFACTOR_SRC_ALPHA},
8023 + /* Out */ {0, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_ZERO},
8024 + /* OutReverse */ {1, BLENDFACTOR_ZERO, BLENDFACTOR_INV_SRC_ALPHA},
8025 + /* Atop */ {1, BLENDFACTOR_DST_ALPHA, BLENDFACTOR_INV_SRC_ALPHA},
8026 + /* AtopReverse */ {1, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_SRC_ALPHA},
8027 + /* Xor */ {1, BLENDFACTOR_INV_DST_ALPHA, BLENDFACTOR_INV_SRC_ALPHA},
8028 + /* Add */ {0, BLENDFACTOR_ONE, BLENDFACTOR_ONE},
8029 +};
8031 +/**
8032 + * Highest-valued BLENDFACTOR used in gen9_blend_op.
8033 + *
8034 + * This leaves out GEN9_BLENDFACTOR_INV_DST_COLOR,
8035 + * GEN9_BLENDFACTOR_INV_CONST_{COLOR,ALPHA},
8036 + * GEN9_BLENDFACTOR_INV_SRC1_{COLOR,ALPHA}
8037 + */
8038 +#define GEN9_BLENDFACTOR_COUNT (BLENDFACTOR_INV_DST_ALPHA + 1)
8040 +#define GEN9_BLEND_STATE_PADDED_SIZE ALIGN(sizeof(struct gen9_blend_state), 64)
8042 +#define BLEND_OFFSET(s, d) \
8043 + ((d != BLENDFACTOR_ZERO) << 15 | ((s) * GEN9_BLENDFACTOR_COUNT + (d)) << 4)
8045 +#define NO_BLEND BLEND_OFFSET(BLENDFACTOR_ONE, BLENDFACTOR_ZERO)
8046 +#define CLEAR BLEND_OFFSET(BLENDFACTOR_ZERO, BLENDFACTOR_ZERO)
8048 +#define SAMPLER_OFFSET(sf, se, mf, me) \
8049 + (((((sf) * EXTEND_COUNT + (se)) * FILTER_COUNT + (mf)) * EXTEND_COUNT + (me)) + 2)
8051 +#define VERTEX_2s2s 0
8053 +#define COPY_SAMPLER 0
8054 +#define COPY_VERTEX VERTEX_2s2s
8055 +#define COPY_FLAGS(a) GEN9_SET_FLAGS(COPY_SAMPLER, (a) == GXcopy ? NO_BLEND : CLEAR, GEN9_WM_KERNEL_NOMASK, COPY_VERTEX)
8057 +#define FILL_SAMPLER 1
8058 +#define FILL_VERTEX VERTEX_2s2s
8059 +#define FILL_FLAGS(op, format) GEN9_SET_FLAGS(FILL_SAMPLER, gen9_get_blend((op), false, (format)), GEN9_WM_KERNEL_NOMASK, FILL_VERTEX)
8060 +#define FILL_FLAGS_NOBLEND GEN9_SET_FLAGS(FILL_SAMPLER, NO_BLEND, GEN9_WM_KERNEL_NOMASK, FILL_VERTEX)
8062 +#define GEN9_SAMPLER(f) (((f) >> 20) & 0xfff)
8063 +#define GEN9_BLEND(f) (((f) >> 4) & 0x7ff)
8064 +#define GEN9_READS_DST(f) (((f) >> 15) & 1)
8065 +#define GEN9_KERNEL(f) (((f) >> 16) & 0xf)
8066 +#define GEN9_VERTEX(f) (((f) >> 0) & 0xf)
8067 +#define GEN9_SET_FLAGS(S, B, K, V) ((S) << 20 | (K) << 16 | (B) | (V))
8069 +#define OUT_BATCH(v) batch_emit(sna, v)
8070 +#define OUT_BATCH64(v) batch_emit64(sna, v)
8071 +#define OUT_VERTEX(x,y) vertex_emit_2s(sna, x,y)
8072 +#define OUT_VERTEX_F(v) vertex_emit(sna, v)
8074 +struct gt_info {
8075 + const char *name;
8076 + struct {
8077 + int max_vs_entries;
8078 + } urb;
8079 +};
8081 +static const struct gt_info min_gt_info = {
8082 + .name = "Skylake (gen9)",
8083 + .urb = { .max_vs_entries = 240 },
8084 +};
8086 +static const struct gt_info skl_gt_info = {
8087 + .name = "Skylake (gen9)",
8088 + .urb = { .max_vs_entries = 960 },
8089 +};
8091 +static const struct gt_info bxt_gt_info = {
8092 + .name = "Broxton (gen9)",
8093 + .urb = { .max_vs_entries = 320 },
8094 +};
8096 +static const struct gt_info kbl_gt_info = {
8097 + .name = "Kabylake (gen9)",
8098 + .urb = { .max_vs_entries = 960 },
8099 +};
8101 +static const struct gt_info glk_gt_info = {
8102 + .name = "Geminilake (gen9)",
8103 + .urb = { .max_vs_entries = 320 },
8104 +};
8106 +static bool is_skl(struct sna *sna)
8107 +{
8108 + return sna->kgem.gen == 0110;
8109 +}
8111 +static bool is_bxt(struct sna *sna)
8112 +{
8113 + return sna->kgem.gen == 0111;
8114 +}
8116 +static bool is_kbl(struct sna *sna)
8117 +{
8118 + return sna->kgem.gen == 0112;
8119 +}
8121 +static bool is_glk(struct sna *sna)
8122 +{
8123 + return sna->kgem.gen == 0113;
8124 +}
8127 +static inline bool too_large(int width, int height)
8128 +{
8129 + return width > GEN9_MAX_SIZE || height > GEN9_MAX_SIZE;
8130 +}
8132 +static inline bool unaligned(struct kgem_bo *bo, int bpp)
8133 +{
8134 + /* XXX What exactly do we need to meet H_ALIGN and V_ALIGN? */
8135 +#if 0
8136 + int x, y;
8138 + if (bo->proxy == NULL)
8139 + return false;
8141 + /* Assume that all tiled proxies are constructed correctly. */
8142 + if (bo->tiling)
8143 + return false;
8145 + DBG(("%s: checking alignment of a linear proxy, offset=%d, pitch=%d, bpp=%d: => (%d, %d)\n",
8146 + __FUNCTION__, bo->delta, bo->pitch, bpp,
8147 + 8 * (bo->delta % bo->pitch) / bpp, bo->delta / bo->pitch));
8149 + /* This may be a random userptr map, check that it meets the
8150 + * render alignment of SURFACE_VALIGN_4 | SURFACE_HALIGN_4.
8151 + */
8152 + y = bo->delta / bo->pitch;
8153 + if (y & 3)
8154 + return true;
8156 + x = 8 * (bo->delta - y * bo->pitch);
8157 + if (x & (4*bpp - 1))
8158 + return true;
8160 + return false;
8161 +#else
8162 + return false;
8163 +#endif
8164 +}
8166 +static uint32_t gen9_get_blend(int op,
8167 + bool has_component_alpha,
8168 + uint32_t dst_format)
8169 +{
8170 + uint32_t src, dst;
8172 + COMPILE_TIME_ASSERT(BLENDFACTOR_INV_DST_ALPHA*GEN9_BLENDFACTOR_COUNT + BLENDFACTOR_INV_DST_ALPHA <= 0x7ff);
8174 + src = gen9_blend_op[op].src_blend;
8175 + dst = gen9_blend_op[op].dst_blend;
8177 + /* If there's no dst alpha channel, adjust the blend op so that
8178 + * we'll treat it always as 1.
8179 + */
8180 + if (PICT_FORMAT_A(dst_format) == 0) {
8181 + if (src == BLENDFACTOR_DST_ALPHA)
8182 + src = BLENDFACTOR_ONE;
8183 + else if (src == BLENDFACTOR_INV_DST_ALPHA)
8184 + src = BLENDFACTOR_ZERO;
8185 + }
8187 + /* If the source alpha is being used, then we should only be in a
8188 + * case where the source blend factor is 0, and the source blend
8189 + * value is the mask channels multiplied by the source picture's alpha.
8190 + */
8191 + if (has_component_alpha && gen9_blend_op[op].src_alpha) {
8192 + if (dst == BLENDFACTOR_SRC_ALPHA)
8193 + dst = BLENDFACTOR_SRC_COLOR;
8194 + else if (dst == BLENDFACTOR_INV_SRC_ALPHA)
8195 + dst = BLENDFACTOR_INV_SRC_COLOR;
8196 + }
8198 + DBG(("blend op=%d, dst=%x [A=%d] => src=%d, dst=%d => offset=%x\n",
8199 + op, dst_format, PICT_FORMAT_A(dst_format),
8200 + src, dst, (int)(BLEND_OFFSET(src, dst)>>4)));
8201 + assert(BLEND_OFFSET(src, dst) >> 4 <= 0xfff);
8202 + return BLEND_OFFSET(src, dst);
8203 +}
8205 +static uint32_t gen9_get_card_format(PictFormat format)
8206 +{
8207 + switch (format) {
8208 + default:
8209 + return -1;
8210 + case PICT_a8r8g8b8:
8211 + return SURFACEFORMAT_B8G8R8A8_UNORM;
8212 + case PICT_x8r8g8b8:
8213 + return SURFACEFORMAT_B8G8R8X8_UNORM;
8214 + case PICT_a8b8g8r8:
8215 + return SURFACEFORMAT_R8G8B8A8_UNORM;
8216 + case PICT_x8b8g8r8:
8217 + return SURFACEFORMAT_R8G8B8X8_UNORM;
8218 +#ifdef PICT_a2r10g10b10
8219 + case PICT_a2r10g10b10:
8220 + return SURFACEFORMAT_B10G10R10A2_UNORM;
8221 + case PICT_x2r10g10b10:
8222 + return SURFACEFORMAT_B10G10R10X2_UNORM;
8223 +#endif
8224 + case PICT_r8g8b8:
8225 + return SURFACEFORMAT_R8G8B8_UNORM;
8226 + case PICT_r5g6b5:
8227 + return SURFACEFORMAT_B5G6R5_UNORM;
8228 + case PICT_a1r5g5b5:
8229 + return SURFACEFORMAT_B5G5R5A1_UNORM;
8230 + case PICT_a8:
8231 + return SURFACEFORMAT_A8_UNORM;
8232 + case PICT_a4r4g4b4:
8233 + return SURFACEFORMAT_B4G4R4A4_UNORM;
8234 + }
8235 +}
8237 +static uint32_t gen9_get_dest_format(PictFormat format)
8238 +{
8239 + switch (format) {
8240 + default:
8241 + return -1;
8242 + case PICT_a8r8g8b8:
8243 + case PICT_x8r8g8b8:
8244 + return SURFACEFORMAT_B8G8R8A8_UNORM;
8245 + case PICT_a8b8g8r8:
8246 + case PICT_x8b8g8r8:
8247 + return SURFACEFORMAT_R8G8B8A8_UNORM;
8248 +#ifdef PICT_a2r10g10b10
8249 + case PICT_a2r10g10b10:
8250 + case PICT_x2r10g10b10:
8251 + return SURFACEFORMAT_B10G10R10A2_UNORM;
8252 +#endif
8253 + case PICT_r5g6b5:
8254 + return SURFACEFORMAT_B5G6R5_UNORM;
8255 + case PICT_x1r5g5b5:
8256 + case PICT_a1r5g5b5:
8257 + return SURFACEFORMAT_B5G5R5A1_UNORM;
8258 + case PICT_a8:
8259 + return SURFACEFORMAT_A8_UNORM;
8260 + case PICT_a4r4g4b4:
8261 + case PICT_x4r4g4b4:
8262 + return SURFACEFORMAT_B4G4R4A4_UNORM;
8263 + }
8264 +}
8266 +static bool gen9_check_dst_format(PictFormat format)
8267 +{
8268 + if (gen9_get_dest_format(format) != -1)
8269 + return true;
8271 + DBG(("%s: unhandled format: %x\n", __FUNCTION__, (int)format));
8272 + return false;
8273 +}
8275 +static bool gen9_check_format(uint32_t format)
8276 +{
8277 + if (gen9_get_card_format(format) != -1)
8278 + return true;
8280 + DBG(("%s: unhandled format: %x\n", __FUNCTION__, (int)format));
8281 + return false;
8282 +}
8284 +static uint32_t gen9_filter(uint32_t filter)
8285 +{
8286 + switch (filter) {
8287 + default:
8288 + assert(0);
8289 + case PictFilterNearest:
8290 + return SAMPLER_FILTER_NEAREST;
8291 + case PictFilterBilinear:
8292 + return SAMPLER_FILTER_BILINEAR;
8293 + }
8294 +}
8296 +static uint32_t gen9_check_filter(PicturePtr picture)
8297 +{
8298 + switch (picture->filter) {
8299 + case PictFilterNearest:
8300 + case PictFilterBilinear:
8301 + return true;
8302 + default:
8303 + return false;
8304 + }
8305 +}
8307 +static uint32_t gen9_repeat(uint32_t repeat)
8308 +{
8309 + switch (repeat) {
8310 + default:
8311 + assert(0);
8312 + case RepeatNone:
8313 + return SAMPLER_EXTEND_NONE;
8314 + case RepeatNormal:
8315 + return SAMPLER_EXTEND_REPEAT;
8316 + case RepeatPad:
8317 + return SAMPLER_EXTEND_PAD;
8318 + case RepeatReflect:
8319 + return SAMPLER_EXTEND_REFLECT;
8320 + }
8321 +}
8323 +static bool gen9_check_repeat(PicturePtr picture)
8324 +{
8325 + if (!picture->repeat)
8326 + return true;
8328 + switch (picture->repeatType) {
8329 + case RepeatNone:
8330 + case RepeatNormal:
8331 + case RepeatPad:
8332 + case RepeatReflect:
8333 + return true;
8334 + default:
8335 + return false;
8336 + }
8337 +}
8339 +static int
8340 +gen9_choose_composite_kernel(int op, bool has_mask, bool is_ca, bool is_affine)
8341 +{
8342 + int base;
8344 + if (has_mask) {
8345 + if (is_ca) {
8346 + if (gen9_blend_op[op].src_alpha)
8347 + base = GEN9_WM_KERNEL_MASKSA;
8348 + else
8349 + base = GEN9_WM_KERNEL_MASKCA;
8350 + } else
8351 + base = GEN9_WM_KERNEL_MASK;
8352 + } else
8353 + base = GEN9_WM_KERNEL_NOMASK;
8355 + return base + !is_affine;
8356 +}
8358 +static void
8359 +gen9_emit_push_constants(struct sna *sna)
8360 +{
8361 +#if SIM
8362 + OUT_BATCH(GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_VS | (2 - 2));
8363 + OUT_BATCH(0);
8365 + OUT_BATCH(GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_HS | (2 - 2));
8366 + OUT_BATCH(0);
8368 + OUT_BATCH(GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_DS | (2 - 2));
8369 + OUT_BATCH(0);
8371 + OUT_BATCH(GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_GS | (2 - 2));
8372 + OUT_BATCH(0);
8374 + OUT_BATCH(GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_PS | (2 - 2));
8375 + OUT_BATCH(0);
8376 +#endif
8377 +}
8379 +static void
8380 +gen9_emit_urb(struct sna *sna)
8381 +{
8382 + /* num of VS entries must be divisible by 8 if size < 9 */
8383 + OUT_BATCH(GEN9_3DSTATE_URB_VS | (2 - 2));
8384 + OUT_BATCH(sna->render_state.gen9.info->urb.max_vs_entries << URB_ENTRY_NUMBER_SHIFT |
8385 + (2 - 1) << URB_ENTRY_SIZE_SHIFT |
8386 + 4 << URB_STARTING_ADDRESS_SHIFT);
8388 + OUT_BATCH(GEN9_3DSTATE_URB_HS | (2 - 2));
8389 + OUT_BATCH(0 << URB_ENTRY_SIZE_SHIFT |
8390 + 4 << URB_STARTING_ADDRESS_SHIFT);
8392 + OUT_BATCH(GEN9_3DSTATE_URB_DS | (2 - 2));
8393 + OUT_BATCH(0 << URB_ENTRY_SIZE_SHIFT |
8394 + 4 << URB_STARTING_ADDRESS_SHIFT);
8396 + OUT_BATCH(GEN9_3DSTATE_URB_GS | (2 - 2));
8397 + OUT_BATCH(0 << URB_ENTRY_SIZE_SHIFT |
8398 + 4 << URB_STARTING_ADDRESS_SHIFT);
8399 +}
8401 +static void
8402 +gen9_emit_state_base_address(struct sna *sna)
8403 +{
8404 + uint32_t num_pages;
8406 + assert(sna->kgem.surface - sna->kgem.nbatch <= 16384);
8408 + /* WaBindlessSurfaceStateModifyEnable:skl,bxt */
8409 + OUT_BATCH(GEN9_STATE_BASE_ADDRESS | (19 - 1 - 2));
8410 + OUT_BATCH64(0); /* general */
8411 + OUT_BATCH(0); /* stateless dataport */
8412 + OUT_BATCH64(kgem_add_reloc64(&sna->kgem, /* surface */
8413 + sna->kgem.nbatch,
8414 + NULL,
8415 + I915_GEM_DOMAIN_INSTRUCTION << 16,
8416 + BASE_ADDRESS_MODIFY));
8417 + OUT_BATCH64(kgem_add_reloc64(&sna->kgem, /* dynamic */
8418 + sna->kgem.nbatch,
8419 + sna->render_state.gen9.general_bo,
8420 + I915_GEM_DOMAIN_INSTRUCTION << 16,
8421 + BASE_ADDRESS_MODIFY));
8422 + OUT_BATCH64(0); /* indirect */
8423 + OUT_BATCH64(kgem_add_reloc64(&sna->kgem, /* instruction */
8424 + sna->kgem.nbatch,
8425 + sna->render_state.gen9.general_bo,
8426 + I915_GEM_DOMAIN_INSTRUCTION << 16,
8427 + BASE_ADDRESS_MODIFY));
8428 + /* upper bounds */
8429 + num_pages = sna->render_state.gen9.general_bo->size.pages.count;
8430 + OUT_BATCH(0); /* general */
8431 + OUT_BATCH(num_pages << 12 | 1); /* dynamic */
8432 + OUT_BATCH(0); /* indirect */
8433 + OUT_BATCH(num_pages << 12 | 1); /* instruction */
8435 + /* Bindless */
8436 + OUT_BATCH(0);
8437 + OUT_BATCH(0);
8438 + OUT_BATCH(0);
8439 +}
8441 +static void
8442 +gen9_emit_vs_invariant(struct sna *sna)
8443 +{
8444 + OUT_BATCH(GEN9_3DSTATE_VS | (9 - 2));
8445 + OUT_BATCH64(0); /* no VS kernel */
8446 + OUT_BATCH(0);
8447 + OUT_BATCH64(0); /* scratch */
8448 + OUT_BATCH(0);
8449 + OUT_BATCH(1 << 1); /* pass-through */
8450 + OUT_BATCH(1 << 16 | 1 << 21); /* urb write to SBE */
8452 +#if SIM
8453 + OUT_BATCH(GEN9_3DSTATE_CONSTANT_VS | (11 - 2));
8454 + OUT_BATCH(0);
8455 + OUT_BATCH(0);
8456 + OUT_BATCH64(0);
8457 + OUT_BATCH64(0);
8458 + OUT_BATCH64(0);
8459 + OUT_BATCH64(0);
8461 + OUT_BATCH(GEN9_3DSTATE_BINDING_TABLE_POINTERS_VS | (2 - 2));
8462 + OUT_BATCH(0);
8464 + OUT_BATCH(GEN9_3DSTATE_SAMPLER_STATE_POINTERS_VS | (2 - 2));
8465 + OUT_BATCH(0);
8466 +#endif
8467 +}
8469 +static void
8470 +gen9_emit_hs_invariant(struct sna *sna)
8471 +{
8472 + OUT_BATCH(GEN9_3DSTATE_HS | (9 - 2));
8473 + OUT_BATCH(0);
8474 + OUT_BATCH(0);
8475 + OUT_BATCH64(0); /* no HS kernel */
8476 + OUT_BATCH64(0); /* scratch */
8477 + OUT_BATCH(0);
8478 + OUT_BATCH(0); /* pass-through */
8480 +#if SIM
8481 + OUT_BATCH(GEN9_3DSTATE_CONSTANT_HS | (11 - 2));
8482 + OUT_BATCH(0);
8483 + OUT_BATCH(0);
8484 + OUT_BATCH64(0);
8485 + OUT_BATCH64(0);
8486 + OUT_BATCH64(0);
8487 + OUT_BATCH64(0);
8489 +#if 1
8490 + OUT_BATCH(GEN9_3DSTATE_BINDING_TABLE_POINTERS_HS | (2 - 2));
8491 + OUT_BATCH(0);
8493 + OUT_BATCH(GEN9_3DSTATE_SAMPLER_STATE_POINTERS_HS | (2 - 2));
8494 + OUT_BATCH(0);
8495 +#endif
8496 +#endif
8497 +}
8499 +static void
8500 +gen9_emit_te_invariant(struct sna *sna)
8501 +{
8502 + OUT_BATCH(GEN9_3DSTATE_TE | (4 - 2));
8503 + OUT_BATCH(0);
8504 + OUT_BATCH(0);
8505 + OUT_BATCH(0);
8506 +}
8508 +static void
8509 +gen9_emit_ds_invariant(struct sna *sna)
8510 +{
8511 + OUT_BATCH(GEN9_3DSTATE_DS | (11 - 2));
8512 + OUT_BATCH64(0); /* no kernel */
8513 + OUT_BATCH(0);
8514 + OUT_BATCH64(0); /* scratch */
8515 + OUT_BATCH(0);
8516 + OUT_BATCH(0);
8517 + OUT_BATCH(0);
8518 + OUT_BATCH(0);
8519 + OUT_BATCH(0);
8521 +#if SIM
8522 + OUT_BATCH(GEN9_3DSTATE_CONSTANT_DS | (11 - 2));
8523 + OUT_BATCH(0);
8524 + OUT_BATCH(0);
8525 + OUT_BATCH64(0);
8526 + OUT_BATCH64(0);
8527 + OUT_BATCH64(0);
8528 + OUT_BATCH64(0);
8530 +#if 1
8531 + OUT_BATCH(GEN9_3DSTATE_BINDING_TABLE_POINTERS_DS | (2 - 2));
8532 + OUT_BATCH(0);
8534 + OUT_BATCH(GEN9_3DSTATE_SAMPLER_STATE_POINTERS_DS | (2 - 2));
8535 + OUT_BATCH(0);
8536 +#endif
8537 +#endif
8538 +}
8540 +static void
8541 +gen9_emit_gs_invariant(struct sna *sna)
8542 +{
8543 + OUT_BATCH(GEN9_3DSTATE_GS | (10 - 2));
8544 + OUT_BATCH64(0); /* no GS kernel */
8545 + OUT_BATCH(0);
8546 + OUT_BATCH64(0); /* scratch */
8547 + OUT_BATCH(0);
8548 + OUT_BATCH(0); /* pass-through */
8549 + OUT_BATCH(0);
8550 + OUT_BATCH(0);
8552 +#if SIM
8553 + OUT_BATCH(GEN9_3DSTATE_CONSTANT_GS | (11 - 2));
8554 + OUT_BATCH(0);
8555 + OUT_BATCH(0);
8556 + OUT_BATCH64(0);
8557 + OUT_BATCH64(0);
8558 + OUT_BATCH64(0);
8559 + OUT_BATCH64(0);
8561 +#if 1
8562 + OUT_BATCH(GEN9_3DSTATE_BINDING_TABLE_POINTERS_GS | (2 - 2));
8563 + OUT_BATCH(0);
8565 + OUT_BATCH(GEN9_3DSTATE_SAMPLER_STATE_POINTERS_GS | (2 - 2));
8566 + OUT_BATCH(0);
8567 +#endif
8568 +#endif
8569 +}
8571 +static void
8572 +gen9_emit_sol_invariant(struct sna *sna)
8573 +{
8574 + OUT_BATCH(GEN9_3DSTATE_STREAMOUT | (5 - 2));
8575 + OUT_BATCH(0);
8576 + OUT_BATCH(0);
8577 + OUT_BATCH(0);
8578 + OUT_BATCH(0);
8579 +}
8581 +static void
8582 +gen9_emit_sf_invariant(struct sna *sna)
8583 +{
8584 + OUT_BATCH(GEN9_3DSTATE_SF | (4 - 2));
8585 + OUT_BATCH(0);
8586 + OUT_BATCH(0);
8587 + OUT_BATCH(0);
8588 +}
8590 +static void
8591 +gen9_emit_clip_invariant(struct sna *sna)
8592 +{
8593 + OUT_BATCH(GEN9_3DSTATE_CLIP | (4 - 2));
8594 + OUT_BATCH(0);
8595 + OUT_BATCH(0); /* pass-through */
8596 + OUT_BATCH(0);
8598 + OUT_BATCH(GEN9_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP | (2 - 2));
8599 + OUT_BATCH(0);
8601 + OUT_BATCH(GEN9_3DSTATE_VIEWPORT_STATE_POINTERS_CC | (2 - 2));
8602 + OUT_BATCH(0);
8603 +}
8605 +static void
8606 +gen9_emit_null_depth_buffer(struct sna *sna)
8607 +{
8608 + OUT_BATCH(GEN9_3DSTATE_DEPTH_BUFFER | (8 - 2));
8609 +#if 1
8610 + OUT_BATCH(SURFACE_NULL << DEPTH_BUFFER_TYPE_SHIFT |
8611 + DEPTHFORMAT_D32_FLOAT << DEPTH_BUFFER_FORMAT_SHIFT);
8612 +#else
8613 + OUT_BATCH(SURFACE_2D << DEPTH_BUFFER_TYPE_SHIFT |
8614 + DEPTHFORMAT_D16_UNORM << DEPTH_BUFFER_FORMAT_SHIFT);
8615 +#endif
8616 + OUT_BATCH64(0);
8617 + OUT_BATCH(0);
8618 + OUT_BATCH(0);
8619 + OUT_BATCH(0);
8620 + OUT_BATCH(0);
8622 +#if SIM
8623 + OUT_BATCH(GEN9_3DSTATE_HIER_DEPTH_BUFFER | (5 - 2));
8624 + OUT_BATCH(0);
8625 + OUT_BATCH64(0);
8626 + OUT_BATCH(0);
8627 +#endif
8629 +#if SIM
8630 + OUT_BATCH(GEN9_3DSTATE_STENCIL_BUFFER | (5 - 2));
8631 + OUT_BATCH(0);
8632 + OUT_BATCH64(0);
8633 + OUT_BATCH(0);
8634 +#endif
8636 +#if SIM
8637 + OUT_BATCH(GEN9_3DSTATE_WM_DEPTH_STENCIL | (4 - 2));
8638 + OUT_BATCH(0);
8639 + OUT_BATCH(0);
8640 + OUT_BATCH(0);
8641 +#endif
8643 +#if SIM
8644 + OUT_BATCH(GEN9_3DSTATE_CLEAR_PARAMS | (3 - 2));
8645 + OUT_BATCH(0);
8646 + OUT_BATCH(0);
8647 +#endif
8648 +}
8650 +static void
8651 +gen9_emit_wm_invariant(struct sna *sna)
8652 +{
8653 + gen9_emit_null_depth_buffer(sna);
8655 +#if SIM
8656 + OUT_BATCH(GEN9_3DSTATE_SCISSOR_STATE_POINTERS | (2 - 2));
8657 + OUT_BATCH(0);
8658 +#endif
8660 + OUT_BATCH(GEN9_3DSTATE_WM | (2 - 2));
8661 + //OUT_BATCH(WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC); /* XXX */
8662 + OUT_BATCH(WM_PERSPECTIVE_PIXEL_BARYCENTRIC);
8664 +#if SIM
8665 + OUT_BATCH(GEN9_3DSTATE_WM_CHROMAKEY | (2 - 2));
8666 + OUT_BATCH(0);
8667 +#endif
8669 +#if 0
8670 + OUT_BATCH(GEN9_3DSTATE_WM_HZ_OP | (5 - 2));
8671 + OUT_BATCH(0);
8672 + OUT_BATCH(0);
8673 + OUT_BATCH(0);
8674 + OUT_BATCH(0);
8675 +#endif
8677 + OUT_BATCH(GEN9_3DSTATE_PS_EXTRA | (2 - 2));
8678 + OUT_BATCH(PSX_PIXEL_SHADER_VALID |
8679 + PSX_ATTRIBUTE_ENABLE);
8681 + OUT_BATCH(GEN9_3DSTATE_RASTER | (5 - 2));
8682 + OUT_BATCH(RASTER_FRONT_WINDING_CCW |
8683 + RASTER_CULL_NONE);
8684 + OUT_BATCH(0);
8685 + OUT_BATCH(0);
8686 + OUT_BATCH(0);
8688 + OUT_BATCH(GEN9_3DSTATE_SBE_SWIZ | (11 - 2));
8689 + OUT_BATCH(0);
8690 + OUT_BATCH(0);
8691 + OUT_BATCH(0);
8692 + OUT_BATCH(0);
8693 + OUT_BATCH(0);
8694 + OUT_BATCH(0);
8695 + OUT_BATCH(0);
8696 + OUT_BATCH(0);
8697 + OUT_BATCH(0);
8698 + OUT_BATCH(0);
8700 +#if SIM
8701 + OUT_BATCH(GEN9_3DSTATE_CONSTANT_PS | (11 - 2));
8702 + OUT_BATCH(0);
8703 + OUT_BATCH(0);
8704 + OUT_BATCH64(0);
8705 + OUT_BATCH64(0);
8706 + OUT_BATCH64(0);
8707 + OUT_BATCH64(0);
8708 +#endif
8709 +}
8711 +static void
8712 +gen9_emit_cc_invariant(struct sna *sna)
8713 +{
8714 +}
8716 +static void
8717 +gen9_emit_vf_invariant(struct sna *sna)
8718 +{
8719 + int n;
8721 +#if 1
8722 + OUT_BATCH(GEN9_3DSTATE_VF | (2 - 2));
8723 + OUT_BATCH(0);
8724 +#endif
8726 + OUT_BATCH(GEN9_3DSTATE_VF_SGVS | (2 - 2));
8727 + OUT_BATCH(0);
8729 + OUT_BATCH(GEN9_3DSTATE_VF_TOPOLOGY | (2 - 2));
8730 + OUT_BATCH(RECTLIST);
8732 + OUT_BATCH(GEN9_3DSTATE_VF_STATISTICS | 0);
8734 + for (n = 1; n <= 3; n++) {
8735 + OUT_BATCH(GEN9_3DSTATE_VF_INSTANCING | (3 - 2));
8736 + OUT_BATCH(n);
8737 + OUT_BATCH(0);
8738 + }
8739 +}
8741 +static void
8742 +gen9_emit_invariant(struct sna *sna)
8743 +{
8744 + OUT_BATCH(GEN9_PIPELINE_SELECT |
8745 + PIPELINE_SELECTION_MASK |
8746 + PIPELINE_SELECT_3D);
8748 +#if SIM
8749 + OUT_BATCH(GEN9_STATE_SIP | (3 - 2));
8750 + OUT_BATCH64(0);
8751 +#endif
8753 + OUT_BATCH(GEN9_3DSTATE_MULTISAMPLE | (2 - 2));
8754 + OUT_BATCH(MULTISAMPLE_PIXEL_LOCATION_CENTER |
8755 + MULTISAMPLE_NUMSAMPLES_1); /* 1 sample/pixel */
8757 + OUT_BATCH(GEN9_3DSTATE_SAMPLE_MASK | (2 - 2));
8758 + OUT_BATCH(1);
8760 +#if SIM
8761 + OUT_BATCH(GEN9_3DSTATE_SAMPLE_PATTERN | (5 - 2));
8762 + OUT_BATCH(0);
8763 + OUT_BATCH(0);
8764 + OUT_BATCH(0);
8765 + //OUT_BATCH(8<<20 | 8<<16);
8766 + OUT_BATCH(0);
8767 +#endif
8769 + gen9_emit_push_constants(sna);
8770 + gen9_emit_urb(sna);
8772 + gen9_emit_state_base_address(sna);
8774 + gen9_emit_vf_invariant(sna);
8775 + gen9_emit_vs_invariant(sna);
8776 + gen9_emit_hs_invariant(sna);
8777 + gen9_emit_te_invariant(sna);
8778 + gen9_emit_ds_invariant(sna);
8779 + gen9_emit_gs_invariant(sna);
8780 + gen9_emit_sol_invariant(sna);
8781 + gen9_emit_clip_invariant(sna);
8782 + gen9_emit_sf_invariant(sna);
8783 + gen9_emit_wm_invariant(sna);
8784 + gen9_emit_cc_invariant(sna);
8786 + sna->render_state.gen9.needs_invariant = false;
8787 +}
8789 +static void
8790 +gen9_emit_cc(struct sna *sna, uint32_t blend)
8791 +{
8792 + struct gen9_render_state *render = &sna->render_state.gen9;
8794 + if (render->blend == blend)
8795 + return;
8797 + DBG(("%s: blend=%x (current=%x), src=%d, dst=%d\n",
8798 + __FUNCTION__, blend, render->blend,
8799 + blend / GEN9_BLENDFACTOR_COUNT,
8800 + blend % GEN9_BLENDFACTOR_COUNT));
8802 + assert(blend < GEN9_BLENDFACTOR_COUNT * GEN9_BLENDFACTOR_COUNT);
8803 + assert(blend / GEN9_BLENDFACTOR_COUNT > 0);
8804 + assert(blend % GEN9_BLENDFACTOR_COUNT > 0);
8806 + /* XXX can have up to 8 blend states preload, selectable via
8807 + * Render Target Index. What other side-effects of Render Target Index?
8808 + */
8810 + OUT_BATCH(GEN9_3DSTATE_PS_BLEND | (2 - 2));
8811 + if (blend != GEN9_BLEND(NO_BLEND)) {
8812 + uint32_t src = blend / GEN9_BLENDFACTOR_COUNT;
8813 + uint32_t dst = blend % GEN9_BLENDFACTOR_COUNT;
8814 + OUT_BATCH(PS_BLEND_HAS_WRITEABLE_RT |
8815 + PS_BLEND_COLOR_BLEND_ENABLE |
8816 + src << PS_BLEND_SRC_ALPHA_SHIFT |
8817 + dst << PS_BLEND_DST_ALPHA_SHIFT |
8818 + src << PS_BLEND_SRC_SHIFT |
8819 + dst << PS_BLEND_DST_SHIFT);
8820 + } else
8821 + OUT_BATCH(PS_BLEND_HAS_WRITEABLE_RT);
8823 + assert(is_aligned(render->cc_blend + blend * GEN9_BLEND_STATE_PADDED_SIZE, 64));
8824 + OUT_BATCH(GEN9_3DSTATE_BLEND_STATE_POINTERS | (2 - 2));
8825 + OUT_BATCH((render->cc_blend + blend * GEN9_BLEND_STATE_PADDED_SIZE) | 1);
8827 + /* Force a CC_STATE pointer change to improve blend performance */
8828 + OUT_BATCH(GEN9_3DSTATE_CC_STATE_POINTERS | (2 - 2));
8829 + OUT_BATCH(0);
8831 + render->blend = blend;
8832 +}
8834 +static void
8835 +gen9_emit_sampler(struct sna *sna, uint32_t state)
8836 +{
8837 + if (sna->render_state.gen9.samplers == state)
8838 + return;
8840 + sna->render_state.gen9.samplers = state;
8842 + DBG(("%s: sampler = %x\n", __FUNCTION__, state));
8844 + assert(2 * sizeof(struct gen9_sampler_state) == 32);
8845 + OUT_BATCH(GEN9_3DSTATE_SAMPLER_STATE_POINTERS_PS | (2 - 2));
8846 + OUT_BATCH(sna->render_state.gen9.wm_state + state * 2 * sizeof(struct gen9_sampler_state));
8847 +}
8849 +static void
8850 +gen9_emit_sf(struct sna *sna, bool has_mask)
8851 +{
8852 + int num_sf_outputs = has_mask ? 2 : 1;
8854 + if (sna->render_state.gen9.num_sf_outputs == num_sf_outputs)
8855 + return;
8857 + DBG(("%s: num_sf_outputs=%d\n", __FUNCTION__, num_sf_outputs));
8859 + sna->render_state.gen9.num_sf_outputs = num_sf_outputs;
8861 + OUT_BATCH(GEN9_3DSTATE_SBE | (6 - 2));
8862 + OUT_BATCH(num_sf_outputs << SBE_NUM_OUTPUTS_SHIFT |
8863 + SBE_FORCE_VERTEX_URB_READ_LENGTH | /* forced is faster */
8864 + SBE_FORCE_VERTEX_URB_READ_OFFSET |
8865 + 1 << SBE_URB_ENTRY_READ_LENGTH_SHIFT |
8866 + 1 << SBE_URB_ENTRY_READ_OFFSET_SHIFT);
8867 + OUT_BATCH(0);
8868 + OUT_BATCH(0);
8869 + OUT_BATCH(SBE_ACTIVE_COMPONENT_XYZW << 0 |
8870 + SBE_ACTIVE_COMPONENT_XYZW << 1);
8871 + OUT_BATCH(0);
8872 +}
8874 +static void
8875 +gen9_emit_wm(struct sna *sna, int kernel)
8876 +{
8877 + const uint32_t *kernels;
8879 + assert(kernel < ARRAY_SIZE(wm_kernels));
8880 + if (sna->render_state.gen9.kernel == kernel)
8881 + return;
8883 + sna->render_state.gen9.kernel = kernel;
8884 + kernels = sna->render_state.gen9.wm_kernel[kernel];
8886 + DBG(("%s: switching to %s, num_surfaces=%d (8-wide? %d, 16-wide? %d, 32-wide? %d)\n",
8887 + __FUNCTION__,
8888 + wm_kernels[kernel].name,
8889 + wm_kernels[kernel].num_surfaces,
8890 + kernels[0], kernels[1], kernels[2]));
8891 + assert(is_aligned(kernels[0], 64));
8892 + assert(is_aligned(kernels[1], 64));
8893 + assert(is_aligned(kernels[2], 64));
8895 + OUT_BATCH(GEN9_3DSTATE_PS | (12 - 2));
8896 + OUT_BATCH64(kernels[0] ?: kernels[1] ?: kernels[2]);
8897 + OUT_BATCH(1 << PS_SAMPLER_COUNT_SHIFT |
8898 + PS_VECTOR_MASK_ENABLE |
8899 + wm_kernels[kernel].num_surfaces << PS_BINDING_TABLE_ENTRY_COUNT_SHIFT);
8900 + OUT_BATCH64(0); /* scratch address */
8901 + OUT_BATCH(PS_MAX_THREADS |
8902 + (kernels[0] ? PS_8_DISPATCH_ENABLE : 0) |
8903 + (kernels[1] ? PS_16_DISPATCH_ENABLE : 0) |
8904 + (kernels[2] ? PS_32_DISPATCH_ENABLE : 0));
8905 + OUT_BATCH((kernels[0] ? 4 : kernels[1] ? 6 : 8) << PS_DISPATCH_START_GRF_SHIFT_0 |
8906 + 8 << PS_DISPATCH_START_GRF_SHIFT_1 |
8907 + 6 << PS_DISPATCH_START_GRF_SHIFT_2);
8908 + OUT_BATCH64(kernels[2]);
8909 + OUT_BATCH64(kernels[1]);
8910 +}
8912 +static bool
8913 +gen9_emit_binding_table(struct sna *sna, uint16_t offset)
8914 +{
8915 + if (sna->render_state.gen9.surface_table == offset)
8916 + return false;
8918 + /* Binding table pointers */
8919 + assert(is_aligned(4*offset, 32));
8920 + OUT_BATCH(GEN9_3DSTATE_BINDING_TABLE_POINTERS_PS | (2 - 2));
8921 + OUT_BATCH(offset*4);
8923 + sna->render_state.gen9.surface_table = offset;
8924 + return true;
8925 +}
8927 +static bool
8928 +gen9_emit_drawing_rectangle(struct sna *sna,
8929 + const struct sna_composite_op *op)
8930 +{
8931 + uint32_t limit = (op->dst.height - 1) << 16 | (op->dst.width - 1);
8932 + uint32_t offset = (uint16_t)op->dst.y << 16 | (uint16_t)op->dst.x;
8934 + assert(!too_large(abs(op->dst.x), abs(op->dst.y)));
8935 + assert(!too_large(op->dst.width, op->dst.height));
8937 + if (sna->render_state.gen9.drawrect_limit == limit &&
8938 + sna->render_state.gen9.drawrect_offset == offset)
8939 + return true;
8941 + sna->render_state.gen9.drawrect_offset = offset;
8942 + sna->render_state.gen9.drawrect_limit = limit;
8944 + OUT_BATCH(GEN9_3DSTATE_DRAWING_RECTANGLE | (4 - 2));
8945 + OUT_BATCH(0);
8946 + OUT_BATCH(limit);
8947 + OUT_BATCH(offset);
8948 + return false;
8949 +}
8951 +static void
8952 +gen9_emit_vertex_elements(struct sna *sna,
8953 + const struct sna_composite_op *op)
8954 +{
8955 + /*
8956 + * vertex data in vertex buffer
8957 + * position: (x, y)
8958 + * texture coordinate 0: (u0, v0) if (is_affine is true) else (u0, v0, w0)
8959 + * texture coordinate 1 if (has_mask is true): same as above
8960 + */
8961 + struct gen9_render_state *render = &sna->render_state.gen9;
8962 + uint32_t src_format, dw;
8963 + int id = GEN9_VERTEX(op->u.gen9.flags);
8964 + bool has_mask;
8966 + DBG(("%s: setup id=%d\n", __FUNCTION__, id));
8968 + if (render->ve_id == id)
8969 + return;
8970 + render->ve_id = id;
8972 + if (render->ve_dirty) {
8973 + /* dummy primitive to flush vertex before change? */
8974 + OUT_BATCH(GEN9_3DPRIMITIVE | (7 - 2));
8975 + OUT_BATCH(0); /* ignored, see VF_TOPOLOGY */
8976 + OUT_BATCH(0);
8977 + OUT_BATCH(0);
8978 + OUT_BATCH(1); /* single instance */
8979 + OUT_BATCH(0); /* start instance location */
8980 + OUT_BATCH(0); /* index buffer offset, ignored */
8981 + }
8983 + /* The VUE layout
8984 + * dword 0-3: pad (0.0, 0.0, 0.0. 0.0)
8985 + * dword 4-7: position (x, y, 1.0, 1.0),
8986 + * dword 8-11: texture coordinate 0 (u0, v0, w0, 1.0)
8987 + * dword 12-15: texture coordinate 1 (u1, v1, w1, 1.0)
8988 + *
8989 + * dword 4-15 are fetched from vertex buffer
8990 + */
8991 + has_mask = (id >> 2) != 0;
8992 + OUT_BATCH(GEN9_3DSTATE_VERTEX_ELEMENTS |
8993 + ((2 * (3 + has_mask)) + 1 - 2));
8995 + OUT_BATCH(id << VE_INDEX_SHIFT | VE_VALID |
8996 + SURFACEFORMAT_R32G32B32A32_FLOAT << VE_FORMAT_SHIFT |
8997 + 0 << VE_OFFSET_SHIFT);
8998 + OUT_BATCH(COMPONENT_STORE_0 << VE_COMPONENT_0_SHIFT |
8999 + COMPONENT_STORE_0 << VE_COMPONENT_1_SHIFT |
9000 + COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT |
9001 + COMPONENT_STORE_0 << VE_COMPONENT_3_SHIFT);
9003 + /* x,y */
9004 + OUT_BATCH(id << VE_INDEX_SHIFT | VE_VALID |
9005 + SURFACEFORMAT_R16G16_SSCALED << VE_FORMAT_SHIFT |
9006 + 0 << VE_OFFSET_SHIFT);
9007 + OUT_BATCH(COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT |
9008 + COMPONENT_STORE_SRC << VE_COMPONENT_1_SHIFT |
9009 + COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT |
9010 + COMPONENT_STORE_1_FLT << VE_COMPONENT_3_SHIFT);
9012 + /* u0, v0, w0 */
9013 + DBG(("%s: first channel %d floats, offset=4\n", __FUNCTION__, id & 3));
9014 + dw = COMPONENT_STORE_1_FLT << VE_COMPONENT_3_SHIFT;
9015 + switch (id & 3) {
9016 + default:
9017 + assert(0);
9018 + case 0:
9019 + src_format = SURFACEFORMAT_R16G16_SSCALED;
9020 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
9021 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_1_SHIFT;
9022 + dw |= COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT;
9023 + break;
9024 + case 1:
9025 + src_format = SURFACEFORMAT_R32_FLOAT;
9026 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
9027 + dw |= COMPONENT_STORE_0 << VE_COMPONENT_1_SHIFT;
9028 + dw |= COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT;
9029 + break;
9030 + case 2:
9031 + src_format = SURFACEFORMAT_R32G32_FLOAT;
9032 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
9033 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_1_SHIFT;
9034 + dw |= COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT;
9035 + break;
9036 + case 3:
9037 + src_format = SURFACEFORMAT_R32G32B32_FLOAT;
9038 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
9039 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_1_SHIFT;
9040 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_2_SHIFT;
9041 + break;
9042 + }
9043 + OUT_BATCH(id << VE_INDEX_SHIFT | VE_VALID |
9044 + src_format << VE_FORMAT_SHIFT |
9045 + 4 << VE_OFFSET_SHIFT);
9046 + OUT_BATCH(dw);
9048 + /* u1, v1, w1 */
9049 + if (has_mask) {
9050 + unsigned offset = 4 + ((id & 3) ?: 1) * sizeof(float);
9051 + DBG(("%s: second channel %d floats, offset=%d\n", __FUNCTION__, (id >> 2) & 3, offset));
9052 + dw = COMPONENT_STORE_1_FLT << VE_COMPONENT_3_SHIFT;
9053 + switch (id >> 2) {
9054 + case 1:
9055 + src_format = SURFACEFORMAT_R32_FLOAT;
9056 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
9057 + dw |= COMPONENT_STORE_0 << VE_COMPONENT_1_SHIFT;
9058 + dw |= COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT;
9059 + break;
9060 + default:
9061 + assert(0);
9062 + case 2:
9063 + src_format = SURFACEFORMAT_R32G32_FLOAT;
9064 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
9065 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_1_SHIFT;
9066 + dw |= COMPONENT_STORE_0 << VE_COMPONENT_2_SHIFT;
9067 + break;
9068 + case 3:
9069 + src_format = SURFACEFORMAT_R32G32B32_FLOAT;
9070 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_0_SHIFT;
9071 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_1_SHIFT;
9072 + dw |= COMPONENT_STORE_SRC << VE_COMPONENT_2_SHIFT;
9073 + break;
9074 + }
9075 + OUT_BATCH(id << VE_INDEX_SHIFT | VE_VALID |
9076 + src_format << VE_FORMAT_SHIFT |
9077 + offset << VE_OFFSET_SHIFT);
9078 + OUT_BATCH(dw);
9079 + }
9081 + render->ve_dirty = true;
9082 +}
9084 +inline static void
9085 +gen9_emit_pipe_invalidate(struct sna *sna)
9086 +{
9087 + OUT_BATCH(GEN9_PIPE_CONTROL | (6 - 2));
9088 + OUT_BATCH(PIPE_CONTROL_WC_FLUSH |
9089 + PIPE_CONTROL_TC_FLUSH |
9090 + PIPE_CONTROL_CS_STALL);
9091 + OUT_BATCH64(0);
9092 + OUT_BATCH64(0);
9093 +}
9095 +inline static void
9096 +gen9_emit_pipe_flush(struct sna *sna, bool need_stall)
9097 +{
9098 + unsigned stall;
9100 + stall = 0;
9101 + if (need_stall)
9102 + stall = (PIPE_CONTROL_CS_STALL |
9103 + PIPE_CONTROL_STALL_AT_SCOREBOARD);
9105 + OUT_BATCH(GEN9_PIPE_CONTROL | (6 - 2));
9106 + OUT_BATCH(PIPE_CONTROL_WC_FLUSH | stall);
9107 + OUT_BATCH64(0);
9108 + OUT_BATCH64(0);
9109 +}
9111 +inline static void
9112 +gen9_emit_pipe_stall(struct sna *sna)
9113 +{
9114 + OUT_BATCH(GEN9_PIPE_CONTROL | (6 - 2));
9115 + OUT_BATCH(PIPE_CONTROL_CS_STALL |
9116 + PIPE_CONTROL_FLUSH |
9117 + PIPE_CONTROL_STALL_AT_SCOREBOARD);
9118 + OUT_BATCH64(0);
9119 + OUT_BATCH64(0);
9120 +}
9122 +static void
9123 +gen9_emit_state(struct sna *sna,
9124 + const struct sna_composite_op *op,
9125 + uint16_t wm_binding_table)
9126 +{
9127 + bool need_invalidate;
9128 + bool need_flush;
9129 + bool need_stall;
9131 + assert(op->dst.bo->exec);
9133 + need_flush = wm_binding_table & 1 ||
9134 + (sna->render_state.gen9.emit_flush && GEN9_READS_DST(op->u.gen9.flags));
9135 + if (ALWAYS_FLUSH)
9136 + need_flush = true;
9138 + wm_binding_table &= ~1;
9140 + need_stall = sna->render_state.gen9.surface_table != wm_binding_table;
9142 + need_invalidate = kgem_bo_is_dirty(op->src.bo) || kgem_bo_is_dirty(op->mask.bo);
9143 + if (ALWAYS_INVALIDATE)
9144 + need_invalidate = true;
9146 + need_stall &= gen9_emit_drawing_rectangle(sna, op);
9147 + if (ALWAYS_STALL)
9148 + need_stall = true;
9150 + if (need_invalidate) {
9151 + gen9_emit_pipe_invalidate(sna);
9152 + kgem_clear_dirty(&sna->kgem);
9153 + assert(op->dst.bo->exec);
9154 + kgem_bo_mark_dirty(op->dst.bo);
9156 + need_flush = false;
9157 + need_stall = false;
9158 + }
9159 + if (need_flush) {
9160 + gen9_emit_pipe_flush(sna, need_stall);
9161 + need_stall = false;
9162 + }
9163 + if (need_stall)
9164 + gen9_emit_pipe_stall(sna);
9166 + gen9_emit_cc(sna, GEN9_BLEND(op->u.gen9.flags));
9167 + gen9_emit_sampler(sna, GEN9_SAMPLER(op->u.gen9.flags));
9168 + gen9_emit_sf(sna, GEN9_VERTEX(op->u.gen9.flags) >> 2);
9169 + gen9_emit_wm(sna, GEN9_KERNEL(op->u.gen9.flags));
9170 + gen9_emit_vertex_elements(sna, op);
9171 + gen9_emit_binding_table(sna, wm_binding_table);
9173 + sna->render_state.gen9.emit_flush = GEN9_READS_DST(op->u.gen9.flags);
9174 +}
9176 +static bool gen9_magic_ca_pass(struct sna *sna,
9177 + const struct sna_composite_op *op)
9178 +{
9179 + struct gen9_render_state *state = &sna->render_state.gen9;
9181 + if (!op->need_magic_ca_pass)
9182 + return false;
9184 + DBG(("%s: CA fixup (%d -> %d)\n", __FUNCTION__,
9185 + sna->render.vertex_start, sna->render.vertex_index));
9187 + gen9_emit_pipe_stall(sna);
9189 + gen9_emit_cc(sna,
9190 + GEN9_BLEND(gen9_get_blend(PictOpAdd, true,
9191 + op->dst.format)));
9192 + gen9_emit_wm(sna,
9193 + gen9_choose_composite_kernel(PictOpAdd,
9194 + true, true,
9195 + op->is_affine));
9197 + OUT_BATCH(GEN9_3DPRIMITIVE | (7 - 2));
9198 + OUT_BATCH(0); /* ignored, see VF_TOPOLOGY */
9199 + OUT_BATCH(sna->render.vertex_index - sna->render.vertex_start);
9200 + OUT_BATCH(sna->render.vertex_start);
9201 + OUT_BATCH(1); /* single instance */
9202 + OUT_BATCH(0); /* start instance location */
9203 + OUT_BATCH(0); /* index buffer offset, ignored */
9205 + state->last_primitive = sna->kgem.nbatch;
9206 + state->ve_dirty = false;
9207 + return true;
9208 +}
9210 +static void null_create(struct sna_static_stream *stream)
9211 +{
9212 + /* A bunch of zeros useful for legacy border color and depth-stencil */
9213 + sna_static_stream_map(stream, 64, 64);
9214 +}
9216 +static void
9217 +sampler_state_init(struct gen9_sampler_state *sampler_state,
9218 + sampler_filter_t filter,
9219 + sampler_extend_t extend)
9220 +{
9221 + COMPILE_TIME_ASSERT(sizeof(*sampler_state) == 4*sizeof(uint32_t));
9223 + sampler_state->ss0.lod_preclamp = 2; /* GL mode */
9224 + sampler_state->ss0.default_color_mode = 1;
9226 + switch (filter) {
9227 + default:
9228 + case SAMPLER_FILTER_NEAREST:
9229 + sampler_state->ss0.min_filter = MAPFILTER_NEAREST;
9230 + sampler_state->ss0.mag_filter = MAPFILTER_NEAREST;
9231 + break;
9232 + case SAMPLER_FILTER_BILINEAR:
9233 + sampler_state->ss0.min_filter = MAPFILTER_LINEAR;
9234 + sampler_state->ss0.mag_filter = MAPFILTER_LINEAR;
9235 + break;
9236 + }
9238 + /* XXX bicubic filter using MAPFILTER_FLEXIBLE */
9240 + switch (extend) {
9241 + default:
9242 + case SAMPLER_EXTEND_NONE:
9243 + sampler_state->ss3.r_wrap_mode = TEXCOORDMODE_CLAMP_BORDER;
9244 + sampler_state->ss3.s_wrap_mode = TEXCOORDMODE_CLAMP_BORDER;
9245 + sampler_state->ss3.t_wrap_mode = TEXCOORDMODE_CLAMP_BORDER;
9246 + break;
9247 + case SAMPLER_EXTEND_REPEAT:
9248 + sampler_state->ss3.r_wrap_mode = TEXCOORDMODE_WRAP;
9249 + sampler_state->ss3.s_wrap_mode = TEXCOORDMODE_WRAP;
9250 + sampler_state->ss3.t_wrap_mode = TEXCOORDMODE_WRAP;
9251 + break;
9252 + case SAMPLER_EXTEND_PAD:
9253 + sampler_state->ss3.r_wrap_mode = TEXCOORDMODE_CLAMP;
9254 + sampler_state->ss3.s_wrap_mode = TEXCOORDMODE_CLAMP;
9255 + sampler_state->ss3.t_wrap_mode = TEXCOORDMODE_CLAMP;
9256 + break;
9257 + case SAMPLER_EXTEND_REFLECT:
9258 + sampler_state->ss3.r_wrap_mode = TEXCOORDMODE_MIRROR;
9259 + sampler_state->ss3.s_wrap_mode = TEXCOORDMODE_MIRROR;
9260 + sampler_state->ss3.t_wrap_mode = TEXCOORDMODE_MIRROR;
9261 + break;
9262 + }
9263 +}
9265 +static void
9266 +sampler_copy_init(struct gen9_sampler_state *ss)
9267 +{
9268 + sampler_state_init(ss, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE);
9269 + ss->ss3.non_normalized_coord = 1;
9271 + sampler_state_init(ss+1, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE);
9272 +}
9274 +static void
9275 +sampler_fill_init(struct gen9_sampler_state *ss)
9276 +{
9277 + sampler_state_init(ss, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_REPEAT);
9278 + ss->ss3.non_normalized_coord = 1;
9280 + sampler_state_init(ss+1, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE);
9281 +}
9283 +static uint32_t
9284 +gen9_tiling_bits(uint32_t tiling)
9285 +{
9286 + switch (tiling) {
9287 + default: assert(0);
9288 + case I915_TILING_NONE: return 0;
9289 + case I915_TILING_X: return SURFACE_TILED;
9290 + case I915_TILING_Y: return SURFACE_TILED | SURFACE_TILED_Y;
9291 + }
9292 +}
9294 +#define MOCS_PTE (1 << 1)
9295 +#define MOCS_WB (2 << 1)
9297 +/**
9298 + * Sets up the common fields for a surface state buffer for the given
9299 + * picture in the given surface state buffer.
9300 + */
9301 +static uint32_t
9302 +gen9_bind_bo(struct sna *sna,
9303 + struct kgem_bo *bo,
9304 + uint32_t width,
9305 + uint32_t height,
9306 + uint32_t format,
9307 + bool is_dst)
9308 +{
9309 + uint32_t *ss;
9310 + uint32_t domains;
9311 + int offset;
9312 + uint32_t is_scanout = is_dst && bo->scanout;
9314 + /* After the first bind, we manage the cache domains within the batch */
9315 + offset = kgem_bo_get_binding(bo, format | is_dst << 30 | is_scanout << 31);
9316 + if (offset) {
9317 + if (is_dst)
9318 + kgem_bo_mark_dirty(bo);
9319 + assert(offset >= sna->kgem.surface);
9320 + return offset * sizeof(uint32_t);
9321 + }
9323 + offset = sna->kgem.surface -= SURFACE_DW;
9324 + ss = sna->kgem.batch + offset;
9325 + ss[0] = (SURFACE_2D << SURFACE_TYPE_SHIFT |
9326 + gen9_tiling_bits(bo->tiling) |
9327 + format << SURFACE_FORMAT_SHIFT |
9328 + SURFACE_VALIGN_4 | SURFACE_HALIGN_4);
9329 + if (is_dst) {
9330 + ss[0] |= SURFACE_RC_READ_WRITE;
9331 + domains = I915_GEM_DOMAIN_RENDER << 16 |I915_GEM_DOMAIN_RENDER;
9332 + } else
9333 + domains = I915_GEM_DOMAIN_SAMPLER << 16;
9334 + ss[1] = (is_scanout || (is_dst && is_uncached(sna, bo))) ? MOCS_PTE << 24 : MOCS_WB << 24;
9335 + ss[2] = ((width - 1) << SURFACE_WIDTH_SHIFT |
9336 + (height - 1) << SURFACE_HEIGHT_SHIFT);
9337 + ss[3] = (bo->pitch - 1) << SURFACE_PITCH_SHIFT;
9338 + ss[4] = 0;
9339 + ss[5] = 0;
9340 + ss[6] = 0;
9341 + ss[7] = SURFACE_SWIZZLE(RED, GREEN, BLUE, ALPHA);
9342 + *(uint64_t *)(ss+8) = kgem_add_reloc64(&sna->kgem, offset + 8, bo, domains, 0);
9343 + ss[10] = 0;
9344 + ss[11] = 0;
9345 + ss[12] = 0;
9346 + ss[13] = 0;
9347 + ss[14] = 0;
9348 + ss[15] = 0;
9350 + kgem_bo_set_binding(bo, format | is_dst << 30 | is_scanout << 31, offset);
9352 + DBG(("[%x] bind bo(handle=%d, addr=%lx), format=%d, width=%d, height=%d, pitch=%d, tiling=%d -> %s\n",
9353 + offset, bo->handle, *(uint64_t *)(ss+8),
9354 + format, width, height, bo->pitch, bo->tiling,
9355 + domains & 0xffff ? "render" : "sampler"));
9357 + return offset * sizeof(uint32_t);
9358 +}
9360 +static void gen9_emit_vertex_buffer(struct sna *sna,
9361 + const struct sna_composite_op *op)
9362 +{
9363 + int id = GEN9_VERTEX(op->u.gen9.flags);
9365 + OUT_BATCH(GEN9_3DSTATE_VERTEX_BUFFERS | (5 - 2));
9366 + OUT_BATCH(id << VB_INDEX_SHIFT | VB_MODIFY_ENABLE |
9367 + 4*op->floats_per_vertex);
9368 + sna->render.vertex_reloc[sna->render.nvertex_reloc++] = sna->kgem.nbatch;
9369 + OUT_BATCH64(0);
9370 + OUT_BATCH(~0); /* buffer size: disabled */
9372 + sna->render.vb_id |= 1 << id;
9373 +}
9375 +static void gen9_emit_primitive(struct sna *sna)
9376 +{
9377 + if (sna->kgem.nbatch == sna->render_state.gen9.last_primitive) {
9378 + sna->render.vertex_offset = sna->kgem.nbatch - 5;
9379 + return;
9380 + }
9382 + OUT_BATCH(GEN9_3DPRIMITIVE | (7 - 2));
9383 + OUT_BATCH(0); /* ignored, see VF_TOPOLOGY */
9384 + sna->render.vertex_offset = sna->kgem.nbatch;
9385 + OUT_BATCH(0); /* vertex count, to be filled in later */
9386 + OUT_BATCH(sna->render.vertex_index);
9387 + OUT_BATCH(1); /* single instance */
9388 + OUT_BATCH(0); /* start instance location */
9389 + OUT_BATCH(0); /* index buffer offset, ignored */
9390 + sna->render.vertex_start = sna->render.vertex_index;
9392 + sna->render_state.gen9.last_primitive = sna->kgem.nbatch;
9393 + sna->render_state.gen9.ve_dirty = false;
9394 +}
9396 +static bool gen9_rectangle_begin(struct sna *sna,
9397 + const struct sna_composite_op *op)
9398 +{
9399 + int id = 1 << GEN9_VERTEX(op->u.gen9.flags);
9400 + int ndwords;
9402 + if (sna_vertex_wait__locked(&sna->render) && sna->render.vertex_offset)
9403 + return true;
9405 + ndwords = op->need_magic_ca_pass ? 60 : 6;
9406 + if ((sna->render.vb_id & id) == 0)
9407 + ndwords += 5;
9408 + if (!kgem_check_batch(&sna->kgem, ndwords))
9409 + return false;
9411 + if ((sna->render.vb_id & id) == 0)
9412 + gen9_emit_vertex_buffer(sna, op);
9414 + gen9_emit_primitive(sna);
9415 + return true;
9416 +}
9418 +static int gen9_get_rectangles__flush(struct sna *sna,
9419 + const struct sna_composite_op *op)
9420 +{
9421 + /* Preventing discarding new vbo after lock contention */
9422 + if (sna_vertex_wait__locked(&sna->render)) {
9423 + int rem = vertex_space(sna);
9424 + if (rem > op->floats_per_rect)
9425 + return rem;
9426 + }
9428 + if (!kgem_check_batch(&sna->kgem, op->need_magic_ca_pass ? 65 : 6))
9429 + return 0;
9430 + if (!kgem_check_reloc_and_exec(&sna->kgem, 2))
9431 + return 0;
9433 + if (sna->render.vertex_offset) {
9434 + gen8_vertex_flush(sna);
9435 + if (gen9_magic_ca_pass(sna, op)) {
9436 + gen9_emit_pipe_invalidate(sna);
9437 + gen9_emit_cc(sna, GEN9_BLEND(op->u.gen9.flags));
9438 + gen9_emit_wm(sna, GEN9_KERNEL(op->u.gen9.flags));
9439 + }
9440 + }
9442 + return gen8_vertex_finish(sna);
9443 +}
9445 +inline static int gen9_get_rectangles(struct sna *sna,
9446 + const struct sna_composite_op *op,
9447 + int want,
9448 + void (*emit_state)(struct sna *sna, const struct sna_composite_op *op))
9449 +{
9450 + int rem;
9452 + assert(want);
9454 +start:
9455 + rem = vertex_space(sna);
9456 + if (unlikely(rem < op->floats_per_rect)) {
9457 + DBG(("flushing vbo for %s: %d < %d\n",
9458 + __FUNCTION__, rem, op->floats_per_rect));
9459 + rem = gen9_get_rectangles__flush(sna, op);
9460 + if (unlikely(rem == 0))
9461 + goto flush;
9462 + }
9464 + if (unlikely(sna->render.vertex_offset == 0)) {
9465 + if (!gen9_rectangle_begin(sna, op))
9466 + goto flush;
9467 + else
9468 + goto start;
9469 + }
9471 + assert(rem <= vertex_space(sna));
9472 + assert(op->floats_per_rect <= rem);
9473 + if (want > 1 && want * op->floats_per_rect > rem)
9474 + want = rem / op->floats_per_rect;
9476 + assert(want > 0);
9477 + sna->render.vertex_index += 3*want;
9478 + return want;
9480 +flush:
9481 + if (sna->render.vertex_offset) {
9482 + gen8_vertex_flush(sna);
9483 + gen9_magic_ca_pass(sna, op);
9484 + }
9485 + sna_vertex_wait__locked(&sna->render);
9486 + _kgem_submit(&sna->kgem);
9487 + emit_state(sna, op);
9488 + goto start;
9489 +}
9491 +inline static uint32_t *gen9_composite_get_binding_table(struct sna *sna,
9492 + uint16_t *offset)
9493 +{
9494 + uint32_t *table;
9496 + assert(sna->kgem.surface <= 16384);
9497 + sna->kgem.surface -= SURFACE_DW;
9498 + /* Clear all surplus entries to zero in case of prefetch */
9499 + table = memset(sna->kgem.batch + sna->kgem.surface, 0, 64);
9501 + DBG(("%s(%x)\n", __FUNCTION__, 4*sna->kgem.surface));
9503 + *offset = sna->kgem.surface;
9504 + return table;
9505 +}
9507 +static void
9508 +gen9_get_batch(struct sna *sna, const struct sna_composite_op *op)
9509 +{
9510 + kgem_set_mode(&sna->kgem, KGEM_RENDER, op->dst.bo);
9512 + if (!kgem_check_batch_with_surfaces(&sna->kgem, 150, 2*(1+3))) {
9513 + DBG(("%s: flushing batch: %d < %d+%d\n",
9514 + __FUNCTION__, sna->kgem.surface - sna->kgem.nbatch,
9515 + 150, 4*8*2));
9516 + _kgem_submit(&sna->kgem);
9517 + _kgem_set_mode(&sna->kgem, KGEM_RENDER);
9518 + }
9520 + assert(sna->kgem.mode == KGEM_RENDER);
9521 + assert(sna->kgem.ring == KGEM_RENDER);
9523 + if (sna->render_state.gen9.needs_invariant)
9524 + gen9_emit_invariant(sna);
9525 +}
9527 +static void gen9_emit_composite_state(struct sna *sna,
9528 + const struct sna_composite_op *op)
9529 +{
9530 + uint32_t *binding_table;
9531 + uint16_t offset, dirty;
9533 + gen9_get_batch(sna, op);
9535 + binding_table = gen9_composite_get_binding_table(sna, &offset);
9537 + dirty = kgem_bo_is_dirty(op->dst.bo);
9539 + binding_table[0] =
9540 + gen9_bind_bo(sna,
9541 + op->dst.bo, op->dst.width, op->dst.height,
9542 + gen9_get_dest_format(op->dst.format),
9543 + true);
9544 + binding_table[1] =
9545 + gen9_bind_bo(sna,
9546 + op->src.bo, op->src.width, op->src.height,
9547 + op->src.card_format,
9548 + false);
9549 + if (op->mask.bo) {
9550 + binding_table[2] =
9551 + gen9_bind_bo(sna,
9552 + op->mask.bo,
9553 + op->mask.width,
9554 + op->mask.height,
9555 + op->mask.card_format,
9556 + false);
9557 + }
9559 + if (sna->kgem.surface == offset &&
9560 + *(uint64_t *)(sna->kgem.batch + sna->render_state.gen9.surface_table) == *(uint64_t*)binding_table &&
9561 + (op->mask.bo == NULL ||
9562 + sna->kgem.batch[sna->render_state.gen9.surface_table+2] == binding_table[2])) {
9563 + sna->kgem.surface += SURFACE_DW;
9564 + offset = sna->render_state.gen9.surface_table;
9565 + }
9567 + if (sna->kgem.batch[sna->render_state.gen9.surface_table] == binding_table[0])
9568 + dirty = 0;
9570 + gen9_emit_state(sna, op, offset | dirty);
9571 +}
9573 +static void
9574 +gen9_align_vertex(struct sna *sna, const struct sna_composite_op *op)
9575 +{
9576 + if (op->floats_per_vertex != sna->render_state.gen9.floats_per_vertex) {
9577 + DBG(("aligning vertex: was %d, now %d floats per vertex\n",
9578 + sna->render_state.gen9.floats_per_vertex, op->floats_per_vertex));
9579 + gen8_vertex_align(sna, op);
9580 + sna->render_state.gen9.floats_per_vertex = op->floats_per_vertex;
9581 + }
9582 +}
9584 +fastcall static void
9585 +gen9_render_composite_blt(struct sna *sna,
9586 + const struct sna_composite_op *op,
9587 + const struct sna_composite_rectangles *r)
9588 +{
9589 + gen9_get_rectangles(sna, op, 1, gen9_emit_composite_state);
9590 + op->prim_emit(sna, op, r);
9591 +}
9593 +fastcall static void
9594 +gen9_render_composite_box(struct sna *sna,
9595 + const struct sna_composite_op *op,
9596 + const BoxRec *box)
9597 +{
9598 + struct sna_composite_rectangles r;
9600 + gen9_get_rectangles(sna, op, 1, gen9_emit_composite_state);
9602 + DBG((" %s: (%d, %d), (%d, %d)\n",
9603 + __FUNCTION__,
9604 + box->x1, box->y1, box->x2, box->y2));
9606 + r.dst.x = box->x1;
9607 + r.dst.y = box->y1;
9608 + r.width = box->x2 - box->x1;
9609 + r.height = box->y2 - box->y1;
9610 + r.src = r.mask = r.dst;
9612 + op->prim_emit(sna, op, &r);
9613 +}
9615 +static void
9616 +gen9_render_composite_boxes__blt(struct sna *sna,
9617 + const struct sna_composite_op *op,
9618 + const BoxRec *box, int nbox)
9619 +{
9620 + DBG(("composite_boxes(%d)\n", nbox));
9622 + do {
9623 + int nbox_this_time;
9625 + nbox_this_time = gen9_get_rectangles(sna, op, nbox,
9626 + gen9_emit_composite_state);
9627 + nbox -= nbox_this_time;
9629 + do {
9630 + struct sna_composite_rectangles r;
9632 + DBG((" %s: (%d, %d), (%d, %d)\n",
9633 + __FUNCTION__,
9634 + box->x1, box->y1, box->x2, box->y2));
9636 + r.dst.x = box->x1;
9637 + r.dst.y = box->y1;
9638 + r.width = box->x2 - box->x1;
9639 + r.height = box->y2 - box->y1;
9640 + r.src = r.mask = r.dst;
9642 + op->prim_emit(sna, op, &r);
9643 + box++;
9644 + } while (--nbox_this_time);
9645 + } while (nbox);
9646 +}
9648 +static void
9649 +gen9_render_composite_boxes(struct sna *sna,
9650 + const struct sna_composite_op *op,
9651 + const BoxRec *box, int nbox)
9652 +{
9653 + DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
9655 + do {
9656 + int nbox_this_time;
9657 + float *v;
9659 + nbox_this_time = gen9_get_rectangles(sna, op, nbox,
9660 + gen9_emit_composite_state);
9661 + assert(nbox_this_time);
9662 + nbox -= nbox_this_time;
9664 + v = sna->render.vertices + sna->render.vertex_used;
9665 + sna->render.vertex_used += nbox_this_time * op->floats_per_rect;
9667 + op->emit_boxes(op, box, nbox_this_time, v);
9668 + box += nbox_this_time;
9669 + } while (nbox);
9670 +}
9672 +static void
9673 +gen9_render_composite_boxes__thread(struct sna *sna,
9674 + const struct sna_composite_op *op,
9675 + const BoxRec *box, int nbox)
9676 +{
9677 + DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
9679 + sna_vertex_lock(&sna->render);
9680 + do {
9681 + int nbox_this_time;
9682 + float *v;
9684 + nbox_this_time = gen9_get_rectangles(sna, op, nbox,
9685 + gen9_emit_composite_state);
9686 + assert(nbox_this_time);
9687 + nbox -= nbox_this_time;
9689 + v = sna->render.vertices + sna->render.vertex_used;
9690 + sna->render.vertex_used += nbox_this_time * op->floats_per_rect;
9692 + sna_vertex_acquire__locked(&sna->render);
9693 + sna_vertex_unlock(&sna->render);
9695 + op->emit_boxes(op, box, nbox_this_time, v);
9696 + box += nbox_this_time;
9698 + sna_vertex_lock(&sna->render);
9699 + sna_vertex_release__locked(&sna->render);
9700 + } while (nbox);
9701 + sna_vertex_unlock(&sna->render);
9702 +}
9704 +static uint32_t
9705 +gen9_create_blend_state(struct sna_static_stream *stream)
9706 +{
9707 + char *base, *ptr;
9708 + int src, dst;
9710 + COMPILE_TIME_ASSERT(((GEN9_BLENDFACTOR_COUNT * GEN9_BLENDFACTOR_COUNT << 4) & (1 << 15)) == 0);
9712 + base = sna_static_stream_map(stream,
9713 + GEN9_BLENDFACTOR_COUNT * GEN9_BLENDFACTOR_COUNT * GEN9_BLEND_STATE_PADDED_SIZE,
9714 + 64);
9716 + ptr = base;
9717 + for (src = 0; src < GEN9_BLENDFACTOR_COUNT; src++) {
9718 + for (dst = 0; dst < GEN9_BLENDFACTOR_COUNT; dst++) {
9719 + struct gen9_blend_state *blend =
9720 + (struct gen9_blend_state *)ptr;
9722 + assert(((ptr - base) & 63) == 0);
9723 + COMPILE_TIME_ASSERT(sizeof(blend->common) == 4);
9724 + COMPILE_TIME_ASSERT(sizeof(blend->rt) == 8);
9725 + COMPILE_TIME_ASSERT((char *)&blend->rt - (char *)blend == 4);
9727 + blend->rt.post_blend_clamp = 1;
9728 + blend->rt.pre_blend_clamp = 1;
9730 + blend->rt.color_blend =
9731 + !(dst == BLENDFACTOR_ZERO && src == BLENDFACTOR_ONE);
9732 + blend->rt.dest_blend_factor = dst;
9733 + blend->rt.source_blend_factor = src;
9734 + blend->rt.color_blend_function = BLENDFUNCTION_ADD;
9736 + blend->rt.dest_alpha_blend_factor = dst;
9737 + blend->rt.source_alpha_blend_factor = src;
9738 + blend->rt.alpha_blend_function = BLENDFUNCTION_ADD;
9740 + ptr += GEN9_BLEND_STATE_PADDED_SIZE;
9741 + }
9742 + }
9744 + return sna_static_stream_offsetof(stream, base);
9745 +}
9747 +static int
9748 +gen9_composite_picture(struct sna *sna,
9749 + PicturePtr picture,
9750 + struct sna_composite_channel *channel,
9751 + int x, int y,
9752 + int w, int h,
9753 + int dst_x, int dst_y,
9754 + bool precise)
9755 +{
9756 + PixmapPtr pixmap;
9757 + uint32_t color;
9758 + int16_t dx, dy;
9760 + DBG(("%s: (%d, %d)x(%d, %d), dst=(%d, %d)\n",
9761 + __FUNCTION__, x, y, w, h, dst_x, dst_y));
9763 + channel->is_solid = false;
9764 + channel->card_format = -1;
9766 + if (sna_picture_is_solid(picture, &color))
9767 + return gen4_channel_init_solid(sna, channel, color);
9769 + if (picture->pDrawable == NULL) {
9770 + int ret;
9772 + if (picture->pSourcePict->type == SourcePictTypeLinear)
9773 + return gen4_channel_init_linear(sna, picture, channel,
9774 + x, y,
9775 + w, h,
9776 + dst_x, dst_y);
9778 + DBG(("%s -- fixup, gradient\n", __FUNCTION__));
9779 + ret = -1;
9780 + if (!precise)
9781 + ret = sna_render_picture_approximate_gradient(sna, picture, channel,
9782 + x, y, w, h, dst_x, dst_y);
9783 + if (ret == -1)
9784 + ret = sna_render_picture_fixup(sna, picture, channel,
9785 + x, y, w, h, dst_x, dst_y);
9786 + return ret;
9787 + }
9789 + if (picture->alphaMap) {
9790 + DBG(("%s -- fallback, alphamap\n", __FUNCTION__));
9791 + return sna_render_picture_fixup(sna, picture, channel,
9792 + x, y, w, h, dst_x, dst_y);
9793 + }
9795 + if (!gen9_check_repeat(picture))
9796 + return sna_render_picture_fixup(sna, picture, channel,
9797 + x, y, w, h, dst_x, dst_y);
9799 + if (!gen9_check_filter(picture))
9800 + return sna_render_picture_fixup(sna, picture, channel,
9801 + x, y, w, h, dst_x, dst_y);
9803 + channel->repeat = picture->repeat ? picture->repeatType : RepeatNone;
9804 + channel->filter = picture->filter;
9806 + pixmap = get_drawable_pixmap(picture->pDrawable);
9807 + get_drawable_deltas(picture->pDrawable, pixmap, &dx, &dy);
9809 + x += dx + picture->pDrawable->x;
9810 + y += dy + picture->pDrawable->y;
9812 + channel->is_affine = sna_transform_is_affine(picture->transform);
9813 + if (sna_transform_is_imprecise_integer_translation(picture->transform, picture->filter, precise, &dx, &dy)) {
9814 + DBG(("%s: integer translation (%d, %d), removing\n",
9815 + __FUNCTION__, dx, dy));
9816 + x += dx;
9817 + y += dy;
9818 + channel->transform = NULL;
9819 + channel->filter = PictFilterNearest;
9821 + if (channel->repeat ||
9822 + (x >= 0 &&
9823 + y >= 0 &&
9824 + x + w <= pixmap->drawable.width &&
9825 + y + h <= pixmap->drawable.height)) {
9826 + struct sna_pixmap *priv = sna_pixmap(pixmap);
9827 + if (priv && priv->clear) {
9828 + DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
9829 + return gen4_channel_init_solid(sna, channel, solid_color(picture->format, priv->clear_color));
9830 + }
9831 + }
9832 + } else
9833 + channel->transform = picture->transform;
9835 + channel->pict_format = picture->format;
9836 + channel->card_format = gen9_get_card_format(picture->format);
9837 + if (channel->card_format == (unsigned)-1)
9838 + return sna_render_picture_convert(sna, picture, channel, pixmap,
9839 + x, y, w, h, dst_x, dst_y,
9840 + false);
9842 + if (too_large(pixmap->drawable.width, pixmap->drawable.height)) {
9843 + DBG(("%s: extracting from pixmap %dx%d\n", __FUNCTION__,
9844 + pixmap->drawable.width, pixmap->drawable.height));
9845 + return sna_render_picture_extract(sna, picture, channel,
9846 + x, y, w, h, dst_x, dst_y);
9847 + }
9849 + return sna_render_pixmap_bo(sna, channel, pixmap,
9850 + x, y, w, h, dst_x, dst_y);
9851 +}
9853 +inline static bool gen9_composite_channel_convert(struct sna_composite_channel *channel)
9854 +{
9855 + if (unaligned(channel->bo, PICT_FORMAT_BPP(channel->pict_format)))
9856 + return false;
9858 + channel->repeat = gen9_repeat(channel->repeat);
9859 + channel->filter = gen9_filter(channel->filter);
9860 + if (channel->card_format == (unsigned)-1)
9861 + channel->card_format = gen9_get_card_format(channel->pict_format);
9862 + assert(channel->card_format != (unsigned)-1);
9864 + return true;
9865 +}
9867 +static void gen9_render_composite_done(struct sna *sna,
9868 + const struct sna_composite_op *op)
9869 +{
9870 + if (sna->render.vertex_offset) {
9871 + gen8_vertex_flush(sna);
9872 + gen9_magic_ca_pass(sna, op);
9873 + }
9875 + if (op->mask.bo)
9876 + kgem_bo_destroy(&sna->kgem, op->mask.bo);
9877 + if (op->src.bo)
9878 + kgem_bo_destroy(&sna->kgem, op->src.bo);
9880 + sna_render_composite_redirect_done(sna, op);
9881 +}
9883 +inline static bool
9884 +gen9_composite_set_target(struct sna *sna,
9885 + struct sna_composite_op *op,
9886 + PicturePtr dst,
9887 + int x, int y, int w, int h,
9888 + bool partial)
9889 +{
9890 + BoxRec box;
9891 + unsigned int hint;
9893 + DBG(("%s: (%d, %d)x(%d, %d), partial?=%d\n", __FUNCTION__, x, y, w, h, partial));
9895 + op->dst.pixmap = get_drawable_pixmap(dst->pDrawable);
9896 + op->dst.format = dst->format;
9897 + op->dst.width = op->dst.pixmap->drawable.width;
9898 + op->dst.height = op->dst.pixmap->drawable.height;
9900 + if (w | h) {
9901 + assert(w && h);
9902 + box.x1 = x;
9903 + box.y1 = y;
9904 + box.x2 = x + w;
9905 + box.y2 = y + h;
9906 + } else
9907 + sna_render_picture_extents(dst, &box);
9909 + hint = PREFER_GPU | RENDER_GPU;
9910 + if (!need_tiling(sna, op->dst.width, op->dst.height))
9911 + hint |= FORCE_GPU;
9912 + if (!partial) {
9913 + hint |= IGNORE_DAMAGE;
9914 + if (w == op->dst.width && h == op->dst.height)
9915 + hint |= REPLACES;
9916 + }
9918 + op->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint, &box, &op->damage);
9919 + if (op->dst.bo == NULL)
9920 + return false;
9922 + assert(!op->damage || !DAMAGE_IS_ALL(*op->damage));
9924 + if (unaligned(op->dst.bo, dst->pDrawable->bitsPerPixel))
9925 + return false;
9927 + if (hint & REPLACES) {
9928 + struct sna_pixmap *priv = sna_pixmap(op->dst.pixmap);
9929 + kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
9930 + }
9932 + get_drawable_deltas(dst->pDrawable, op->dst.pixmap,
9933 + &op->dst.x, &op->dst.y);
9935 + DBG(("%s: pixmap=%ld, format=%08x, size=%dx%d, pitch=%d, delta=(%d,%d),damage=%p\n",
9936 + __FUNCTION__,
9937 + op->dst.pixmap->drawable.serialNumber, (int)op->dst.format,
9938 + op->dst.width, op->dst.height,
9939 + op->dst.bo->pitch,
9940 + op->dst.x, op->dst.y,
9941 + op->damage ? *op->damage : (void *)-1));
9943 + assert(op->dst.bo->proxy == NULL);
9945 + if (too_large(op->dst.width, op->dst.height) &&
9946 + !sna_render_composite_redirect(sna, op, x, y, w, h, partial))
9947 + return false;
9949 + return true;
9950 +}
9952 +static bool
9953 +try_blt(struct sna *sna,
9954 + uint8_t op,
9955 + PicturePtr src,
9956 + PicturePtr mask,
9957 + PicturePtr dst,
9958 + int16_t src_x, int16_t src_y,
9959 + int16_t msk_x, int16_t msk_y,
9960 + int16_t dst_x, int16_t dst_y,
9961 + int16_t width, int16_t height,
9962 + unsigned flags,
9963 + struct sna_composite_op *tmp)
9964 +{
9965 + struct kgem_bo *bo;
9967 + if (sna->kgem.mode == KGEM_BLT) {
9968 + DBG(("%s: already performing BLT\n", __FUNCTION__));
9969 + goto execute;
9970 + }
9972 + if (too_large(width, height)) {
9973 + DBG(("%s: operation too large for 3D pipe (%d, %d)\n",
9974 + __FUNCTION__, width, height));
9975 + goto execute;
9976 + }
9978 + bo = __sna_drawable_peek_bo(dst->pDrawable);
9979 + if (bo == NULL)
9980 + goto execute;
9982 + if (untiled_tlb_miss(bo))
9983 + goto execute;
9985 + if (bo->rq) {
9986 + if (RQ_IS_BLT(bo->rq))
9987 + goto execute;
9989 + return false;
9990 + }
9992 + if (bo->tiling == I915_TILING_Y)
9993 + goto upload;
9995 + if (sna_picture_is_solid(src, NULL) && can_switch_to_blt(sna, bo, 0))
9996 + goto execute;
9998 + if (src->pDrawable == dst->pDrawable &&
9999 + (sna->render_state.gt < 3 || width*height < 1024) &&
10000 + can_switch_to_blt(sna, bo, 0))
10001 + goto execute;
10003 + if (src->pDrawable) {
10004 + struct kgem_bo *s = __sna_drawable_peek_bo(src->pDrawable);
10005 + if (s == NULL)
10006 + goto upload;
10008 + if (prefer_blt_bo(sna, s, bo))
10009 + goto execute;
10010 + }
10012 + if (sna->kgem.ring == KGEM_BLT) {
10013 + DBG(("%s: already performing BLT\n", __FUNCTION__));
10014 + goto execute;
10015 + }
10017 +upload:
10018 + flags |= COMPOSITE_UPLOAD;
10019 +execute:
10020 + return sna_blt_composite(sna, op,
10021 + src, dst,
10022 + src_x, src_y,
10023 + dst_x, dst_y,
10024 + width, height,
10025 + flags, tmp);
10026 +}
10028 +static bool
10029 +check_gradient(PicturePtr picture, bool precise)
10030 +{
10031 + if (picture->pDrawable)
10032 + return false;
10034 + switch (picture->pSourcePict->type) {
10035 + case SourcePictTypeSolidFill:
10036 + case SourcePictTypeLinear:
10037 + return false;
10038 + default:
10039 + return precise;
10040 + }
10041 +}
10043 +static bool
10044 +has_alphamap(PicturePtr p)
10045 +{
10046 + return p->alphaMap != NULL;
10047 +}
10049 +static bool
10050 +need_upload(PicturePtr p)
10051 +{
10052 + return p->pDrawable && unattached(p->pDrawable) && untransformed(p);
10053 +}
10055 +static bool
10056 +source_is_busy(PixmapPtr pixmap)
10057 +{
10058 + struct sna_pixmap *priv = sna_pixmap(pixmap);
10059 + if (priv == NULL || priv->clear)
10060 + return false;
10062 + if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo))
10063 + return true;
10065 + if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo))
10066 + return true;
10068 + return priv->gpu_damage && !priv->cpu_damage;
10069 +}
10071 +static bool
10072 +source_fallback(PicturePtr p, PixmapPtr pixmap, bool precise)
10073 +{
10074 + if (sna_picture_is_solid(p, NULL))
10075 + return false;
10077 + if (p->pSourcePict)
10078 + return check_gradient(p, precise);
10080 + if (!gen9_check_repeat(p) || !gen9_check_format(p->format))
10081 + return true;
10083 + if (pixmap && source_is_busy(pixmap))
10084 + return false;
10086 + return has_alphamap(p) || !gen9_check_filter(p) || need_upload(p);
10087 +}
10089 +static bool
10090 +gen9_composite_fallback(struct sna *sna,
10091 + PicturePtr src,
10092 + PicturePtr mask,
10093 + PicturePtr dst)
10094 +{
10095 + PixmapPtr src_pixmap;
10096 + PixmapPtr mask_pixmap;
10097 + PixmapPtr dst_pixmap;
10098 + bool src_fallback, mask_fallback;
10100 + if (!gen9_check_dst_format(dst->format)) {
10101 + DBG(("%s: unknown destination format: %d\n",
10102 + __FUNCTION__, dst->format));
10103 + return true;
10104 + }
10106 + dst_pixmap = get_drawable_pixmap(dst->pDrawable);
10108 + src_pixmap = src->pDrawable ? get_drawable_pixmap(src->pDrawable) : NULL;
10109 + src_fallback = source_fallback(src, src_pixmap,
10110 + dst->polyMode == PolyModePrecise);
10112 + if (mask) {
10113 + mask_pixmap = mask->pDrawable ? get_drawable_pixmap(mask->pDrawable) : NULL;
10114 + mask_fallback = source_fallback(mask, mask_pixmap,
10115 + dst->polyMode == PolyModePrecise);
10116 + } else {
10117 + mask_pixmap = NULL;
10118 + mask_fallback = false;
10119 + }
10121 + /* If we are using the destination as a source and need to
10122 + * readback in order to upload the source, do it all
10123 + * on the cpu.
10124 + */
10125 + if (src_pixmap == dst_pixmap && src_fallback) {
10126 + DBG(("%s: src is dst and will fallback\n",__FUNCTION__));
10127 + return true;
10128 + }
10129 + if (mask_pixmap == dst_pixmap && mask_fallback) {
10130 + DBG(("%s: mask is dst and will fallback\n",__FUNCTION__));
10131 + return true;
10132 + }
10134 + /* If anything is on the GPU, push everything out to the GPU */
10135 + if (dst_use_gpu(dst_pixmap)) {
10136 + DBG(("%s: dst is already on the GPU, try to use GPU\n",
10137 + __FUNCTION__));
10138 + return false;
10139 + }
10141 + if (src_pixmap && !src_fallback) {
10142 + DBG(("%s: src is already on the GPU, try to use GPU\n",
10143 + __FUNCTION__));
10144 + return false;
10145 + }
10146 + if (mask_pixmap && !mask_fallback) {
10147 + DBG(("%s: mask is already on the GPU, try to use GPU\n",
10148 + __FUNCTION__));
10149 + return false;
10150 + }
10152 + /* However if the dst is not on the GPU and we need to
10153 + * render one of the sources using the CPU, we may
10154 + * as well do the entire operation in place onthe CPU.
10155 + */
10156 + if (src_fallback) {
10157 + DBG(("%s: dst is on the CPU and src will fallback\n",
10158 + __FUNCTION__));
10159 + return true;
10160 + }
10162 + if (mask && mask_fallback) {
10163 + DBG(("%s: dst is on the CPU and mask will fallback\n",
10164 + __FUNCTION__));
10165 + return true;
10166 + }
10168 + if (too_large(dst_pixmap->drawable.width,
10169 + dst_pixmap->drawable.height) &&
10170 + dst_is_cpu(dst_pixmap)) {
10171 + DBG(("%s: dst is on the CPU and too large\n", __FUNCTION__));
10172 + return true;
10173 + }
10175 + DBG(("%s: dst is not on the GPU and the operation should not fallback\n",
10176 + __FUNCTION__));
10177 + return dst_use_cpu(dst_pixmap);
10178 +}
10180 +static int
10181 +reuse_source(struct sna *sna,
10182 + PicturePtr src, struct sna_composite_channel *sc, int src_x, int src_y,
10183 + PicturePtr mask, struct sna_composite_channel *mc, int msk_x, int msk_y)
10184 +{
10185 + uint32_t color;
10187 + if (src_x != msk_x || src_y != msk_y)
10188 + return false;
10190 + if (src == mask) {
10191 + DBG(("%s: mask is source\n", __FUNCTION__));
10192 + *mc = *sc;
10193 + mc->bo = kgem_bo_reference(mc->bo);
10194 + return true;
10195 + }
10197 + if (sna_picture_is_solid(mask, &color))
10198 + return gen4_channel_init_solid(sna, mc, color);
10200 + if (sc->is_solid)
10201 + return false;
10203 + if (src->pDrawable == NULL || mask->pDrawable != src->pDrawable)
10204 + return false;
10206 + DBG(("%s: mask reuses source drawable\n", __FUNCTION__));
10208 + if (!sna_transform_equal(src->transform, mask->transform))
10209 + return false;
10211 + if (!sna_picture_alphamap_equal(src, mask))
10212 + return false;
10214 + if (!gen9_check_repeat(mask))
10215 + return false;
10217 + if (!gen9_check_filter(mask))
10218 + return false;
10220 + if (!gen9_check_format(mask->format))
10221 + return false;
10223 + DBG(("%s: reusing source channel for mask with a twist\n",
10224 + __FUNCTION__));
10226 + *mc = *sc;
10227 + mc->repeat = gen9_repeat(mask->repeat ? mask->repeatType : RepeatNone);
10228 + mc->filter = gen9_filter(mask->filter);
10229 + mc->pict_format = mask->format;
10230 + mc->card_format = gen9_get_card_format(mask->format);
10231 + mc->bo = kgem_bo_reference(mc->bo);
10232 + return true;
10233 +}
10235 +static bool
10236 +gen9_render_composite(struct sna *sna,
10237 + uint8_t op,
10238 + PicturePtr src,
10239 + PicturePtr mask,
10240 + PicturePtr dst,
10241 + int16_t src_x, int16_t src_y,
10242 + int16_t msk_x, int16_t msk_y,
10243 + int16_t dst_x, int16_t dst_y,
10244 + int16_t width, int16_t height,
10245 + unsigned flags,
10246 + struct sna_composite_op *tmp)
10247 +{
10248 + if (op >= ARRAY_SIZE(gen9_blend_op))
10249 + return false;
10251 + DBG(("%s: %dx%d, current mode=%d/%d\n", __FUNCTION__,
10252 + width, height, sna->kgem.mode, sna->kgem.ring));
10254 + if (mask == NULL &&
10255 + try_blt(sna, op,
10256 + src, mask, dst,
10257 + src_x, src_y,
10258 + msk_x, msk_y,
10259 + dst_x, dst_y,
10260 + width, height,
10261 + flags, tmp))
10262 + return true;
10264 + if (gen9_composite_fallback(sna, src, mask, dst))
10265 + goto fallback;
10267 + if (need_tiling(sna, width, height))
10268 + return sna_tiling_composite(op, src, mask, dst,
10269 + src_x, src_y,
10270 + msk_x, msk_y,
10271 + dst_x, dst_y,
10272 + width, height,
10273 + tmp);
10275 + if (op == PictOpClear && src == sna->clear)
10276 + op = PictOpSrc;
10277 + tmp->op = op;
10278 + if (!gen9_composite_set_target(sna, tmp, dst,
10279 + dst_x, dst_y, width, height,
10280 + flags & COMPOSITE_PARTIAL || op > PictOpSrc))
10281 + goto fallback;
10283 + switch (gen9_composite_picture(sna, src, &tmp->src,
10284 + src_x, src_y,
10285 + width, height,
10286 + dst_x, dst_y,
10287 + dst->polyMode == PolyModePrecise)) {
10288 + case -1:
10289 + goto cleanup_dst;
10290 + case 0:
10291 + if (!gen4_channel_init_solid(sna, &tmp->src, 0))
10292 + goto cleanup_dst;
10293 + /* fall through to fixup */
10294 + case 1:
10295 + /* Did we just switch rings to prepare the source? */
10296 + if (mask == NULL &&
10297 + (prefer_blt_composite(sna, tmp) ||
10298 + unaligned(tmp->src.bo, PICT_FORMAT_BPP(tmp->src.pict_format))) &&
10299 + sna_blt_composite__convert(sna,
10300 + dst_x, dst_y, width, height,
10301 + tmp))
10302 + return true;
10304 + if (!gen9_composite_channel_convert(&tmp->src))
10305 + goto cleanup_src;
10307 + break;
10308 + }
10310 + tmp->is_affine = tmp->src.is_affine;
10311 + tmp->has_component_alpha = false;
10312 + tmp->need_magic_ca_pass = false;
10314 + tmp->mask.bo = NULL;
10315 + tmp->mask.filter = SAMPLER_FILTER_NEAREST;
10316 + tmp->mask.repeat = SAMPLER_EXTEND_NONE;
10318 + if (mask) {
10319 + if (mask->componentAlpha && PICT_FORMAT_RGB(mask->format)) {
10320 + tmp->has_component_alpha = true;
10322 + /* Check if it's component alpha that relies on a source alpha and on
10323 + * the source value. We can only get one of those into the single
10324 + * source value that we get to blend with.
10325 + */
10326 + if (gen9_blend_op[op].src_alpha &&
10327 + (gen9_blend_op[op].src_blend != BLENDFACTOR_ZERO)) {
10328 + if (op != PictOpOver)
10329 + goto cleanup_src;
10331 + tmp->need_magic_ca_pass = true;
10332 + tmp->op = PictOpOutReverse;
10333 + }
10334 + }
10336 + if (!reuse_source(sna,
10337 + src, &tmp->src, src_x, src_y,
10338 + mask, &tmp->mask, msk_x, msk_y)) {
10339 + switch (gen9_composite_picture(sna, mask, &tmp->mask,
10340 + msk_x, msk_y,
10341 + width, height,
10342 + dst_x, dst_y,
10343 + dst->polyMode == PolyModePrecise)) {
10344 + case -1:
10345 + goto cleanup_src;
10346 + case 0:
10347 + if (!gen4_channel_init_solid(sna, &tmp->mask, 0))
10348 + goto cleanup_src;
10349 + /* fall through to fixup */
10350 + case 1:
10351 + if (!gen9_composite_channel_convert(&tmp->mask))
10352 + goto cleanup_mask;
10353 + break;
10354 + }
10355 + }
10357 + tmp->is_affine &= tmp->mask.is_affine;
10358 + }
10360 + tmp->u.gen9.flags =
10361 + GEN9_SET_FLAGS(SAMPLER_OFFSET(tmp->src.filter,
10362 + tmp->src.repeat,
10363 + tmp->mask.filter,
10364 + tmp->mask.repeat),
10365 + gen9_get_blend(tmp->op,
10366 + tmp->has_component_alpha,
10367 + tmp->dst.format),
10368 + gen9_choose_composite_kernel(tmp->op,
10369 + tmp->mask.bo != NULL,
10370 + tmp->has_component_alpha,
10371 + tmp->is_affine),
10372 + gen4_choose_composite_emitter(sna, tmp));
10374 + tmp->blt = gen9_render_composite_blt;
10375 + tmp->box = gen9_render_composite_box;
10376 + tmp->boxes = gen9_render_composite_boxes__blt;
10377 + if (tmp->emit_boxes){
10378 + tmp->boxes = gen9_render_composite_boxes;
10379 + tmp->thread_boxes = gen9_render_composite_boxes__thread;
10380 + }
10381 + tmp->done = gen9_render_composite_done;
10383 + kgem_set_mode(&sna->kgem, KGEM_RENDER, tmp->dst.bo);
10384 + if (!kgem_check_bo(&sna->kgem,
10385 + tmp->dst.bo, tmp->src.bo, tmp->mask.bo,
10386 + NULL)) {
10387 + kgem_submit(&sna->kgem);
10388 + if (!kgem_check_bo(&sna->kgem,
10389 + tmp->dst.bo, tmp->src.bo, tmp->mask.bo,
10390 + NULL))
10391 + goto cleanup_mask;
10392 + _kgem_set_mode(&sna->kgem, KGEM_RENDER);
10393 + }
10395 + gen9_align_vertex(sna, tmp);
10396 + gen9_emit_composite_state(sna, tmp);
10397 + return true;
10399 +cleanup_mask:
10400 + if (tmp->mask.bo) {
10401 + kgem_bo_destroy(&sna->kgem, tmp->mask.bo);
10402 + tmp->mask.bo = NULL;
10403 + }
10404 +cleanup_src:
10405 + if (tmp->src.bo) {
10406 + kgem_bo_destroy(&sna->kgem, tmp->src.bo);
10407 + tmp->src.bo = NULL;
10408 + }
10409 +cleanup_dst:
10410 + if (tmp->redirect.real_bo) {
10411 + kgem_bo_destroy(&sna->kgem, tmp->dst.bo);
10412 + tmp->redirect.real_bo = NULL;
10413 + }
10414 +fallback:
10415 + return (mask == NULL &&
10416 + sna_blt_composite(sna, op,
10417 + src, dst,
10418 + src_x, src_y,
10419 + dst_x, dst_y,
10420 + width, height,
10421 + flags | COMPOSITE_FALLBACK, tmp));
10422 +}
10424 +#if !NO_COMPOSITE_SPANS
10425 +fastcall static void
10426 +gen9_render_composite_spans_box(struct sna *sna,
10427 + const struct sna_composite_spans_op *op,
10428 + const BoxRec *box, float opacity)
10429 +{
10430 + DBG(("%s: src=+(%d, %d), opacity=%f, dst=+(%d, %d), box=(%d, %d) x (%d, %d)\n",
10431 + __FUNCTION__,
10432 + op->base.src.offset[0], op->base.src.offset[1],
10433 + opacity,
10434 + op->base.dst.x, op->base.dst.y,
10435 + box->x1, box->y1,
10436 + box->x2 - box->x1,
10437 + box->y2 - box->y1));
10439 + gen9_get_rectangles(sna, &op->base, 1, gen9_emit_composite_state);
10440 + op->prim_emit(sna, op, box, opacity);
10441 +}
10443 +static void
10444 +gen9_render_composite_spans_boxes(struct sna *sna,
10445 + const struct sna_composite_spans_op *op,
10446 + const BoxRec *box, int nbox,
10447 + float opacity)
10448 +{
10449 + DBG(("%s: nbox=%d, src=+(%d, %d), opacity=%f, dst=+(%d, %d)\n",
10450 + __FUNCTION__, nbox,
10451 + op->base.src.offset[0], op->base.src.offset[1],
10452 + opacity,
10453 + op->base.dst.x, op->base.dst.y));
10455 + do {
10456 + int nbox_this_time;
10458 + nbox_this_time = gen9_get_rectangles(sna, &op->base, nbox,
10459 + gen9_emit_composite_state);
10460 + nbox -= nbox_this_time;
10462 + do {
10463 + DBG((" %s: (%d, %d) x (%d, %d)\n", __FUNCTION__,
10464 + box->x1, box->y1,
10465 + box->x2 - box->x1,
10466 + box->y2 - box->y1));
10468 + op->prim_emit(sna, op, box++, opacity);
10469 + } while (--nbox_this_time);
10470 + } while (nbox);
10471 +}
10473 +fastcall static void
10474 +gen9_render_composite_spans_boxes__thread(struct sna *sna,
10475 + const struct sna_composite_spans_op *op,
10476 + const struct sna_opacity_box *box,
10477 + int nbox)
10478 +{
10479 + DBG(("%s: nbox=%d, src=+(%d, %d), dst=+(%d, %d)\n",
10480 + __FUNCTION__, nbox,
10481 + op->base.src.offset[0], op->base.src.offset[1],
10482 + op->base.dst.x, op->base.dst.y));
10484 + sna_vertex_lock(&sna->render);
10485 + do {
10486 + int nbox_this_time;
10487 + float *v;
10489 + nbox_this_time = gen9_get_rectangles(sna, &op->base, nbox,
10490 + gen9_emit_composite_state);
10491 + assert(nbox_this_time);
10492 + nbox -= nbox_this_time;
10494 + v = sna->render.vertices + sna->render.vertex_used;
10495 + sna->render.vertex_used += nbox_this_time * op->base.floats_per_rect;
10497 + sna_vertex_acquire__locked(&sna->render);
10498 + sna_vertex_unlock(&sna->render);
10500 + op->emit_boxes(op, box, nbox_this_time, v);
10501 + box += nbox_this_time;
10503 + sna_vertex_lock(&sna->render);
10504 + sna_vertex_release__locked(&sna->render);
10505 + } while (nbox);
10506 + sna_vertex_unlock(&sna->render);
10507 +}
10509 +fastcall static void
10510 +gen9_render_composite_spans_done(struct sna *sna,
10511 + const struct sna_composite_spans_op *op)
10512 +{
10513 + if (sna->render.vertex_offset)
10514 + gen8_vertex_flush(sna);
10516 + DBG(("%s()\n", __FUNCTION__));
10518 + if (op->base.src.bo)
10519 + kgem_bo_destroy(&sna->kgem, op->base.src.bo);
10521 + sna_render_composite_redirect_done(sna, &op->base);
10522 +}
10524 +static bool
10525 +gen9_check_composite_spans(struct sna *sna,
10526 + uint8_t op, PicturePtr src, PicturePtr dst,
10527 + int16_t width, int16_t height, unsigned flags)
10528 +{
10529 + if (op >= ARRAY_SIZE(gen9_blend_op))
10530 + return false;
10532 + if (gen9_composite_fallback(sna, src, NULL, dst))
10533 + return false;
10535 + if (need_tiling(sna, width, height) &&
10536 + !is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS)) {
10537 + DBG(("%s: fallback, tiled operation not on GPU\n",
10538 + __FUNCTION__));
10539 + return false;
10540 + }
10542 + return true;
10543 +}
10545 +static bool
10546 +gen9_render_composite_spans(struct sna *sna,
10547 + uint8_t op,
10548 + PicturePtr src,
10549 + PicturePtr dst,
10550 + int16_t src_x, int16_t src_y,
10551 + int16_t dst_x, int16_t dst_y,
10552 + int16_t width, int16_t height,
10553 + unsigned flags,
10554 + struct sna_composite_spans_op *tmp)
10555 +{
10556 + DBG(("%s: %dx%d with flags=%x, current mode=%d\n", __FUNCTION__,
10557 + width, height, flags, sna->kgem.ring));
10559 + assert(gen9_check_composite_spans(sna, op, src, dst, width, height, flags));
10561 + if (need_tiling(sna, width, height)) {
10562 + DBG(("%s: tiling, operation (%dx%d) too wide for pipeline\n",
10563 + __FUNCTION__, width, height));
10564 + return sna_tiling_composite_spans(op, src, dst,
10565 + src_x, src_y, dst_x, dst_y,
10566 + width, height, flags, tmp);
10567 + }
10569 + tmp->base.op = op;
10570 + if (!gen9_composite_set_target(sna, &tmp->base, dst,
10571 + dst_x, dst_y, width, height, true))
10572 + return false;
10574 + switch (gen9_composite_picture(sna, src, &tmp->base.src,
10575 + src_x, src_y,
10576 + width, height,
10577 + dst_x, dst_y,
10578 + dst->polyMode == PolyModePrecise)) {
10579 + case -1:
10580 + goto cleanup_dst;
10581 + case 0:
10582 + if (!gen4_channel_init_solid(sna, &tmp->base.src, 0))
10583 + goto cleanup_dst;
10584 + /* fall through to fixup */
10585 + case 1:
10586 + if (!gen9_composite_channel_convert(&tmp->base.src))
10587 + goto cleanup_src;
10588 + break;
10589 + }
10590 + tmp->base.mask.bo = NULL;
10592 + tmp->base.is_affine = tmp->base.src.is_affine;
10593 + tmp->base.need_magic_ca_pass = false;
10595 + tmp->base.u.gen9.flags =
10596 + GEN9_SET_FLAGS(SAMPLER_OFFSET(tmp->base.src.filter,
10597 + tmp->base.src.repeat,
10598 + SAMPLER_FILTER_NEAREST,
10599 + SAMPLER_EXTEND_PAD),
10600 + gen9_get_blend(tmp->base.op, false, tmp->base.dst.format),
10601 + GEN9_WM_KERNEL_OPACITY | !tmp->base.is_affine,
10602 + gen4_choose_spans_emitter(sna, tmp));
10604 + tmp->box = gen9_render_composite_spans_box;
10605 + tmp->boxes = gen9_render_composite_spans_boxes;
10606 + if (tmp->emit_boxes)
10607 + tmp->thread_boxes = gen9_render_composite_spans_boxes__thread;
10608 + tmp->done = gen9_render_composite_spans_done;
10610 + kgem_set_mode(&sna->kgem, KGEM_RENDER, tmp->base.dst.bo);
10611 + if (!kgem_check_bo(&sna->kgem,
10612 + tmp->base.dst.bo, tmp->base.src.bo,
10613 + NULL)) {
10614 + kgem_submit(&sna->kgem);
10615 + if (!kgem_check_bo(&sna->kgem,
10616 + tmp->base.dst.bo, tmp->base.src.bo,
10617 + NULL))
10618 + goto cleanup_src;
10619 + _kgem_set_mode(&sna->kgem, KGEM_RENDER);
10620 + }
10622 + gen9_align_vertex(sna, &tmp->base);
10623 + gen9_emit_composite_state(sna, &tmp->base);
10624 + return true;
10626 +cleanup_src:
10627 + if (tmp->base.src.bo)
10628 + kgem_bo_destroy(&sna->kgem, tmp->base.src.bo);
10629 +cleanup_dst:
10630 + if (tmp->base.redirect.real_bo)
10631 + kgem_bo_destroy(&sna->kgem, tmp->base.dst.bo);
10632 + return false;
10633 +}
10634 +#endif
10636 +static void
10637 +gen9_emit_copy_state(struct sna *sna,
10638 + const struct sna_composite_op *op)
10639 +{
10640 + uint32_t *binding_table;
10641 + uint16_t offset, dirty;
10643 + gen9_get_batch(sna, op);
10645 + binding_table = gen9_composite_get_binding_table(sna, &offset);
10647 + dirty = kgem_bo_is_dirty(op->dst.bo);
10649 + binding_table[0] =
10650 + gen9_bind_bo(sna,
10651 + op->dst.bo, op->dst.width, op->dst.height,
10652 + gen9_get_dest_format(op->dst.format),
10653 + true);
10654 + binding_table[1] =
10655 + gen9_bind_bo(sna,
10656 + op->src.bo, op->src.width, op->src.height,
10657 + op->src.card_format,
10658 + false);
10660 + if (sna->kgem.surface == offset &&
10661 + *(uint64_t *)(sna->kgem.batch + sna->render_state.gen9.surface_table) == *(uint64_t*)binding_table) {
10662 + sna->kgem.surface += SURFACE_DW;
10663 + offset = sna->render_state.gen9.surface_table;
10664 + }
10666 + if (sna->kgem.batch[sna->render_state.gen9.surface_table] == binding_table[0])
10667 + dirty = 0;
10669 + assert(!GEN9_READS_DST(op->u.gen9.flags));
10670 + gen9_emit_state(sna, op, offset | dirty);
10671 +}
10673 +static inline bool
10674 +prefer_blt_copy(struct sna *sna,
10675 + struct kgem_bo *src_bo,
10676 + struct kgem_bo *dst_bo,
10677 + unsigned flags)
10678 +{
10679 + if (sna->kgem.mode == KGEM_BLT)
10680 + return true;
10682 + assert((flags & COPY_SYNC) == 0);
10684 + if (untiled_tlb_miss(src_bo) ||
10685 + untiled_tlb_miss(dst_bo))
10686 + return true;
10688 + if (flags & COPY_DRI && !sna->kgem.has_semaphores)
10689 + return false;
10691 + if (force_blt_ring(sna, dst_bo))
10692 + return true;
10694 + if ((flags & COPY_SMALL ||
10695 + (sna->render_state.gt < 3 && src_bo == dst_bo)) &&
10696 + can_switch_to_blt(sna, dst_bo, flags))
10697 + return true;
10699 + if (kgem_bo_is_render(dst_bo) ||
10700 + kgem_bo_is_render(src_bo))
10701 + return false;
10703 + if (flags & COPY_LAST &&
10704 + sna->render_state.gt < 3 &&
10705 + can_switch_to_blt(sna, dst_bo, flags))
10706 + return true;
10708 + if (prefer_render_ring(sna, dst_bo))
10709 + return false;
10711 + if (!prefer_blt_ring(sna, dst_bo, flags))
10712 + return false;
10714 + return prefer_blt_bo(sna, src_bo, dst_bo);
10715 +}
10717 +static bool
10718 +gen9_render_copy_boxes(struct sna *sna, uint8_t alu,
10719 + const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
10720 + const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
10721 + const BoxRec *box, int n, unsigned flags)
10722 +{
10723 + struct sna_composite_op tmp;
10724 + BoxRec extents;
10726 + DBG(("%s (%d, %d)->(%d, %d) x %d, alu=%x, flags=%x, self-copy=%d, overlaps? %d\n",
10727 + __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy, n, alu, flags,
10728 + src_bo == dst_bo,
10729 + overlaps(sna,
10730 + src_bo, src_dx, src_dy,
10731 + dst_bo, dst_dx, dst_dy,
10732 + box, n, flags, &extents)));
10734 + if (prefer_blt_copy(sna, src_bo, dst_bo, flags) &&
10735 + sna_blt_compare_depth(src, dst) &&
10736 + sna_blt_copy_boxes(sna, alu,
10737 + src_bo, src_dx, src_dy,
10738 + dst_bo, dst_dx, dst_dy,
10739 + dst->bitsPerPixel,
10740 + box, n))
10741 + return true;
10743 + if (!(alu == GXcopy || alu == GXclear) ||
10744 + unaligned(src_bo, src->bitsPerPixel) ||
10745 + unaligned(dst_bo, dst->bitsPerPixel)) {
10746 +fallback_blt:
10747 + DBG(("%s: fallback blt\n", __FUNCTION__));
10748 + if (!sna_blt_compare_depth(src, dst))
10749 + return false;
10751 + return sna_blt_copy_boxes_fallback(sna, alu,
10752 + src, src_bo, src_dx, src_dy,
10753 + dst, dst_bo, dst_dx, dst_dy,
10754 + box, n);
10755 + }
10757 + if (overlaps(sna,
10758 + src_bo, src_dx, src_dy,
10759 + dst_bo, dst_dx, dst_dy,
10760 + box, n, flags,
10761 + &extents)) {
10762 + bool big = too_large(extents.x2-extents.x1, extents.y2-extents.y1);
10764 + if ((big || !prefer_render_ring(sna, dst_bo)) &&
10765 + sna_blt_copy_boxes(sna, alu,
10766 + src_bo, src_dx, src_dy,
10767 + dst_bo, dst_dx, dst_dy,
10768 + dst->bitsPerPixel,
10769 + box, n))
10770 + return true;
10772 + if (big)
10773 + goto fallback_blt;
10775 + assert(src_bo == dst_bo);
10776 + assert(src->depth == dst->depth);
10777 + assert(src->width == dst->width);
10778 + assert(src->height == dst->height);
10779 + return sna_render_copy_boxes__overlap(sna, alu, dst, dst_bo,
10780 + src_dx, src_dy,
10781 + dst_dx, dst_dy,
10782 + box, n, &extents);
10783 + }
10785 + if (dst->depth == src->depth) {
10786 + tmp.dst.format = sna_render_format_for_depth(dst->depth);
10787 + tmp.src.pict_format = tmp.dst.format;
10788 + } else {
10789 + tmp.dst.format = sna_format_for_depth(dst->depth);
10790 + tmp.src.pict_format = sna_format_for_depth(src->depth);
10791 + }
10792 + if (!gen9_check_format(tmp.src.pict_format))
10793 + goto fallback_blt;
10795 + tmp.dst.pixmap = (PixmapPtr)dst;
10796 + tmp.dst.width = dst->width;
10797 + tmp.dst.height = dst->height;
10798 + tmp.dst.bo = dst_bo;
10799 + tmp.dst.x = tmp.dst.y = 0;
10800 + tmp.damage = NULL;
10802 + sna_render_composite_redirect_init(&tmp);
10803 + if (too_large(tmp.dst.width, tmp.dst.height)) {
10804 + int i;
10806 + extents = box[0];
10807 + for (i = 1; i < n; i++) {
10808 + if (box[i].x1 < extents.x1)
10809 + extents.x1 = box[i].x1;
10810 + if (box[i].y1 < extents.y1)
10811 + extents.y1 = box[i].y1;
10813 + if (box[i].x2 > extents.x2)
10814 + extents.x2 = box[i].x2;
10815 + if (box[i].y2 > extents.y2)
10816 + extents.y2 = box[i].y2;
10817 + }
10819 + if (!sna_render_composite_redirect(sna, &tmp,
10820 + extents.x1 + dst_dx,
10821 + extents.y1 + dst_dy,
10822 + extents.x2 - extents.x1,
10823 + extents.y2 - extents.y1,
10824 + n > 1))
10825 + goto fallback_tiled;
10826 + }
10828 + tmp.src.card_format = gen9_get_card_format(tmp.src.pict_format);
10829 + if (too_large(src->width, src->height)) {
10830 + int i;
10832 + extents = box[0];
10833 + for (i = 1; i < n; i++) {
10834 + if (box[i].x1 < extents.x1)
10835 + extents.x1 = box[i].x1;
10836 + if (box[i].y1 < extents.y1)
10837 + extents.y1 = box[i].y1;
10839 + if (box[i].x2 > extents.x2)
10840 + extents.x2 = box[i].x2;
10841 + if (box[i].y2 > extents.y2)
10842 + extents.y2 = box[i].y2;
10843 + }
10845 + if (!sna_render_pixmap_partial(sna, src, src_bo, &tmp.src,
10846 + extents.x1 + src_dx,
10847 + extents.y1 + src_dy,
10848 + extents.x2 - extents.x1,
10849 + extents.y2 - extents.y1))
10850 + goto fallback_tiled_dst;
10851 + } else {
10852 + tmp.src.bo = src_bo;
10853 + tmp.src.width = src->width;
10854 + tmp.src.height = src->height;
10855 + tmp.src.offset[0] = tmp.src.offset[1] = 0;
10856 + }
10858 + tmp.mask.bo = NULL;
10860 + tmp.floats_per_vertex = 2;
10861 + tmp.floats_per_rect = 6;
10862 + tmp.need_magic_ca_pass = 0;
10864 + tmp.u.gen9.flags = COPY_FLAGS(alu);
10866 + kgem_set_mode(&sna->kgem, KGEM_RENDER, tmp.dst.bo);
10867 + if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, tmp.src.bo, NULL)) {
10868 + kgem_submit(&sna->kgem);
10869 + if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, tmp.src.bo, NULL)) {
10870 + if (tmp.src.bo != src_bo)
10871 + kgem_bo_destroy(&sna->kgem, tmp.src.bo);
10872 + if (tmp.redirect.real_bo)
10873 + kgem_bo_destroy(&sna->kgem, tmp.dst.bo);
10874 + goto fallback_blt;
10875 + }
10876 + _kgem_set_mode(&sna->kgem, KGEM_RENDER);
10877 + }
10879 + src_dx += tmp.src.offset[0];
10880 + src_dy += tmp.src.offset[1];
10882 + dst_dx += tmp.dst.x;
10883 + dst_dy += tmp.dst.y;
10885 + tmp.dst.x = tmp.dst.y = 0;
10887 + gen9_align_vertex(sna, &tmp);
10888 + gen9_emit_copy_state(sna, &tmp);
10890 + do {
10891 + int16_t *v;
10892 + int n_this_time;
10894 + n_this_time = gen9_get_rectangles(sna, &tmp, n,
10895 + gen9_emit_copy_state);
10896 + n -= n_this_time;
10898 + v = (int16_t *)(sna->render.vertices + sna->render.vertex_used);
10899 + sna->render.vertex_used += 6 * n_this_time;
10900 + assert(sna->render.vertex_used <= sna->render.vertex_size);
10901 + do {
10903 + DBG((" (%d, %d) -> (%d, %d) + (%d, %d)\n",
10904 + box->x1 + src_dx, box->y1 + src_dy,
10905 + box->x1 + dst_dx, box->y1 + dst_dy,
10906 + box->x2 - box->x1, box->y2 - box->y1));
10907 + v[0] = box->x2 + dst_dx;
10908 + v[2] = box->x2 + src_dx;
10909 + v[1] = v[5] = box->y2 + dst_dy;
10910 + v[3] = v[7] = box->y2 + src_dy;
10911 + v[8] = v[4] = box->x1 + dst_dx;
10912 + v[10] = v[6] = box->x1 + src_dx;
10913 + v[9] = box->y1 + dst_dy;
10914 + v[11] = box->y1 + src_dy;
10915 + v += 12; box++;
10916 + } while (--n_this_time);
10917 + } while (n);
10919 + gen8_vertex_flush(sna);
10920 + sna_render_composite_redirect_done(sna, &tmp);
10921 + if (tmp.src.bo != src_bo)
10922 + kgem_bo_destroy(&sna->kgem, tmp.src.bo);
10923 + return true;
10925 +fallback_tiled_dst:
10926 + if (tmp.redirect.real_bo)
10927 + kgem_bo_destroy(&sna->kgem, tmp.dst.bo);
10928 +fallback_tiled:
10929 + DBG(("%s: fallback tiled\n", __FUNCTION__));
10930 + if (sna_blt_compare_depth(src, dst) &&
10931 + sna_blt_copy_boxes(sna, alu,
10932 + src_bo, src_dx, src_dy,
10933 + dst_bo, dst_dx, dst_dy,
10934 + dst->bitsPerPixel,
10935 + box, n))
10936 + return true;
10938 + return sna_tiling_copy_boxes(sna, alu,
10939 + src, src_bo, src_dx, src_dy,
10940 + dst, dst_bo, dst_dx, dst_dy,
10941 + box, n);
10942 +}
10944 +static void
10945 +gen9_render_copy_blt(struct sna *sna,
10946 + const struct sna_copy_op *op,
10947 + int16_t sx, int16_t sy,
10948 + int16_t w, int16_t h,
10949 + int16_t dx, int16_t dy)
10950 +{
10951 + int16_t *v;
10953 + gen9_get_rectangles(sna, &op->base, 1, gen9_emit_copy_state);
10955 + v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
10956 + sna->render.vertex_used += 6;
10957 + assert(sna->render.vertex_used <= sna->render.vertex_size);
10959 + v[0] = dx+w; v[1] = dy+h;
10960 + v[2] = sx+w; v[3] = sy+h;
10961 + v[4] = dx; v[5] = dy+h;
10962 + v[6] = sx; v[7] = sy+h;
10963 + v[8] = dx; v[9] = dy;
10964 + v[10] = sx; v[11] = sy;
10965 +}
10967 +static void
10968 +gen9_render_copy_done(struct sna *sna, const struct sna_copy_op *op)
10969 +{
10970 + if (sna->render.vertex_offset)
10971 + gen8_vertex_flush(sna);
10972 +}
10974 +static bool
10975 +gen9_render_copy(struct sna *sna, uint8_t alu,
10976 + PixmapPtr src, struct kgem_bo *src_bo,
10977 + PixmapPtr dst, struct kgem_bo *dst_bo,
10978 + struct sna_copy_op *op)
10979 +{
10980 + DBG(("%s (alu=%d, src=(%dx%d), dst=(%dx%d))\n",
10981 + __FUNCTION__, alu,
10982 + src->drawable.width, src->drawable.height,
10983 + dst->drawable.width, dst->drawable.height));
10985 + if (prefer_blt_copy(sna, src_bo, dst_bo, 0) &&
10986 + sna_blt_compare_depth(&src->drawable, &dst->drawable) &&
10987 + sna_blt_copy(sna, alu,
10988 + src_bo, dst_bo,
10989 + dst->drawable.bitsPerPixel,
10990 + op))
10991 + return true;
10993 + if (!(alu == GXcopy || alu == GXclear) || src_bo == dst_bo ||
10994 + too_large(src->drawable.width, src->drawable.height) ||
10995 + too_large(dst->drawable.width, dst->drawable.height) ||
10996 + unaligned(src_bo, src->drawable.bitsPerPixel) ||
10997 + unaligned(dst_bo, dst->drawable.bitsPerPixel)) {
10998 +fallback:
10999 + if (!sna_blt_compare_depth(&src->drawable, &dst->drawable))
11000 + return false;
11002 + return sna_blt_copy(sna, alu, src_bo, dst_bo,
11003 + dst->drawable.bitsPerPixel,
11004 + op);
11005 + }
11007 + if (dst->drawable.depth == src->drawable.depth) {
11008 + op->base.dst.format = sna_render_format_for_depth(dst->drawable.depth);
11009 + op->base.src.pict_format = op->base.dst.format;
11010 + } else {
11011 + op->base.dst.format = sna_format_for_depth(dst->drawable.depth);
11012 + op->base.src.pict_format = sna_format_for_depth(src->drawable.depth);
11013 + }
11014 + if (!gen9_check_format(op->base.src.pict_format))
11015 + goto fallback;
11017 + op->base.dst.pixmap = dst;
11018 + op->base.dst.width = dst->drawable.width;
11019 + op->base.dst.height = dst->drawable.height;
11020 + op->base.dst.bo = dst_bo;
11022 + op->base.src.bo = src_bo;
11023 + op->base.src.card_format =
11024 + gen9_get_card_format(op->base.src.pict_format);
11025 + op->base.src.width = src->drawable.width;
11026 + op->base.src.height = src->drawable.height;
11028 + op->base.mask.bo = NULL;
11030 + op->base.floats_per_vertex = 2;
11031 + op->base.floats_per_rect = 6;
11033 + op->base.u.gen9.flags = COPY_FLAGS(alu);
11035 + kgem_set_mode(&sna->kgem, KGEM_RENDER, dst_bo);
11036 + if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL)) {
11037 + kgem_submit(&sna->kgem);
11038 + if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL))
11039 + goto fallback;
11040 + _kgem_set_mode(&sna->kgem, KGEM_RENDER);
11041 + }
11043 + gen9_align_vertex(sna, &op->base);
11044 + gen9_emit_copy_state(sna, &op->base);
11046 + op->blt = gen9_render_copy_blt;
11047 + op->done = gen9_render_copy_done;
11048 + return true;
11049 +}
11051 +static void
11052 +gen9_emit_fill_state(struct sna *sna, const struct sna_composite_op *op)
11053 +{
11054 + uint32_t *binding_table;
11055 + uint16_t offset, dirty;
11057 + /* XXX Render Target Fast Clear
11058 + * Set RTFC Enable in PS and render a rectangle.
11059 + * Limited to a clearing the full MSC surface only with a
11060 + * specific kernel.
11061 + */
11063 + gen9_get_batch(sna, op);
11065 + binding_table = gen9_composite_get_binding_table(sna, &offset);
11067 + dirty = kgem_bo_is_dirty(op->dst.bo);
11069 + binding_table[0] =
11070 + gen9_bind_bo(sna,
11071 + op->dst.bo, op->dst.width, op->dst.height,
11072 + gen9_get_dest_format(op->dst.format),
11073 + true);
11074 + binding_table[1] =
11075 + gen9_bind_bo(sna,
11076 + op->src.bo, 1, 1,
11077 + SURFACEFORMAT_B8G8R8A8_UNORM,
11078 + false);
11080 + if (sna->kgem.surface == offset &&
11081 + *(uint64_t *)(sna->kgem.batch + sna->render_state.gen9.surface_table) == *(uint64_t*)binding_table) {
11082 + sna->kgem.surface += SURFACE_DW;
11083 + offset = sna->render_state.gen9.surface_table;
11084 + }
11086 + if (sna->kgem.batch[sna->render_state.gen9.surface_table] == binding_table[0])
11087 + dirty = 0;
11089 + gen9_emit_state(sna, op, offset | dirty);
11090 +}
11092 +static bool
11093 +gen9_render_fill_boxes(struct sna *sna,
11094 + CARD8 op,
11095 + PictFormat format,
11096 + const xRenderColor *color,
11097 + const DrawableRec *dst, struct kgem_bo *dst_bo,
11098 + const BoxRec *box, int n)
11099 +{
11100 + struct sna_composite_op tmp;
11101 + uint32_t pixel;
11103 + DBG(("%s (op=%d, color=(%04x, %04x, %04x, %04x) [%08x])\n",
11104 + __FUNCTION__, op,
11105 + color->red, color->green, color->blue, color->alpha, (int)format));
11107 + if (op >= ARRAY_SIZE(gen9_blend_op)) {
11108 + DBG(("%s: fallback due to unhandled blend op: %d\n",
11109 + __FUNCTION__, op));
11110 + return false;
11111 + }
11113 + if (prefer_blt_fill(sna, dst_bo, FILL_BOXES) ||
11114 + !gen9_check_dst_format(format) ||
11115 + unaligned(dst_bo, PICT_FORMAT_BPP(format))) {
11116 + uint8_t alu = GXinvalid;
11118 + if (op <= PictOpSrc) {
11119 + pixel = 0;
11120 + if (op == PictOpClear)
11121 + alu = GXclear;
11122 + else if (sna_get_pixel_from_rgba(&pixel,
11123 + color->red,
11124 + color->green,
11125 + color->blue,
11126 + color->alpha,
11127 + format))
11128 + alu = GXcopy;
11129 + }
11131 + if (alu != GXinvalid &&
11132 + sna_blt_fill_boxes(sna, alu,
11133 + dst_bo, dst->bitsPerPixel,
11134 + pixel, box, n))
11135 + return true;
11137 + if (!gen9_check_dst_format(format))
11138 + return false;
11139 + }
11141 + if (op == PictOpClear) {
11142 + pixel = 0;
11143 + op = PictOpSrc;
11144 + } else if (!sna_get_pixel_from_rgba(&pixel,
11145 + color->red,
11146 + color->green,
11147 + color->blue,
11148 + color->alpha,
11149 + PICT_a8r8g8b8))
11150 + return false;
11152 + DBG(("%s(%08x x %d [(%d, %d), (%d, %d) ...])\n",
11153 + __FUNCTION__, pixel, n,
11154 + box[0].x1, box[0].y1, box[0].x2, box[0].y2));
11156 + tmp.dst.pixmap = (PixmapPtr)dst;
11157 + tmp.dst.width = dst->width;
11158 + tmp.dst.height = dst->height;
11159 + tmp.dst.format = format;
11160 + tmp.dst.bo = dst_bo;
11161 + tmp.dst.x = tmp.dst.y = 0;
11162 + tmp.damage = NULL;
11164 + sna_render_composite_redirect_init(&tmp);
11165 + if (too_large(dst->width, dst->height)) {
11166 + BoxRec extents;
11168 + boxes_extents(box, n, &extents);
11169 + if (!sna_render_composite_redirect(sna, &tmp,
11170 + extents.x1, extents.y1,
11171 + extents.x2 - extents.x1,
11172 + extents.y2 - extents.y1,
11173 + n > 1))
11174 + return sna_tiling_fill_boxes(sna, op, format, color,
11175 + dst, dst_bo, box, n);
11176 + }
11178 + tmp.src.bo = sna_render_get_solid(sna, pixel);
11179 + tmp.mask.bo = NULL;
11181 + tmp.floats_per_vertex = 2;
11182 + tmp.floats_per_rect = 6;
11183 + tmp.need_magic_ca_pass = false;
11185 + tmp.u.gen9.flags = FILL_FLAGS(op, format);
11187 + kgem_set_mode(&sna->kgem, KGEM_RENDER, dst_bo);
11188 + if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
11189 + kgem_submit(&sna->kgem);
11190 + if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
11191 + kgem_bo_destroy(&sna->kgem, tmp.src.bo);
11192 + tmp.src.bo = NULL;
11194 + if (tmp.redirect.real_bo) {
11195 + kgem_bo_destroy(&sna->kgem, tmp.dst.bo);
11196 + tmp.redirect.real_bo = NULL;
11197 + }
11199 + return false;
11200 + }
11201 + _kgem_set_mode(&sna->kgem, KGEM_RENDER);
11202 + }
11204 + gen9_align_vertex(sna, &tmp);
11205 + gen9_emit_fill_state(sna, &tmp);
11207 + do {
11208 + int n_this_time;
11209 + int16_t *v;
11211 + n_this_time = gen9_get_rectangles(sna, &tmp, n,
11212 + gen9_emit_fill_state);
11213 + n -= n_this_time;
11215 + v = (int16_t *)(sna->render.vertices + sna->render.vertex_used);
11216 + sna->render.vertex_used += 6 * n_this_time;
11217 + assert(sna->render.vertex_used <= sna->render.vertex_size);
11218 + do {
11219 + DBG((" (%d, %d), (%d, %d)\n",
11220 + box->x1, box->y1, box->x2, box->y2));
11222 + v[0] = box->x2;
11223 + v[5] = v[1] = box->y2;
11224 + v[8] = v[4] = box->x1;
11225 + v[9] = box->y1;
11226 + v[2] = v[3] = v[7] = 1;
11227 + v[6] = v[10] = v[11] = 0;
11228 + v += 12; box++;
11229 + } while (--n_this_time);
11230 + } while (n);
11232 + gen8_vertex_flush(sna);
11233 + kgem_bo_destroy(&sna->kgem, tmp.src.bo);
11234 + sna_render_composite_redirect_done(sna, &tmp);
11235 + return true;
11236 +}
11238 +static void
11239 +gen9_render_fill_op_blt(struct sna *sna,
11240 + const struct sna_fill_op *op,
11241 + int16_t x, int16_t y, int16_t w, int16_t h)
11242 +{
11243 + int16_t *v;
11245 + DBG(("%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
11247 + gen9_get_rectangles(sna, &op->base, 1, gen9_emit_fill_state);
11249 + v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
11250 + sna->render.vertex_used += 6;
11251 + assert(sna->render.vertex_used <= sna->render.vertex_size);
11253 + v[0] = x+w;
11254 + v[4] = v[8] = x;
11255 + v[1] = v[5] = y+h;
11256 + v[9] = y;
11258 + v[2] = v[3] = v[7] = 1;
11259 + v[6] = v[10] = v[11] = 0;
11260 +}
11262 +fastcall static void
11263 +gen9_render_fill_op_box(struct sna *sna,
11264 + const struct sna_fill_op *op,
11265 + const BoxRec *box)
11266 +{
11267 + int16_t *v;
11269 + DBG(("%s: (%d, %d),(%d, %d)\n", __FUNCTION__,
11270 + box->x1, box->y1, box->x2, box->y2));
11272 + gen9_get_rectangles(sna, &op->base, 1, gen9_emit_fill_state);
11274 + v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
11275 + sna->render.vertex_used += 6;
11276 + assert(sna->render.vertex_used <= sna->render.vertex_size);
11278 + v[0] = box->x2;
11279 + v[8] = v[4] = box->x1;
11280 + v[5] = v[1] = box->y2;
11281 + v[9] = box->y1;
11283 + v[7] = v[2] = v[3] = 1;
11284 + v[6] = v[10] = v[11] = 0;
11285 +}
11287 +fastcall static void
11288 +gen9_render_fill_op_boxes(struct sna *sna,
11289 + const struct sna_fill_op *op,
11290 + const BoxRec *box,
11291 + int nbox)
11292 +{
11293 + DBG(("%s: (%d, %d),(%d, %d)... x %d\n", __FUNCTION__,
11294 + box->x1, box->y1, box->x2, box->y2, nbox));
11296 + do {
11297 + int nbox_this_time;
11298 + int16_t *v;
11300 + nbox_this_time = gen9_get_rectangles(sna, &op->base, nbox,
11301 + gen9_emit_fill_state);
11302 + nbox -= nbox_this_time;
11304 + v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
11305 + sna->render.vertex_used += 6 * nbox_this_time;
11306 + assert(sna->render.vertex_used <= sna->render.vertex_size);
11308 + do {
11309 + v[0] = box->x2;
11310 + v[8] = v[4] = box->x1;
11311 + v[5] = v[1] = box->y2;
11312 + v[9] = box->y1;
11313 + v[7] = v[2] = v[3] = 1;
11314 + v[6] = v[10] = v[11] = 0;
11315 + box++; v += 12;
11316 + } while (--nbox_this_time);
11317 + } while (nbox);
11318 +}
11320 +static void
11321 +gen9_render_fill_op_done(struct sna *sna, const struct sna_fill_op *op)
11322 +{
11323 + if (sna->render.vertex_offset)
11324 + gen8_vertex_flush(sna);
11325 + kgem_bo_destroy(&sna->kgem, op->base.src.bo);
11326 +}
11328 +static bool
11329 +gen9_render_fill(struct sna *sna, uint8_t alu,
11330 + PixmapPtr dst, struct kgem_bo *dst_bo,
11331 + uint32_t color, unsigned flags,
11332 + struct sna_fill_op *op)
11333 +{
11334 + DBG(("%s: (alu=%d, color=%x)\n", __FUNCTION__, alu, color));
11336 + if (prefer_blt_fill(sna, dst_bo, flags) &&
11337 + sna_blt_fill(sna, alu,
11338 + dst_bo, dst->drawable.bitsPerPixel,
11339 + color,
11340 + op))
11341 + return true;
11343 + if (!(alu == GXcopy || alu == GXclear) ||
11344 + too_large(dst->drawable.width, dst->drawable.height) ||
11345 + unaligned(dst_bo, dst->drawable.bitsPerPixel))
11346 + return sna_blt_fill(sna, alu,
11347 + dst_bo, dst->drawable.bitsPerPixel,
11348 + color,
11349 + op);
11351 + if (alu == GXclear)
11352 + color = 0;
11354 + op->base.dst.pixmap = dst;
11355 + op->base.dst.width = dst->drawable.width;
11356 + op->base.dst.height = dst->drawable.height;
11357 + op->base.dst.format = sna_format_for_depth(dst->drawable.depth);
11358 + op->base.dst.bo = dst_bo;
11359 + op->base.dst.x = op->base.dst.y = 0;
11361 + op->base.src.bo =
11362 + sna_render_get_solid(sna,
11363 + sna_rgba_for_color(color,
11364 + dst->drawable.depth));
11365 + op->base.mask.bo = NULL;
11367 + op->base.need_magic_ca_pass = false;
11368 + op->base.floats_per_vertex = 2;
11369 + op->base.floats_per_rect = 6;
11371 + op->base.u.gen9.flags = FILL_FLAGS_NOBLEND;
11373 + kgem_set_mode(&sna->kgem, KGEM_RENDER, dst_bo);
11374 + if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
11375 + kgem_submit(&sna->kgem);
11376 + if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
11377 + kgem_bo_destroy(&sna->kgem, op->base.src.bo);
11378 + return false;
11379 + }
11381 + _kgem_set_mode(&sna->kgem, KGEM_RENDER);
11382 + }
11384 + gen9_align_vertex(sna, &op->base);
11385 + gen9_emit_fill_state(sna, &op->base);
11387 + op->blt = gen9_render_fill_op_blt;
11388 + op->box = gen9_render_fill_op_box;
11389 + op->boxes = gen9_render_fill_op_boxes;
11390 + op->points = NULL;
11391 + op->done = gen9_render_fill_op_done;
11392 + return true;
11393 +}
11395 +static bool
11396 +gen9_render_fill_one_try_blt(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
11397 + uint32_t color,
11398 + int16_t x1, int16_t y1, int16_t x2, int16_t y2,
11399 + uint8_t alu)
11400 +{
11401 + BoxRec box;
11403 + box.x1 = x1;
11404 + box.y1 = y1;
11405 + box.x2 = x2;
11406 + box.y2 = y2;
11408 + return sna_blt_fill_boxes(sna, alu,
11409 + bo, dst->drawable.bitsPerPixel,
11410 + color, &box, 1);
11411 +}
11413 +static bool
11414 +gen9_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
11415 + uint32_t color,
11416 + int16_t x1, int16_t y1,
11417 + int16_t x2, int16_t y2,
11418 + uint8_t alu)
11419 +{
11420 + struct sna_composite_op tmp;
11421 + int16_t *v;
11423 + /* Prefer to use the BLT if already engaged */
11424 + if (prefer_blt_fill(sna, bo, FILL_BOXES) &&
11425 + gen9_render_fill_one_try_blt(sna, dst, bo, color,
11426 + x1, y1, x2, y2, alu))
11427 + return true;
11429 + /* Must use the BLT if we can't RENDER... */
11430 + if (!(alu == GXcopy || alu == GXclear) ||
11431 + too_large(dst->drawable.width, dst->drawable.height) ||
11432 + unaligned(bo, dst->drawable.bitsPerPixel))
11433 + return gen9_render_fill_one_try_blt(sna, dst, bo, color,
11434 + x1, y1, x2, y2, alu);
11436 + if (alu == GXclear)
11437 + color = 0;
11439 + tmp.dst.pixmap = dst;
11440 + tmp.dst.width = dst->drawable.width;
11441 + tmp.dst.height = dst->drawable.height;
11442 + tmp.dst.format = sna_format_for_depth(dst->drawable.depth);
11443 + tmp.dst.bo = bo;
11444 + tmp.dst.x = tmp.dst.y = 0;
11446 + tmp.src.bo =
11447 + sna_render_get_solid(sna,
11448 + sna_rgba_for_color(color,
11449 + dst->drawable.depth));
11450 + tmp.mask.bo = NULL;
11452 + tmp.floats_per_vertex = 2;
11453 + tmp.floats_per_rect = 6;
11454 + tmp.need_magic_ca_pass = false;
11456 + tmp.u.gen9.flags = FILL_FLAGS_NOBLEND;
11458 + kgem_set_mode(&sna->kgem, KGEM_RENDER, bo);
11459 + if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
11460 + kgem_submit(&sna->kgem);
11461 + if (kgem_check_bo(&sna->kgem, bo, NULL)) {
11462 + kgem_bo_destroy(&sna->kgem, tmp.src.bo);
11463 + return false;
11464 + }
11465 + _kgem_set_mode(&sna->kgem, KGEM_RENDER);
11466 + }
11468 + gen9_align_vertex(sna, &tmp);
11469 + gen9_emit_fill_state(sna, &tmp);
11471 + gen9_get_rectangles(sna, &tmp, 1, gen9_emit_fill_state);
11473 + DBG((" (%d, %d), (%d, %d)\n", x1, y1, x2, y2));
11475 + v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
11476 + sna->render.vertex_used += 6;
11477 + assert(sna->render.vertex_used <= sna->render.vertex_size);
11479 + v[0] = x2;
11480 + v[8] = v[4] = x1;
11481 + v[5] = v[1] = y2;
11482 + v[9] = y1;
11483 + v[7] = v[2] = v[3] = 1;
11484 + v[6] = v[10] = v[11] = 0;
11486 + gen8_vertex_flush(sna);
11487 + kgem_bo_destroy(&sna->kgem, tmp.src.bo);
11489 + return true;
11490 +}
11492 +static bool
11493 +gen9_render_clear_try_blt(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
11494 +{
11495 + BoxRec box;
11497 + box.x1 = 0;
11498 + box.y1 = 0;
11499 + box.x2 = dst->drawable.width;
11500 + box.y2 = dst->drawable.height;
11502 + return sna_blt_fill_boxes(sna, GXclear,
11503 + bo, dst->drawable.bitsPerPixel,
11504 + 0, &box, 1);
11505 +}
11507 +static bool
11508 +gen9_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
11509 +{
11510 + struct sna_composite_op tmp;
11511 + int16_t *v;
11513 + DBG(("%s: %dx%d\n",
11514 + __FUNCTION__,
11515 + dst->drawable.width,
11516 + dst->drawable.height));
11518 + /* Prefer to use the BLT if already engaged */
11519 + if (sna->kgem.mode == KGEM_BLT &&
11520 + gen9_render_clear_try_blt(sna, dst, bo))
11521 + return true;
11523 + /* Must use the BLT if we can't RENDER... */
11524 + if (too_large(dst->drawable.width, dst->drawable.height) ||
11525 + unaligned(bo, dst->drawable.bitsPerPixel))
11526 + return gen9_render_clear_try_blt(sna, dst, bo);
11528 + tmp.dst.pixmap = dst;
11529 + tmp.dst.width = dst->drawable.width;
11530 + tmp.dst.height = dst->drawable.height;
11531 + tmp.dst.format = sna_format_for_depth(dst->drawable.depth);
11532 + tmp.dst.bo = bo;
11533 + tmp.dst.x = tmp.dst.y = 0;
11535 + tmp.src.bo = sna_render_get_solid(sna, 0);
11536 + tmp.mask.bo = NULL;
11538 + tmp.floats_per_vertex = 2;
11539 + tmp.floats_per_rect = 6;
11540 + tmp.need_magic_ca_pass = false;
11542 + tmp.u.gen9.flags = FILL_FLAGS_NOBLEND;
11544 + kgem_set_mode(&sna->kgem, KGEM_RENDER, bo);
11545 + if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
11546 + kgem_submit(&sna->kgem);
11547 + if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
11548 + kgem_bo_destroy(&sna->kgem, tmp.src.bo);
11549 + return false;
11550 + }
11551 + _kgem_set_mode(&sna->kgem, KGEM_RENDER);
11552 + }
11554 + gen9_align_vertex(sna, &tmp);
11555 + gen9_emit_fill_state(sna, &tmp);
11557 + gen9_get_rectangles(sna, &tmp, 1, gen9_emit_fill_state);
11559 + v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
11560 + sna->render.vertex_used += 6;
11561 + assert(sna->render.vertex_used <= sna->render.vertex_size);
11563 + v[0] = dst->drawable.width;
11564 + v[5] = v[1] = dst->drawable.height;
11565 + v[8] = v[4] = 0;
11566 + v[9] = 0;
11568 + v[7] = v[2] = v[3] = 1;
11569 + v[6] = v[10] = v[11] = 0;
11571 + gen8_vertex_flush(sna);
11572 + kgem_bo_destroy(&sna->kgem, tmp.src.bo);
11574 + return true;
11575 +}
11577 +#if !NO_VIDEO
11578 +static uint32_t gen9_bind_video_source(struct sna *sna,
11579 + struct kgem_bo *bo,
11580 + uint32_t delta,
11581 + int width,
11582 + int height,
11583 + int pitch,
11584 + uint32_t format)
11585 +{
11586 + uint32_t *ss;
11587 + int offset;
11589 + offset = sna->kgem.surface -= SURFACE_DW;
11590 + ss = sna->kgem.batch + offset;
11591 + ss[0] = (SURFACE_2D << SURFACE_TYPE_SHIFT |
11592 + gen9_tiling_bits(bo->tiling) |
11593 + format << SURFACE_FORMAT_SHIFT |
11594 + SURFACE_VALIGN_4 | SURFACE_HALIGN_4);
11595 + ss[1] = 0;
11596 + ss[2] = ((width - 1) << SURFACE_WIDTH_SHIFT |
11597 + (height - 1) << SURFACE_HEIGHT_SHIFT);
11598 + ss[3] = (pitch - 1) << SURFACE_PITCH_SHIFT;
11599 + ss[4] = 0;
11600 + ss[5] = 0;
11601 + ss[6] = 0;
11602 + ss[7] = SURFACE_SWIZZLE(RED, GREEN, BLUE, ALPHA);
11603 + *(uint64_t *)(ss+8) =
11604 + kgem_add_reloc64(&sna->kgem, offset + 8, bo,
11605 + I915_GEM_DOMAIN_SAMPLER << 16,
11606 + delta);
11607 + ss[10] = 0;
11608 + ss[11] = 0;
11609 + ss[12] = 0;
11610 + ss[13] = 0;
11611 + ss[14] = 0;
11612 + ss[15] = 0;
11614 + DBG(("[%x] bind bo(handle=%d, addr=%d), format=%d, width=%d, height=%d, pitch=%d, tiling=%d -> sampler\n",
11615 + offset, bo->handle, ss[1],
11616 + format, width, height, bo->pitch, bo->tiling));
11618 + return offset * sizeof(uint32_t);
11619 +}
11621 +static void gen9_emit_video_state(struct sna *sna,
11622 + const struct sna_composite_op *op)
11623 +{
11624 + struct sna_video_frame *frame = op->priv;
11625 + uint32_t src_surf_format;
11626 + uint32_t src_surf_base[6];
11627 + int src_width[6];
11628 + int src_height[6];
11629 + int src_pitch[6];
11630 + uint32_t *binding_table;
11631 + uint16_t offset;
11632 + int n_src, n;
11634 + /* XXX VeBox, bicubic */
11636 + gen9_get_batch(sna, op);
11638 + src_surf_base[0] = 0;
11639 + src_surf_base[1] = 0;
11640 + src_surf_base[2] = frame->VBufOffset;
11641 + src_surf_base[3] = frame->VBufOffset;
11642 + src_surf_base[4] = frame->UBufOffset;
11643 + src_surf_base[5] = frame->UBufOffset;
11645 + if (is_planar_fourcc(frame->id)) {
11646 + src_surf_format = SURFACEFORMAT_R8_UNORM;
11647 + src_width[1] = src_width[0] = frame->width;
11648 + src_height[1] = src_height[0] = frame->height;
11649 + src_pitch[1] = src_pitch[0] = frame->pitch[1];
11650 + src_width[4] = src_width[5] = src_width[2] = src_width[3] =
11651 + frame->width / 2;
11652 + src_height[4] = src_height[5] = src_height[2] = src_height[3] =
11653 + frame->height / 2;
11654 + src_pitch[4] = src_pitch[5] = src_pitch[2] = src_pitch[3] =
11655 + frame->pitch[0];
11656 + n_src = 6;
11657 + } else {
11658 + if (frame->id == FOURCC_RGB888)
11659 + src_surf_format = SURFACEFORMAT_B8G8R8X8_UNORM;
11660 + else if (frame->id == FOURCC_UYVY)
11661 + src_surf_format = SURFACEFORMAT_YCRCB_SWAPY;
11662 + else
11663 + src_surf_format = SURFACEFORMAT_YCRCB_NORMAL;
11665 + src_width[0] = frame->width;
11666 + src_height[0] = frame->height;
11667 + src_pitch[0] = frame->pitch[0];
11668 + n_src = 1;
11669 + }
11671 + binding_table = gen9_composite_get_binding_table(sna, &offset);
11673 + binding_table[0] =
11674 + gen9_bind_bo(sna,
11675 + op->dst.bo, op->dst.width, op->dst.height,
11676 + gen9_get_dest_format(op->dst.format),
11677 + true);
11678 + for (n = 0; n < n_src; n++) {
11679 + binding_table[1+n] =
11680 + gen9_bind_video_source(sna,
11681 + frame->bo,
11682 + src_surf_base[n],
11683 + src_width[n],
11684 + src_height[n],
11685 + src_pitch[n],
11686 + src_surf_format);
11687 + }
11689 + gen9_emit_state(sna, op, offset);
11690 +}
11692 +static unsigned select_video_kernel(const struct sna_video_frame *frame)
11693 +{
11694 + switch (frame->id) {
11695 + case FOURCC_YV12:
11696 + case FOURCC_I420:
11697 + case FOURCC_XVMC:
11698 + return GEN9_WM_KERNEL_VIDEO_PLANAR;
11700 + case FOURCC_RGB888:
11701 + case FOURCC_RGB565:
11702 + return GEN9_WM_KERNEL_VIDEO_RGB;
11704 + default:
11705 + return GEN9_WM_KERNEL_VIDEO_PACKED;
11706 + }
11707 +}
11709 +static bool
11710 +gen9_render_video(struct sna *sna,
11711 + struct sna_video *video,
11712 + struct sna_video_frame *frame,
11713 + RegionPtr dstRegion,
11714 + PixmapPtr pixmap)
11715 +{
11716 + struct sna_composite_op tmp;
11717 + struct sna_pixmap *priv = sna_pixmap(pixmap);
11718 + int dst_width = dstRegion->extents.x2 - dstRegion->extents.x1;
11719 + int dst_height = dstRegion->extents.y2 - dstRegion->extents.y1;
11720 + int src_width = frame->src.x2 - frame->src.x1;
11721 + int src_height = frame->src.y2 - frame->src.y1;
11722 + float src_offset_x, src_offset_y;
11723 + float src_scale_x, src_scale_y;
11724 + unsigned filter;
11725 + const BoxRec *box;
11726 + int nbox;
11728 + DBG(("%s: src=(%d, %d), dst=(%d, %d), %dx[(%d, %d), (%d, %d)...]\n",
11729 + __FUNCTION__,
11730 + src_width, src_height, dst_width, dst_height,
11731 + region_num_rects(dstRegion),
11732 + REGION_EXTENTS(NULL, dstRegion)->x1,
11733 + REGION_EXTENTS(NULL, dstRegion)->y1,
11734 + REGION_EXTENTS(NULL, dstRegion)->x2,
11735 + REGION_EXTENTS(NULL, dstRegion)->y2));
11737 + assert(priv->gpu_bo);
11738 + assert(!too_large(pixmap->drawable.width, pixmap->drawable.height));
11739 + assert(!unaligned(priv->gpu_bo, pixmap->drawable.bitsPerPixel));
11741 + memset(&tmp, 0, sizeof(tmp));
11743 + tmp.dst.pixmap = pixmap;
11744 + tmp.dst.width = pixmap->drawable.width;
11745 + tmp.dst.height = pixmap->drawable.height;
11746 + tmp.dst.format = sna_render_format_for_depth(pixmap->drawable.depth);
11747 + tmp.dst.bo = priv->gpu_bo;
11749 + tmp.src.bo = frame->bo;
11750 + tmp.mask.bo = NULL;
11752 + tmp.floats_per_vertex = 3;
11753 + tmp.floats_per_rect = 9;
11755 + DBG(("%s: scaling?=%d, planar?=%d [%x]\n",
11756 + __FUNCTION__,
11757 + src_width != dst_width || src_height != dst_height,
11758 + is_planar_fourcc(frame->id), frame->id));
11760 + if (src_width == dst_width && src_height == dst_height)
11761 + filter = SAMPLER_FILTER_NEAREST;
11762 + else
11763 + filter = SAMPLER_FILTER_BILINEAR;
11765 + tmp.u.gen9.flags =
11766 + GEN9_SET_FLAGS(SAMPLER_OFFSET(filter, SAMPLER_EXTEND_PAD,
11767 + SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE),
11768 + NO_BLEND,
11769 + select_video_kernel(frame),
11770 + 2);
11771 + tmp.priv = frame;
11773 + kgem_set_mode(&sna->kgem, KGEM_RENDER, tmp.dst.bo);
11774 + if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, frame->bo, NULL)) {
11775 + kgem_submit(&sna->kgem);
11776 + if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, frame->bo, NULL))
11777 + return false;
11779 + _kgem_set_mode(&sna->kgem, KGEM_RENDER);
11780 + }
11782 + gen9_align_vertex(sna, &tmp);
11783 + gen9_emit_video_state(sna, &tmp);
11785 + DBG(("%s: src=(%d, %d)x(%d, %d); frame=(%dx%d), dst=(%dx%d)\n",
11786 + __FUNCTION__,
11787 + frame->src.x1, frame->src.y1,
11788 + src_width, src_height,
11789 + dst_width, dst_height,
11790 + frame->width, frame->height));
11792 + src_scale_x = (float)src_width / dst_width / frame->width;
11793 + src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
11795 + src_scale_y = (float)src_height / dst_height / frame->height;
11796 + src_offset_y = (float)frame->src.y1 / frame->height - dstRegion->extents.y1 * src_scale_y;
11798 + DBG(("%s: scale=(%f, %f), offset=(%f, %f)\n",
11799 + __FUNCTION__,
11800 + src_scale_x, src_scale_y,
11801 + src_offset_x, src_offset_y));
11803 + box = region_rects(dstRegion);
11804 + nbox = region_num_rects(dstRegion);
11805 + while (nbox--) {
11806 + DBG(("%s: dst=(%d, %d), (%d, %d) + (%d, %d); src=(%f, %f), (%f, %f)\n",
11807 + __FUNCTION__,
11808 + box->x1, box->y1,
11809 + box->x2, box->y2,
11810 + box->x1 * src_scale_x + src_offset_x,
11811 + box->y1 * src_scale_y + src_offset_y,
11812 + box->x2 * src_scale_x + src_offset_x,
11813 + box->y2 * src_scale_y + src_offset_y));
11815 + gen9_get_rectangles(sna, &tmp, 1, gen9_emit_video_state);
11817 + OUT_VERTEX(box->x2, box->y2);
11818 + OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
11819 + OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
11821 + OUT_VERTEX(box->x1, box->y2);
11822 + OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
11823 + OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
11825 + OUT_VERTEX(box->x1, box->y1);
11826 + OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
11827 + OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
11829 + box++;
11830 + }
11831 + gen8_vertex_flush(sna);
11833 + if (!DAMAGE_IS_ALL(priv->gpu_damage))
11834 + sna_damage_add(&priv->gpu_damage, dstRegion);
11836 + return true;
11837 +}
11838 +#endif
11840 +static void gen9_render_flush(struct sna *sna)
11841 +{
11842 + gen8_vertex_close(sna);
11844 + assert(sna->render.vb_id == 0);
11845 + assert(sna->render.vertex_offset == 0);
11846 +}
11848 +static void gen9_render_reset(struct sna *sna)
11849 +{
11850 + sna->render_state.gen9.emit_flush = false;
11851 + sna->render_state.gen9.needs_invariant = true;
11852 + sna->render_state.gen9.ve_id = 3 << 2;
11853 + sna->render_state.gen9.ve_dirty = false;
11854 + sna->render_state.gen9.last_primitive = -1;
11856 + sna->render_state.gen9.num_sf_outputs = 0;
11857 + sna->render_state.gen9.samplers = -1;
11858 + sna->render_state.gen9.blend = -1;
11859 + sna->render_state.gen9.kernel = -1;
11860 + sna->render_state.gen9.drawrect_offset = -1;
11861 + sna->render_state.gen9.drawrect_limit = -1;
11862 + sna->render_state.gen9.surface_table = 0;
11864 + if (sna->render.vbo && !kgem_bo_can_map(&sna->kgem, sna->render.vbo)) {
11865 + DBG(("%s: discarding unmappable vbo\n", __FUNCTION__));
11866 + discard_vbo(sna);
11867 + }
11869 + sna->render.vertex_offset = 0;
11870 + sna->render.nvertex_reloc = 0;
11871 + sna->render.vb_id = 0;
11872 +}
11874 +static void gen9_render_fini(struct sna *sna)
11875 +{
11876 + kgem_bo_destroy(&sna->kgem, sna->render_state.gen9.general_bo);
11877 +}
11879 +static bool gen9_render_setup(struct sna *sna)
11880 +{
11881 + struct gen9_render_state *state = &sna->render_state.gen9;
11882 + struct sna_static_stream general;
11883 + struct gen9_sampler_state *ss;
11884 + int i, j, k, l, m;
11885 + uint32_t devid;
11887 + devid = intel_get_device_id(sna->dev);
11888 + if (devid & 0xf)
11889 + state->gt = GEN9_GT_BIAS + ((devid >> 4) & 0xf) + 1;
11890 + DBG(("%s: gt=%d\n", __FUNCTION__, state->gt));
11892 + state->info = &min_gt_info;
11893 + if (is_skl(sna))
11894 + state->info = &skl_gt_info;
11895 + if (is_bxt(sna))
11896 + state->info = &bxt_gt_info;
11897 + if (is_kbl(sna))
11898 + state->info = &kbl_gt_info;
11899 + if (is_glk(sna))
11900 + state->info = &glk_gt_info;
11902 + sna_static_stream_init(&general);
11904 + /* Zero pad the start. If you see an offset of 0x0 in the batchbuffer
11905 + * dumps, you know it points to zero.
11906 + */
11907 + null_create(&general);
11909 + for (m = 0; m < ARRAY_SIZE(wm_kernels); m++) {
11910 + if (wm_kernels[m].size) {
11911 + state->wm_kernel[m][1] =
11912 + sna_static_stream_add(&general,
11913 + wm_kernels[m].data,
11914 + wm_kernels[m].size,
11915 + 64);
11916 + } else {
11917 + if (USE_8_PIXEL_DISPATCH) {
11918 + state->wm_kernel[m][0] =
11919 + sna_static_stream_compile_wm(sna, &general,
11920 + wm_kernels[m].data, 8);
11921 + }
11923 + if (USE_16_PIXEL_DISPATCH) {
11924 + state->wm_kernel[m][1] =
11925 + sna_static_stream_compile_wm(sna, &general,
11926 + wm_kernels[m].data, 16);
11927 + }
11929 + if (USE_32_PIXEL_DISPATCH) {
11930 + state->wm_kernel[m][2] =
11931 + sna_static_stream_compile_wm(sna, &general,
11932 + wm_kernels[m].data, 32);
11933 + }
11934 + }
11935 + assert(state->wm_kernel[m][0]|state->wm_kernel[m][1]|state->wm_kernel[m][2]);
11936 + }
11938 + COMPILE_TIME_ASSERT(SAMPLER_OFFSET(FILTER_COUNT, EXTEND_COUNT, FILTER_COUNT, EXTEND_COUNT) <= 0x7ff);
11939 + ss = sna_static_stream_map(&general,
11940 + 2 * sizeof(*ss) *
11941 + (2 +
11942 + FILTER_COUNT * EXTEND_COUNT *
11943 + FILTER_COUNT * EXTEND_COUNT),
11944 + 32);
11945 + state->wm_state = sna_static_stream_offsetof(&general, ss);
11946 + sampler_copy_init(ss); ss += 2;
11947 + sampler_fill_init(ss); ss += 2;
11948 + for (i = 0; i < FILTER_COUNT; i++) {
11949 + for (j = 0; j < EXTEND_COUNT; j++) {
11950 + for (k = 0; k < FILTER_COUNT; k++) {
11951 + for (l = 0; l < EXTEND_COUNT; l++) {
11952 + sampler_state_init(ss++, i, j);
11953 + sampler_state_init(ss++, k, l);
11954 + }
11955 + }
11956 + }
11957 + }
11959 + state->cc_blend = gen9_create_blend_state(&general);
11961 + state->general_bo = sna_static_stream_fini(sna, &general);
11962 + return state->general_bo != NULL;
11963 +}
11965 +const char *gen9_render_init(struct sna *sna, const char *backend)
11966 +{
11967 + if (!gen9_render_setup(sna))
11968 + return backend;
11970 + sna->kgem.context_switch = gen6_render_context_switch;
11971 + sna->kgem.retire = gen6_render_retire;
11972 + sna->kgem.expire = gen4_render_expire;
11974 +#if !NO_COMPOSITE
11975 + sna->render.composite = gen9_render_composite;
11976 + sna->render.prefer_gpu |= PREFER_GPU_RENDER;
11977 +#endif
11978 +#if !NO_COMPOSITE_SPANS
11979 + sna->render.check_composite_spans = gen9_check_composite_spans;
11980 + sna->render.composite_spans = gen9_render_composite_spans;
11981 + sna->render.prefer_gpu |= PREFER_GPU_SPANS;
11982 +#endif
11983 +#if !NO_VIDEO
11984 + sna->render.video = gen9_render_video;
11985 +#endif
11987 +#if !NO_COPY_BOXES
11988 + sna->render.copy_boxes = gen9_render_copy_boxes;
11989 +#endif
11990 +#if !NO_COPY
11991 + sna->render.copy = gen9_render_copy;
11992 +#endif
11994 +#if !NO_FILL_BOXES
11995 + sna->render.fill_boxes = gen9_render_fill_boxes;
11996 +#endif
11997 +#if !NO_FILL
11998 + sna->render.fill = gen9_render_fill;
11999 +#endif
12000 +#if !NO_FILL_ONE
12001 + sna->render.fill_one = gen9_render_fill_one;
12002 +#endif
12003 +#if !NO_FILL_CLEAR
12004 + sna->render.clear = gen9_render_clear;
12005 +#endif
12007 + sna->render.flush = gen9_render_flush;
12008 + sna->render.reset = gen9_render_reset;
12009 + sna->render.fini = gen9_render_fini;
12011 + sna->render.max_3d_size = GEN9_MAX_SIZE;
12012 + sna->render.max_3d_pitch = 1 << 18;
12013 + return sna->render_state.gen9.info->name;
12014 +}
12015 diff --git a/src/sna/gen9_render.h b/src/sna/gen9_render.h
12016 new file mode 100644
12017 index 00000000..e3cb3f93
12018 --- /dev/null
12019 +++ b/src/sna/gen9_render.h
12020 @@ -0,0 +1,1130 @@
12021 +#ifndef GEN9_RENDER_H
12022 +#define GEN9_RENDER_H
12024 +#define INTEL_MASK(high, low) (((1 << ((high) - (low) + 1)) - 1) << (low))
12026 +#define GEN9_3D(pipeline,op,sub) \
12027 + ((3 << 29) | ((pipeline) << 27) | ((op) << 24) | ((sub) << 16))
12029 +#define GEN9_STATE_BASE_ADDRESS GEN9_3D(0, 1, 1)
12030 +# define BASE_ADDRESS_MODIFY (1 << 0)
12032 +#define GEN9_STATE_SIP GEN9_3D(0, 1, 2)
12034 +#define GEN9_3DSTATE_VF_STATISTICS GEN9_3D(1, 0, 0xb)
12035 +#define GEN9_PIPELINE_SELECT GEN9_3D(1, 1, 4)
12036 +# define PIPELINE_SELECT_3D 0
12037 +# define PIPELINE_SELECT_MEDIA 1
12038 +#define PIPELINE_SELECTION_MASK (3 << 8)
12040 +#define GEN9_MEDIA_STATE_POINTERS GEN9_3D(2, 0, 0)
12041 +#define GEN9_MEDIA_OBJECT GEN9_3D(2, 1, 0)
12043 +#define GEN9_3DSTATE_CLEAR_PARAMS GEN9_3D(3, 0, 0x04)
12044 +#define GEN9_3DSTATE_DEPTH_BUFFER GEN9_3D(3, 0, 0x05)
12045 +# define DEPTH_BUFFER_TYPE_SHIFT 29
12046 +# define DEPTH_BUFFER_FORMAT_SHIFT 18
12048 +#define GEN9_3DSTATE_STENCIL_BUFFER GEN9_3D(3, 0, 0x06)
12049 +#define GEN9_3DSTATE_HIER_DEPTH_BUFFER GEN9_3D(3, 0, 0x07)
12050 +#define GEN9_3DSTATE_VERTEX_BUFFERS GEN9_3D(3, 0, 0x08)
12051 +# define VB_INDEX_SHIFT 26
12052 +# define VB_MODIFY_ENABLE (1 << 14)
12053 +#define GEN9_3DSTATE_VERTEX_ELEMENTS GEN9_3D(3, 0, 0x09)
12054 +# define VE_INDEX_SHIFT 26
12055 +# define VE_VALID (1 << 25)
12056 +# define VE_FORMAT_SHIFT 16
12057 +# define VE_OFFSET_SHIFT 0
12058 +# define VE_COMPONENT_0_SHIFT 28
12059 +# define VE_COMPONENT_1_SHIFT 24
12060 +# define VE_COMPONENT_2_SHIFT 20
12061 +# define VE_COMPONENT_3_SHIFT 16
12062 +#define GEN9_3DSTATE_INDEX_BUFFER GEN9_3D(3, 0, 0x0a)
12063 +#define GEN9_3DSTATE_VF GEN9_3D(3, 0, 0x0c)
12065 +#define GEN9_3DSTATE_MULTISAMPLE GEN9_3D(3, 0, 0x0d)
12066 +/* DW1 */
12067 +# define MULTISAMPLE_PIXEL_LOCATION_CENTER (0 << 4)
12068 +# define MULTISAMPLE_PIXEL_LOCATION_UPPER_LEFT (1 << 4)
12069 +# define MULTISAMPLE_NUMSAMPLES_1 (0 << 1)
12070 +# define MULTISAMPLE_NUMSAMPLES_4 (2 << 1)
12071 +# define MULTISAMPLE_NUMSAMPLES_8 (3 << 1)
12073 +#define GEN9_3DSTATE_CC_STATE_POINTERS GEN9_3D(3, 0, 0x0e)
12074 +#define GEN9_3DSTATE_SCISSOR_STATE_POINTERS GEN9_3D(3, 0, 0x0f)
12076 +#define GEN9_3DSTATE_VS GEN9_3D(3, 0, 0x10)
12077 +#define GEN9_3DSTATE_GS GEN9_3D(3, 0, 0x11)
12078 +#define GEN9_3DSTATE_CLIP GEN9_3D(3, 0, 0x12)
12079 +#define GEN9_3DSTATE_SF GEN9_3D(3, 0, 0x13)
12080 +# define SF_TRI_PROVOKE_SHIFT 29
12081 +# define SF_LINE_PROVOKE_SHIFT 27
12082 +# define SF_FAN_PROVOKE_SHIFT 25
12084 +#define GEN9_3DSTATE_WM GEN9_3D(3, 0, 0x14)
12085 +/* DW1 */
12086 +# define WM_STATISTICS_ENABLE (1 << 31)
12087 +# define WM_DEPTH_CLEAR (1 << 30)
12088 +# define WM_DEPTH_RESOLVE (1 << 28)
12089 +# define WM_HIERARCHICAL_DEPTH_RESOLVE (1 << 27)
12090 +# define WM_KILL_ENABLE (1 << 25)
12091 +# define WM_POSITION_ZW_PIXEL (0 << 17)
12092 +# define WM_POSITION_ZW_CENTROID (2 << 17)
12093 +# define WM_POSITION_ZW_SAMPLE (3 << 17)
12094 +# define WM_NONPERSPECTIVE_SAMPLE_BARYCENTRIC (1 << 16)
12095 +# define WM_NONPERSPECTIVE_CENTROID_BARYCENTRIC (1 << 15)
12096 +# define WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC (1 << 14)
12097 +# define WM_PERSPECTIVE_SAMPLE_BARYCENTRIC (1 << 13)
12098 +# define WM_PERSPECTIVE_CENTROID_BARYCENTRIC (1 << 12)
12099 +# define WM_PERSPECTIVE_PIXEL_BARYCENTRIC (1 << 11)
12100 +# define WM_LINE_END_CAP_AA_WIDTH_0_5 (0 << 8)
12101 +# define WM_LINE_END_CAP_AA_WIDTH_1_0 (1 << 8)
12102 +# define WM_LINE_END_CAP_AA_WIDTH_2_0 (2 << 8)
12103 +# define WM_LINE_END_CAP_AA_WIDTH_4_0 (3 << 8)
12104 +# define WM_LINE_AA_WIDTH_0_5 (0 << 6)
12105 +# define WM_LINE_AA_WIDTH_1_0 (1 << 6)
12106 +# define WM_LINE_AA_WIDTH_2_0 (2 << 6)
12107 +# define WM_LINE_AA_WIDTH_4_0 (3 << 6)
12108 +# define WM_POLYGON_STIPPLE_ENABLE (1 << 4)
12109 +# define WM_LINE_STIPPLE_ENABLE (1 << 3)
12110 +# define WM_POINT_RASTRULE_UPPER_RIGHT (1 << 2)
12111 +# define WM_MSRAST_OFF_PIXEL (0 << 0)
12112 +# define WM_MSRAST_OFF_PATTERN (1 << 0)
12113 +# define WM_MSRAST_ON_PIXEL (2 << 0)
12114 +# define WM_MSRAST_ON_PATTERN (3 << 0)
12116 +#define GEN9_3DSTATE_CONSTANT_VS GEN9_3D(3, 0, 0x15)
12117 +#define GEN9_3DSTATE_CONSTANT_GS GEN9_3D(3, 0, 0x16)
12118 +#define GEN9_3DSTATE_CONSTANT_PS GEN9_3D(3, 0, 0x17)
12120 +#define GEN9_3DSTATE_SAMPLE_MASK GEN9_3D(3, 0, 0x18)
12122 +#define GEN9_3DSTATE_CONSTANT_HS GEN9_3D(3, 0, 0x19)
12123 +#define GEN9_3DSTATE_CONSTANT_DS GEN9_3D(3, 0, 0x1a)
12125 +#define GEN9_3DSTATE_HS GEN9_3D(3, 0, 0x1b)
12126 +#define GEN9_3DSTATE_TE GEN9_3D(3, 0, 0x1c)
12127 +#define GEN9_3DSTATE_DS GEN9_3D(3, 0, 0x1d)
12128 +#define GEN9_3DSTATE_STREAMOUT GEN9_3D(3, 0, 0x1e)
12130 +#define GEN9_3DSTATE_SBE GEN9_3D(3, 0, 0x1f)
12131 +/* DW1 */
12132 +# define SBE_FORCE_VERTEX_URB_READ_LENGTH (1<<29)
12133 +# define SBE_FORCE_VERTEX_URB_READ_OFFSET (1<<28)
12134 +# define SBE_NUM_OUTPUTS_SHIFT 22
12135 +# define SBE_SWIZZLE_ENABLE (1 << 21)
12136 +# define SBE_POINT_SPRITE_LOWERLEFT (1 << 20)
12137 +# define SBE_URB_ENTRY_READ_LENGTH_SHIFT 11
12138 +# define SBE_URB_ENTRY_READ_OFFSET_SHIFT 5
12139 +#define SBE_ACTIVE_COMPONENT_NONE 0
12140 +#define SBE_ACTIVE_COMPONENT_XY 1
12141 +#define SBE_ACTIVE_COMPONENT_XYZ 2
12142 +#define SBE_ACTIVE_COMPONENT_XYZW 3
12145 +#define GEN9_3DSTATE_PS GEN9_3D(3, 0, 0x20)
12146 +/* DW1:DW2 kernel pointer */
12147 +/* DW3 */
12148 +# define PS_SPF_MODE (1 << 31)
12149 +# define PS_VECTOR_MASK_ENABLE (1 << 30)
12150 +# define PS_SAMPLER_COUNT_SHIFT 27
12151 +# define PS_BINDING_TABLE_ENTRY_COUNT_SHIFT 18
12152 +# define PS_FLOATING_POINT_MODE_IEEE_754 (0 << 16)
12153 +# define PS_FLOATING_POINT_MODE_ALT (1 << 16)
12154 +/* DW4:DW5: scratch space */
12155 +/* DW6 */
12156 +# define PS_MAX_THREADS_SHIFT 23
12157 +# define PS_MAX_THREADS (63 << PS_MAX_THREADS_SHIFT)
12158 +# define PS_PUSH_CONSTANT_ENABLE (1 << 11)
12159 +# define PS_RENDER_TARGET_CLEAR (1 << 8)
12160 +# define PS_RENDER_TARGET_RESOLVE (1 << 6)
12161 +# define PS_POSOFFSET_NONE (0 << 3)
12162 +# define PS_POSOFFSET_CENTROID (2 << 3)
12163 +# define PS_POSOFFSET_SAMPLE (3 << 3)
12164 +# define PS_32_DISPATCH_ENABLE (1 << 2)
12165 +# define PS_16_DISPATCH_ENABLE (1 << 1)
12166 +# define PS_8_DISPATCH_ENABLE (1 << 0)
12167 +/* DW7 */
12168 +# define PS_DISPATCH_START_GRF_SHIFT_0 16
12169 +# define PS_DISPATCH_START_GRF_SHIFT_1 8
12170 +# define PS_DISPATCH_START_GRF_SHIFT_2 0
12171 +/* DW8:D9: kernel 1 pointer */
12172 +/* DW10:D11: kernel 2 pointer */
12174 +#define GEN9_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP GEN9_3D(3, 0, 0x21)
12175 +#define GEN9_3DSTATE_VIEWPORT_STATE_POINTERS_CC GEN9_3D(3, 0, 0x23)
12177 +#define GEN9_3DSTATE_BLEND_STATE_POINTERS GEN9_3D(3, 0, 0x24)
12179 +#define GEN9_3DSTATE_BINDING_TABLE_POINTERS_VS GEN9_3D(3, 0, 0x26)
12180 +#define GEN9_3DSTATE_BINDING_TABLE_POINTERS_HS GEN9_3D(3, 0, 0x27)
12181 +#define GEN9_3DSTATE_BINDING_TABLE_POINTERS_DS GEN9_3D(3, 0, 0x28)
12182 +#define GEN9_3DSTATE_BINDING_TABLE_POINTERS_GS GEN9_3D(3, 0, 0x29)
12183 +#define GEN9_3DSTATE_BINDING_TABLE_POINTERS_PS GEN9_3D(3, 0, 0x2a)
12185 +#define GEN9_3DSTATE_SAMPLER_STATE_POINTERS_VS GEN9_3D(3, 0, 0x2b)
12186 +#define GEN9_3DSTATE_SAMPLER_STATE_POINTERS_HS GEN9_3D(3, 0, 0x2c)
12187 +#define GEN9_3DSTATE_SAMPLER_STATE_POINTERS_DS GEN9_3D(3, 0, 0x2d)
12188 +#define GEN9_3DSTATE_SAMPLER_STATE_POINTERS_GS GEN9_3D(3, 0, 0x2e)
12189 +#define GEN9_3DSTATE_SAMPLER_STATE_POINTERS_PS GEN9_3D(3, 0, 0x2f)
12191 +#define GEN9_3DSTATE_URB_VS GEN9_3D(3, 0, 0x30)
12192 +#define GEN9_3DSTATE_URB_HS GEN9_3D(3, 0, 0x31)
12193 +#define GEN9_3DSTATE_URB_DS GEN9_3D(3, 0, 0x32)
12194 +#define GEN9_3DSTATE_URB_GS GEN9_3D(3, 0, 0x33)
12195 +/* DW1 */
12196 +# define URB_ENTRY_NUMBER_SHIFT 0
12197 +# define URB_ENTRY_SIZE_SHIFT 16
12198 +# define URB_STARTING_ADDRESS_SHIFT 25
12200 +#define GEN9_3DSTATE_GATHER_CONSTANT_VS GEN9_3D(3, 0, 0x34)
12201 +#define GEN9_3DSTATE_GATHER_CONSTANT_GS GEN9_3D(3, 0, 0x35)
12202 +#define GEN9_3DSTATE_GATHER_CONSTANT_HS GEN9_3D(3, 0, 0x36)
12203 +#define GEN9_3DSTATE_GATHER_CONSTANT_DS GEN9_3D(3, 0, 0x37)
12204 +#define GEN9_3DSTATE_GATHER_CONSTANT_PS GEN9_3D(3, 0, 0x38)
12206 +#define GEN9_3DSTATE_DX9_CONSTANTF_VS GEN9_3D(3, 0, 0x39)
12207 +#define GEN9_3DSTATE_DX9_CONSTANTF_PS GEN9_3D(3, 0, 0x3a)
12208 +#define GEN9_3DSTATE_DX9_CONSTANTI_VS GEN9_3D(3, 0, 0x3b)
12209 +#define GEN9_3DSTATE_DX9_CONSTANTI_PS GEN9_3D(3, 0, 0x3c)
12210 +#define GEN9_3DSTATE_DX9_CONSTANTB_VS GEN9_3D(3, 0, 0x3d)
12211 +#define GEN9_3DSTATE_DX9_CONSTANTB_PS GEN9_3D(3, 0, 0x3e)
12212 +#define GEN9_3DSTATE_DX9_LOCAL_VALID_VS GEN9_3D(3, 0, 0x3f)
12213 +#define GEN9_3DSTATE_DX9_LOCAL_VALID_PS GEN9_3D(3, 0, 0x40)
12214 +#define GEN9_3DSTATE_DX9_GENERATE_ACTIVE_VS GEN9_3D(3, 0, 0x41)
12215 +#define GEN9_3DSTATE_DX9_GENERATE_ACTIVE_PS GEN9_3D(3, 0, 0x42)
12217 +#define GEN9_3DSTATE_BINDING_TABLE_EDIT_VS GEN9_3D(3, 0, 0x43)
12218 +#define GEN9_3DSTATE_BINDING_TABLE_EDIT_GS GEN9_3D(3, 0, 0x44)
12219 +#define GEN9_3DSTATE_BINDING_TABLE_EDIT_HS GEN9_3D(3, 0, 0x45)
12220 +#define GEN9_3DSTATE_BINDING_TABLE_EDIT_DS GEN9_3D(3, 0, 0x46)
12221 +#define GEN9_3DSTATE_BINDING_TABLE_EDIT_PS GEN9_3D(3, 0, 0x47)
12223 +#define GEN9_3DSTATE_VF_INSTANCING GEN9_3D(3, 0, 0x49)
12224 +#define GEN9_3DSTATE_VF_SGVS GEN9_3D(3, 0, 0x4a)
12225 +# define SGVS_ENABLE_INSTANCE_ID (1 << 31)
12226 +# define SGVS_INSTANCE_ID_COMPONENT_SHIFT 29
12227 +# define SGVS_INSTANCE_ID_ELEMENT_OFFSET_SHIFT 16
12228 +# define SGVS_ENABLE_VERTEX_ID (1 << 15)
12229 +# define SGVS_VERTEX_ID_COMPONENT_SHIFT 13
12230 +# define SGVS_VERTEX_ID_ELEMENT_OFFSET_SHIFT 0
12231 +#define GEN9_3DSTATE_VF_TOPOLOGY GEN9_3D(3, 0, 0x4b)
12232 +# define POINTLIST 0x01
12233 +# define LINELIST 0x02
12234 +# define LINESTRIP 0x03
12235 +# define TRILIST 0x04
12236 +# define TRISTRIP 0x05
12237 +# define TRIFAN 0x06
12238 +# define QUADLIST 0x07
12239 +# define QUADSTRIP 0x08
12240 +# define LINELIST_ADJ 0x09
12241 +# define LINESTRIP_ADJ 0x0A
12242 +# define TRILIST_ADJ 0x0B
12243 +# define TRISTRIP_ADJ 0x0C
12244 +# define TRISTRIP_REVERSE 0x0D
12245 +# define POLYGON 0x0E
12246 +# define RECTLIST 0x0F
12247 +# define LINELOOP 0x10
12248 +# define POINTLIST_BF 0x11
12249 +# define LINESTRIP_CONT 0x12
12250 +# define LINESTRIP_BF 0x13
12251 +# define LINESTRIP_CONT_BF 0x14
12252 +# define TRIFAN_NOSTIPPLE 0x15
12254 +#define GEN9_3DSTATE_WM_CHROMAKEY GEN9_3D(3, 0, 0x4c)
12256 +#define GEN9_3DSTATE_PS_BLEND GEN9_3D(3, 0, 0x4d)
12257 +# define PS_BLEND_ALPHA_TO_COVERAGE_ENABLE (1 << 31)
12258 +# define PS_BLEND_HAS_WRITEABLE_RT (1 << 30)
12259 +# define PS_BLEND_COLOR_BLEND_ENABLE (1 << 29)
12260 +# define PS_BLEND_SRC_ALPHA_SHIFT 24
12261 +# define PS_BLEND_DST_ALPHA_SHIFT 19
12262 +# define PS_BLEND_SRC_SHIFT 14
12263 +# define PS_BLEND_DST_SHIFT 9
12264 +# define PS_BLEND_ALPHA_TEST_ENABLE (1 << 8)
12265 +# define PS_BLEND_INDEPENDENT_ALPHA_BLEND_ENABLE (1 << 7)
12267 +#define GEN9_3DSTATE_WM_DEPTH_STENCIL GEN9_3D(3, 0, 0x4e)
12268 +/* DW1 */
12269 +# define WM_DS_STENCIL_TEST_MASK_MASK INTEL_MASK(31, 24)
12270 +# define WM_DS_STENCIL_TEST_MASK_SHIFT 24
12271 +# define WM_DS_STENCIL_WRITE_MASK_MASK INTEL_MASK(23, 16)
12272 +# define WM_DS_STENCIL_WRITE_MASK_SHIFT 16
12273 +# define WM_DS_BF_STENCIL_TEST_MASK_MASK INTEL_MASK(15, 8)
12274 +# define WM_DS_BF_STENCIL_TEST_MASK_SHIFT 8
12275 +# define WM_DS_BF_STENCIL_WRITE_MASK_MASK INTEL_MASK(7, 0)
12276 +# define WM_DS_DEPTH_FUNC_SHIFT 5
12277 +# define WM_DS_DOUBLE_SIDED_STENCIL_ENABLE (1 << 4)
12278 +# define WM_DS_STENCIL_TEST_ENABLE (1 << 3)
12279 +# define WM_DS_STENCIL_BUFFER_WRITE_ENABLE (1 << 2)
12280 +# define WM_DS_DEPTH_TEST_ENABLE (1 << 1)
12281 +# define WM_DS_DEPTH_BUFFER_WRITE_ENABLE (1 << 0)
12282 +/* DW2 */
12283 +# define WM_DS_STENCIL_TEST_MASK_MASK INTEL_MASK(31, 24)
12284 +# define WM_DS_STENCIL_TEST_MASK_SHIFT 24
12285 +# define WM_DS_STENCIL_WRITE_MASK_MASK INTEL_MASK(23, 16)
12286 +# define WM_DS_STENCIL_WRITE_MASK_SHIFT 16
12287 +# define WM_DS_BF_STENCIL_TEST_MASK_MASK INTEL_MASK(15, 8)
12288 +# define WM_DS_BF_STENCIL_TEST_MASK_SHIFT 8
12289 +# define WM_DS_BF_STENCIL_WRITE_MASK_MASK INTEL_MASK(7, 0)
12290 +# define WM_DS_BF_STENCIL_WRITE_MASK_SHIFT 0
12292 +#define GEN9_3DSTATE_PS_EXTRA GEN9_3D(3, 0, 0x4f)
12293 +# define PSX_PIXEL_SHADER_VALID (1 << 31)
12294 +# define PSX_PIXEL_SHADER_NO_RT_WRITE (1 << 30)
12295 +# define PSX_OMASK_TO_RENDER_TARGET (1 << 29)
12296 +# define PSX_KILL_ENABLE (1 << 28)
12297 +# define PSX_PSCDEPTH_OFF (0 << 26)
12298 +# define PSX_PSCDEPTH_ON (1 << 26)
12299 +# define PSX_PSCDEPTH_ON_GE (2 << 26)
12300 +# define PSX_PSCDEPTH_ON_LE (3 << 26)
12301 +# define PSX_FORCE_COMPUTED_DEPTH (1 << 25)
12302 +# define PSX_USES_SOURCE_DEPTH (1 << 24)
12303 +# define PSX_USES_SOURCE_W (1 << 23)
12304 +# define PSX_ATTRIBUTE_ENABLE (1 << 8)
12305 +# define PSX_SHADER_DISABLES_ALPHA_TO_COVERAGE (1 << 7)
12306 +# define PSX_SHADER_IS_PER_SAMPLE (1 << 6)
12307 +# define PSX_SHADER_HAS_UAV (1 << 2)
12308 +# define PSX_SHADER_USES_INPUT_COVERAGE_MASK (1 << 1)
12310 +#define GEN9_3DSTATE_RASTER GEN9_3D(3, 0, 0x50)
12311 +/* DW1 */
12312 +# define RASTER_FRONT_WINDING_CCW (1 << 21)
12313 +# define RASTER_CULL_BOTH (0 << 16)
12314 +# define RASTER_CULL_NONE (1 << 16)
12315 +# define RASTER_CULL_FRONT (2 << 16)
12316 +# define RASTER_CULL_BACK (3 << 16)
12317 +# define RASTER_SMOOTH_POINT_ENABLE (1 << 13)
12318 +# define RASTER_LINE_AA_ENABLE (1 << 2)
12319 +# define RASTER_VIEWPORT_Z_CLIP_TEST_ENABLE (1 << 0)
12321 +#define GEN9_3DSTATE_SBE_SWIZ GEN9_3D(3, 0, 0x51)
12322 +#define GEN9_3DSTATE_WM_HZ_OP GEN9_3D(3, 0, 0x52)
12324 +#define GEN9_3DSTATE_COMPONENT_PACKING GEN6_3D(3, 0, 0x55)
12328 +#define GEN9_3DSTATE_DRAWING_RECTANGLE GEN9_3D(3, 1, 0x00)
12329 +#define GEN9_3DSTATE_SAMPLER_PALETTE_LOAD GEN9_3D(3, 1, 0x02)
12330 +#define GEN9_3DSTATE_CHROMA_KEY GEN9_3D(3, 1, 0x04)
12332 +#define GEN9_3DSTATE_POLY_STIPPLE_OFFSET GEN9_3D(3, 1, 0x06)
12333 +#define GEN9_3DSTATE_POLY_STIPPLE_PATTERN GEN9_3D(3, 1, 0x07)
12334 +#define GEN9_3DSTATE_LINE_STIPPLE GEN9_3D(3, 1, 0x08)
12335 +#define GEN9_3DSTATE_AA_LINE_PARAMS GEN9_3D(3, 1, 0x0a)
12336 +#define GEN9_3DSTATE_SAMPLER_PALETTE_LOAD1 GEN9_3D(3, 1, 0x0c)
12337 +#define GEN9_3DSTATE_MONOFILTER_SIZE GEN9_3D(3, 1, 0x11)
12338 +#define GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_VS GEN9_3D(3, 1, 0x12)
12339 +#define GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_HS GEN9_3D(3, 1, 0x13)
12340 +#define GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_DS GEN9_3D(3, 1, 0x14)
12341 +#define GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_GS GEN9_3D(3, 1, 0x15)
12342 +#define GEN9_3DSTATE_PUSH_CONSTANT_ALLOC_PS GEN9_3D(3, 1, 0x16)
12343 +/* DW1 */
12344 +# define PUSH_CONSTANT_BUFFER_OFFSET_SHIFT 16
12345 +# define PUSH_CONSTANT_BUFFER_SIZE_SHIFT 0
12347 +#define GEN9_3DSTATE_SO_DECL_LIST GEN9_3D(3, 1, 0x17)
12348 +#define GEN9_3DSTATE_SO_BUFFER GEN9_3D(3, 1, 0x18)
12349 +#define GEN9_3DSTATE_BINDING_TABLE_POOL_ALLOC GEN9_3D(3, 1, 0x19)
12350 +#define GEN9_3DSTATE_GATHER_BUFFER_POOL_ALLOC GEN9_3D(3, 1, 0x1a)
12351 +#define GEN9_3DSTATE_DX9_CONSTANT_BUFFER_POOL_ALLOC GEN9_3D(3, 1, 0x1b)
12352 +#define GEN9_3DSTATE_SAMPLE_PATTERN GEN9_3D(3, 1, 0x1c)
12355 +/* for GEN9_PIPE_CONTROL */
12356 +#define GEN9_PIPE_CONTROL GEN9_3D(3, 2, 0)
12357 +#define PIPE_CONTROL_CS_STALL (1 << 20)
12358 +#define PIPE_CONTROL_NOWRITE (0 << 14)
12359 +#define PIPE_CONTROL_WRITE_QWORD (1 << 14)
12360 +#define PIPE_CONTROL_WRITE_DEPTH (2 << 14)
12361 +#define PIPE_CONTROL_WRITE_TIME (3 << 14)
12362 +#define PIPE_CONTROL_DEPTH_STALL (1 << 13)
12363 +#define PIPE_CONTROL_WC_FLUSH (1 << 12)
12364 +#define PIPE_CONTROL_IS_FLUSH (1 << 11)
12365 +#define PIPE_CONTROL_TC_FLUSH (1 << 10)
12366 +#define PIPE_CONTROL_NOTIFY_ENABLE (1 << 8)
12367 +#define PIPE_CONTROL_FLUSH (1 << 7)
12368 +#define PIPE_CONTROL_GLOBAL_GTT (1 << 2)
12369 +#define PIPE_CONTROL_LOCAL_PGTT (0 << 2)
12370 +#define PIPE_CONTROL_STALL_AT_SCOREBOARD (1 << 1)
12371 +#define PIPE_CONTROL_DEPTH_CACHE_FLUSH (1 << 0)
12374 +#define GEN9_3DPRIMITIVE GEN9_3D(3, 3, 0)
12376 +/* 3DPRIMITIVE bits */
12377 +#define VERTEX_SEQUENTIAL (0 << 15)
12378 +#define VERTEX_RANDOM (1 << 15)
12380 +#define ANISORATIO_2 0
12381 +#define ANISORATIO_4 1
12382 +#define ANISORATIO_6 2
12383 +#define ANISORATIO_8 3
12384 +#define ANISORATIO_10 4
12385 +#define ANISORATIO_12 5
12386 +#define ANISORATIO_14 6
12387 +#define ANISORATIO_16 7
12389 +#define BLENDFACTOR_ONE 0x1
12390 +#define BLENDFACTOR_SRC_COLOR 0x2
12391 +#define BLENDFACTOR_SRC_ALPHA 0x3
12392 +#define BLENDFACTOR_DST_ALPHA 0x4
12393 +#define BLENDFACTOR_DST_COLOR 0x5
12394 +#define BLENDFACTOR_SRC_ALPHA_SATURATE 0x6
12395 +#define BLENDFACTOR_CONST_COLOR 0x7
12396 +#define BLENDFACTOR_CONST_ALPHA 0x8
12397 +#define BLENDFACTOR_SRC1_COLOR 0x9
12398 +#define BLENDFACTOR_SRC1_ALPHA 0x0A
12399 +#define BLENDFACTOR_ZERO 0x11
12400 +#define BLENDFACTOR_INV_SRC_COLOR 0x12
12401 +#define BLENDFACTOR_INV_SRC_ALPHA 0x13
12402 +#define BLENDFACTOR_INV_DST_ALPHA 0x14
12403 +#define BLENDFACTOR_INV_DST_COLOR 0x15
12404 +#define BLENDFACTOR_INV_CONST_COLOR 0x17
12405 +#define BLENDFACTOR_INV_CONST_ALPHA 0x18
12406 +#define BLENDFACTOR_INV_SRC1_COLOR 0x19
12407 +#define BLENDFACTOR_INV_SRC1_ALPHA 0x1A
12409 +#define BLENDFUNCTION_ADD 0
12410 +#define BLENDFUNCTION_SUBTRACT 1
12411 +#define BLENDFUNCTION_REVERSE_SUBTRACT 2
12412 +#define GEN9_BLENDFUNCTION_MIN 3
12413 +#define BLENDFUNCTION_MAX 4
12415 +#define ALPHATEST_FORMAT_UNORM8 0
12416 +#define ALPHATEST_FORMAT_FLOAT32 1
12418 +#define CHROMAKEY_KILL_ON_ANY_MATCH 0
12419 +#define CHROMAKEY_REPLACE_BLACK 1
12421 +#define CLIP_API_OGL 0
12422 +#define CLIP_API_DX 1
12424 +#define CLIPMODE_NORMAL 0
12425 +#define CLIPMODE_CLIP_ALL 1
12426 +#define CLIPMODE_CLIP_NON_REJECTED 2
12427 +#define CLIPMODE_REJECT_ALL 3
12428 +#define CLIPMODE_ACCEPT_ALL 4
12430 +#define CLIP_NDCSPACE 0
12431 +#define CLIP_SCREENSPACE 1
12433 +#define COMPAREFUNCTION_ALWAYS 0
12434 +#define COMPAREFUNCTION_NEVER 1
12435 +#define COMPAREFUNCTION_LESS 2
12436 +#define COMPAREFUNCTION_EQUAL 3
12437 +#define COMPAREFUNCTION_LEQUAL 4
12438 +#define COMPAREFUNCTION_GREATER 5
12439 +#define COMPAREFUNCTION_NOTEQUAL 6
12440 +#define COMPAREFUNCTION_GEQUAL 7
12442 +#define COVERAGE_PIXELS_HALF 0
12443 +#define COVERAGE_PIXELS_1 1
12444 +#define COVERAGE_PIXELS_2 2
12445 +#define COVERAGE_PIXELS_4 3
12447 +#define DEPTHFORMAT_D32_FLOAT_S8X24_UINT 0
12448 +#define DEPTHFORMAT_D32_FLOAT 1
12449 +#define DEPTHFORMAT_D24_UNORM_S8_UINT 2
12450 +#define DEPTHFORMAT_D16_UNORM 5
12452 +#define FLOATING_POINT_IEEE_754 0
12453 +#define FLOATING_POINT_NON_IEEE_754 1
12455 +#define INDEX_BYTE 0
12456 +#define INDEX_WORD 1
12457 +#define INDEX_DWORD 2
12459 +#define LOGICOPFUNCTION_CLEAR 0
12460 +#define LOGICOPFUNCTION_NOR 1
12461 +#define LOGICOPFUNCTION_AND_INVERTED 2
12462 +#define LOGICOPFUNCTION_COPY_INVERTED 3
12463 +#define LOGICOPFUNCTION_AND_REVERSE 4
12464 +#define LOGICOPFUNCTION_INVERT 5
12465 +#define LOGICOPFUNCTION_XOR 6
12466 +#define LOGICOPFUNCTION_NAND 7
12467 +#define LOGICOPFUNCTION_AND 8
12468 +#define LOGICOPFUNCTION_EQUIV 9
12469 +#define LOGICOPFUNCTION_NOOP 10
12470 +#define LOGICOPFUNCTION_OR_INVERTED 11
12471 +#define LOGICOPFUNCTION_COPY 12
12472 +#define LOGICOPFUNCTION_OR_REVERSE 13
12473 +#define LOGICOPFUNCTION_OR 14
12474 +#define LOGICOPFUNCTION_SET 15
12476 +#define MAPFILTER_NEAREST 0x0
12477 +#define MAPFILTER_LINEAR 0x1
12478 +#define MAPFILTER_ANISOTROPIC 0x2
12479 +#define MAPFILTER_FLEXIBLE 0x3
12480 +#define MAPFILTER_MONO 0x6
12482 +#define MIPFILTER_NONE 0
12483 +#define MIPFILTER_NEAREST 1
12484 +#define MIPFILTER_LINEAR 3
12486 +#define POLYGON_FRONT_FACING 0
12487 +#define POLYGON_BACK_FACING 1
12489 +#define PREFILTER_ALWAYS 0x0
12490 +#define PREFILTER_NEVER 0x1
12491 +#define PREFILTER_LESS 0x2
12492 +#define PREFILTER_EQUAL 0x3
12493 +#define PREFILTER_LEQUAL 0x4
12494 +#define PREFILTER_GREATER 0x5
12495 +#define PREFILTER_NOTEQUAL 0x6
12496 +#define PREFILTER_GEQUAL 0x7
12498 +#define RASTRULE_UPPER_LEFT 0
12499 +#define RASTRULE_UPPER_RIGHT 1
12501 +#define STENCILOP_KEEP 0
12502 +#define STENCILOP_ZERO 1
12503 +#define STENCILOP_REPLACE 2
12504 +#define STENCILOP_INCRSAT 3
12505 +#define STENCILOP_DECRSAT 4
12506 +#define STENCILOP_INCR 5
12507 +#define STENCILOP_DECR 6
12508 +#define STENCILOP_INVERT 7
12510 +#define SURFACE_MIPMAPLAYOUT_BELOW 0
12511 +#define SURFACE_MIPMAPLAYOUT_RIGHT 1
12513 +#define SURFACEFORMAT_R32G32B32A32_FLOAT 0x000
12514 +#define SURFACEFORMAT_R32G32B32A32_SINT 0x001
12515 +#define SURFACEFORMAT_R32G32B32A32_UINT 0x002
12516 +#define SURFACEFORMAT_R32G32B32A32_UNORM 0x003
12517 +#define SURFACEFORMAT_R32G32B32A32_SNORM 0x004
12518 +#define SURFACEFORMAT_R64G64_FLOAT 0x005
12519 +#define SURFACEFORMAT_R32G32B32X32_FLOAT 0x006
12520 +#define SURFACEFORMAT_R32G32B32A32_SSCALED 0x007
12521 +#define SURFACEFORMAT_R32G32B32A32_USCALED 0x008
12522 +#define SURFACEFORMAT_R32G32B32_FLOAT 0x040
12523 +#define SURFACEFORMAT_R32G32B32_SINT 0x041
12524 +#define SURFACEFORMAT_R32G32B32_UINT 0x042
12525 +#define SURFACEFORMAT_R32G32B32_UNORM 0x043
12526 +#define SURFACEFORMAT_R32G32B32_SNORM 0x044
12527 +#define SURFACEFORMAT_R32G32B32_SSCALED 0x045
12528 +#define SURFACEFORMAT_R32G32B32_USCALED 0x046
12529 +#define SURFACEFORMAT_R16G16B16A16_UNORM 0x080
12530 +#define SURFACEFORMAT_R16G16B16A16_SNORM 0x081
12531 +#define SURFACEFORMAT_R16G16B16A16_SINT 0x082
12532 +#define SURFACEFORMAT_R16G16B16A16_UINT 0x083
12533 +#define SURFACEFORMAT_R16G16B16A16_FLOAT 0x084
12534 +#define SURFACEFORMAT_R32G32_FLOAT 0x085
12535 +#define SURFACEFORMAT_R32G32_SINT 0x086
12536 +#define SURFACEFORMAT_R32G32_UINT 0x087
12537 +#define SURFACEFORMAT_R32_FLOAT_X8X24_TYPELESS 0x088
12538 +#define SURFACEFORMAT_X32_TYPELESS_G8X24_UINT 0x089
12539 +#define SURFACEFORMAT_L32A32_FLOAT 0x08A
12540 +#define SURFACEFORMAT_R32G32_UNORM 0x08B
12541 +#define SURFACEFORMAT_R32G32_SNORM 0x08C
12542 +#define SURFACEFORMAT_R64_FLOAT 0x08D
12543 +#define SURFACEFORMAT_R16G16B16X16_UNORM 0x08E
12544 +#define SURFACEFORMAT_R16G16B16X16_FLOAT 0x08F
12545 +#define SURFACEFORMAT_A32X32_FLOAT 0x090
12546 +#define SURFACEFORMAT_L32X32_FLOAT 0x091
12547 +#define SURFACEFORMAT_I32X32_FLOAT 0x092
12548 +#define SURFACEFORMAT_R16G16B16A16_SSCALED 0x093
12549 +#define SURFACEFORMAT_R16G16B16A16_USCALED 0x094
12550 +#define SURFACEFORMAT_R32G32_SSCALED 0x095
12551 +#define SURFACEFORMAT_R32G32_USCALED 0x096
12552 +#define SURFACEFORMAT_B8G8R8A8_UNORM 0x0C0
12553 +#define SURFACEFORMAT_B8G8R8A8_UNORM_SRGB 0x0C1
12554 +#define SURFACEFORMAT_R10G10B10A2_UNORM 0x0C2
12555 +#define SURFACEFORMAT_R10G10B10A2_UNORM_SRGB 0x0C3
12556 +#define SURFACEFORMAT_R10G10B10A2_UINT 0x0C4
12557 +#define SURFACEFORMAT_R10G10B10_SNORM_A2_UNORM 0x0C5
12558 +#define SURFACEFORMAT_R8G8B8A8_UNORM 0x0C7
12559 +#define SURFACEFORMAT_R8G8B8A8_UNORM_SRGB 0x0C8
12560 +#define SURFACEFORMAT_R8G8B8A8_SNORM 0x0C9
12561 +#define SURFACEFORMAT_R8G8B8A8_SINT 0x0CA
12562 +#define SURFACEFORMAT_R8G8B8A8_UINT 0x0CB
12563 +#define SURFACEFORMAT_R16G16_UNORM 0x0CC
12564 +#define SURFACEFORMAT_R16G16_SNORM 0x0CD
12565 +#define SURFACEFORMAT_R16G16_SINT 0x0CE
12566 +#define SURFACEFORMAT_R16G16_UINT 0x0CF
12567 +#define SURFACEFORMAT_R16G16_FLOAT 0x0D0
12568 +#define SURFACEFORMAT_B10G10R10A2_UNORM 0x0D1
12569 +#define SURFACEFORMAT_B10G10R10A2_UNORM_SRGB 0x0D2
12570 +#define SURFACEFORMAT_R11G11B10_FLOAT 0x0D3
12571 +#define SURFACEFORMAT_R32_SINT 0x0D6
12572 +#define SURFACEFORMAT_R32_UINT 0x0D7
12573 +#define SURFACEFORMAT_R32_FLOAT 0x0D8
12574 +#define SURFACEFORMAT_R24_UNORM_X8_TYPELESS 0x0D9
12575 +#define SURFACEFORMAT_X24_TYPELESS_G8_UINT 0x0DA
12576 +#define SURFACEFORMAT_L16A16_UNORM 0x0DF
12577 +#define SURFACEFORMAT_I24X8_UNORM 0x0E0
12578 +#define SURFACEFORMAT_L24X8_UNORM 0x0E1
12579 +#define SURFACEFORMAT_A24X8_UNORM 0x0E2
12580 +#define SURFACEFORMAT_I32_FLOAT 0x0E3
12581 +#define SURFACEFORMAT_L32_FLOAT 0x0E4
12582 +#define SURFACEFORMAT_A32_FLOAT 0x0E5
12583 +#define SURFACEFORMAT_B8G8R8X8_UNORM 0x0E9
12584 +#define SURFACEFORMAT_B8G8R8X8_UNORM_SRGB 0x0EA
12585 +#define SURFACEFORMAT_R8G8B8X8_UNORM 0x0EB
12586 +#define SURFACEFORMAT_R8G8B8X8_UNORM_SRGB 0x0EC
12587 +#define SURFACEFORMAT_R9G9B9E5_SHAREDEXP 0x0ED
12588 +#define SURFACEFORMAT_B10G10R10X2_UNORM 0x0EE
12589 +#define SURFACEFORMAT_L16A16_FLOAT 0x0F0
12590 +#define SURFACEFORMAT_R32_UNORM 0x0F1
12591 +#define SURFACEFORMAT_R32_SNORM 0x0F2
12592 +#define SURFACEFORMAT_R10G10B10X2_USCALED 0x0F3
12593 +#define SURFACEFORMAT_R8G8B8A8_SSCALED 0x0F4
12594 +#define SURFACEFORMAT_R8G8B8A8_USCALED 0x0F5
12595 +#define SURFACEFORMAT_R16G16_SSCALED 0x0F6
12596 +#define SURFACEFORMAT_R16G16_USCALED 0x0F7
12597 +#define SURFACEFORMAT_R32_SSCALED 0x0F8
12598 +#define SURFACEFORMAT_R32_USCALED 0x0F9
12599 +#define SURFACEFORMAT_B5G6R5_UNORM 0x100
12600 +#define SURFACEFORMAT_B5G6R5_UNORM_SRGB 0x101
12601 +#define SURFACEFORMAT_B5G5R5A1_UNORM 0x102
12602 +#define SURFACEFORMAT_B5G5R5A1_UNORM_SRGB 0x103
12603 +#define SURFACEFORMAT_B4G4R4A4_UNORM 0x104
12604 +#define SURFACEFORMAT_B4G4R4A4_UNORM_SRGB 0x105
12605 +#define SURFACEFORMAT_R8G8_UNORM 0x106
12606 +#define SURFACEFORMAT_R8G8_SNORM 0x107
12607 +#define SURFACEFORMAT_R8G8_SINT 0x108
12608 +#define SURFACEFORMAT_R8G8_UINT 0x109
12609 +#define SURFACEFORMAT_R16_UNORM 0x10A
12610 +#define SURFACEFORMAT_R16_SNORM 0x10B
12611 +#define SURFACEFORMAT_R16_SINT 0x10C
12612 +#define SURFACEFORMAT_R16_UINT 0x10D
12613 +#define SURFACEFORMAT_R16_FLOAT 0x10E
12614 +#define SURFACEFORMAT_I16_UNORM 0x111
12615 +#define SURFACEFORMAT_L16_UNORM 0x112
12616 +#define SURFACEFORMAT_A16_UNORM 0x113
12617 +#define SURFACEFORMAT_L8A8_UNORM 0x114
12618 +#define SURFACEFORMAT_I16_FLOAT 0x115
12619 +#define SURFACEFORMAT_L16_FLOAT 0x116
12620 +#define SURFACEFORMAT_A16_FLOAT 0x117
12621 +#define SURFACEFORMAT_R5G5_SNORM_B6_UNORM 0x119
12622 +#define SURFACEFORMAT_B5G5R5X1_UNORM 0x11A
12623 +#define SURFACEFORMAT_B5G5R5X1_UNORM_SRGB 0x11B
12624 +#define SURFACEFORMAT_R8G8_SSCALED 0x11C
12625 +#define SURFACEFORMAT_R8G8_USCALED 0x11D
12626 +#define SURFACEFORMAT_R16_SSCALED 0x11E
12627 +#define SURFACEFORMAT_R16_USCALED 0x11F
12628 +#define SURFACEFORMAT_R8_UNORM 0x140
12629 +#define SURFACEFORMAT_R8_SNORM 0x141
12630 +#define SURFACEFORMAT_R8_SINT 0x142
12631 +#define SURFACEFORMAT_R8_UINT 0x143
12632 +#define SURFACEFORMAT_A8_UNORM 0x144
12633 +#define SURFACEFORMAT_I8_UNORM 0x145
12634 +#define SURFACEFORMAT_L8_UNORM 0x146
12635 +#define SURFACEFORMAT_P4A4_UNORM 0x147
12636 +#define SURFACEFORMAT_A4P4_UNORM 0x148
12637 +#define SURFACEFORMAT_R8_SSCALED 0x149
12638 +#define SURFACEFORMAT_R8_USCALED 0x14A
12639 +#define SURFACEFORMAT_R1_UINT 0x181
12640 +#define SURFACEFORMAT_YCRCB_NORMAL 0x182
12641 +#define SURFACEFORMAT_YCRCB_SWAPUVY 0x183
12642 +#define SURFACEFORMAT_BC1_UNORM 0x186
12643 +#define SURFACEFORMAT_BC2_UNORM 0x187
12644 +#define SURFACEFORMAT_BC3_UNORM 0x188
12645 +#define SURFACEFORMAT_BC4_UNORM 0x189
12646 +#define SURFACEFORMAT_BC5_UNORM 0x18A
12647 +#define SURFACEFORMAT_BC1_UNORM_SRGB 0x18B
12648 +#define SURFACEFORMAT_BC2_UNORM_SRGB 0x18C
12649 +#define SURFACEFORMAT_BC3_UNORM_SRGB 0x18D
12650 +#define SURFACEFORMAT_MONO8 0x18E
12651 +#define SURFACEFORMAT_YCRCB_SWAPUV 0x18F
12652 +#define SURFACEFORMAT_YCRCB_SWAPY 0x190
12653 +#define SURFACEFORMAT_DXT1_RGB 0x191
12654 +#define SURFACEFORMAT_FXT1 0x192
12655 +#define SURFACEFORMAT_R8G8B8_UNORM 0x193
12656 +#define SURFACEFORMAT_R8G8B8_SNORM 0x194
12657 +#define SURFACEFORMAT_R8G8B8_SSCALED 0x195
12658 +#define SURFACEFORMAT_R8G8B8_USCALED 0x196
12659 +#define SURFACEFORMAT_R64G64B64A64_FLOAT 0x197
12660 +#define SURFACEFORMAT_R64G64B64_FLOAT 0x198
12661 +#define SURFACEFORMAT_BC4_SNORM 0x199
12662 +#define SURFACEFORMAT_BC5_SNORM 0x19A
12663 +#define SURFACEFORMAT_R16G16B16_UNORM 0x19C
12664 +#define SURFACEFORMAT_R16G16B16_SNORM 0x19D
12665 +#define SURFACEFORMAT_R16G16B16_SSCALED 0x19E
12666 +#define SURFACEFORMAT_R16G16B16_USCALED 0x19F
12668 +#define SURFACE_1D 0
12669 +#define SURFACE_2D 1
12670 +#define SURFACE_3D 2
12671 +#define SURFACE_CUBE 3
12672 +#define SURFACE_BUFFER 4
12673 +#define SURFACE_NULL 7
12675 +#define TEXCOORDMODE_WRAP 0
12676 +#define TEXCOORDMODE_MIRROR 1
12677 +#define TEXCOORDMODE_CLAMP 2
12678 +#define TEXCOORDMODE_CUBE 3
12679 +#define TEXCOORDMODE_CLAMP_BORDER 4
12680 +#define TEXCOORDMODE_MIRROR_ONCE 5
12682 +#define THREAD_PRIORITY_NORMAL 0
12683 +#define THREAD_PRIORITY_HIGH 1
12685 +#define VERTEX_SUBPIXEL_PRECISION_8BITS 0
12686 +#define VERTEX_SUBPIXEL_PRECISION_4BITS 1
12688 +#define COMPONENT_NOSTORE 0
12689 +#define COMPONENT_STORE_SRC 1
12690 +#define COMPONENT_STORE_0 2
12691 +#define COMPONENT_STORE_1_FLT 3
12692 +#define COMPONENT_STORE_1_INT 4
12693 +#define COMPONENT_STORE_VID 5
12694 +#define COMPONENT_STORE_IID 6
12695 +#define COMPONENT_STORE_PID 7
12697 +/* Execution Unit (EU) defines
12698 + */
12700 +#define GEN9_ALIGN_1 0
12701 +#define GEN9_ALIGN_16 1
12703 +#define GEN9_ADDRESS_DIRECT 0
12704 +#define GEN9_ADDRESS_REGISTER_INDIRECT_REGISTER 1
12706 +#define GEN9_CHANNEL_X 0
12707 +#define GEN9_CHANNEL_Y 1
12708 +#define GEN9_CHANNEL_Z 2
12709 +#define GEN9_CHANNEL_W 3
12711 +#define GEN9_COMPRESSION_NONE 0
12712 +#define GEN9_COMPRESSION_2NDHALF 1
12713 +#define GEN9_COMPRESSION_COMPRESSED 2
12715 +#define GEN9_CONDITIONAL_NONE 0
12716 +#define GEN9_CONDITIONAL_Z 1
12717 +#define GEN9_CONDITIONAL_NZ 2
12718 +#define GEN9_CONDITIONAL_EQ 1 /* Z */
12719 +#define GEN9_CONDITIONAL_NEQ 2 /* NZ */
12720 +#define GEN9_CONDITIONAL_G 3
12721 +#define GEN9_CONDITIONAL_GE 4
12722 +#define GEN9_CONDITIONAL_L 5
12723 +#define GEN9_CONDITIONAL_LE 6
12724 +#define GEN9_CONDITIONAL_C 7
12725 +#define GEN9_CONDITIONAL_O 8
12727 +#define GEN9_DEBUG_NONE 0
12728 +#define GEN9_DEBUG_BREAKPOINT 1
12730 +#define GEN9_DEPENDENCY_NORMAL 0
12731 +#define GEN9_DEPENDENCY_NOTCLEARED 1
12732 +#define GEN9_DEPENDENCY_NOTCHECKED 2
12733 +#define GEN9_DEPENDENCY_DISABLE 3
12735 +#define GEN9_EXECUTE_1 0
12736 +#define GEN9_EXECUTE_2 1
12737 +#define GEN9_EXECUTE_4 2
12738 +#define GEN9_EXECUTE_8 3
12739 +#define GEN9_EXECUTE_16 4
12740 +#define GEN9_EXECUTE_32 5
12742 +#define GEN9_HORIZONTAL_STRIDE_0 0
12743 +#define GEN9_HORIZONTAL_STRIDE_1 1
12744 +#define GEN9_HORIZONTAL_STRIDE_2 2
12745 +#define GEN9_HORIZONTAL_STRIDE_4 3
12747 +#define GEN9_INSTRUCTION_NORMAL 0
12748 +#define GEN9_INSTRUCTION_SATURATE 1
12750 +#define GEN9_OPCODE_MOV 1
12751 +#define GEN9_OPCODE_SEL 2
12752 +#define GEN9_OPCODE_NOT 4
12753 +#define GEN9_OPCODE_AND 5
12754 +#define GEN9_OPCODE_OR 6
12755 +#define GEN9_OPCODE_XOR 7
12756 +#define GEN9_OPCODE_SHR 8
12757 +#define GEN9_OPCODE_SHL 9
12758 +#define GEN9_OPCODE_RSR 10
12759 +#define GEN9_OPCODE_RSL 11
12760 +#define GEN9_OPCODE_ASR 12
12761 +#define GEN9_OPCODE_CMP 16
12762 +#define GEN9_OPCODE_JMPI 32
12763 +#define GEN9_OPCODE_IF 34
12764 +#define GEN9_OPCODE_IFF 35
12765 +#define GEN9_OPCODE_ELSE 36
12766 +#define GEN9_OPCODE_ENDIF 37
12767 +#define GEN9_OPCODE_DO 38
12768 +#define GEN9_OPCODE_WHILE 39
12769 +#define GEN9_OPCODE_BREAK 40
12770 +#define GEN9_OPCODE_CONTINUE 41
12771 +#define GEN9_OPCODE_HALT 42
12772 +#define GEN9_OPCODE_MSAVE 44
12773 +#define GEN9_OPCODE_MRESTORE 45
12774 +#define GEN9_OPCODE_PUSH 46
12775 +#define GEN9_OPCODE_POP 47
12776 +#define GEN9_OPCODE_WAIT 48
12777 +#define GEN9_OPCODE_SEND 49
12778 +#define GEN9_OPCODE_ADD 64
12779 +#define GEN9_OPCODE_MUL 65
12780 +#define GEN9_OPCODE_AVG 66
12781 +#define GEN9_OPCODE_FRC 67
12782 +#define GEN9_OPCODE_RNDU 68
12783 +#define GEN9_OPCODE_RNDD 69
12784 +#define GEN9_OPCODE_RNDE 70
12785 +#define GEN9_OPCODE_RNDZ 71
12786 +#define GEN9_OPCODE_MAC 72
12787 +#define GEN9_OPCODE_MACH 73
12788 +#define GEN9_OPCODE_LZD 74
12789 +#define GEN9_OPCODE_SAD2 80
12790 +#define GEN9_OPCODE_SADA2 81
12791 +#define GEN9_OPCODE_DP4 84
12792 +#define GEN9_OPCODE_DPH 85
12793 +#define GEN9_OPCODE_DP3 86
12794 +#define GEN9_OPCODE_DP2 87
12795 +#define GEN9_OPCODE_DPA2 88
12796 +#define GEN9_OPCODE_LINE 89
12797 +#define GEN9_OPCODE_NOP 126
12799 +#define GEN9_PREDICATE_NONE 0
12800 +#define GEN9_PREDICATE_NORMAL 1
12801 +#define GEN9_PREDICATE_ALIGN1_ANYV 2
12802 +#define GEN9_PREDICATE_ALIGN1_ALLV 3
12803 +#define GEN9_PREDICATE_ALIGN1_ANY2H 4
12804 +#define GEN9_PREDICATE_ALIGN1_ALL2H 5
12805 +#define GEN9_PREDICATE_ALIGN1_ANY4H 6
12806 +#define GEN9_PREDICATE_ALIGN1_ALL4H 7
12807 +#define GEN9_PREDICATE_ALIGN1_ANY8H 8
12808 +#define GEN9_PREDICATE_ALIGN1_ALL8H 9
12809 +#define GEN9_PREDICATE_ALIGN1_ANY16H 10
12810 +#define GEN9_PREDICATE_ALIGN1_ALL16H 11
12811 +#define GEN9_PREDICATE_ALIGN16_REPLICATE_X 2
12812 +#define GEN9_PREDICATE_ALIGN16_REPLICATE_Y 3
12813 +#define GEN9_PREDICATE_ALIGN16_REPLICATE_Z 4
12814 +#define GEN9_PREDICATE_ALIGN16_REPLICATE_W 5
12815 +#define GEN9_PREDICATE_ALIGN16_ANY4H 6
12816 +#define GEN9_PREDICATE_ALIGN16_ALL4H 7
12818 +#define GEN9_ARCHITECTURE_REGISTER_FILE 0
12819 +#define GEN9_GENERAL_REGISTER_FILE 1
12820 +#define GEN9_MESSAGE_REGISTER_FILE 2
12821 +#define GEN9_IMMEDIATE_VALUE 3
12823 +#define GEN9_REGISTER_TYPE_UD 0
12824 +#define GEN9_REGISTER_TYPE_D 1
12825 +#define GEN9_REGISTER_TYPE_UW 2
12826 +#define GEN9_REGISTER_TYPE_W 3
12827 +#define GEN9_REGISTER_TYPE_UB 4
12828 +#define GEN9_REGISTER_TYPE_B 5
12829 +#define GEN9_REGISTER_TYPE_VF 5 /* packed float vector, immediates only? */
12830 +#define GEN9_REGISTER_TYPE_HF 6
12831 +#define GEN9_REGISTER_TYPE_V 6 /* packed int vector, immediates only, uword dest only */
12832 +#define GEN9_REGISTER_TYPE_F 7
12834 +#define GEN9_ARF_NULL 0x00
12835 +#define GEN9_ARF_ADDRESS 0x10
12836 +#define GEN9_ARF_ACCUMULATOR 0x20
12837 +#define GEN9_ARF_FLAG 0x30
12838 +#define GEN9_ARF_MASK 0x40
12839 +#define GEN9_ARF_MASK_STACK 0x50
12840 +#define GEN9_ARF_MASK_STACK_DEPTH 0x60
12841 +#define GEN9_ARF_STATE 0x70
12842 +#define GEN9_ARF_CONTROL 0x80
12843 +#define GEN9_ARF_NOTIFICATION_COUNT 0x90
12844 +#define GEN9_ARF_IP 0xA0
12846 +#define GEN9_AMASK 0
12847 +#define GEN9_IMASK 1
12848 +#define GEN9_LMASK 2
12849 +#define GEN9_CMASK 3
12851 +#define GEN9_THREAD_NORMAL 0
12852 +#define GEN9_THREAD_ATOMIC 1
12853 +#define GEN9_THREAD_SWITCH 2
12855 +#define GEN9_VERTICAL_STRIDE_0 0
12856 +#define GEN9_VERTICAL_STRIDE_1 1
12857 +#define GEN9_VERTICAL_STRIDE_2 2
12858 +#define GEN9_VERTICAL_STRIDE_4 3
12859 +#define GEN9_VERTICAL_STRIDE_8 4
12860 +#define GEN9_VERTICAL_STRIDE_16 5
12861 +#define GEN9_VERTICAL_STRIDE_32 6
12862 +#define GEN9_VERTICAL_STRIDE_64 7
12863 +#define GEN9_VERTICAL_STRIDE_128 8
12864 +#define GEN9_VERTICAL_STRIDE_256 9
12865 +#define GEN9_VERTICAL_STRIDE_ONE_DIMENSIONAL 0xF
12867 +#define GEN9_WIDTH_1 0
12868 +#define GEN9_WIDTH_2 1
12869 +#define GEN9_WIDTH_4 2
12870 +#define GEN9_WIDTH_8 3
12871 +#define GEN9_WIDTH_16 4
12873 +#define GEN9_STATELESS_BUFFER_BOUNDARY_1K 0
12874 +#define GEN9_STATELESS_BUFFER_BOUNDARY_2K 1
12875 +#define GEN9_STATELESS_BUFFER_BOUNDARY_4K 2
12876 +#define GEN9_STATELESS_BUFFER_BOUNDARY_8K 3
12877 +#define GEN9_STATELESS_BUFFER_BOUNDARY_16K 4
12878 +#define GEN9_STATELESS_BUFFER_BOUNDARY_32K 5
12879 +#define GEN9_STATELESS_BUFFER_BOUNDARY_64K 6
12880 +#define GEN9_STATELESS_BUFFER_BOUNDARY_128K 7
12881 +#define GEN9_STATELESS_BUFFER_BOUNDARY_256K 8
12882 +#define GEN9_STATELESS_BUFFER_BOUNDARY_512K 9
12883 +#define GEN9_STATELESS_BUFFER_BOUNDARY_1M 10
12884 +#define GEN9_STATELESS_BUFFER_BOUNDARY_2M 11
12886 +#define GEN9_POLYGON_FACING_FRONT 0
12887 +#define GEN9_POLYGON_FACING_BACK 1
12889 +#define GEN9_MESSAGE_TARGET_NULL 0
12890 +#define GEN9_MESSAGE_TARGET_MATH 1
12891 +#define GEN9_MESSAGE_TARGET_SAMPLER 2
12892 +#define GEN9_MESSAGE_TARGET_GATEWAY 3
12893 +#define GEN9_MESSAGE_TARGET_DATAPORT_READ 4
12894 +#define GEN9_MESSAGE_TARGET_DATAPORT_WRITE 5
12895 +#define GEN9_MESSAGE_TARGET_URB 6
12896 +#define GEN9_MESSAGE_TARGET_THREAD_SPAWNER 7
12898 +#define GEN9_SAMPLER_RETURN_FORMAT_FLOAT32 0
12899 +#define GEN9_SAMPLER_RETURN_FORMAT_UINT32 2
12900 +#define GEN9_SAMPLER_RETURN_FORMAT_SINT32 3
12902 +#define GEN9_SAMPLER_MESSAGE_SIMD8_SAMPLE 0
12903 +#define GEN9_SAMPLER_MESSAGE_SIMD16_SAMPLE 0
12904 +#define GEN9_SAMPLER_MESSAGE_SIMD16_SAMPLE_BIAS 0
12905 +#define GEN9_SAMPLER_MESSAGE_SIMD8_KILLPIX 1
12906 +#define GEN9_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_LOD 1
12907 +#define GEN9_SAMPLER_MESSAGE_SIMD16_SAMPLE_LOD 1
12908 +#define GEN9_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_GRADIENTS 2
12909 +#define GEN9_SAMPLER_MESSAGE_SIMD8_SAMPLE_GRADIENTS 2
12910 +#define GEN9_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_COMPARE 0
12911 +#define GEN9_SAMPLER_MESSAGE_SIMD16_SAMPLE_COMPARE 2
12912 +#define GEN9_SAMPLER_MESSAGE_SIMD4X2_RESINFO 2
12913 +#define GEN9_SAMPLER_MESSAGE_SIMD8_RESINFO 2
12914 +#define GEN9_SAMPLER_MESSAGE_SIMD16_RESINFO 2
12915 +#define GEN9_SAMPLER_MESSAGE_SIMD4X2_LD 3
12916 +#define GEN9_SAMPLER_MESSAGE_SIMD8_LD 3
12917 +#define GEN9_SAMPLER_MESSAGE_SIMD16_LD 3
12919 +#define GEN9_DATAPORT_OWORD_BLOCK_1_OWORDLOW 0
12920 +#define GEN9_DATAPORT_OWORD_BLOCK_1_OWORDHIGH 1
12921 +#define GEN9_DATAPORT_OWORD_BLOCK_2_OWORDS 2
12922 +#define GEN9_DATAPORT_OWORD_BLOCK_4_OWORDS 3
12923 +#define GEN9_DATAPORT_OWORD_BLOCK_8_OWORDS 4
12925 +#define GEN9_DATAPORT_OWORD_DUAL_BLOCK_1OWORD 0
12926 +#define GEN9_DATAPORT_OWORD_DUAL_BLOCK_4OWORDS 2
12928 +#define GEN9_DATAPORT_DWORD_SCATTERED_BLOCK_8DWORDS 2
12929 +#define GEN9_DATAPORT_DWORD_SCATTERED_BLOCK_16DWORDS 3
12931 +#define GEN9_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ 0
12932 +#define GEN9_DATAPORT_READ_MESSAGE_OWORD_DUAL_BLOCK_READ 1
12933 +#define GEN9_DATAPORT_READ_MESSAGE_DWORD_BLOCK_READ 2
12934 +#define GEN9_DATAPORT_READ_MESSAGE_DWORD_SCATTERED_READ 3
12936 +#define GEN9_DATAPORT_READ_TARGET_DATA_CACHE 0
12937 +#define GEN9_DATAPORT_READ_TARGET_RENDER_CACHE 1
12938 +#define GEN9_DATAPORT_READ_TARGET_SAMPLER_CACHE 2
12940 +#define GEN9_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE 0
12941 +#define GEN9_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE_REPLICATED 1
12942 +#define GEN9_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN01 2
12943 +#define GEN9_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN23 3
12944 +#define GEN9_DATAPORT_RENDER_TARGET_WRITE_SIMD8_SINGLE_SOURCE_SUBSPAN01 4
12946 +#define GEN9_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE 0
12947 +#define GEN9_DATAPORT_WRITE_MESSAGE_OWORD_DUAL_BLOCK_WRITE 1
12948 +#define GEN9_DATAPORT_WRITE_MESSAGE_DWORD_BLOCK_WRITE 2
12949 +#define GEN9_DATAPORT_WRITE_MESSAGE_DWORD_SCATTERED_WRITE 3
12950 +#define GEN9_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE 4
12951 +#define GEN9_DATAPORT_WRITE_MESSAGE_STREAMED_VERTEX_BUFFER_WRITE 5
12952 +#define GEN9_DATAPORT_WRITE_MESSAGE_FLUSH_RENDER_CACHE 7
12954 +#define GEN9_MATH_FUNCTION_INV 1
12955 +#define GEN9_MATH_FUNCTION_LOG 2
12956 +#define GEN9_MATH_FUNCTION_EXP 3
12957 +#define GEN9_MATH_FUNCTION_SQRT 4
12958 +#define GEN9_MATH_FUNCTION_RSQ 5
12959 +#define GEN9_MATH_FUNCTION_SIN 6 /* was 7 */
12960 +#define GEN9_MATH_FUNCTION_COS 7 /* was 8 */
12961 +#define GEN9_MATH_FUNCTION_SINCOS 8 /* was 6 */
12962 +#define GEN9_MATH_FUNCTION_TAN 9
12963 +#define GEN9_MATH_FUNCTION_POW 10
12964 +#define GEN9_MATH_FUNCTION_INT_DIV_QUOTIENT_AND_REMAINDER 11
12965 +#define GEN9_MATH_FUNCTION_INT_DIV_QUOTIENT 12
12966 +#define GEN9_MATH_FUNCTION_INT_DIV_REMAINDER 13
12968 +#define GEN9_MATH_INTEGER_UNSIGNED 0
12969 +#define GEN9_MATH_INTEGER_SIGNED 1
12971 +#define GEN9_MATH_PRECISION_FULL 0
12972 +#define GEN9_MATH_PRECISION_PARTIAL 1
12974 +#define GEN9_MATH_SATURATE_NONE 0
12975 +#define GEN9_MATH_SATURATE_SATURATE 1
12977 +#define GEN9_MATH_DATA_VECTOR 0
12978 +#define GEN9_MATH_DATA_SCALAR 1
12980 +#define GEN9_URB_OPCODE_WRITE 0
12982 +#define GEN9_URB_SWIZZLE_NONE 0
12983 +#define GEN9_URB_SWIZZLE_INTERLEAVE 1
12984 +#define GEN9_URB_SWIZZLE_TRANSPOSE 2
12986 +#define GEN9_SCRATCH_SPACE_SIZE_1K 0
12987 +#define GEN9_SCRATCH_SPACE_SIZE_2K 1
12988 +#define GEN9_SCRATCH_SPACE_SIZE_4K 2
12989 +#define GEN9_SCRATCH_SPACE_SIZE_8K 3
12990 +#define GEN9_SCRATCH_SPACE_SIZE_16K 4
12991 +#define GEN9_SCRATCH_SPACE_SIZE_32K 5
12992 +#define GEN9_SCRATCH_SPACE_SIZE_64K 6
12993 +#define GEN9_SCRATCH_SPACE_SIZE_128K 7
12994 +#define GEN9_SCRATCH_SPACE_SIZE_256K 8
12995 +#define GEN9_SCRATCH_SPACE_SIZE_512K 9
12996 +#define GEN9_SCRATCH_SPACE_SIZE_1M 10
12997 +#define GEN9_SCRATCH_SPACE_SIZE_2M 11
12999 +struct gen9_blend_state {
13000 + struct {
13001 + /* 00 */ uint32_t pad:19;
13002 + /* 19 */ uint32_t y_dither_offset:2;
13003 + /* 21 */ uint32_t x_dither_offset:2;
13004 + /* 23 */ uint32_t color_dither_enable:1;
13005 + /* 24 */ uint32_t alpha_test_function:3;
13006 + /* 27 */ uint32_t alpha_test:1;
13007 + /* 28 */ uint32_t alpha_to_coverage_dither:1;
13008 + /* 29 */ uint32_t alpha_to_one:1;
13009 + /* 30 */ uint32_t ia_blend:1;
13010 + /* 31 */ uint32_t alpha_to_coverage:1;
13011 + } common;
13013 + struct {
13014 + /* 00 */ uint32_t write_disable_blue:1;
13015 + /* 01 */ uint32_t write_disable_green:1;
13016 + /* 02 */ uint32_t write_disable_red:1;
13017 + /* 03 */ uint32_t write_disable_alpha:1;
13018 + /* 04 */ uint32_t pad0:1;
13019 + /* 05 */ uint32_t alpha_blend_function:3;
13020 + /* 08 */ uint32_t dest_alpha_blend_factor:5;
13021 + /* 13 */ uint32_t source_alpha_blend_factor:5;
13022 + /* 18 */ uint32_t color_blend_function:3;
13023 + /* 21 */ uint32_t dest_blend_factor:5;
13024 + /* 26 */ uint32_t source_blend_factor:5;
13025 + /* 31 */ uint32_t color_blend:1;
13026 + /* 32 */ uint32_t post_blend_clamp:1;
13027 + /* 33 */ uint32_t pre_blend_clamp:1;
13028 + /* 34 */ uint32_t color_clamp_range:2;
13029 + /* 36 */ uint32_t pre_blend_source_only_clamp:1;
13030 + /* 37 */ uint32_t pad1:22;
13031 + /* 59 */ uint32_t logic_op_function:4;
13032 + /* 63 */ uint32_t logic_op:1;
13033 + } rt;
13034 +};
13036 +struct gen9_color_calc_state {
13037 + struct {
13038 + /* 00 */ uint32_t alpha_test_format:1;
13039 + /* 01 */ uint32_t pad0:14;
13040 + /* 15 */ uint32_t round_disable:1;
13041 + /* 16 */ uint32_t bf_stencil_ref:8;
13042 + /* 24 */ uint32_t stencil_ref:8;
13043 + } cc0;
13045 + union {
13046 + float alpha_ref_f;
13047 + struct {
13048 + uint32_t ui:8;
13049 + uint32_t pad0:24;
13050 + } alpha_ref_fi;
13051 + } cc1;
13053 + float constant_r;
13054 + float constant_g;
13055 + float constant_b;
13056 + float constant_a;
13057 +};
13059 +struct gen9_sampler_state {
13060 + struct {
13061 + /* 00 */ unsigned int aniso_algorithm:1;
13062 + /* 01 */ unsigned int lod_bias:13;
13063 + /* 14 */ unsigned int min_filter:3;
13064 + /* 17 */ unsigned int mag_filter:3;
13065 + /* 20 */ unsigned int mip_filter:2;
13066 + /* 22 */ unsigned int base_level:5;
13067 + /* 27 */ unsigned int lod_preclamp:2;
13068 + /* 29 */ unsigned int default_color_mode:1;
13069 + /* 30 */ unsigned int flexible_filter_clamp:1;
13070 + /* 31 */ unsigned int disable:1;
13071 + } ss0;
13073 + struct {
13074 + /* 00 */ unsigned int cube_control_mode:1;
13075 + /* 01 */ unsigned int shadow_function:3;
13076 + /* 04 */ unsigned int chroma_key_mode:1;
13077 + /* 05 */ unsigned int chroma_key_index:2;
13078 + /* 07 */ unsigned int chroma_key_enable:1;
13079 + /* 08 */ unsigned int max_lod:12;
13080 + /* 20 */ unsigned int min_lod:12;
13081 + } ss1;
13083 + struct {
13084 + unsigned int pad:6;
13085 + unsigned int default_color_pointer:26;
13086 + } ss2;
13088 + struct {
13089 + /* 00 */ unsigned int r_wrap_mode:3;
13090 + /* 03 */ unsigned int t_wrap_mode:3;
13091 + /* 06 */ unsigned int s_wrap_mode:3;
13092 + /* 09 */ unsigned int pad:1;
13093 + /* 10 */ unsigned int non_normalized_coord:1;
13094 + /* 11 */ unsigned int trilinear_quality:2;
13095 + /* 13 */ unsigned int address_round:6;
13096 + /* 19 */ unsigned int max_aniso:3;
13097 + /* 22 */ unsigned int pad0:2;
13098 + /* 24 */ unsigned int non_separable_filter:8;
13099 + } ss3;
13100 +};
13102 +/* Surface state DW0 */
13103 +#define SURFACE_RC_READ_WRITE (1 << 8)
13104 +#define SURFACE_TILED (1 << 13)
13105 +#define SURFACE_TILED_Y (1 << 12)
13106 +#define SURFACE_FORMAT_SHIFT 18
13107 +#define SURFACE_VALIGN_1 (0 << 16) /* reserved! */
13108 +#define SURFACE_VALIGN_4 (1 << 16)
13109 +#define SURFACE_VALIGN_8 (2 << 16)
13110 +#define SURFACE_VALIGN_16 (3 << 16)
13111 +#define SURFACE_HALIGN_1 (0 << 14) /* reserved! */
13112 +#define SURFACE_HALIGN_4 (1 << 14)
13113 +#define SURFACE_HALIGN_8 (2 << 14)
13114 +#define SURFACE_HALIGN_16 (3 << 14)
13115 +#define SURFACE_TYPE_SHIFT 29
13117 +/* Surface state DW2 */
13118 +#define SURFACE_HEIGHT_SHIFT 16
13119 +#define SURFACE_WIDTH_SHIFT 0
13121 +/* Surface state DW3 */
13122 +#define SURFACE_DEPTH_SHIFT 21
13123 +#define SURFACE_PITCH_SHIFT 0
13125 +#define SWIZZLE_ZERO 0
13126 +#define SWIZZLE_ONE 1
13127 +#define SWIZZLE_RED 4
13128 +#define SWIZZLE_GREEN 5
13129 +#define SWIZZLE_BLUE 6
13130 +#define SWIZZLE_ALPHA 7
13131 +#define __SURFACE_SWIZZLE(r,g,b,a) \
13132 + ((a) << 16 | (b) << 19 | (g) << 22 | (r) << 25)
13133 +#define SURFACE_SWIZZLE(r,g,b,a) \
13134 + __SURFACE_SWIZZLE(SWIZZLE_##r, SWIZZLE_##g, SWIZZLE_##b, SWIZZLE_##a)
13136 +typedef enum {
13137 + SAMPLER_FILTER_NEAREST = 0,
13138 + SAMPLER_FILTER_BILINEAR,
13139 + FILTER_COUNT
13140 +} sampler_filter_t;
13142 +typedef enum {
13143 + SAMPLER_EXTEND_NONE = 0,
13144 + SAMPLER_EXTEND_REPEAT,
13145 + SAMPLER_EXTEND_PAD,
13146 + SAMPLER_EXTEND_REFLECT,
13147 + EXTEND_COUNT
13148 +} sampler_extend_t;
13150 +#endif
13151 diff --git a/src/sna/kgem.c b/src/sna/kgem.c
13152 index 78ed5407..f0d171ac 100644
13153 --- a/src/sna/kgem.c
13154 +++ b/src/sna/kgem.c
13155 @@ -84,6 +84,10 @@ search_snoop_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags);
13156 #define DBG_NO_HANDLE_LUT 0
13157 #define DBG_NO_WT 0
13158 #define DBG_NO_WC_MMAP 0
13159 +#define DBG_NO_BLT_Y 0
13160 +#define DBG_NO_SCANOUT_Y 0
13161 +#define DBG_NO_DIRTYFB 0
13162 +#define DBG_NO_DETILING 0
13163 #define DBG_DUMP 0
13164 #define DBG_NO_MALLOC_CACHE 0
13166 @@ -96,11 +100,6 @@ search_snoop_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags);
13167 #define SHOW_BATCH_BEFORE 0
13168 #define SHOW_BATCH_AFTER 0
13170 -#if !USE_WC_MMAP
13171 -#undef DBG_NO_WC_MMAP
13172 -#define DBG_NO_WC_MMAP 1
13173 -#endif
13175 #if 0
13176 #define ASSERT_IDLE(kgem__, handle__) assert(!__kgem_busy(kgem__, handle__))
13177 #define ASSERT_MAYBE_IDLE(kgem__, handle__, expect__) assert(!(expect__) || !__kgem_busy(kgem__, handle__))
13178 @@ -187,6 +186,15 @@ struct local_i915_gem_caching {
13179 #define LOCAL_IOCTL_I915_GEM_SET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_SET_CACHING, struct local_i915_gem_caching)
13180 #define LOCAL_IOCTL_I915_GEM_GET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_GET_CACHING, struct local_i915_gem_caching)
13182 +struct local_i915_gem_mmap {
13183 + uint32_t handle;
13184 + uint32_t pad;
13185 + uint64_t offset;
13186 + uint64_t size;
13187 + uint64_t addr_ptr;
13188 +};
13189 +#define LOCAL_IOCTL_I915_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP, struct local_i915_gem_mmap)
13191 struct local_i915_gem_mmap2 {
13192 uint32_t handle;
13193 uint32_t pad;
13194 @@ -216,6 +224,12 @@ static struct kgem_bo *__kgem_freed_bo;
13195 static struct kgem_request *__kgem_freed_request;
13196 static struct drm_i915_gem_exec_object2 _kgem_dummy_exec;
13198 +static inline struct sna *__to_sna(struct kgem *kgem)
13199 +{
13200 + /* minor layering violations */
13201 + return container_of(kgem, struct sna, kgem);
13202 +}
13204 static inline int bytes(struct kgem_bo *bo)
13206 return __kgem_bo_size(bo);
13207 @@ -224,25 +238,31 @@ static inline int bytes(struct kgem_bo *bo)
13208 #define bucket(B) (B)->size.pages.bucket
13209 #define num_pages(B) (B)->size.pages.count
13211 -static int do_ioctl(int fd, unsigned long req, void *arg)
13212 +static int __do_ioctl(int fd, unsigned long req, void *arg)
13214 - int err;
13216 -restart:
13217 - if (ioctl(fd, req, arg) == 0)
13218 - return 0;
13219 + do {
13220 + int err;
13222 - err = errno;
13223 + switch ((err = errno)) {
13224 + case EAGAIN:
13225 + sched_yield();
13226 + case EINTR:
13227 + break;
13228 + default:
13229 + return -err;
13230 + }
13232 - if (err == EINTR)
13233 - goto restart;
13234 + if (likely(ioctl(fd, req, arg) == 0))
13235 + return 0;
13236 + } while (1);
13237 +}
13239 - if (err == EAGAIN) {
13240 - sched_yield();
13241 - goto restart;
13242 - }
13243 +inline static int do_ioctl(int fd, unsigned long req, void *arg)
13244 +{
13245 + if (likely(ioctl(fd, req, arg) == 0))
13246 + return 0;
13248 - return -err;
13249 + return __do_ioctl(fd, req, arg);
13252 #ifdef DEBUG_MEMORY
13253 @@ -266,6 +286,9 @@ static void assert_tiling(struct kgem *kgem, struct kgem_bo *bo)
13255 assert(bo);
13257 + if (!kgem->can_fence && kgem->gen >= 040 && bo->tiling)
13258 + return; /* lies */
13260 VG_CLEAR(tiling);
13261 tiling.handle = bo->handle;
13262 tiling.tiling_mode = bo->tiling;
13263 @@ -273,7 +296,7 @@ static void assert_tiling(struct kgem *kgem, struct kgem_bo *bo)
13264 assert(tiling.tiling_mode == bo->tiling);
13267 -static void assert_cacheing(struct kgem *kgem, struct kgem_bo *bo)
13268 +static void assert_caching(struct kgem *kgem, struct kgem_bo *bo)
13270 struct local_i915_gem_caching arg;
13271 int expect = kgem->has_llc ? SNOOPED : UNCACHED;
13272 @@ -294,24 +317,117 @@ static void assert_bo_retired(struct kgem_bo *bo)
13273 assert(bo->refcnt);
13274 assert(bo->rq == NULL);
13275 assert(bo->exec == NULL);
13276 + assert(!bo->needs_flush);
13277 assert(list_is_empty(&bo->request));
13279 #else
13280 #define assert_tiling(kgem, bo)
13281 -#define assert_cacheing(kgem, bo)
13282 +#define assert_caching(kgem, bo)
13283 #define assert_bo_retired(bo)
13284 #endif
13286 +static int __find_debugfs(struct kgem *kgem)
13287 +{
13288 + int i;
13290 + for (i = 0; i < DRM_MAX_MINOR; i++) {
13291 + char path[80];
13293 + sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i);
13294 + if (access(path, R_OK) == 0)
13295 + return i;
13297 + sprintf(path, "/debug/dri/%d/i915_wedged", i);
13298 + if (access(path, R_OK) == 0)
13299 + return i;
13300 + }
13302 + return -1;
13303 +}
13305 +static int kgem_get_minor(struct kgem *kgem)
13306 +{
13307 + struct stat st;
13309 + if (fstat(kgem->fd, &st))
13310 + return __find_debugfs(kgem);
13312 + if (!S_ISCHR(st.st_mode))
13313 + return __find_debugfs(kgem);
13315 + return st.st_rdev & 0x63;
13316 +}
13318 +static bool find_hang_state(struct kgem *kgem, char *path, int maxlen)
13319 +{
13320 + int minor = kgem_get_minor(kgem);
13322 + /* Search for our hang state in a few canonical locations.
13323 + * In the unlikely event of having multiple devices, we
13324 + * will need to check which minor actually corresponds to ours.
13325 + */
13327 + snprintf(path, maxlen, "/sys/class/drm/card%d/error", minor);
13328 + if (access(path, R_OK) == 0)
13329 + return true;
13331 + snprintf(path, maxlen, "/sys/kernel/debug/dri/%d/i915_error_state", minor);
13332 + if (access(path, R_OK) == 0)
13333 + return true;
13335 + snprintf(path, maxlen, "/debug/dri/%d/i915_error_state", minor);
13336 + if (access(path, R_OK) == 0)
13337 + return true;
13339 + path[0] = '\0';
13340 + return false;
13341 +}
13343 +static bool has_error_state(struct kgem *kgem, char *path)
13344 +{
13345 + bool ret = false;
13346 + char no;
13347 + int fd;
13349 + fd = open(path, O_RDONLY);
13350 + if (fd >= 0) {
13351 + ret = read(fd, &no, 1) == 1 && no != 'N';
13352 + close(fd);
13353 + }
13355 + return ret;
13356 +}
13358 +static int kgem_get_screen_index(struct kgem *kgem)
13359 +{
13360 + return __to_sna(kgem)->scrn->scrnIndex;
13361 +}
13363 static void
13364 __kgem_set_wedged(struct kgem *kgem)
13366 + static int once;
13367 + char path[256];
13369 + if (kgem->wedged)
13370 + return;
13372 + if (!once &&
13373 + find_hang_state(kgem, path, sizeof(path)) &&
13374 + has_error_state(kgem, path)) {
13375 + xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
13376 + "When reporting this, please include %s and the full dmesg.\n",
13377 + path);
13378 + once = 1;
13379 + }
13381 kgem->wedged = true;
13382 - sna_render_mark_wedged(container_of(kgem, struct sna, kgem));
13383 + sna_render_mark_wedged(__to_sna(kgem));
13386 static void kgem_sna_reset(struct kgem *kgem)
13388 - struct sna *sna = container_of(kgem, struct sna, kgem);
13389 + struct sna *sna = __to_sna(kgem);
13391 sna->render.reset(sna);
13392 sna->blt_state.fill_bo = 0;
13393 @@ -319,7 +435,7 @@ static void kgem_sna_reset(struct kgem *kgem)
13395 static void kgem_sna_flush(struct kgem *kgem)
13397 - struct sna *sna = container_of(kgem, struct sna, kgem);
13398 + struct sna *sna = __to_sna(kgem);
13400 sna->render.flush(sna);
13402 @@ -327,22 +443,53 @@ static void kgem_sna_flush(struct kgem *kgem)
13403 sna_render_flush_solid(sna);
13406 -static bool gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
13407 +static bool kgem_bo_rmfb(struct kgem *kgem, struct kgem_bo *bo)
13408 +{
13409 + if (bo->scanout && bo->delta) {
13410 + DBG(("%s: releasing fb=%d for handle=%d\n",
13411 + __FUNCTION__, bo->delta, bo->handle));
13412 + /* XXX will leak if we are not DRM_MASTER. *shrug* */
13413 + do_ioctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &bo->delta);
13414 + bo->delta = 0;
13415 + return true;
13416 + } else
13417 + return false;
13418 +}
13420 +static bool kgem_set_tiling(struct kgem *kgem, struct kgem_bo *bo,
13421 + int tiling, int stride)
13423 struct drm_i915_gem_set_tiling set_tiling;
13424 int err;
13426 + if (tiling == bo->tiling) {
13427 + if (tiling == I915_TILING_NONE) {
13428 + bo->pitch = stride;
13429 + return true;
13430 + }
13431 + if (stride == bo->pitch)
13432 + return true;
13433 + }
13435 if (DBG_NO_TILING)
13436 return false;
13438 VG_CLEAR(set_tiling);
13439 restart:
13440 - set_tiling.handle = handle;
13441 + set_tiling.handle = bo->handle;
13442 set_tiling.tiling_mode = tiling;
13443 - set_tiling.stride = stride;
13444 + set_tiling.stride = tiling ? stride : 0;
13446 - if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0)
13447 - return true;
13448 + if (ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) {
13449 + bo->tiling = set_tiling.tiling_mode;
13450 + bo->pitch = set_tiling.tiling_mode ? set_tiling.stride : stride;
13451 + DBG(("%s: handle=%d, tiling=%d [%d], pitch=%d [%d]: %d\n",
13452 + __FUNCTION__, bo->handle,
13453 + bo->tiling, tiling,
13454 + bo->pitch, stride,
13455 + set_tiling.tiling_mode == tiling));
13456 + return set_tiling.tiling_mode == tiling;
13457 + }
13459 err = errno;
13460 if (err == EINTR)
13461 @@ -353,6 +500,11 @@ restart:
13462 goto restart;
13465 + if (err == EBUSY && kgem_bo_rmfb(kgem, bo))
13466 + goto restart;
13468 + ERR(("%s: failed to set-tiling(tiling=%d, pitch=%d) for handle=%d: %d\n",
13469 + __FUNCTION__, tiling, stride, bo->handle, err));
13470 return false;
13473 @@ -437,10 +589,15 @@ static void *__kgem_bo_map__gtt(struct kgem *kgem, struct kgem_bo *bo)
13474 DBG(("%s(handle=%d, size=%d)\n", __FUNCTION__,
13475 bo->handle, bytes(bo)));
13477 + if (bo->tiling && !kgem->can_fence)
13478 + return NULL;
13480 VG_CLEAR(gtt);
13481 retry_gtt:
13482 gtt.handle = bo->handle;
13483 if ((err = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &gtt))) {
13484 + DBG(("%s: failed %d, throttling/cleaning caches\n",
13485 + __FUNCTION__, err));
13486 assert(err != EINVAL);
13488 (void)__kgem_throttle_retire(kgem, 0);
13489 @@ -460,6 +617,8 @@ retry_mmap:
13490 kgem->fd, gtt.offset);
13491 if (ptr == MAP_FAILED) {
13492 err = errno;
13493 + DBG(("%s: failed %d, throttling/cleaning caches\n",
13494 + __FUNCTION__, err));
13495 assert(err != EINVAL);
13497 if (__kgem_throttle_retire(kgem, 0))
13498 @@ -498,6 +657,8 @@ retry_wc:
13499 wc.size = bytes(bo);
13500 wc.flags = I915_MMAP_WC;
13501 if ((err = do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_MMAP_v2, &wc))) {
13502 + DBG(("%s: failed %d, throttling/cleaning caches\n",
13503 + __FUNCTION__, err));
13504 assert(err != EINVAL);
13506 if (__kgem_throttle_retire(kgem, 0))
13507 @@ -519,16 +680,19 @@ retry_wc:
13509 static void *__kgem_bo_map__cpu(struct kgem *kgem, struct kgem_bo *bo)
13511 - struct drm_i915_gem_mmap mmap_arg;
13512 + struct local_i915_gem_mmap arg;
13513 int err;
13515 + VG_CLEAR(arg);
13516 + arg.offset = 0;
13518 retry:
13519 - VG_CLEAR(mmap_arg);
13520 - mmap_arg.handle = bo->handle;
13521 - mmap_arg.offset = 0;
13522 - mmap_arg.size = bytes(bo);
13523 - if ((err = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg))) {
13524 - assert(err != EINVAL);
13525 + arg.handle = bo->handle;
13526 + arg.size = bytes(bo);
13527 + if ((err = do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_MMAP, &arg))) {
13528 + DBG(("%s: failed %d, throttling/cleaning caches\n",
13529 + __FUNCTION__, err));
13530 + assert(err != -EINVAL || bo->prime);
13532 if (__kgem_throttle_retire(kgem, 0))
13533 goto retry;
13534 @@ -536,15 +700,16 @@ retry:
13535 if (kgem_cleanup_cache(kgem))
13536 goto retry;
13538 - ERR(("%s: failed to mmap handle=%d, %d bytes, into CPU domain: %d\n",
13539 - __FUNCTION__, bo->handle, bytes(bo), -err));
13540 + ERR(("%s: failed to mmap handle=%d (prime? %d), %d bytes, into CPU domain: %d\n",
13541 + __FUNCTION__, bo->handle, bo->prime, bytes(bo), -err));
13542 + bo->purged = 1;
13543 return NULL;
13546 - VG(VALGRIND_MAKE_MEM_DEFINED(mmap_arg.addr_ptr, bytes(bo)));
13547 + VG(VALGRIND_MAKE_MEM_DEFINED(arg.addr_ptr, bytes(bo)));
13549 DBG(("%s: caching CPU vma for %d\n", __FUNCTION__, bo->handle));
13550 - return bo->map__cpu = (void *)(uintptr_t)mmap_arg.addr_ptr;
13551 + return bo->map__cpu = (void *)(uintptr_t)arg.addr_ptr;
13554 static int gem_write(int fd, uint32_t handle,
13555 @@ -634,16 +799,10 @@ static void kgem_bo_retire(struct kgem *kgem, struct kgem_bo *bo)
13556 assert(bo->exec == NULL);
13557 assert(list_is_empty(&bo->vma));
13559 - if (bo->rq) {
13560 - __kgem_bo_clear_busy(bo);
13561 - kgem_retire(kgem);
13562 - assert_bo_retired(bo);
13563 - } else {
13564 - assert(bo->exec == NULL);
13565 - assert(list_is_empty(&bo->request));
13566 - assert(!bo->needs_flush);
13567 - ASSERT_IDLE(kgem, bo->handle);
13568 - }
13569 + if (bo->rq)
13570 + __kgem_retire_requests_upto(kgem, bo);
13571 + ASSERT_IDLE(kgem, bo->handle);
13572 + assert_bo_retired(bo);
13575 static void kgem_bo_maybe_retire(struct kgem *kgem, struct kgem_bo *bo)
13576 @@ -655,10 +814,8 @@ static void kgem_bo_maybe_retire(struct kgem *kgem, struct kgem_bo *bo)
13577 assert(list_is_empty(&bo->vma));
13579 if (bo->rq) {
13580 - if (!__kgem_busy(kgem, bo->handle)) {
13581 - __kgem_bo_clear_busy(bo);
13582 - kgem_retire(kgem);
13583 - }
13584 + if (!__kgem_busy(kgem, bo->handle))
13585 + __kgem_retire_requests_upto(kgem, bo);
13586 } else {
13587 assert(!bo->needs_flush);
13588 ASSERT_IDLE(kgem, bo->handle);
13589 @@ -694,6 +851,8 @@ retry:
13592 if ((err = gem_write(kgem->fd, bo->handle, 0, length, data))) {
13593 + DBG(("%s: failed %d, throttling/cleaning caches\n",
13594 + __FUNCTION__, err));
13595 assert(err != EINVAL);
13597 (void)__kgem_throttle_retire(kgem, 0);
13598 @@ -728,27 +887,21 @@ static uint32_t gem_create(int fd, int num_pages)
13599 return create.handle;
13602 -static bool
13603 +static void
13604 kgem_bo_set_purgeable(struct kgem *kgem, struct kgem_bo *bo)
13606 -#if DBG_NO_MADV
13607 - return true;
13608 -#else
13609 +#if !DBG_NO_MADV
13610 struct drm_i915_gem_madvise madv;
13612 assert(bo->exec == NULL);
13613 - assert(!bo->purged);
13615 VG_CLEAR(madv);
13616 madv.handle = bo->handle;
13617 madv.madv = I915_MADV_DONTNEED;
13618 if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) {
13619 - bo->purged = 1;
13620 - kgem->need_purge |= !madv.retained && bo->domain == DOMAIN_GPU;
13621 - return madv.retained;
13622 + bo->purged = true;
13623 + kgem->need_purge |= !madv.retained && bo->domain != DOMAIN_CPU;
13626 - return true;
13627 #endif
13630 @@ -788,7 +941,7 @@ kgem_bo_clear_purgeable(struct kgem *kgem, struct kgem_bo *bo)
13631 madv.madv = I915_MADV_WILLNEED;
13632 if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv) == 0) {
13633 bo->purged = !madv.retained;
13634 - kgem->need_purge |= !madv.retained && bo->domain == DOMAIN_GPU;
13635 + kgem->need_purge |= !madv.retained && bo->domain != DOMAIN_CPU;
13636 return madv.retained;
13639 @@ -869,13 +1022,17 @@ static struct kgem_request *__kgem_request_alloc(struct kgem *kgem)
13641 struct kgem_request *rq;
13643 - rq = __kgem_freed_request;
13644 - if (rq) {
13645 - __kgem_freed_request = *(struct kgem_request **)rq;
13646 + if (unlikely(kgem->wedged)) {
13647 + rq = &kgem->static_request;
13648 } else {
13649 - rq = malloc(sizeof(*rq));
13650 - if (rq == NULL)
13651 - rq = &kgem->static_request;
13652 + rq = __kgem_freed_request;
13653 + if (rq) {
13654 + __kgem_freed_request = *(struct kgem_request **)rq;
13655 + } else {
13656 + rq = malloc(sizeof(*rq));
13657 + if (rq == NULL)
13658 + rq = &kgem->static_request;
13659 + }
13662 list_init(&rq->buffers);
13663 @@ -925,11 +1082,11 @@ total_ram_size(void)
13664 #ifdef HAVE_STRUCT_SYSINFO_TOTALRAM
13665 struct sysinfo info;
13666 if (sysinfo(&info) == 0)
13667 - return info.totalram * info.mem_unit;
13668 + return (size_t)info.totalram * info.mem_unit;
13669 #endif
13671 #ifdef _SC_PHYS_PAGES
13672 - return sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGE_SIZE);
13673 + return (size_t)sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGE_SIZE);
13674 #endif
13676 return 0;
13677 @@ -1150,6 +1307,10 @@ static bool test_has_wc_mmap(struct kgem *kgem)
13678 if (DBG_NO_WC_MMAP)
13679 return false;
13681 + /* XXX See https://bugs.freedesktop.org/show_bug.cgi?id=90841 */
13682 + if (kgem->gen < 033)
13683 + return false;
13685 if (gem_param(kgem, LOCAL_I915_PARAM_MMAP_VERSION) < 1)
13686 return false;
13688 @@ -1187,7 +1348,7 @@ static bool test_has_caching(struct kgem *kgem)
13690 static bool test_has_userptr(struct kgem *kgem)
13692 - uint32_t handle;
13693 + struct local_i915_gem_userptr arg;
13694 void *ptr;
13696 if (DBG_NO_USERPTR)
13697 @@ -1200,11 +1361,23 @@ static bool test_has_userptr(struct kgem *kgem)
13698 if (posix_memalign(&ptr, PAGE_SIZE, PAGE_SIZE))
13699 return false;
13701 - handle = gem_userptr(kgem->fd, ptr, PAGE_SIZE, false);
13702 - gem_close(kgem->fd, handle);
13703 - free(ptr);
13704 + VG_CLEAR(arg);
13705 + arg.user_ptr = (uintptr_t)ptr;
13706 + arg.user_size = PAGE_SIZE;
13707 + arg.flags = I915_USERPTR_UNSYNCHRONIZED;
13709 - return handle != 0;
13710 + if (DBG_NO_UNSYNCHRONIZED_USERPTR ||
13711 + do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_USERPTR, &arg)) {
13712 + arg.flags &= ~I915_USERPTR_UNSYNCHRONIZED;
13713 + if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_USERPTR, &arg))
13714 + arg.handle = 0;
13715 + /* Leak the userptr bo to keep the mmu_notifier alive */
13716 + } else {
13717 + gem_close(kgem->fd, arg.handle);
13718 + free(ptr);
13719 + }
13721 + return arg.handle != 0;
13724 static bool test_has_create2(struct kgem *kgem)
13725 @@ -1227,67 +1400,187 @@ static bool test_has_create2(struct kgem *kgem)
13726 #endif
13729 -static bool test_has_secure_batches(struct kgem *kgem)
13730 +static bool test_can_blt_y(struct kgem *kgem)
13732 - if (DBG_NO_SECURE_BATCHES)
13733 + struct drm_i915_gem_exec_object2 object;
13734 + uint32_t batch[] = {
13735 +#define MI_LOAD_REGISTER_IMM (0x22<<23 | (3-2))
13736 +#define BCS_SWCTRL 0x22200
13737 +#define BCS_SRC_Y (1 << 0)
13738 +#define BCS_DST_Y (1 << 1)
13739 + MI_LOAD_REGISTER_IMM,
13740 + BCS_SWCTRL,
13741 + (BCS_SRC_Y | BCS_DST_Y) << 16 | (BCS_SRC_Y | BCS_DST_Y),
13743 + MI_LOAD_REGISTER_IMM,
13744 + BCS_SWCTRL,
13745 + (BCS_SRC_Y | BCS_DST_Y) << 16,
13747 + MI_BATCH_BUFFER_END,
13748 + 0,
13749 + };
13750 + int ret;
13752 + if (DBG_NO_BLT_Y)
13753 return false;
13755 - return gem_param(kgem, LOCAL_I915_PARAM_HAS_SECURE_BATCHES) > 0;
13756 + if (kgem->gen < 060)
13757 + return false;
13759 + memset(&object, 0, sizeof(object));
13760 + object.handle = gem_create(kgem->fd, 1);
13762 + ret = gem_write(kgem->fd, object.handle, 0, sizeof(batch), batch);
13763 + if (ret == 0) {
13764 + struct drm_i915_gem_execbuffer2 execbuf;
13766 + memset(&execbuf, 0, sizeof(execbuf));
13767 + execbuf.buffers_ptr = (uintptr_t)&object;
13768 + execbuf.buffer_count = 1;
13769 + execbuf.flags = KGEM_BLT;
13771 + ret = do_ioctl(kgem->fd,
13772 + DRM_IOCTL_I915_GEM_EXECBUFFER2,
13773 + &execbuf);
13774 + }
13775 + gem_close(kgem->fd, object.handle);
13777 + return ret == 0;
13780 -static bool test_has_pinned_batches(struct kgem *kgem)
13781 +static bool gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
13783 - if (DBG_NO_PINNED_BATCHES)
13784 + struct drm_i915_gem_set_tiling set_tiling;
13786 + if (DBG_NO_TILING)
13787 return false;
13789 - return gem_param(kgem, LOCAL_I915_PARAM_HAS_PINNED_BATCHES) > 0;
13790 + VG_CLEAR(set_tiling);
13791 + set_tiling.handle = handle;
13792 + set_tiling.tiling_mode = tiling;
13793 + set_tiling.stride = stride;
13795 + if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0)
13796 + return set_tiling.tiling_mode == tiling;
13798 + return false;
13801 -static int kgem_get_screen_index(struct kgem *kgem)
13802 +static bool test_can_scanout_y(struct kgem *kgem)
13804 - struct sna *sna = container_of(kgem, struct sna, kgem);
13805 - return sna->scrn->scrnIndex;
13806 + struct drm_mode_fb_cmd arg;
13807 + bool ret = false;
13809 + if (DBG_NO_SCANOUT_Y)
13810 + return false;
13812 + VG_CLEAR(arg);
13813 + arg.width = 32;
13814 + arg.height = 32;
13815 + arg.pitch = 4*32;
13816 + arg.bpp = 32;
13817 + arg.depth = 24;
13818 + arg.handle = gem_create(kgem->fd, 1);
13820 + if (gem_set_tiling(kgem->fd, arg.handle, I915_TILING_Y, arg.pitch))
13821 + ret = do_ioctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &arg) == 0;
13822 + if (!ret) {
13823 + struct local_mode_fb_cmd2 {
13824 + uint32_t fb_id;
13825 + uint32_t width, height;
13826 + uint32_t pixel_format;
13827 + uint32_t flags;
13829 + uint32_t handles[4];
13830 + uint32_t pitches[4];
13831 + uint32_t offsets[4];
13832 + uint64_t modifiers[4];
13833 + } f;
13834 +#define LOCAL_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct local_mode_fb_cmd2)
13835 + memset(&f, 0, sizeof(f));
13836 + f.width = arg.width;
13837 + f.height = arg.height;
13838 + f.handles[0] = arg.handle;
13839 + f.pitches[0] = arg.pitch;
13840 + f.modifiers[0] = (uint64_t)1 << 56 | 2; /* MOD_Y_TILED */
13841 + f.pixel_format = 'X' | 'R' << 8 | '2' << 16 | '4' << 24; /* XRGB8888 */
13842 + f.flags = 1 << 1; /* + modifier */
13843 + if (drmIoctl(kgem->fd, LOCAL_IOCTL_MODE_ADDFB2, &f) == 0) {
13844 + ret = true;
13845 + arg.fb_id = f.fb_id;
13846 + }
13847 + }
13848 + do_ioctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &arg.fb_id);
13849 + gem_close(kgem->fd, arg.handle);
13851 + return ret;
13854 -static int __find_debugfs(struct kgem *kgem)
13855 +static bool test_has_dirtyfb(struct kgem *kgem)
13857 - int i;
13858 + struct drm_mode_fb_cmd create;
13859 + bool ret = false;
13861 - for (i = 0; i < DRM_MAX_MINOR; i++) {
13862 - char path[80];
13863 + if (DBG_NO_DIRTYFB)
13864 + return false;
13866 - sprintf(path, "/sys/kernel/debug/dri/%d/i915_wedged", i);
13867 - if (access(path, R_OK) == 0)
13868 - return i;
13869 + VG_CLEAR(create);
13870 + create.width = 32;
13871 + create.height = 32;
13872 + create.pitch = 4*32;
13873 + create.bpp = 32;
13874 + create.depth = 32;
13875 + create.handle = gem_create(kgem->fd, 1);
13876 + if (create.handle == 0)
13877 + return false;
13879 - sprintf(path, "/debug/dri/%d/i915_wedged", i);
13880 - if (access(path, R_OK) == 0)
13881 - return i;
13882 + if (drmIoctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &create) == 0) {
13883 + struct drm_mode_fb_dirty_cmd dirty;
13885 + memset(&dirty, 0, sizeof(dirty));
13886 + dirty.fb_id = create.fb_id;
13887 + ret = drmIoctl(kgem->fd,
13888 + DRM_IOCTL_MODE_DIRTYFB,
13889 + &dirty) == 0;
13891 + /* XXX There may be multiple levels of DIRTYFB, depending on
13892 + * whether the kernel thinks tracking dirty regions is
13893 + * beneficial vs flagging the whole fb as dirty.
13894 + */
13896 + drmIoctl(kgem->fd,
13897 + DRM_IOCTL_MODE_RMFB,
13898 + &create.fb_id);
13900 + gem_close(kgem->fd, create.handle);
13902 - return -1;
13903 + return ret;
13906 -static int kgem_get_minor(struct kgem *kgem)
13907 +static bool test_has_secure_batches(struct kgem *kgem)
13909 - struct stat st;
13910 + if (DBG_NO_SECURE_BATCHES)
13911 + return false;
13913 - if (fstat(kgem->fd, &st))
13914 - return __find_debugfs(kgem);
13915 + return gem_param(kgem, LOCAL_I915_PARAM_HAS_SECURE_BATCHES) > 0;
13916 +}
13918 - if (!S_ISCHR(st.st_mode))
13919 - return __find_debugfs(kgem);
13920 +static bool test_has_pinned_batches(struct kgem *kgem)
13921 +{
13922 + if (DBG_NO_PINNED_BATCHES)
13923 + return false;
13925 - return st.st_rdev & 0x63;
13926 + return gem_param(kgem, LOCAL_I915_PARAM_HAS_PINNED_BATCHES) > 0;
13929 static bool kgem_init_pinned_batches(struct kgem *kgem)
13931 int count[2] = { 16, 4 };
13932 int size[2] = { 1, 4 };
13933 + int ret = 0;
13934 int n, i;
13936 - if (kgem->wedged)
13937 + if (unlikely(kgem->wedged))
13938 return true;
13940 for (n = 0; n < ARRAY_SIZE(count); n++) {
13941 @@ -1311,7 +1604,8 @@ static bool kgem_init_pinned_batches(struct kgem *kgem)
13944 pin.alignment = 0;
13945 - if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_PIN, &pin)) {
13946 + ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_PIN, &pin);
13947 + if (ret) {
13948 gem_close(kgem->fd, pin.handle);
13949 free(bo);
13950 goto err;
13951 @@ -1333,6 +1627,16 @@ err:
13955 + /* If we fail to pin some memory for 830gm/845g, we need to disable
13956 + * acceleration as otherwise the machine will eventually fail. However,
13957 + * the kernel started arbitrarily rejecting PIN, so hope for the best
13958 + * if the ioctl no longer works.
13959 + */
13960 + if (ret != -ENODEV && kgem->gen == 020)
13961 + return false;
13963 + kgem->has_pinned_batches = false;
13965 /* For simplicity populate the lists with a single unpinned bo */
13966 for (n = 0; n < ARRAY_SIZE(count); n++) {
13967 struct kgem_bo *bo;
13968 @@ -1340,18 +1644,18 @@ err:
13970 handle = gem_create(kgem->fd, size[n]);
13971 if (handle == 0)
13972 - break;
13973 + return false;
13975 bo = __kgem_bo_alloc(handle, size[n]);
13976 if (bo == NULL) {
13977 gem_close(kgem->fd, handle);
13978 - break;
13979 + return false;
13982 debug_alloc__bo(kgem, bo);
13983 list_add(&bo->list, &kgem->pinned_batches[n]);
13985 - return false;
13986 + return true;
13989 static void kgem_init_swizzling(struct kgem *kgem)
13990 @@ -1364,7 +1668,7 @@ static void kgem_init_swizzling(struct kgem *kgem)
13991 } tiling;
13992 #define LOCAL_IOCTL_I915_GEM_GET_TILING DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct local_i915_gem_get_tiling_v2)
13994 - VG_CLEAR(tiling);
13995 + memset(&tiling, 0, sizeof(tiling));
13996 tiling.handle = gem_create(kgem->fd, 1);
13997 if (!tiling.handle)
13998 return;
13999 @@ -1375,12 +1679,23 @@ static void kgem_init_swizzling(struct kgem *kgem)
14000 if (do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_GET_TILING, &tiling))
14001 goto out;
14003 - if (kgem->gen < 50 && tiling.phys_swizzle_mode != tiling.swizzle_mode)
14004 + DBG(("%s: swizzle_mode=%d, phys_swizzle_mode=%d\n",
14005 + __FUNCTION__, tiling.swizzle_mode, tiling.phys_swizzle_mode));
14007 + kgem->can_fence =
14008 + !DBG_NO_TILING &&
14009 + tiling.swizzle_mode != I915_BIT_6_SWIZZLE_UNKNOWN;
14011 + if (kgem->gen < 050 && tiling.phys_swizzle_mode != tiling.swizzle_mode)
14012 goto out;
14014 - choose_memcpy_tiled_x(kgem, tiling.swizzle_mode);
14015 + if (!DBG_NO_DETILING)
14016 + choose_memcpy_tiled_x(kgem,
14017 + tiling.swizzle_mode,
14018 + __to_sna(kgem)->cpu_features);
14019 out:
14020 gem_close(kgem->fd, tiling.handle);
14021 + DBG(("%s: can fence?=%d\n", __FUNCTION__, kgem->can_fence));
14024 static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
14025 @@ -1399,6 +1714,7 @@ static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
14026 bo->handle, (long long)bo->presumed_offset));
14027 for (n = 0; n < kgem->nreloc__self; n++) {
14028 int i = kgem->reloc__self[n];
14029 + uint64_t addr;
14031 assert(kgem->reloc[i].target_handle == ~0U);
14032 kgem->reloc[i].target_handle = bo->target_handle;
14033 @@ -1412,13 +1728,17 @@ static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
14035 kgem->reloc[i].delta -= shrink;
14037 - kgem->batch[kgem->reloc[i].offset/sizeof(uint32_t)] =
14038 - kgem->reloc[i].delta + bo->presumed_offset;
14039 + addr = (int)kgem->reloc[i].delta + bo->presumed_offset;
14040 + kgem->batch[kgem->reloc[i].offset/sizeof(uint32_t)] = addr;
14041 + if (kgem->gen >= 0100)
14042 + kgem->batch[kgem->reloc[i].offset/sizeof(uint32_t) + 1] = addr >> 32;
14045 if (n == 256) {
14046 for (n = kgem->reloc__self[255]; n < kgem->nreloc; n++) {
14047 if (kgem->reloc[n].target_handle == ~0U) {
14048 + uint64_t addr;
14050 kgem->reloc[n].target_handle = bo->target_handle;
14051 kgem->reloc[n].presumed_offset = bo->presumed_offset;
14053 @@ -1429,8 +1749,11 @@ static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
14054 kgem->reloc[n].delta - shrink));
14055 kgem->reloc[n].delta -= shrink;
14057 - kgem->batch[kgem->reloc[n].offset/sizeof(uint32_t)] =
14058 - kgem->reloc[n].delta + bo->presumed_offset;
14060 + addr = (int)kgem->reloc[n].delta + bo->presumed_offset;
14061 + kgem->batch[kgem->reloc[n].offset/sizeof(uint32_t)] = addr;
14062 + if (kgem->gen >= 0100)
14063 + kgem->batch[kgem->reloc[n].offset/sizeof(uint32_t) + 1] = addr >> 32;
14067 @@ -1444,6 +1767,44 @@ static void kgem_fixup_relocs(struct kgem *kgem, struct kgem_bo *bo, int shrink)
14071 +static int kgem_bo_wait(struct kgem *kgem, struct kgem_bo *bo)
14072 +{
14073 + struct local_i915_gem_wait {
14074 + uint32_t handle;
14075 + uint32_t flags;
14076 + int64_t timeout;
14077 + } wait;
14078 +#define LOCAL_I915_GEM_WAIT 0x2c
14079 +#define LOCAL_IOCTL_I915_GEM_WAIT DRM_IOWR(DRM_COMMAND_BASE + LOCAL_I915_GEM_WAIT, struct local_i915_gem_wait)
14080 + int ret;
14082 + DBG(("%s: waiting for handle=%d\n", __FUNCTION__, bo->handle));
14083 + if (bo->rq == NULL)
14084 + return 0;
14086 + VG_CLEAR(wait);
14087 + wait.handle = bo->handle;
14088 + wait.flags = 0;
14089 + wait.timeout = -1;
14090 + ret = do_ioctl(kgem->fd, LOCAL_IOCTL_I915_GEM_WAIT, &wait);
14091 + if (ret) {
14092 + struct drm_i915_gem_set_domain set_domain;
14094 + VG_CLEAR(set_domain);
14095 + set_domain.handle = bo->handle;
14096 + set_domain.read_domains = I915_GEM_DOMAIN_GTT;
14097 + set_domain.write_domain = I915_GEM_DOMAIN_GTT;
14098 + ret = do_ioctl(kgem->fd,
14099 + DRM_IOCTL_I915_GEM_SET_DOMAIN,
14100 + &set_domain);
14101 + }
14103 + if (ret == 0)
14104 + __kgem_retire_requests_upto(kgem, bo);
14106 + return ret;
14107 +}
14109 static struct kgem_bo *kgem_new_batch(struct kgem *kgem)
14111 struct kgem_bo *last;
14112 @@ -1464,20 +1825,41 @@ static struct kgem_bo *kgem_new_batch(struct kgem *kgem)
14113 if (!kgem->has_llc)
14114 flags |= CREATE_UNCACHED;
14116 +restart:
14117 kgem->batch_bo = kgem_create_linear(kgem,
14118 sizeof(uint32_t)*kgem->batch_size,
14119 flags);
14120 if (kgem->batch_bo)
14121 kgem->batch = kgem_bo_map__cpu(kgem, kgem->batch_bo);
14122 if (kgem->batch == NULL) {
14123 - DBG(("%s: unable to map batch bo, mallocing(size=%d)\n",
14124 - __FUNCTION__,
14125 - sizeof(uint32_t)*kgem->batch_size));
14126 + int ring = kgem->ring == KGEM_BLT;
14127 + assert(ring < ARRAY_SIZE(kgem->requests));
14129 if (kgem->batch_bo) {
14130 kgem_bo_destroy(kgem, kgem->batch_bo);
14131 kgem->batch_bo = NULL;
14134 + if (!list_is_empty(&kgem->requests[ring])) {
14135 + struct kgem_request *rq;
14137 + rq = list_first_entry(&kgem->requests[ring],
14138 + struct kgem_request, list);
14139 + assert(rq->ring == ring);
14140 + assert(rq->bo);
14141 + assert(RQ(rq->bo->rq) == rq);
14142 + if (kgem_bo_wait(kgem, rq->bo) == 0)
14143 + goto restart;
14144 + }
14146 + if (flags & CREATE_NO_THROTTLE) {
14147 + flags &= ~CREATE_NO_THROTTLE;
14148 + if (kgem_cleanup_cache(kgem))
14149 + goto restart;
14150 + }
14152 + DBG(("%s: unable to map batch bo, mallocing(size=%d)\n",
14153 + __FUNCTION__, sizeof(uint32_t)*kgem->batch_size));
14154 if (posix_memalign((void **)&kgem->batch, PAGE_SIZE,
14155 ALIGN(sizeof(uint32_t) * kgem->batch_size, PAGE_SIZE))) {
14156 ERR(("%s: batch allocation failed, disabling acceleration\n", __FUNCTION__));
14157 @@ -1495,18 +1877,79 @@ static struct kgem_bo *kgem_new_batch(struct kgem *kgem)
14158 return last;
14161 -void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
14162 +static void
14163 +no_retire(struct kgem *kgem)
14164 +{
14165 + (void)kgem;
14166 +}
14168 +static void
14169 +no_expire(struct kgem *kgem)
14170 +{
14171 + (void)kgem;
14172 +}
14174 +static void
14175 +no_context_switch(struct kgem *kgem, int new_mode)
14176 +{
14177 + (void)kgem;
14178 + (void)new_mode;
14179 +}
14181 +static uint64_t get_gtt_size(int fd)
14183 struct drm_i915_gem_get_aperture aperture;
14184 + struct local_i915_gem_context_param {
14185 + uint32_t context;
14186 + uint32_t size;
14187 + uint64_t param;
14188 +#define LOCAL_CONTEXT_PARAM_BAN_PERIOD 0x1
14189 +#define LOCAL_CONTEXT_PARAM_NO_ZEROMAP 0x2
14190 +#define LOCAL_CONTEXT_PARAM_GTT_SIZE 0x3
14191 + uint64_t value;
14192 + } p;
14193 +#define LOCAL_I915_GEM_CONTEXT_GETPARAM 0x34
14194 +#define LOCAL_IOCTL_I915_GEM_CONTEXT_GETPARAM DRM_IOWR (DRM_COMMAND_BASE + LOCAL_I915_GEM_CONTEXT_GETPARAM, struct local_i915_gem_context_param)
14196 + memset(&aperture, 0, sizeof(aperture));
14198 + memset(&p, 0, sizeof(p));
14199 + p.param = LOCAL_CONTEXT_PARAM_GTT_SIZE;
14200 + if (drmIoctl(fd, LOCAL_IOCTL_I915_GEM_CONTEXT_GETPARAM, &p) == 0)
14201 + aperture.aper_size = p.value;
14202 + if (aperture.aper_size == 0)
14203 + (void)drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
14204 + if (aperture.aper_size == 0)
14205 + aperture.aper_size = 64*1024*1024;
14207 + DBG(("%s: aperture size %lld, available now %lld\n",
14208 + __FUNCTION__,
14209 + (long long)aperture.aper_size,
14210 + (long long)aperture.aper_available_size));
14212 + /* clamp aperture to uint32_t for simplicity */
14213 + if (aperture.aper_size > 0xc0000000)
14214 + aperture.aper_size = 0xc0000000;
14216 + return aperture.aper_size;
14217 +}
14219 +void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
14220 +{
14221 size_t totalram;
14222 unsigned half_gpu_max;
14223 unsigned int i, j;
14224 + uint64_t gtt_size;
14226 DBG(("%s: fd=%d, gen=%d\n", __FUNCTION__, fd, gen));
14228 kgem->fd = fd;
14229 kgem->gen = gen;
14231 + kgem->retire = no_retire;
14232 + kgem->expire = no_expire;
14233 + kgem->context_switch = no_context_switch;
14235 list_init(&kgem->requests[0]);
14236 list_init(&kgem->requests[1]);
14237 list_init(&kgem->batch_buffers);
14238 @@ -1586,10 +2029,21 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
14239 DBG(("%s: can blt to cpu? %d\n", __FUNCTION__,
14240 kgem->can_blt_cpu));
14242 + kgem->can_blt_y = test_can_blt_y(kgem);
14243 + DBG(("%s: can blit to Y-tiled surfaces? %d\n", __FUNCTION__,
14244 + kgem->can_blt_y));
14246 kgem->can_render_y = gen != 021 && (gen >> 3) != 4;
14247 DBG(("%s: can render to Y-tiled surfaces? %d\n", __FUNCTION__,
14248 kgem->can_render_y));
14250 + kgem->can_scanout_y = test_can_scanout_y(kgem);
14251 + DBG(("%s: can scanout Y-tiled surfaces? %d\n", __FUNCTION__,
14252 + kgem->can_scanout_y));
14254 + kgem->has_dirtyfb = test_has_dirtyfb(kgem);
14255 + DBG(("%s: has dirty fb? %d\n", __FUNCTION__, kgem->has_dirtyfb));
14257 kgem->has_secure_batches = test_has_secure_batches(kgem);
14258 DBG(("%s: can use privileged batchbuffers? %d\n", __FUNCTION__,
14259 kgem->has_secure_batches));
14260 @@ -1620,7 +2074,7 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
14261 if (!kgem->has_relaxed_delta && kgem->batch_size > 4*1024)
14262 kgem->batch_size = 4*1024;
14264 - if (!kgem_init_pinned_batches(kgem) && gen == 020) {
14265 + if (!kgem_init_pinned_batches(kgem)) {
14266 xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING,
14267 "Unable to reserve memory for GPU, disabling acceleration.\n");
14268 __kgem_set_wedged(kgem);
14269 @@ -1640,35 +2094,24 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
14270 !DBG_NO_CPU && (kgem->has_llc | kgem->has_userptr | kgem->has_caching),
14271 kgem->has_llc, kgem->has_caching, kgem->has_userptr));
14273 - VG_CLEAR(aperture);
14274 - aperture.aper_size = 0;
14275 - (void)do_ioctl(fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture);
14276 - if (aperture.aper_size == 0)
14277 - aperture.aper_size = 64*1024*1024;
14279 - DBG(("%s: aperture size %lld, available now %lld\n",
14280 - __FUNCTION__,
14281 - (long long)aperture.aper_size,
14282 - (long long)aperture.aper_available_size));
14284 - kgem->aperture_total = aperture.aper_size;
14285 - kgem->aperture_high = aperture.aper_size * 3/4;
14286 - kgem->aperture_low = aperture.aper_size * 1/3;
14287 + gtt_size = get_gtt_size(fd);
14288 + kgem->aperture_total = gtt_size;
14289 + kgem->aperture_high = gtt_size * 3/4;
14290 + kgem->aperture_low = gtt_size * 1/3;
14291 if (gen < 033) {
14292 /* Severe alignment penalties */
14293 kgem->aperture_high /= 2;
14294 kgem->aperture_low /= 2;
14296 - DBG(("%s: aperture low=%d [%d], high=%d [%d]\n", __FUNCTION__,
14297 + DBG(("%s: aperture low=%u [%u], high=%u [%u]\n", __FUNCTION__,
14298 kgem->aperture_low, kgem->aperture_low / (1024*1024),
14299 kgem->aperture_high, kgem->aperture_high / (1024*1024)));
14301 kgem->aperture_mappable = 256 * 1024 * 1024;
14302 if (dev != NULL)
14303 kgem->aperture_mappable = agp_aperture_size(dev, gen);
14304 - if (kgem->aperture_mappable == 0 ||
14305 - kgem->aperture_mappable > aperture.aper_size)
14306 - kgem->aperture_mappable = aperture.aper_size;
14307 + if (kgem->aperture_mappable == 0 || kgem->aperture_mappable > gtt_size)
14308 + kgem->aperture_mappable = gtt_size;
14309 DBG(("%s: aperture mappable=%d [%d MiB]\n", __FUNCTION__,
14310 kgem->aperture_mappable, kgem->aperture_mappable / (1024*1024)));
14312 @@ -1697,7 +2140,7 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
14313 __FUNCTION__));
14314 totalram = kgem->aperture_total;
14316 - DBG(("%s: total ram=%ld\n", __FUNCTION__, (long)totalram));
14317 + DBG(("%s: total ram=%lld\n", __FUNCTION__, (long long)totalram));
14318 if (kgem->max_object_size > totalram / 2)
14319 kgem->max_object_size = totalram / 2;
14320 if (kgem->max_gpu_size > totalram / 4)
14321 @@ -1749,11 +2192,11 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
14322 if (DBG_NO_CPU)
14323 kgem->max_cpu_size = 0;
14325 - DBG(("%s: maximum object size=%d\n",
14326 + DBG(("%s: maximum object size=%u\n",
14327 __FUNCTION__, kgem->max_object_size));
14328 - DBG(("%s: large object thresold=%d\n",
14329 + DBG(("%s: large object thresold=%u\n",
14330 __FUNCTION__, kgem->large_object_size));
14331 - DBG(("%s: max object sizes (gpu=%d, cpu=%d, tile upload=%d, copy=%d)\n",
14332 + DBG(("%s: max object sizes (gpu=%u, cpu=%u, tile upload=%u, copy=%u)\n",
14333 __FUNCTION__,
14334 kgem->max_gpu_size, kgem->max_cpu_size,
14335 kgem->max_upload_tile_size, kgem->max_copy_tile_size));
14336 @@ -2043,8 +2486,34 @@ static void kgem_add_bo(struct kgem *kgem, struct kgem_bo *bo)
14337 kgem->flush |= bo->flush;
14340 +static void kgem_clear_swctrl(struct kgem *kgem)
14341 +{
14342 + uint32_t *b;
14344 + if (kgem->bcs_state == 0)
14345 + return;
14347 + DBG(("%s: clearin SWCTRL LRI from %x\n",
14348 + __FUNCTION__, kgem->bcs_state));
14350 + b = kgem->batch + kgem->nbatch;
14351 + kgem->nbatch += 7;
14353 + *b++ = MI_FLUSH_DW;
14354 + *b++ = 0;
14355 + *b++ = 0;
14356 + *b++ = 0;
14358 + *b++ = MI_LOAD_REGISTER_IMM;
14359 + *b++ = BCS_SWCTRL;
14360 + *b++ = (BCS_SRC_Y | BCS_DST_Y) << 16;
14362 + kgem->bcs_state = 0;
14363 +}
14365 static uint32_t kgem_end_batch(struct kgem *kgem)
14367 + kgem_clear_swctrl(kgem);
14368 kgem->batch[kgem->nbatch++] = MI_BATCH_BUFFER_END;
14369 if (kgem->nbatch & 1)
14370 kgem->batch[kgem->nbatch++] = MI_NOOP;
14371 @@ -2064,17 +2533,6 @@ static void kgem_bo_binding_free(struct kgem *kgem, struct kgem_bo *bo)
14375 -static void kgem_bo_rmfb(struct kgem *kgem, struct kgem_bo *bo)
14376 -{
14377 - if (bo->scanout && bo->delta) {
14378 - DBG(("%s: releasing fb=%d for handle=%d\n",
14379 - __FUNCTION__, bo->delta, bo->handle));
14380 - /* XXX will leak if we are not DRM_MASTER. *shrug* */
14381 - do_ioctl(kgem->fd, DRM_IOCTL_MODE_RMFB, &bo->delta);
14382 - bo->delta = 0;
14383 - }
14384 -}
14386 static void kgem_bo_free(struct kgem *kgem, struct kgem_bo *bo)
14388 DBG(("%s: handle=%d, size=%d\n", __FUNCTION__, bo->handle, bytes(bo)));
14389 @@ -2150,13 +2608,16 @@ inline static void kgem_bo_move_to_inactive(struct kgem *kgem,
14390 assert(!bo->snoop);
14391 assert(!bo->flush);
14392 assert(!bo->needs_flush);
14393 + assert(!bo->delta);
14394 assert(list_is_empty(&bo->vma));
14395 assert_tiling(kgem, bo);
14396 - assert_cacheing(kgem, bo);
14397 + assert_caching(kgem, bo);
14398 ASSERT_IDLE(kgem, bo->handle);
14400 if (bucket(bo) >= NUM_CACHE_BUCKETS) {
14401 if (bo->map__gtt) {
14402 + DBG(("%s: relinquishing large GTT mapping for handle=%d\n",
14403 + __FUNCTION__, bo->handle));
14404 munmap(bo->map__gtt, bytes(bo));
14405 bo->map__gtt = NULL;
14407 @@ -2167,6 +2628,8 @@ inline static void kgem_bo_move_to_inactive(struct kgem *kgem,
14408 assert(list_is_empty(&bo->vma));
14409 list_move(&bo->list, &kgem->inactive[bucket(bo)]);
14410 if (bo->map__gtt && !kgem_bo_can_map(kgem, bo)) {
14411 + DBG(("%s: relinquishing old GTT mapping for handle=%d\n",
14412 + __FUNCTION__, bo->handle));
14413 munmap(bo->map__gtt, bytes(bo));
14414 bo->map__gtt = NULL;
14416 @@ -2191,6 +2654,10 @@ static struct kgem_bo *kgem_bo_replace_io(struct kgem_bo *bo)
14417 return bo;
14419 assert(!bo->snoop);
14420 + assert(!bo->purged);
14421 + assert(!bo->scanout);
14422 + assert(!bo->delta);
14424 if (__kgem_freed_bo) {
14425 base = __kgem_freed_bo;
14426 __kgem_freed_bo = *(struct kgem_bo **)base;
14427 @@ -2221,6 +2688,7 @@ inline static void kgem_bo_remove_from_inactive(struct kgem *kgem,
14428 list_del(&bo->list);
14429 assert(bo->rq == NULL);
14430 assert(bo->exec == NULL);
14431 + assert(!bo->purged);
14432 if (!list_is_empty(&bo->vma)) {
14433 assert(bo->map__gtt || bo->map__wc || bo->map__cpu);
14434 list_del(&bo->vma);
14435 @@ -2305,7 +2773,6 @@ static void kgem_bo_move_to_scanout(struct kgem *kgem, struct kgem_bo *bo)
14436 list_move(&bo->list, &kgem->scanout);
14438 kgem->need_expire = true;
14442 static void kgem_bo_move_to_snoop(struct kgem *kgem, struct kgem_bo *bo)
14443 @@ -2316,6 +2783,8 @@ static void kgem_bo_move_to_snoop(struct kgem *kgem, struct kgem_bo *bo)
14444 assert(!bo->needs_flush);
14445 assert(bo->refcnt == 0);
14446 assert(bo->exec == NULL);
14447 + assert(!bo->purged);
14448 + assert(!bo->delta);
14450 if (DBG_NO_SNOOP_CACHE) {
14451 kgem_bo_free(kgem, bo);
14452 @@ -2351,8 +2820,7 @@ static bool kgem_bo_move_to_cache(struct kgem *kgem, struct kgem_bo *bo)
14453 kgem_bo_move_to_snoop(kgem, bo);
14454 } else if (bo->scanout) {
14455 kgem_bo_move_to_scanout(kgem, bo);
14456 - } else if ((bo = kgem_bo_replace_io(bo))->reusable &&
14457 - kgem_bo_set_purgeable(kgem, bo)) {
14458 + } else if ((bo = kgem_bo_replace_io(bo))->reusable) {
14459 kgem_bo_move_to_inactive(kgem, bo);
14460 retired = true;
14461 } else
14462 @@ -2429,7 +2897,7 @@ void kgem_bo_undo(struct kgem *kgem, struct kgem_bo *bo)
14463 DBG(("%s: only handle in batch, discarding last operations for handle=%d\n",
14464 __FUNCTION__, bo->handle));
14466 - assert(bo->exec == &kgem->exec[0]);
14467 + assert(bo->exec == &_kgem_dummy_exec || bo->exec == &kgem->exec[0]);
14468 assert(kgem->exec[0].handle == bo->handle);
14469 assert(RQ(bo->rq) == kgem->next_request);
14471 @@ -2457,16 +2925,23 @@ void kgem_bo_pair_undo(struct kgem *kgem, struct kgem_bo *a, struct kgem_bo *b)
14473 if (a == NULL || b == NULL)
14474 return;
14475 + assert(a != b);
14476 if (a->exec == NULL || b->exec == NULL)
14477 return;
14479 - DBG(("%s: only handles in batch, discarding last operations for handle=%d and handle=%d\n",
14480 - __FUNCTION__, a->handle, b->handle));
14481 + DBG(("%s: only handles in batch, discarding last operations for handle=%d (index=%d) and handle=%d (index=%d)\n",
14482 + __FUNCTION__,
14483 + a->handle, a->proxy ? -1 : a->exec - kgem->exec,
14484 + b->handle, b->proxy ? -1 : b->exec - kgem->exec));
14486 - assert(a->exec == &kgem->exec[0] || a->exec == &kgem->exec[1]);
14487 + assert(a->exec == &_kgem_dummy_exec ||
14488 + a->exec == &kgem->exec[0] ||
14489 + a->exec == &kgem->exec[1]);
14490 assert(a->handle == kgem->exec[0].handle || a->handle == kgem->exec[1].handle);
14491 assert(RQ(a->rq) == kgem->next_request);
14492 - assert(b->exec == &kgem->exec[0] || b->exec == &kgem->exec[1]);
14493 + assert(b->exec == &_kgem_dummy_exec ||
14494 + b->exec == &kgem->exec[0] ||
14495 + b->exec == &kgem->exec[1]);
14496 assert(b->handle == kgem->exec[0].handle || b->handle == kgem->exec[1].handle);
14497 assert(RQ(b->rq) == kgem->next_request);
14499 @@ -2487,6 +2962,7 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
14500 DBG(("%s: handle=%d, size=%d\n", __FUNCTION__, bo->handle, bytes(bo)));
14502 assert(list_is_empty(&bo->list));
14503 + assert(list_is_empty(&bo->vma));
14504 assert(bo->refcnt == 0);
14505 assert(bo->proxy == NULL);
14506 assert(bo->active_scanout == 0);
14507 @@ -2532,7 +3008,7 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
14508 assert(bo->snoop == false);
14509 assert(bo->io == false);
14510 assert(bo->scanout == false);
14511 - assert_cacheing(kgem, bo);
14512 + assert_caching(kgem, bo);
14514 kgem_bo_undo(kgem, bo);
14515 assert(bo->refcnt == 0);
14516 @@ -2556,9 +3032,6 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
14517 assert(list_is_empty(&bo->request));
14519 if (bo->map__cpu == NULL || bucket(bo) >= NUM_CACHE_BUCKETS) {
14520 - if (!kgem_bo_set_purgeable(kgem, bo))
14521 - goto destroy;
14523 if (!kgem->has_llc && bo->domain == DOMAIN_CPU)
14524 goto destroy;
14526 @@ -2647,7 +3120,7 @@ static bool kgem_retire__flushing(struct kgem *kgem)
14527 int count = 0;
14528 list_for_each_entry(bo, &kgem->flushing, request)
14529 count++;
14530 - DBG(("%s: %d bo on flushing list\n", __FUNCTION__, count));
14531 + DBG(("%s: %d bo on flushing list, retired? %d\n", __FUNCTION__, count, retired));
14533 #endif
14535 @@ -2656,6 +3129,34 @@ static bool kgem_retire__flushing(struct kgem *kgem)
14536 return retired;
14539 +static bool __kgem_bo_flush(struct kgem *kgem, struct kgem_bo *bo)
14540 +{
14541 + struct drm_i915_gem_busy busy;
14543 + if (!bo->needs_flush)
14544 + return false;
14546 + bo->needs_flush = false;
14548 + VG_CLEAR(busy);
14549 + busy.handle = bo->handle;
14550 + busy.busy = !kgem->wedged;
14551 + (void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
14552 + DBG(("%s: handle=%d, busy=%d, wedged=%d\n",
14553 + __FUNCTION__, bo->handle, busy.busy, kgem->wedged));
14555 + if (busy.busy == 0)
14556 + return false;
14558 + DBG(("%s: moving %d to flushing\n",
14559 + __FUNCTION__, bo->handle));
14560 + list_add(&bo->request, &kgem->flushing);
14561 + bo->rq = MAKE_REQUEST(kgem, !!(busy.busy & ~0x1ffff));
14562 + bo->needs_flush = busy.busy & 0xffff;
14563 + kgem->need_retire = true;
14564 + return true;
14565 +}
14567 static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq)
14569 bool retired = false;
14570 @@ -2663,6 +3164,8 @@ static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq)
14571 DBG(("%s: request %d complete\n",
14572 __FUNCTION__, rq->bo->handle));
14573 assert(RQ(rq->bo->rq) == rq);
14574 + assert(rq != (struct kgem_request *)kgem);
14575 + assert(rq != &kgem->static_request);
14577 if (rq == kgem->fence[rq->ring])
14578 kgem->fence[rq->ring] = NULL;
14579 @@ -2680,19 +3183,14 @@ static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq)
14581 list_del(&bo->request);
14583 - if (bo->needs_flush)
14584 - bo->needs_flush = __kgem_busy(kgem, bo->handle);
14585 - if (bo->needs_flush) {
14586 - DBG(("%s: moving %d to flushing\n",
14587 + if (unlikely(__kgem_bo_flush(kgem, bo))) {
14588 + assert(bo != rq->bo);
14589 + DBG(("%s: movied %d to flushing\n",
14590 __FUNCTION__, bo->handle));
14591 - list_add(&bo->request, &kgem->flushing);
14592 - bo->rq = MAKE_REQUEST(kgem, RQ_RING(bo->rq));
14593 - kgem->need_retire = true;
14594 continue;
14597 bo->domain = DOMAIN_NONE;
14598 - bo->gtt_dirty = false;
14599 bo->rq = NULL;
14600 if (bo->refcnt)
14601 continue;
14602 @@ -2706,14 +3204,8 @@ static bool __kgem_retire_rq(struct kgem *kgem, struct kgem_request *rq)
14603 assert(rq->bo->refcnt > 0);
14605 if (--rq->bo->refcnt == 0) {
14606 - if (kgem_bo_set_purgeable(kgem, rq->bo)) {
14607 - kgem_bo_move_to_inactive(kgem, rq->bo);
14608 - retired = true;
14609 - } else {
14610 - DBG(("%s: closing %d\n",
14611 - __FUNCTION__, rq->bo->handle));
14612 - kgem_bo_free(kgem, rq->bo);
14613 - }
14614 + kgem_bo_move_to_inactive(kgem, rq->bo);
14615 + retired = true;
14618 __kgem_request_free(rq);
14619 @@ -2724,13 +3216,18 @@ static bool kgem_retire__requests_ring(struct kgem *kgem, int ring)
14621 bool retired = false;
14623 + assert(ring < ARRAY_SIZE(kgem->requests));
14624 while (!list_is_empty(&kgem->requests[ring])) {
14625 struct kgem_request *rq;
14627 + DBG(("%s: retiring ring %d\n", __FUNCTION__, ring));
14629 rq = list_first_entry(&kgem->requests[ring],
14630 struct kgem_request,
14631 list);
14632 assert(rq->ring == ring);
14633 + assert(rq->bo);
14634 + assert(RQ(rq->bo->rq) == rq);
14635 if (__kgem_busy(kgem, rq->bo->handle))
14636 break;
14638 @@ -2751,8 +3248,8 @@ static bool kgem_retire__requests_ring(struct kgem *kgem, int ring)
14639 struct kgem_request,
14640 list)->bo;
14642 - DBG(("%s: ring=%d, %d outstanding requests, oldest=%d\n",
14643 - __FUNCTION__, ring, count, bo ? bo->handle : 0));
14644 + DBG(("%s: ring=%d, %d outstanding requests, oldest=%d, retired? %d\n",
14645 + __FUNCTION__, ring, count, bo ? bo->handle : 0, retired));
14647 #endif
14649 @@ -2824,6 +3321,8 @@ bool __kgem_ring_is_idle(struct kgem *kgem, int ring)
14650 rq = list_last_entry(&kgem->requests[ring],
14651 struct kgem_request, list);
14652 assert(rq->ring == ring);
14653 + assert(rq->bo);
14654 + assert(RQ(rq->bo->rq) == rq);
14655 if (__kgem_busy(kgem, rq->bo->handle)) {
14656 DBG(("%s: last requests handle=%d still busy\n",
14657 __FUNCTION__, rq->bo->handle));
14658 @@ -2845,23 +3344,30 @@ bool __kgem_ring_is_idle(struct kgem *kgem, int ring)
14659 return true;
14662 -void __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo)
14663 +bool __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo)
14665 - struct kgem_request *rq = bo->rq, *tmp;
14666 - struct list *requests = &kgem->requests[RQ_RING(rq) == I915_EXEC_BLT];
14667 + struct kgem_request * const rq = RQ(bo->rq), *tmp;
14668 + struct list *requests = &kgem->requests[rq->ring];
14670 + DBG(("%s(handle=%d, ring=%d)\n", __FUNCTION__, bo->handle, rq->ring));
14672 - rq = RQ(rq);
14673 assert(rq != &kgem->static_request);
14674 if (rq == (struct kgem_request *)kgem) {
14675 __kgem_bo_clear_busy(bo);
14676 - return;
14677 + return false;
14680 + assert(rq->ring < ARRAY_SIZE(kgem->requests));
14681 do {
14682 tmp = list_first_entry(requests, struct kgem_request, list);
14683 assert(tmp->ring == rq->ring);
14684 __kgem_retire_rq(kgem, tmp);
14685 } while (tmp != rq);
14687 + assert(bo->needs_flush || bo->rq == NULL);
14688 + assert(bo->needs_flush || list_is_empty(&bo->request));
14689 + assert(bo->needs_flush || bo->domain == DOMAIN_NONE);
14690 + return bo->rq;
14693 #if 0
14694 @@ -2932,6 +3438,7 @@ static void kgem_commit(struct kgem *kgem)
14695 bo->binding.offset = 0;
14696 bo->domain = DOMAIN_GPU;
14697 bo->gpu_dirty = false;
14698 + bo->gtt_dirty = false;
14700 if (bo->proxy) {
14701 /* proxies are not used for domain tracking */
14702 @@ -2955,6 +3462,23 @@ static void kgem_commit(struct kgem *kgem)
14703 kgem_throttle(kgem);
14706 + while (!list_is_empty(&rq->buffers)) {
14707 + bo = list_first_entry(&rq->buffers,
14708 + struct kgem_bo,
14709 + request);
14711 + assert(RQ(bo->rq) == rq);
14712 + assert(bo->exec == NULL);
14713 + assert(bo->domain == DOMAIN_GPU);
14715 + list_del(&bo->request);
14716 + bo->domain = DOMAIN_NONE;
14717 + bo->rq = NULL;
14719 + if (bo->refcnt == 0)
14720 + _kgem_bo_destroy(kgem, bo);
14721 + }
14723 kgem_retire(kgem);
14724 assert(list_is_empty(&rq->buffers));
14726 @@ -2964,7 +3488,9 @@ static void kgem_commit(struct kgem *kgem)
14727 gem_close(kgem->fd, rq->bo->handle);
14728 kgem_cleanup_cache(kgem);
14729 } else {
14730 + assert(rq != (struct kgem_request *)kgem);
14731 assert(rq->ring < ARRAY_SIZE(kgem->requests));
14732 + assert(rq->bo);
14733 list_add_tail(&rq->list, &kgem->requests[rq->ring]);
14734 kgem->need_throttle = kgem->need_retire = 1;
14736 @@ -2988,8 +3514,10 @@ static void kgem_close_inactive(struct kgem *kgem)
14738 unsigned int i;
14740 - for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++)
14741 + for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) {
14742 kgem_close_list(kgem, &kgem->inactive[i]);
14743 + assert(list_is_empty(&kgem->inactive[i]));
14744 + }
14747 static void kgem_finish_buffers(struct kgem *kgem)
14748 @@ -3079,10 +3607,13 @@ static void kgem_finish_buffers(struct kgem *kgem)
14749 kgem->has_handle_lut ? bo->base.target_handle : shrink->handle;
14750 for (n = 0; n < kgem->nreloc; n++) {
14751 if (kgem->reloc[n].target_handle == bo->base.target_handle) {
14752 + uint64_t addr = (int)kgem->reloc[n].delta + shrink->presumed_offset;
14753 + kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] = addr;
14754 + if (kgem->gen >= 0100)
14755 + kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0]) + 1] = addr >> 32;
14757 kgem->reloc[n].target_handle = shrink->target_handle;
14758 kgem->reloc[n].presumed_offset = shrink->presumed_offset;
14759 - kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] =
14760 - kgem->reloc[n].delta + shrink->presumed_offset;
14764 @@ -3124,10 +3655,13 @@ static void kgem_finish_buffers(struct kgem *kgem)
14765 kgem->has_handle_lut ? bo->base.target_handle : shrink->handle;
14766 for (n = 0; n < kgem->nreloc; n++) {
14767 if (kgem->reloc[n].target_handle == bo->base.target_handle) {
14768 + uint64_t addr = (int)kgem->reloc[n].delta + shrink->presumed_offset;
14769 + kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] = addr;
14770 + if (kgem->gen >= 0100)
14771 + kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0]) + 1] = addr >> 32;
14773 kgem->reloc[n].target_handle = shrink->target_handle;
14774 kgem->reloc[n].presumed_offset = shrink->presumed_offset;
14775 - kgem->batch[kgem->reloc[n].offset/sizeof(kgem->batch[0])] =
14776 - kgem->reloc[n].delta + shrink->presumed_offset;
14780 @@ -3195,6 +3729,9 @@ static void kgem_cleanup(struct kgem *kgem)
14781 kgem_bo_free(kgem, bo);
14784 + if (--rq->bo->refcnt == 0)
14785 + kgem_bo_free(kgem, rq->bo);
14787 __kgem_request_free(rq);
14790 @@ -3210,7 +3747,9 @@ kgem_batch_write(struct kgem *kgem,
14791 char *ptr;
14792 int ret;
14794 - ASSERT_IDLE(kgem, bo->handle);
14795 + assert(bo->exec == NULL);
14796 + assert(bo->rq == NULL);
14797 + assert(!__kgem_busy(kgem, bo->handle));
14799 #if DBG_NO_EXEC
14801 @@ -3371,55 +3910,54 @@ static int compact_batch_surface(struct kgem *kgem, int *shrink)
14802 return size * sizeof(uint32_t);
14805 +static struct kgem_bo *first_available(struct kgem *kgem, struct list *list)
14806 +{
14807 + struct kgem_bo *bo;
14809 + list_for_each_entry(bo, list, list) {
14810 + assert(bo->refcnt > 0);
14812 + if (bo->rq) {
14813 + assert(RQ(bo->rq)->bo == bo);
14814 + if (__kgem_busy(kgem, bo->handle))
14815 + break;
14817 + __kgem_retire_rq(kgem, RQ(bo->rq));
14818 + assert(bo->rq == NULL);
14819 + }
14821 + if (bo->refcnt > 1)
14822 + continue;
14824 + list_move_tail(&bo->list, list);
14825 + return kgem_bo_reference(bo);
14826 + }
14828 + return NULL;
14829 +}
14831 static struct kgem_bo *
14832 kgem_create_batch(struct kgem *kgem)
14834 -#if !DBG_NO_SHRINK_BATCHES
14835 - struct drm_i915_gem_set_domain set_domain;
14836 struct kgem_bo *bo;
14837 - int shrink = 0;
14838 - int size;
14839 + int size, shrink = 0;
14841 +#if !DBG_NO_SHRINK_BATCHES
14842 if (kgem->surface != kgem->batch_size)
14843 size = compact_batch_surface(kgem, &shrink);
14844 else
14845 size = kgem->nbatch * sizeof(uint32_t);
14847 if (size <= 4096) {
14848 - bo = list_first_entry(&kgem->pinned_batches[0],
14849 - struct kgem_bo,
14850 - list);
14851 - if (!bo->rq) {
14852 -out_4096:
14853 - assert(bo->refcnt > 0);
14854 - list_move_tail(&bo->list, &kgem->pinned_batches[0]);
14855 - bo = kgem_bo_reference(bo);
14856 + bo = first_available(kgem, &kgem->pinned_batches[0]);
14857 + if (bo)
14858 goto write;
14859 - }
14861 - if (!__kgem_busy(kgem, bo->handle)) {
14862 - assert(RQ(bo->rq)->bo == bo);
14863 - __kgem_retire_rq(kgem, RQ(bo->rq));
14864 - goto out_4096;
14865 - }
14868 - if (size <= 16384) {
14869 - bo = list_first_entry(&kgem->pinned_batches[1],
14870 - struct kgem_bo,
14871 - list);
14872 - if (!bo->rq) {
14873 -out_16384:
14874 - assert(bo->refcnt > 0);
14875 - list_move_tail(&bo->list, &kgem->pinned_batches[1]);
14876 - bo = kgem_bo_reference(bo);
14877 - goto write;
14878 - }
14880 - if (!__kgem_busy(kgem, bo->handle)) {
14881 - __kgem_retire_rq(kgem, RQ(bo->rq));
14882 - goto out_16384;
14883 - }
14884 + if (size <= 16384) {
14885 + bo = first_available(kgem, &kgem->pinned_batches[1]);
14886 + if (bo)
14887 + goto write;
14890 if (kgem->gen == 020) {
14891 @@ -3443,16 +3981,8 @@ out_16384:
14892 list_move_tail(&bo->list, &kgem->pinned_batches[size > 4096]);
14894 DBG(("%s: syncing due to busy batches\n", __FUNCTION__));
14896 - VG_CLEAR(set_domain);
14897 - set_domain.handle = bo->handle;
14898 - set_domain.read_domains = I915_GEM_DOMAIN_GTT;
14899 - set_domain.write_domain = I915_GEM_DOMAIN_GTT;
14900 - if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) {
14901 - DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
14902 - kgem_throttle(kgem);
14903 + if (kgem_bo_wait(kgem, bo))
14904 return NULL;
14905 - }
14907 kgem_retire(kgem);
14908 assert(bo->rq == NULL);
14909 @@ -3460,9 +3990,14 @@ out_16384:
14910 goto write;
14913 +#else
14914 + if (kgem->surface != kgem->batch_size)
14915 + size = kgem->batch_size * sizeof(uint32_t);
14916 + else
14917 + size = kgem->nbatch * sizeof(uint32_t);
14918 +#endif
14920 - bo = NULL;
14921 - if (!kgem->has_llc) {
14922 + if (!kgem->batch_bo || !kgem->has_llc) {
14923 bo = kgem_create_linear(kgem, size, CREATE_NO_THROTTLE);
14924 if (bo) {
14925 write:
14926 @@ -3471,14 +4006,11 @@ write:
14927 kgem_bo_destroy(kgem, bo);
14928 return NULL;
14930 + return bo;
14933 - if (bo == NULL)
14934 - bo = kgem_new_batch(kgem);
14935 - return bo;
14936 -#else
14938 return kgem_new_batch(kgem);
14939 -#endif
14942 #if !NDEBUG
14943 @@ -3530,7 +4062,7 @@ static void dump_fence_regs(struct kgem *kgem)
14945 static int do_execbuf(struct kgem *kgem, struct drm_i915_gem_execbuffer2 *execbuf)
14947 - int ret, err;
14948 + int ret;
14950 retry:
14951 ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf);
14952 @@ -3547,26 +4079,25 @@ retry:
14954 /* last gasp */
14955 ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf);
14956 - if (ret == 0)
14957 - return 0;
14958 + if (ret != -ENOSPC)
14959 + return ret;
14961 + /* One final trick up our sleeve for when we run out of space.
14962 + * We turn everything off to free up our pinned framebuffers,
14963 + * sprites and cursors, and try just one more time.
14964 + */
14966 xf86DrvMsg(kgem_get_screen_index(kgem), X_WARNING,
14967 "Failed to submit rendering commands, trying again with outputs disabled.\n");
14969 - /* One last trick up our sleeve for when we run out of space.
14970 - * We turn everything off to free up our pinned framebuffers,
14971 - * sprites and cursors, and try one last time.
14972 - */
14973 - err = errno;
14974 - if (sna_mode_disable(container_of(kgem, struct sna, kgem))) {
14975 + if (sna_mode_disable(__to_sna(kgem))) {
14976 kgem_cleanup_cache(kgem);
14977 ret = do_ioctl(kgem->fd,
14978 DRM_IOCTL_I915_GEM_EXECBUFFER2,
14979 execbuf);
14980 DBG(("%s: last_gasp ret=%d\n", __FUNCTION__, ret));
14981 - sna_mode_enable(container_of(kgem, struct sna, kgem));
14982 + sna_mode_enable(__to_sna(kgem));
14984 - errno = err;
14986 return ret;
14988 @@ -3575,6 +4106,7 @@ void _kgem_submit(struct kgem *kgem)
14990 struct kgem_request *rq;
14991 uint32_t batch_end;
14992 + int i, ret;
14994 assert(!DBG_NO_HW);
14995 assert(!kgem->wedged);
14996 @@ -3609,7 +4141,6 @@ void _kgem_submit(struct kgem *kgem)
14997 rq->bo = kgem_create_batch(kgem);
14998 if (rq->bo) {
14999 struct drm_i915_gem_execbuffer2 execbuf;
15000 - int i, ret;
15002 assert(!rq->bo->needs_flush);
15004 @@ -3619,7 +4150,8 @@ void _kgem_submit(struct kgem *kgem)
15005 kgem->exec[i].relocs_ptr = (uintptr_t)kgem->reloc;
15006 kgem->exec[i].alignment = 0;
15007 kgem->exec[i].offset = rq->bo->presumed_offset;
15008 - kgem->exec[i].flags = 0;
15009 + /* Make sure the kernel releases any fence, ignored if gen4+ */
15010 + kgem->exec[i].flags = EXEC_OBJECT_NEEDS_FENCE;
15011 kgem->exec[i].rsvd1 = 0;
15012 kgem->exec[i].rsvd2 = 0;
15014 @@ -3631,7 +4163,8 @@ void _kgem_submit(struct kgem *kgem)
15015 memset(&execbuf, 0, sizeof(execbuf));
15016 execbuf.buffers_ptr = (uintptr_t)kgem->exec;
15017 execbuf.buffer_count = kgem->nexec;
15018 - execbuf.batch_len = batch_end*sizeof(uint32_t);
15019 + if (kgem->gen < 030)
15020 + execbuf.batch_len = batch_end*sizeof(uint32_t);
15021 execbuf.flags = kgem->ring | kgem->batch_flags;
15023 if (DBG_DUMP) {
15024 @@ -3645,91 +4178,98 @@ void _kgem_submit(struct kgem *kgem)
15027 ret = do_execbuf(kgem, &execbuf);
15028 - if (DEBUG_SYNC && ret == 0) {
15029 - struct drm_i915_gem_set_domain set_domain;
15031 - VG_CLEAR(set_domain);
15032 - set_domain.handle = rq->bo->handle;
15033 - set_domain.read_domains = I915_GEM_DOMAIN_GTT;
15034 - set_domain.write_domain = I915_GEM_DOMAIN_GTT;
15035 + } else
15036 + ret = -ENOMEM;
15038 - ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
15039 + if (ret < 0) {
15040 + kgem_throttle(kgem);
15041 + if (!kgem->wedged) {
15042 + xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
15043 + "Failed to submit rendering commands (%s), disabling acceleration.\n",
15044 + strerror(-ret));
15045 + __kgem_set_wedged(kgem);
15047 - if (ret < 0) {
15048 - kgem_throttle(kgem);
15049 - if (!kgem->wedged) {
15050 - xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
15051 - "Failed to submit rendering commands, disabling acceleration.\n");
15052 - __kgem_set_wedged(kgem);
15053 - }
15055 #if !NDEBUG
15056 - ErrorF("batch[%d/%d]: %d %d %d, nreloc=%d, nexec=%d, nfence=%d, aperture=%d, fenced=%d, high=%d,%d: errno=%d\n",
15057 - kgem->mode, kgem->ring, batch_end, kgem->nbatch, kgem->surface,
15058 - kgem->nreloc, kgem->nexec, kgem->nfence, kgem->aperture, kgem->aperture_fenced, kgem->aperture_high, kgem->aperture_total, -ret);
15059 + ErrorF("batch[%d/%d]: %d %d %d, nreloc=%d, nexec=%d, nfence=%d, aperture=%d, fenced=%d, high=%d,%d: errno=%d\n",
15060 + kgem->mode, kgem->ring, batch_end, kgem->nbatch, kgem->surface,
15061 + kgem->nreloc, kgem->nexec, kgem->nfence, kgem->aperture, kgem->aperture_fenced, kgem->aperture_high, kgem->aperture_total, -ret);
15063 - for (i = 0; i < kgem->nexec; i++) {
15064 - struct kgem_bo *bo, *found = NULL;
15065 + for (i = 0; i < kgem->nexec; i++) {
15066 + struct kgem_bo *bo, *found = NULL;
15068 - list_for_each_entry(bo, &kgem->next_request->buffers, request) {
15069 - if (bo->handle == kgem->exec[i].handle) {
15070 - found = bo;
15071 - break;
15072 - }
15073 + list_for_each_entry(bo, &kgem->next_request->buffers, request) {
15074 + if (bo->handle == kgem->exec[i].handle) {
15075 + found = bo;
15076 + break;
15078 - ErrorF("exec[%d] = handle:%d, presumed offset: %x, size: %d, tiling %d, fenced %d, snooped %d, deleted %d\n",
15079 - i,
15080 - kgem->exec[i].handle,
15081 - (int)kgem->exec[i].offset,
15082 - found ? kgem_bo_size(found) : -1,
15083 - found ? found->tiling : -1,
15084 - (int)(kgem->exec[i].flags & EXEC_OBJECT_NEEDS_FENCE),
15085 - found ? found->snoop : -1,
15086 - found ? found->purged : -1);
15088 - for (i = 0; i < kgem->nreloc; i++) {
15089 - ErrorF("reloc[%d] = pos:%d, target:%d, delta:%d, read:%x, write:%x, offset:%x\n",
15090 - i,
15091 - (int)kgem->reloc[i].offset,
15092 - kgem->reloc[i].target_handle,
15093 - kgem->reloc[i].delta,
15094 - kgem->reloc[i].read_domains,
15095 - kgem->reloc[i].write_domain,
15096 - (int)kgem->reloc[i].presumed_offset);
15097 + ErrorF("exec[%d] = handle:%d, presumed offset: %x, size: %d, tiling %d, fenced %d, snooped %d, deleted %d\n",
15098 + i,
15099 + kgem->exec[i].handle,
15100 + (int)kgem->exec[i].offset,
15101 + found ? kgem_bo_size(found) : -1,
15102 + found ? found->tiling : -1,
15103 + (int)(kgem->exec[i].flags & EXEC_OBJECT_NEEDS_FENCE),
15104 + found ? found->snoop : -1,
15105 + found ? found->purged : -1);
15106 + }
15107 + for (i = 0; i < kgem->nreloc; i++) {
15108 + ErrorF("reloc[%d] = pos:%d, target:%d, delta:%d, read:%x, write:%x, offset:%x\n",
15109 + i,
15110 + (int)kgem->reloc[i].offset,
15111 + kgem->reloc[i].target_handle,
15112 + kgem->reloc[i].delta,
15113 + kgem->reloc[i].read_domains,
15114 + kgem->reloc[i].write_domain,
15115 + (int)kgem->reloc[i].presumed_offset);
15116 + }
15118 + {
15119 + struct drm_i915_gem_get_aperture aperture;
15120 + if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture) == 0)
15121 + ErrorF("Aperture size %lld, available %lld\n",
15122 + (long long)aperture.aper_size,
15123 + (long long)aperture.aper_available_size);
15124 + }
15126 + if (ret == -ENOSPC)
15127 + dump_gtt_info(kgem);
15128 + if (ret == -EDEADLK)
15129 + dump_fence_regs(kgem);
15131 + if (DEBUG_SYNC) {
15132 + int fd = open("/tmp/batchbuffer", O_WRONLY | O_CREAT | O_APPEND, 0666);
15133 + if (fd != -1) {
15134 + int ignored = write(fd, kgem->batch, batch_end*sizeof(uint32_t));
15135 + assert(ignored == batch_end*sizeof(uint32_t));
15136 + close(fd);
15139 - {
15140 - struct drm_i915_gem_get_aperture aperture;
15141 - if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture) == 0)
15142 - ErrorF("Aperture size %lld, available %lld\n",
15143 - (long long)aperture.aper_size,
15144 - (long long)aperture.aper_available_size);
15145 - }
15146 + FatalError("SNA: failed to submit batchbuffer, errno=%d\n", -ret);
15147 + }
15148 +#endif
15149 + } else {
15150 + if (DEBUG_SYNC) {
15151 + struct drm_i915_gem_set_domain set_domain;
15153 - if (ret == -ENOSPC)
15154 - dump_gtt_info(kgem);
15155 - if (ret == -EDEADLK)
15156 - dump_fence_regs(kgem);
15158 - if (DEBUG_SYNC) {
15159 - int fd = open("/tmp/batchbuffer", O_WRONLY | O_CREAT | O_APPEND, 0666);
15160 - if (fd != -1) {
15161 - int ignored = write(fd, kgem->batch, batch_end*sizeof(uint32_t));
15162 - assert(ignored == batch_end*sizeof(uint32_t));
15163 - close(fd);
15164 - }
15165 + VG_CLEAR(set_domain);
15166 + set_domain.handle = rq->bo->handle;
15167 + set_domain.read_domains = I915_GEM_DOMAIN_GTT;
15168 + set_domain.write_domain = I915_GEM_DOMAIN_GTT;
15170 - FatalError("SNA: failed to submit batchbuffer, errno=%d\n", -ret);
15171 - }
15172 -#endif
15173 + ret = do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
15175 - }
15177 #if SHOW_BATCH_AFTER
15178 - if (gem_read(kgem->fd, rq->bo->handle, kgem->batch, 0, batch_end*sizeof(uint32_t)) == 0)
15179 - __kgem_batch_debug(kgem, batch_end);
15180 + if (gem_read(kgem->fd, rq->bo->handle, kgem->batch, 0, batch_end*sizeof(uint32_t)) == 0)
15181 + __kgem_batch_debug(kgem, batch_end);
15182 #endif
15183 - kgem_commit(kgem);
15184 - if (kgem->wedged)
15186 + kgem_commit(kgem);
15187 + }
15189 + if (unlikely(kgem->wedged))
15190 kgem_cleanup(kgem);
15192 kgem_reset(kgem);
15193 @@ -3737,49 +4277,14 @@ void _kgem_submit(struct kgem *kgem)
15194 assert(kgem->next_request != NULL);
15197 -static bool find_hang_state(struct kgem *kgem, char *path, int maxlen)
15198 -{
15199 - int minor = kgem_get_minor(kgem);
15201 - /* Search for our hang state in a few canonical locations.
15202 - * In the unlikely event of having multiple devices, we
15203 - * will need to check which minor actually corresponds to ours.
15204 - */
15206 - snprintf(path, maxlen, "/sys/class/drm/card%d/error", minor);
15207 - if (access(path, R_OK) == 0)
15208 - return true;
15210 - snprintf(path, maxlen, "/sys/kernel/debug/dri/%d/i915_error_state", minor);
15211 - if (access(path, R_OK) == 0)
15212 - return true;
15214 - snprintf(path, maxlen, "/debug/dri/%d/i915_error_state", minor);
15215 - if (access(path, R_OK) == 0)
15216 - return true;
15218 - path[0] = '\0';
15219 - return false;
15220 -}
15222 void kgem_throttle(struct kgem *kgem)
15224 - if (kgem->wedged)
15225 + if (unlikely(kgem->wedged))
15226 return;
15228 if (__kgem_throttle(kgem, true)) {
15229 - static int once;
15230 - char path[128];
15232 xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
15233 "Detected a hung GPU, disabling acceleration.\n");
15234 - if (!once && find_hang_state(kgem, path, sizeof(path))) {
15235 - xf86DrvMsg(kgem_get_screen_index(kgem), X_ERROR,
15236 - "When reporting this, please include %s and the full dmesg.\n",
15237 - path);
15238 - once = 1;
15239 - }
15241 __kgem_set_wedged(kgem);
15242 kgem->need_throttle = false;
15244 @@ -3860,7 +4365,8 @@ bool kgem_expire_cache(struct kgem *kgem)
15245 bool idle;
15246 unsigned int i;
15248 - time(&now);
15249 + if (!time(&now))
15250 + return false;
15252 while (__kgem_freed_bo) {
15253 bo = __kgem_freed_bo;
15254 @@ -3875,7 +4381,7 @@ bool kgem_expire_cache(struct kgem *kgem)
15257 kgem_clean_large_cache(kgem);
15258 - if (container_of(kgem, struct sna, kgem)->scrn->vtSema)
15259 + if (__to_sna(kgem)->scrn->vtSema)
15260 kgem_clean_scanout_cache(kgem);
15262 expire = 0;
15263 @@ -3885,6 +4391,7 @@ bool kgem_expire_cache(struct kgem *kgem)
15264 break;
15267 + assert(now);
15268 bo->delta = now;
15270 if (expire) {
15271 @@ -3909,7 +4416,7 @@ bool kgem_expire_cache(struct kgem *kgem)
15272 #endif
15274 kgem_retire(kgem);
15275 - if (kgem->wedged)
15276 + if (unlikely(kgem->wedged))
15277 kgem_cleanup(kgem);
15279 kgem->expire(kgem);
15280 @@ -3930,6 +4437,8 @@ bool kgem_expire_cache(struct kgem *kgem)
15281 break;
15284 + assert(now);
15285 + kgem_bo_set_purgeable(kgem, bo);
15286 bo->delta = now;
15289 @@ -3960,16 +4469,11 @@ bool kgem_expire_cache(struct kgem *kgem)
15290 count++;
15291 size += bytes(bo);
15292 kgem_bo_free(kgem, bo);
15293 - DBG(("%s: expiring %d\n",
15294 + DBG(("%s: expiring handle=%d\n",
15295 __FUNCTION__, bo->handle));
15298 - if (!list_is_empty(&preserve)) {
15299 - preserve.prev->next = kgem->inactive[i].next;
15300 - kgem->inactive[i].next->prev = preserve.prev;
15301 - kgem->inactive[i].next = preserve.next;
15302 - preserve.next->prev = &kgem->inactive[i];
15303 - }
15304 + list_splice_tail(&preserve, &kgem->inactive[i]);
15307 #ifdef DEBUG_MEMORY
15308 @@ -3998,31 +4502,30 @@ bool kgem_cleanup_cache(struct kgem *kgem)
15309 unsigned int i;
15310 int n;
15312 + DBG(("%s\n", __FUNCTION__));
15314 /* sync to the most recent request */
15315 for (n = 0; n < ARRAY_SIZE(kgem->requests); n++) {
15316 if (!list_is_empty(&kgem->requests[n])) {
15317 struct kgem_request *rq;
15318 - struct drm_i915_gem_set_domain set_domain;
15320 - rq = list_first_entry(&kgem->requests[n],
15321 - struct kgem_request,
15322 - list);
15323 + rq = list_last_entry(&kgem->requests[n],
15324 + struct kgem_request,
15325 + list);
15327 DBG(("%s: sync on cleanup\n", __FUNCTION__));
15329 - VG_CLEAR(set_domain);
15330 - set_domain.handle = rq->bo->handle;
15331 - set_domain.read_domains = I915_GEM_DOMAIN_GTT;
15332 - set_domain.write_domain = I915_GEM_DOMAIN_GTT;
15333 - (void)do_ioctl(kgem->fd,
15334 - DRM_IOCTL_I915_GEM_SET_DOMAIN,
15335 - &set_domain);
15336 + assert(rq->ring == n);
15337 + assert(rq->bo);
15338 + assert(RQ(rq->bo->rq) == rq);
15339 + kgem_bo_wait(kgem, rq->bo);
15341 + assert(list_is_empty(&kgem->requests[n]));
15344 kgem_retire(kgem);
15345 kgem_cleanup(kgem);
15347 + DBG(("%s: need_expire?=%d\n", __FUNCTION__, kgem->need_expire));
15348 if (!kgem->need_expire)
15349 return false;
15351 @@ -4049,6 +4552,8 @@ bool kgem_cleanup_cache(struct kgem *kgem)
15353 kgem->need_purge = false;
15354 kgem->need_expire = false;
15356 + DBG(("%s: complete\n", __FUNCTION__));
15357 return true;
15360 @@ -4079,16 +4584,15 @@ retry_large:
15361 goto discard;
15363 if (bo->tiling != I915_TILING_NONE) {
15364 - if (use_active)
15365 + if (use_active && kgem->gen < 040)
15366 goto discard;
15368 - if (!gem_set_tiling(kgem->fd, bo->handle,
15369 + if (!kgem_set_tiling(kgem, bo,
15370 I915_TILING_NONE, 0))
15371 goto discard;
15373 - bo->tiling = I915_TILING_NONE;
15374 - bo->pitch = 0;
15376 + assert(bo->tiling == I915_TILING_NONE);
15377 + bo->pitch = 0;
15379 if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo))
15380 goto discard;
15381 @@ -4169,17 +4673,17 @@ discard:
15382 break;
15385 - if (I915_TILING_NONE != bo->tiling &&
15386 - !gem_set_tiling(kgem->fd, bo->handle,
15387 - I915_TILING_NONE, 0))
15388 - continue;
15389 + if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) {
15390 + kgem_bo_free(kgem, bo);
15391 + break;
15392 + }
15394 kgem_bo_remove_from_inactive(kgem, bo);
15395 assert(list_is_empty(&bo->vma));
15396 assert(list_is_empty(&bo->list));
15398 - bo->tiling = I915_TILING_NONE;
15399 - bo->pitch = 0;
15400 + assert(bo->tiling == I915_TILING_NONE);
15401 + assert(bo->pitch == 0);
15402 bo->delta = 0;
15403 DBG((" %s: found handle=%d (num_pages=%d) in linear vma cache\n",
15404 __FUNCTION__, bo->handle, num_pages(bo)));
15405 @@ -4225,13 +4729,13 @@ discard:
15406 if (first)
15407 continue;
15409 - if (!gem_set_tiling(kgem->fd, bo->handle,
15410 - I915_TILING_NONE, 0))
15411 - continue;
15413 - bo->tiling = I915_TILING_NONE;
15414 - bo->pitch = 0;
15415 + if (!kgem_set_tiling(kgem, bo, I915_TILING_NONE, 0)) {
15416 + kgem_bo_free(kgem, bo);
15417 + break;
15418 + }
15420 + assert(bo->tiling == I915_TILING_NONE);
15421 + bo->pitch = 0;
15423 if (bo->map__gtt || bo->map__wc || bo->map__cpu) {
15424 if (flags & (CREATE_CPU_MAP | CREATE_GTT_MAP)) {
15425 @@ -4269,7 +4773,7 @@ discard:
15426 kgem_bo_remove_from_inactive(kgem, bo);
15428 assert(bo->tiling == I915_TILING_NONE);
15429 - bo->pitch = 0;
15430 + assert(bo->pitch == 0);
15431 bo->delta = 0;
15432 DBG((" %s: found handle=%d (num_pages=%d) in linear %s cache\n",
15433 __FUNCTION__, bo->handle, num_pages(bo),
15434 @@ -4340,9 +4844,9 @@ struct kgem_bo *kgem_create_for_name(struct kgem *kgem, uint32_t name)
15436 bo->unique_id = kgem_get_unique_id(kgem);
15437 bo->tiling = tiling.tiling_mode;
15438 - bo->reusable = false;
15439 bo->prime = true;
15440 - bo->purged = true; /* no coherency guarantees */
15441 + bo->reusable = false;
15442 + kgem_bo_unclean(kgem, bo);
15444 debug_alloc__bo(kgem, bo);
15445 return bo;
15446 @@ -4448,6 +4952,8 @@ int kgem_bo_export_to_prime(struct kgem *kgem, struct kgem_bo *bo)
15447 #if defined(DRM_IOCTL_PRIME_HANDLE_TO_FD) && defined(O_CLOEXEC)
15448 struct drm_prime_handle args;
15450 + assert(kgem_bo_is_fenced(kgem, bo));
15452 VG_CLEAR(args);
15453 args.handle = bo->handle;
15454 args.flags = O_CLOEXEC;
15455 @@ -4479,6 +4985,8 @@ struct kgem_bo *kgem_create_linear(struct kgem *kgem, int size, unsigned flags)
15456 if ((flags & CREATE_UNCACHED) == 0) {
15457 bo = search_linear_cache(kgem, size, CREATE_INACTIVE | flags);
15458 if (bo) {
15459 + assert(!bo->purged);
15460 + assert(!bo->delta);
15461 assert(bo->domain != DOMAIN_GPU);
15462 ASSERT_IDLE(kgem, bo->handle);
15463 bo->refcnt = 1;
15464 @@ -4760,8 +5268,7 @@ static void __kgem_bo_make_scanout(struct kgem *kgem,
15465 struct kgem_bo *bo,
15466 int width, int height)
15468 - ScrnInfoPtr scrn =
15469 - container_of(kgem, struct sna, kgem)->scrn;
15470 + ScrnInfoPtr scrn = __to_sna(kgem)->scrn;
15471 struct drm_mode_fb_cmd arg;
15473 assert(bo->proxy == NULL);
15474 @@ -4809,6 +5316,48 @@ static void __kgem_bo_make_scanout(struct kgem *kgem,
15478 +static bool tiling_changed(struct kgem_bo *bo, int tiling, int pitch)
15479 +{
15480 + if (tiling != bo->tiling)
15481 + return true;
15483 + return tiling != I915_TILING_NONE && pitch != bo->pitch;
15484 +}
15486 +static void set_gpu_tiling(struct kgem *kgem,
15487 + struct kgem_bo *bo,
15488 + int tiling, int pitch)
15489 +{
15490 + DBG(("%s: handle=%d, tiling=%d, pitch=%d\n",
15491 + __FUNCTION__, bo->handle, tiling, pitch));
15493 + if (tiling_changed(bo, tiling, pitch) && bo->map__gtt) {
15494 + if (!list_is_empty(&bo->vma)) {
15495 + list_del(&bo->vma);
15496 + kgem->vma[0].count--;
15497 + }
15498 + munmap(bo->map__gtt, bytes(bo));
15499 + bo->map__gtt = NULL;
15500 + }
15502 + bo->tiling = tiling;
15503 + bo->pitch = pitch;
15504 +}
15506 +bool kgem_bo_is_fenced(struct kgem *kgem, struct kgem_bo *bo)
15507 +{
15508 + struct drm_i915_gem_get_tiling tiling;
15510 + assert(kgem);
15511 + assert(bo);
15513 + VG_CLEAR(tiling);
15514 + tiling.handle = bo->handle;
15515 + tiling.tiling_mode = bo->tiling;
15516 + (void)do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &tiling);
15517 + return tiling.tiling_mode == bo->tiling; /* assume pitch is fine! */
15518 +}
15520 struct kgem_bo *kgem_create_2d(struct kgem *kgem,
15521 int width,
15522 int height,
15523 @@ -4892,8 +5441,8 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
15524 return last;
15527 - if (container_of(kgem, struct sna, kgem)->scrn->vtSema) {
15528 - ScrnInfoPtr scrn = container_of(kgem, struct sna, kgem)->scrn;
15529 + if (__to_sna(kgem)->scrn->vtSema) {
15530 + ScrnInfoPtr scrn = __to_sna(kgem)->scrn;
15532 list_for_each_entry_reverse(bo, &kgem->scanout, list) {
15533 struct drm_mode_fb_cmd arg;
15534 @@ -4915,11 +5464,8 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
15535 bo->delta = 0;
15538 - if (gem_set_tiling(kgem->fd, bo->handle,
15539 - tiling, pitch)) {
15540 - bo->tiling = tiling;
15541 - bo->pitch = pitch;
15542 - } else {
15543 + if (!kgem_set_tiling(kgem, bo,
15544 + tiling, pitch)) {
15545 kgem_bo_free(kgem, bo);
15546 break;
15548 @@ -4950,6 +5496,9 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
15552 + if (flags & CREATE_CACHED)
15553 + return NULL;
15555 bo = __kgem_bo_create_as_display(kgem, size, tiling, pitch);
15556 if (bo)
15557 return bo;
15558 @@ -4987,14 +5536,9 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
15559 if (num_pages(bo) < size)
15560 continue;
15562 - if (bo->pitch != pitch || bo->tiling != tiling) {
15563 - if (!gem_set_tiling(kgem->fd, bo->handle,
15564 - tiling, pitch))
15565 - continue;
15567 - bo->pitch = pitch;
15568 - bo->tiling = tiling;
15569 - }
15570 + if (!kgem_set_tiling(kgem, bo, tiling, pitch) &&
15571 + !exact)
15572 + set_gpu_tiling(kgem, bo, tiling, pitch);
15575 kgem_bo_remove_from_active(kgem, bo);
15576 @@ -5020,14 +5564,11 @@ large_inactive:
15577 if (size > num_pages(bo))
15578 continue;
15580 - if (bo->tiling != tiling ||
15581 - (tiling != I915_TILING_NONE && bo->pitch != pitch)) {
15582 - if (!gem_set_tiling(kgem->fd, bo->handle,
15583 - tiling, pitch))
15584 + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) {
15585 + if (kgem->gen >= 040 && !exact)
15586 + set_gpu_tiling(kgem, bo, tiling, pitch);
15587 + else
15588 continue;
15590 - bo->tiling = tiling;
15591 - bo->pitch = pitch;
15594 if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) {
15595 @@ -5039,7 +5580,6 @@ large_inactive:
15597 assert(bo->domain != DOMAIN_GPU);
15598 bo->unique_id = kgem_get_unique_id(kgem);
15599 - bo->pitch = pitch;
15600 bo->delta = 0;
15601 DBG((" 1:from large inactive: pitch=%d, tiling=%d, handle=%d, id=%d\n",
15602 bo->pitch, bo->tiling, bo->handle, bo->unique_id));
15603 @@ -5088,14 +5628,13 @@ large_inactive:
15604 if (bo->tiling != tiling ||
15605 (tiling != I915_TILING_NONE && bo->pitch != pitch)) {
15606 if (bo->map__gtt ||
15607 - !gem_set_tiling(kgem->fd, bo->handle,
15608 - tiling, pitch)) {
15609 + !kgem_set_tiling(kgem, bo,
15610 + tiling, pitch)) {
15611 DBG(("inactive GTT vma with wrong tiling: %d < %d\n",
15612 bo->tiling, tiling));
15613 - continue;
15614 + kgem_bo_free(kgem, bo);
15615 + break;
15617 - bo->tiling = tiling;
15618 - bo->pitch = pitch;
15621 if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) {
15622 @@ -5103,8 +5642,11 @@ large_inactive:
15623 break;
15626 + if (tiling == I915_TILING_NONE)
15627 + bo->pitch = pitch;
15629 assert(bo->tiling == tiling);
15630 - bo->pitch = pitch;
15631 + assert(bo->pitch >= pitch);
15632 bo->delta = 0;
15633 bo->unique_id = kgem_get_unique_id(kgem);
15635 @@ -5170,15 +5712,12 @@ search_active:
15636 if (num_pages(bo) < size)
15637 continue;
15639 - if (bo->pitch != pitch) {
15640 - if (!gem_set_tiling(kgem->fd,
15641 - bo->handle,
15642 - tiling, pitch))
15643 - continue;
15645 - bo->pitch = pitch;
15646 - }
15647 + if (!kgem_set_tiling(kgem, bo, tiling, pitch) &&
15648 + !exact)
15649 + set_gpu_tiling(kgem, bo, tiling, pitch);
15651 + assert(bo->tiling == tiling);
15652 + assert(bo->pitch >= pitch);
15654 kgem_bo_remove_from_active(kgem, bo);
15656 @@ -5233,19 +5772,21 @@ search_active:
15657 if (num_pages(bo) < size)
15658 continue;
15660 - if (bo->tiling != tiling ||
15661 - (tiling != I915_TILING_NONE && bo->pitch != pitch)) {
15662 - if (!gem_set_tiling(kgem->fd,
15663 - bo->handle,
15664 - tiling, pitch))
15665 - continue;
15666 + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) {
15667 + if (kgem->gen >= 040 && !exact) {
15668 + set_gpu_tiling(kgem, bo,
15669 + tiling, pitch);
15670 + } else {
15671 + kgem_bo_free(kgem, bo);
15672 + break;
15673 + }
15675 + assert(bo->tiling == tiling);
15676 + assert(bo->pitch >= pitch);
15678 kgem_bo_remove_from_active(kgem, bo);
15680 bo->unique_id = kgem_get_unique_id(kgem);
15681 - bo->pitch = pitch;
15682 - bo->tiling = tiling;
15683 bo->delta = 0;
15684 DBG((" 1:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n",
15685 bo->pitch, bo->tiling, bo->handle, bo->unique_id));
15686 @@ -5323,11 +5864,13 @@ search_inactive:
15687 continue;
15690 - if (bo->tiling != tiling ||
15691 - (tiling != I915_TILING_NONE && bo->pitch != pitch)) {
15692 - if (!gem_set_tiling(kgem->fd, bo->handle,
15693 - tiling, pitch))
15694 - continue;
15695 + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) {
15696 + if (kgem->gen >= 040 && !exact) {
15697 + set_gpu_tiling(kgem, bo, tiling, pitch);
15698 + } else {
15699 + kgem_bo_free(kgem, bo);
15700 + break;
15701 + }
15704 if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) {
15705 @@ -5338,9 +5881,8 @@ search_inactive:
15706 kgem_bo_remove_from_inactive(kgem, bo);
15707 assert(list_is_empty(&bo->list));
15708 assert(list_is_empty(&bo->vma));
15710 - bo->pitch = pitch;
15711 - bo->tiling = tiling;
15712 + assert(bo->tiling == tiling);
15713 + assert(bo->pitch >= pitch);
15715 bo->delta = 0;
15716 bo->unique_id = kgem_get_unique_id(kgem);
15717 @@ -5388,14 +5930,17 @@ search_inactive:
15718 kgem_bo_remove_from_active(kgem, bo);
15719 __kgem_bo_clear_busy(bo);
15721 - if (tiling != I915_TILING_NONE && bo->pitch != pitch) {
15722 - if (!gem_set_tiling(kgem->fd, bo->handle, tiling, pitch)) {
15723 + if (!kgem_set_tiling(kgem, bo, tiling, pitch)) {
15724 + if (kgem->gen >= 040 && !exact) {
15725 + set_gpu_tiling(kgem, bo, tiling, pitch);
15726 + } else {
15727 kgem_bo_free(kgem, bo);
15728 goto no_retire;
15731 + assert(bo->tiling == tiling);
15732 + assert(bo->pitch >= pitch);
15734 - bo->pitch = pitch;
15735 bo->unique_id = kgem_get_unique_id(kgem);
15736 bo->delta = 0;
15737 DBG((" 2:from active: pitch=%d, tiling=%d, handle=%d, id=%d\n",
15738 @@ -5440,18 +5985,21 @@ create:
15741 bo->unique_id = kgem_get_unique_id(kgem);
15742 - if (tiling == I915_TILING_NONE ||
15743 - gem_set_tiling(kgem->fd, handle, tiling, pitch)) {
15744 - bo->tiling = tiling;
15745 - bo->pitch = pitch;
15746 + if (kgem_set_tiling(kgem, bo, tiling, pitch)) {
15747 if (flags & CREATE_SCANOUT)
15748 __kgem_bo_make_scanout(kgem, bo, width, height);
15749 } else {
15750 - if (flags & CREATE_EXACT) {
15751 - DBG(("%s: failed to set exact tiling (gem_set_tiling)\n", __FUNCTION__));
15752 - gem_close(kgem->fd, handle);
15753 - free(bo);
15754 - return NULL;
15755 + if (kgem->gen >= 040) {
15756 + assert(!kgem->can_fence);
15757 + bo->tiling = tiling;
15758 + bo->pitch = pitch;
15759 + } else {
15760 + if (flags & CREATE_EXACT) {
15761 + DBG(("%s: failed to set exact tiling (gem_set_tiling)\n", __FUNCTION__));
15762 + gem_close(kgem->fd, handle);
15763 + free(bo);
15764 + return NULL;
15765 + }
15769 @@ -5608,7 +6156,7 @@ static void __kgem_flush(struct kgem *kgem, struct kgem_bo *bo)
15771 void kgem_scanout_flush(struct kgem *kgem, struct kgem_bo *bo)
15773 - if (!bo->needs_flush)
15774 + if (!bo->needs_flush && !bo->gtt_dirty)
15775 return;
15777 kgem_bo_submit(kgem, bo);
15778 @@ -5621,18 +6169,24 @@ void kgem_scanout_flush(struct kgem *kgem, struct kgem_bo *bo)
15779 if (bo->rq)
15780 __kgem_flush(kgem, bo);
15782 + if (bo->scanout && kgem->needs_dirtyfb) {
15783 + struct drm_mode_fb_dirty_cmd cmd;
15784 + memset(&cmd, 0, sizeof(cmd));
15785 + cmd.fb_id = bo->delta;
15786 + (void)drmIoctl(kgem->fd, DRM_IOCTL_MODE_DIRTYFB, &cmd);
15787 + }
15789 /* Whatever actually happens, we can regard the GTT write domain
15790 * as being flushed.
15791 */
15792 - bo->gtt_dirty = false;
15793 - bo->needs_flush = false;
15794 - bo->domain = DOMAIN_NONE;
15795 + __kgem_bo_clear_dirty(bo);
15798 inline static bool nearly_idle(struct kgem *kgem)
15800 int ring = kgem->ring == KGEM_BLT;
15802 + assert(ring < ARRAY_SIZE(kgem->requests));
15803 if (list_is_singular(&kgem->requests[ring]))
15804 return true;
15806 @@ -5720,7 +6274,7 @@ static inline bool kgem_flush(struct kgem *kgem, bool flush)
15807 if (kgem->nreloc == 0)
15808 return true;
15810 - if (container_of(kgem, struct sna, kgem)->flags & SNA_POWERSAVE)
15811 + if (__to_sna(kgem)->flags & SNA_POWERSAVE)
15812 return true;
15814 if (kgem->flush == flush && kgem->aperture < kgem->aperture_low)
15815 @@ -5982,6 +6536,55 @@ bool kgem_check_many_bo_fenced(struct kgem *kgem, ...)
15816 return kgem_flush(kgem, flush);
15819 +void __kgem_bcs_set_tiling(struct kgem *kgem,
15820 + struct kgem_bo *src,
15821 + struct kgem_bo *dst)
15822 +{
15823 + uint32_t state, *b;
15825 + DBG(("%s: src handle=%d:tiling=%d, dst handle=%d:tiling=%d\n",
15826 + __FUNCTION__,
15827 + src ? src->handle : 0, src ? src->tiling : 0,
15828 + dst ? dst->handle : 0, dst ? dst->tiling : 0));
15829 + assert(kgem->mode == KGEM_BLT);
15830 + assert(dst == NULL || kgem_bo_can_blt(kgem, dst));
15831 + assert(src == NULL || kgem_bo_can_blt(kgem, src));
15833 + state = 0;
15834 + if (dst && dst->tiling == I915_TILING_Y)
15835 + state |= BCS_DST_Y;
15836 + if (src && src->tiling == I915_TILING_Y)
15837 + state |= BCS_SRC_Y;
15839 + if (kgem->bcs_state == state)
15840 + return;
15842 + DBG(("%s: updating SWCTRL %x -> %x\n", __FUNCTION__,
15843 + kgem->bcs_state, state));
15845 + /* Over-estimate space in case we need to re-emit the cmd packet */
15846 + if (!kgem_check_batch(kgem, 24)) {
15847 + _kgem_submit(kgem);
15848 + _kgem_set_mode(kgem, KGEM_BLT);
15849 + if (state == 0)
15850 + return;
15851 + }
15853 + b = kgem->batch + kgem->nbatch;
15854 + if (kgem->nbatch) {
15855 + *b++ = MI_FLUSH_DW;
15856 + *b++ = 0;
15857 + *b++ = 0;
15858 + *b++ = 0;
15859 + }
15860 + *b++ = MI_LOAD_REGISTER_IMM;
15861 + *b++ = BCS_SWCTRL;
15862 + *b++ = (BCS_SRC_Y | BCS_DST_Y) << 16 | state;
15863 + kgem->nbatch = b - kgem->batch;
15865 + kgem->bcs_state = state;
15866 +}
15868 uint32_t kgem_add_reloc(struct kgem *kgem,
15869 uint32_t pos,
15870 struct kgem_bo *bo,
15871 @@ -6195,12 +6798,6 @@ static void kgem_trim_vma_cache(struct kgem *kgem, int type, int bucket)
15873 list_del(&bo->vma);
15874 kgem->vma[type].count--;
15876 - if (!bo->purged && !kgem_bo_set_purgeable(kgem, bo)) {
15877 - DBG(("%s: freeing unpurgeable old mapping\n",
15878 - __FUNCTION__));
15879 - kgem_bo_free(kgem, bo);
15880 - }
15884 @@ -6216,8 +6813,8 @@ static void *__kgem_bo_map__gtt_or_wc(struct kgem *kgem, struct kgem_bo *bo)
15885 kgem_trim_vma_cache(kgem, MAP_GTT, bucket(bo));
15887 if (bo->tiling || !kgem->has_wc_mmap) {
15888 - assert(num_pages(bo) <= kgem->aperture_mappable / 2);
15889 assert(kgem->gen != 021 || bo->tiling != I915_TILING_Y);
15890 + warn_unless(num_pages(bo) <= kgem->aperture_mappable / 2);
15892 ptr = bo->map__gtt;
15893 if (ptr == NULL)
15894 @@ -6291,6 +6888,7 @@ void *kgem_bo_map(struct kgem *kgem, struct kgem_bo *bo)
15895 DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
15896 kgem_throttle(kgem);
15898 + bo->needs_flush = false;
15899 kgem_bo_retire(kgem, bo);
15900 bo->domain = DOMAIN_GTT;
15901 bo->gtt_dirty = true;
15902 @@ -6319,14 +6917,16 @@ void *kgem_bo_map__wc(struct kgem *kgem, struct kgem_bo *bo)
15903 bo->handle, (long)bo->presumed_offset, bo->tiling, bo->map__gtt, bo->map__cpu, bo->domain));
15905 assert(bo->proxy == NULL);
15906 - assert(bo->exec == NULL);
15907 assert(list_is_empty(&bo->list));
15908 assert_tiling(kgem, bo);
15909 assert(!bo->purged || bo->reusable);
15911 if (bo->map__wc)
15912 return bo->map__wc;
15913 + if (!kgem->has_wc_mmap)
15914 + return NULL;
15916 + kgem_trim_vma_cache(kgem, MAP_GTT, bucket(bo));
15917 return __kgem_bo_map__wc(kgem, bo);
15920 @@ -6373,6 +6973,8 @@ uint32_t kgem_bo_flink(struct kgem *kgem, struct kgem_bo *bo)
15922 struct drm_gem_flink flink;
15924 + assert(kgem_bo_is_fenced(kgem, bo));
15926 VG_CLEAR(flink);
15927 flink.handle = bo->handle;
15928 if (do_ioctl(kgem->fd, DRM_IOCTL_GEM_FLINK, &flink))
15929 @@ -6387,7 +6989,6 @@ uint32_t kgem_bo_flink(struct kgem *kgem, struct kgem_bo *bo)
15930 * party, we track the lifetime accurately.
15931 */
15932 bo->reusable = false;
15934 kgem_bo_unclean(kgem, bo);
15936 return flink.name;
15937 @@ -6411,16 +7012,34 @@ struct kgem_bo *kgem_create_map(struct kgem *kgem,
15938 first_page = (uintptr_t)ptr;
15939 last_page = first_page + size + PAGE_SIZE - 1;
15941 - first_page &= ~(PAGE_SIZE-1);
15942 - last_page &= ~(PAGE_SIZE-1);
15943 + first_page &= ~(uintptr_t)(PAGE_SIZE-1);
15944 + last_page &= ~(uintptr_t)(PAGE_SIZE-1);
15945 assert(last_page > first_page);
15947 handle = gem_userptr(kgem->fd,
15948 (void *)first_page, last_page-first_page,
15949 read_only);
15950 if (handle == 0) {
15951 - DBG(("%s: import failed, errno=%d\n", __FUNCTION__, errno));
15952 - return NULL;
15953 + if (read_only && kgem->has_wc_mmap) {
15954 + struct drm_i915_gem_set_domain set_domain;
15956 + handle = gem_userptr(kgem->fd,
15957 + (void *)first_page, last_page-first_page,
15958 + false);
15960 + VG_CLEAR(set_domain);
15961 + set_domain.handle = handle;
15962 + set_domain.read_domains = I915_GEM_DOMAIN_GTT;
15963 + set_domain.write_domain = 0;
15964 + if (do_ioctl(kgem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) {
15965 + gem_close(kgem->fd, handle);
15966 + handle = 0;
15967 + }
15968 + }
15969 + if (handle == 0) {
15970 + DBG(("%s: import failed, errno=%d\n", __FUNCTION__, errno));
15971 + return NULL;
15972 + }
15975 bo = __kgem_bo_alloc(handle, (last_page - first_page) / PAGE_SIZE);
15976 @@ -6483,8 +7102,10 @@ void kgem_bo_sync__cpu(struct kgem *kgem, struct kgem_bo *bo)
15977 DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
15978 kgem_throttle(kgem);
15980 + bo->needs_flush = false;
15981 kgem_bo_retire(kgem, bo);
15982 bo->domain = DOMAIN_CPU;
15983 + bo->gtt_dirty = true;
15987 @@ -6505,6 +7126,9 @@ void kgem_bo_sync__cpu_full(struct kgem *kgem, struct kgem_bo *bo, bool write)
15988 assert(bo->refcnt);
15989 assert(!bo->purged);
15991 + if (bo->rq == NULL && (kgem->has_llc || bo->snoop) && !write)
15992 + return;
15994 if (bo->domain != DOMAIN_CPU || FORCE_MMAP_SYNC & (1 << DOMAIN_CPU)) {
15995 struct drm_i915_gem_set_domain set_domain;
15997 @@ -6522,9 +7146,11 @@ void kgem_bo_sync__cpu_full(struct kgem *kgem, struct kgem_bo *bo, bool write)
15998 DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
15999 kgem_throttle(kgem);
16001 + bo->needs_flush = false;
16002 if (write) {
16003 kgem_bo_retire(kgem, bo);
16004 bo->domain = DOMAIN_CPU;
16005 + bo->gtt_dirty = true;
16006 } else {
16007 if (bo->exec == NULL)
16008 kgem_bo_maybe_retire(kgem, bo);
16009 @@ -6539,6 +7165,7 @@ void kgem_bo_sync__gtt(struct kgem *kgem, struct kgem_bo *bo)
16010 assert(bo->refcnt);
16011 assert(bo->proxy == NULL);
16012 assert_tiling(kgem, bo);
16013 + assert(!bo->snoop);
16015 kgem_bo_submit(kgem, bo);
16017 @@ -6559,6 +7186,7 @@ void kgem_bo_sync__gtt(struct kgem *kgem, struct kgem_bo *bo)
16018 DBG(("%s: sync: GPU hang detected\n", __FUNCTION__));
16019 kgem_throttle(kgem);
16021 + bo->needs_flush = false;
16022 kgem_bo_retire(kgem, bo);
16023 bo->domain = DOMAIN_GTT;
16024 bo->gtt_dirty = true;
16025 @@ -7485,6 +8113,7 @@ kgem_replace_bo(struct kgem *kgem,
16027 _kgem_set_mode(kgem, KGEM_BLT);
16029 + kgem_bcs_set_tiling(kgem, src, dst);
16031 br00 = XY_SRC_COPY_BLT_CMD;
16032 br13 = pitch;
16033 @@ -7553,6 +8182,9 @@ bool kgem_bo_convert_to_gpu(struct kgem *kgem,
16034 __FUNCTION__, bo->handle, flags, __kgem_bo_is_busy(kgem, bo)));
16035 assert(bo->tiling == I915_TILING_NONE);
16037 + if (flags & (__MOVE_PRIME | __MOVE_SCANOUT))
16038 + return false;
16040 if (kgem->has_llc)
16041 return true;
16043 diff --git a/src/sna/kgem.h b/src/sna/kgem.h
16044 index 2267bacf..08b4eb20 100644
16045 --- a/src/sna/kgem.h
16046 +++ b/src/sna/kgem.h
16047 @@ -42,6 +42,7 @@ struct kgem_bo {
16048 #define RQ(rq) ((struct kgem_request *)((uintptr_t)(rq) & ~3))
16049 #define RQ_RING(rq) ((uintptr_t)(rq) & 3)
16050 #define RQ_IS_BLT(rq) (RQ_RING(rq) == KGEM_BLT)
16051 +#define RQ_IS_RENDER(rq) (RQ_RING(rq) == KGEM_RENDER)
16052 #define MAKE_REQUEST(rq, ring) ((struct kgem_request *)((uintptr_t)(rq) | (ring)))
16054 struct drm_i915_gem_exec_object2 *exec;
16055 @@ -103,7 +104,7 @@ struct kgem_request {
16056 struct list list;
16057 struct kgem_bo *bo;
16058 struct list buffers;
16059 - int ring;
16060 + unsigned ring;
16061 };
16063 enum {
16064 @@ -112,6 +113,12 @@ enum {
16065 NUM_MAP_TYPES,
16066 };
16068 +typedef void (*memcpy_box_func)(const void *src, void *dst, int bpp,
16069 + int32_t src_stride, int32_t dst_stride,
16070 + int16_t src_x, int16_t src_y,
16071 + int16_t dst_x, int16_t dst_y,
16072 + uint16_t width, uint16_t height);
16074 struct kgem {
16075 unsigned wedged;
16076 int fd;
16077 @@ -157,6 +164,8 @@ struct kgem {
16078 int16_t count;
16079 } vma[NUM_MAP_TYPES];
16081 + uint32_t bcs_state;
16083 uint32_t batch_flags;
16084 uint32_t batch_flags_base;
16085 #define I915_EXEC_SECURE (1<<9)
16086 @@ -186,9 +195,15 @@ struct kgem {
16087 uint32_t has_no_reloc :1;
16088 uint32_t has_handle_lut :1;
16089 uint32_t has_wc_mmap :1;
16090 + uint32_t has_dirtyfb :1;
16092 + uint32_t can_fence :1;
16093 uint32_t can_blt_cpu :1;
16094 + uint32_t can_blt_y :1;
16095 uint32_t can_render_y :1;
16096 + uint32_t can_scanout_y :1;
16098 + uint32_t needs_dirtyfb :1;
16100 uint16_t fence_max;
16101 uint16_t half_cpu_cache_pages;
16102 @@ -203,16 +218,9 @@ struct kgem {
16103 void (*retire)(struct kgem *kgem);
16104 void (*expire)(struct kgem *kgem);
16106 - void (*memcpy_to_tiled_x)(const void *src, void *dst, int bpp,
16107 - int32_t src_stride, int32_t dst_stride,
16108 - int16_t src_x, int16_t src_y,
16109 - int16_t dst_x, int16_t dst_y,
16110 - uint16_t width, uint16_t height);
16111 - void (*memcpy_from_tiled_x)(const void *src, void *dst, int bpp,
16112 - int32_t src_stride, int32_t dst_stride,
16113 - int16_t src_x, int16_t src_y,
16114 - int16_t dst_x, int16_t dst_y,
16115 - uint16_t width, uint16_t height);
16116 + memcpy_box_func memcpy_to_tiled_x;
16117 + memcpy_box_func memcpy_from_tiled_x;
16118 + memcpy_box_func memcpy_between_tiled_x;
16120 struct kgem_bo *batch_bo;
16122 @@ -230,7 +238,7 @@ struct kgem {
16124 #define KGEM_MAX_DEFERRED_VBO 16
16126 -#define KGEM_BATCH_RESERVED 1
16127 +#define KGEM_BATCH_RESERVED 8 /* LRI(SWCTRL) + END */
16128 #define KGEM_RELOC_RESERVED (KGEM_MAX_DEFERRED_VBO)
16129 #define KGEM_EXEC_RESERVED (1+KGEM_MAX_DEFERRED_VBO)
16131 @@ -317,6 +325,7 @@ bool kgem_bo_convert_to_gpu(struct kgem *kgem,
16132 struct kgem_bo *bo,
16133 unsigned flags);
16135 +bool kgem_bo_is_fenced(struct kgem *kgem, struct kgem_bo *bo);
16136 uint32_t kgem_bo_get_binding(struct kgem_bo *bo, uint32_t format);
16137 void kgem_bo_set_binding(struct kgem_bo *bo, uint32_t format, uint16_t offset);
16139 @@ -342,6 +351,11 @@ static inline bool kgem_ring_is_idle(struct kgem *kgem, int ring)
16141 ring = ring == KGEM_BLT;
16143 + if (kgem->needs_semaphore &&
16144 + !list_is_empty(&kgem->requests[!ring]) &&
16145 + !__kgem_ring_is_idle(kgem, !ring))
16146 + return false;
16148 if (list_is_empty(&kgem->requests[ring]))
16149 return true;
16151 @@ -390,6 +404,7 @@ void _kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo);
16152 static inline void kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
16154 assert(bo->refcnt);
16155 + assert(bo->refcnt > bo->active_scanout);
16156 if (--bo->refcnt == 0)
16157 _kgem_bo_destroy(kgem, bo);
16159 @@ -400,13 +415,13 @@ static inline void kgem_set_mode(struct kgem *kgem,
16160 enum kgem_mode mode,
16161 struct kgem_bo *bo)
16163 - assert(!kgem->wedged);
16164 + warn_unless(!kgem->wedged);
16166 #if DEBUG_FLUSH_BATCH
16167 kgem_submit(kgem);
16168 #endif
16170 - if (kgem->nreloc && bo->exec == NULL && kgem_ring_is_idle(kgem, kgem->ring)) {
16171 + if (kgem->nreloc && bo->rq == NULL && kgem_ring_is_idle(kgem, kgem->ring)) {
16172 DBG(("%s: flushing before new bo\n", __FUNCTION__));
16173 _kgem_submit(kgem);
16175 @@ -422,7 +437,7 @@ static inline void _kgem_set_mode(struct kgem *kgem, enum kgem_mode mode)
16177 assert(kgem->mode == KGEM_NONE);
16178 assert(kgem->nbatch == 0);
16179 - assert(!kgem->wedged);
16180 + warn_unless(!kgem->wedged);
16181 kgem->context_switch(kgem, mode);
16182 kgem->mode = mode;
16184 @@ -566,7 +581,7 @@ static inline bool kgem_bo_can_blt(struct kgem *kgem,
16186 assert(bo->refcnt);
16188 - if (bo->tiling == I915_TILING_Y) {
16189 + if (bo->tiling == I915_TILING_Y && !kgem->can_blt_y) {
16190 DBG(("%s: can not blt to handle=%d, tiling=Y\n",
16191 __FUNCTION__, bo->handle));
16192 return false;
16193 @@ -581,6 +596,22 @@ static inline bool kgem_bo_can_blt(struct kgem *kgem,
16194 return kgem_bo_blt_pitch_is_ok(kgem, bo);
16197 +void __kgem_bcs_set_tiling(struct kgem *kgem,
16198 + struct kgem_bo *src,
16199 + struct kgem_bo *dst);
16201 +inline static void kgem_bcs_set_tiling(struct kgem *kgem,
16202 + struct kgem_bo *src,
16203 + struct kgem_bo *dst)
16204 +{
16205 + assert(kgem->mode == KGEM_BLT);
16207 + if (!kgem->can_blt_y)
16208 + return;
16210 + __kgem_bcs_set_tiling(kgem, src, dst);
16211 +}
16213 static inline bool kgem_bo_is_snoop(struct kgem_bo *bo)
16215 assert(bo->refcnt);
16216 @@ -607,17 +638,24 @@ static inline void kgem_bo_mark_busy(struct kgem *kgem, struct kgem_bo *bo, int
16220 -inline static void __kgem_bo_clear_busy(struct kgem_bo *bo)
16221 +static inline void __kgem_bo_clear_dirty(struct kgem_bo *bo)
16223 DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle));
16224 - bo->rq = NULL;
16225 - list_del(&bo->request);
16227 bo->domain = DOMAIN_NONE;
16228 bo->needs_flush = false;
16229 bo->gtt_dirty = false;
16232 +inline static void __kgem_bo_clear_busy(struct kgem_bo *bo)
16233 +{
16234 + DBG(("%s: handle=%d\n", __FUNCTION__, bo->handle));
16235 + bo->rq = NULL;
16236 + list_del(&bo->request);
16238 + __kgem_bo_clear_dirty(bo);
16239 +}
16241 static inline bool kgem_bo_is_busy(struct kgem_bo *bo)
16243 DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__,
16244 @@ -626,7 +664,7 @@ static inline bool kgem_bo_is_busy(struct kgem_bo *bo)
16245 return bo->rq;
16248 -void __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo);
16249 +bool __kgem_retire_requests_upto(struct kgem *kgem, struct kgem_bo *bo);
16250 static inline bool __kgem_bo_is_busy(struct kgem *kgem, struct kgem_bo *bo)
16252 DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__,
16253 @@ -636,14 +674,13 @@ static inline bool __kgem_bo_is_busy(struct kgem *kgem, struct kgem_bo *bo)
16254 if (bo->exec)
16255 return true;
16257 - if (bo->rq && !__kgem_busy(kgem, bo->handle)) {
16258 - __kgem_retire_requests_upto(kgem, bo);
16259 - assert(list_is_empty(&bo->request));
16260 - assert(bo->rq == NULL);
16261 - assert(bo->domain == DOMAIN_NONE);
16262 - }
16263 + if (bo->rq == NULL)
16264 + return false;
16266 + if (__kgem_busy(kgem, bo->handle))
16267 + return true;
16269 - return kgem_bo_is_busy(bo);
16270 + return __kgem_retire_requests_upto(kgem, bo);
16273 static inline bool kgem_bo_is_render(struct kgem_bo *bo)
16274 @@ -651,7 +688,15 @@ static inline bool kgem_bo_is_render(struct kgem_bo *bo)
16275 DBG(("%s: handle=%d, rq? %d [%d]\n", __FUNCTION__,
16276 bo->handle, bo->rq != NULL, (int)RQ_RING(bo->rq)));
16277 assert(bo->refcnt);
16278 - return bo->rq && RQ_RING(bo->rq) == I915_EXEC_RENDER;
16279 + return bo->rq && RQ_RING(bo->rq) != KGEM_BLT;
16280 +}
16282 +static inline bool kgem_bo_is_blt(struct kgem_bo *bo)
16283 +{
16284 + DBG(("%s: handle=%d, rq? %d\n", __FUNCTION__,
16285 + bo->handle, bo->rq != NULL, (int)RQ_RING(bo->rq)));
16286 + assert(bo->refcnt);
16287 + return RQ_RING(bo->rq) == KGEM_BLT;
16290 static inline void kgem_bo_mark_unreusable(struct kgem_bo *bo)
16291 @@ -852,6 +897,6 @@ memcpy_from_tiled_x(struct kgem *kgem,
16292 width, height);
16295 -void choose_memcpy_tiled_x(struct kgem *kgem, int swizzling);
16296 +void choose_memcpy_tiled_x(struct kgem *kgem, int swizzling, unsigned cpu);
16298 #endif /* KGEM_H */
16299 diff --git a/src/sna/kgem_debug_gen4.c b/src/sna/kgem_debug_gen4.c
16300 index 9b80dc88..8e6e47b6 100644
16301 --- a/src/sna/kgem_debug_gen4.c
16302 +++ b/src/sna/kgem_debug_gen4.c
16303 @@ -598,7 +598,7 @@ int kgem_gen4_decode_3d(struct kgem *kgem, uint32_t offset)
16304 assert(len == 7);
16305 kgem_debug_print(data, offset, 0,
16306 "3DSTATE_DEPTH_BUFFER\n");
16307 - kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Seperate Stencil %d\n",
16308 + kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Separate Stencil %d\n",
16309 get_965_surfacetype(data[1] >> 29),
16310 get_965_depthformat((data[1] >> 18) & 0x7),
16311 (data[1] & 0x0001ffff) + 1,
16312 diff --git a/src/sna/kgem_debug_gen5.c b/src/sna/kgem_debug_gen5.c
16313 index 8b55dd91..f1b1275f 100644
16314 --- a/src/sna/kgem_debug_gen5.c
16315 +++ b/src/sna/kgem_debug_gen5.c
16316 @@ -573,7 +573,7 @@ int kgem_gen5_decode_3d(struct kgem *kgem, uint32_t offset)
16317 assert(len == 7);
16318 kgem_debug_print(data, offset, 0,
16319 "3DSTATE_DEPTH_BUFFER\n");
16320 - kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Seperate Stencil %d\n",
16321 + kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Separate Stencil %d\n",
16322 get_965_surfacetype(data[1] >> 29),
16323 get_965_depthformat((data[1] >> 18) & 0x7),
16324 (data[1] & 0x0001ffff) + 1,
16325 diff --git a/src/sna/kgem_debug_gen6.c b/src/sna/kgem_debug_gen6.c
16326 index 7ef55d38..579c5d54 100644
16327 --- a/src/sna/kgem_debug_gen6.c
16328 +++ b/src/sna/kgem_debug_gen6.c
16329 @@ -985,7 +985,7 @@ int kgem_gen6_decode_3d(struct kgem *kgem, uint32_t offset)
16330 assert(len == 7);
16331 kgem_debug_print(data, offset, 0,
16332 "3DSTATE_DEPTH_BUFFER\n");
16333 - kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Seperate Stencil %d\n",
16334 + kgem_debug_print(data, offset, 1, "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Separate Stencil %d\n",
16335 get_965_surfacetype(data[1] >> 29),
16336 get_965_depthformat((data[1] >> 18) & 0x7),
16337 (data[1] & 0x0001ffff) + 1,
16338 diff --git a/src/sna/sna.h b/src/sna/sna.h
16339 index 18425e30..7861110a 100644
16340 --- a/src/sna/sna.h
16341 +++ b/src/sna/sna.h
16342 @@ -154,6 +154,8 @@ struct sna_pixmap {
16343 #define MAPPED_GTT 1
16344 #define MAPPED_CPU 2
16345 uint8_t flush :2;
16346 +#define FLUSH_READ 1
16347 +#define FLUSH_WRITE 2
16348 uint8_t shm :1;
16349 uint8_t clear :1;
16350 uint8_t header :1;
16351 @@ -179,18 +181,31 @@ static inline WindowPtr get_root_window(ScreenPtr screen)
16352 #endif
16355 +#if !NDEBUG
16356 +static PixmapPtr check_pixmap(PixmapPtr pixmap)
16357 +{
16358 + if (pixmap != NULL) {
16359 + assert(pixmap->refcnt >= 1);
16360 + assert(pixmap->devKind != 0xdeadbeef);
16361 + }
16362 + return pixmap;
16363 +}
16364 +#else
16365 +#define check_pixmap(p) p
16366 +#endif
16368 static inline PixmapPtr get_window_pixmap(WindowPtr window)
16370 assert(window);
16371 assert(window->drawable.type != DRAWABLE_PIXMAP);
16372 - return fbGetWindowPixmap(window);
16373 + return check_pixmap(fbGetWindowPixmap(window));
16376 static inline PixmapPtr get_drawable_pixmap(DrawablePtr drawable)
16378 assert(drawable);
16379 if (drawable->type == DRAWABLE_PIXMAP)
16380 - return (PixmapPtr)drawable;
16381 + return check_pixmap((PixmapPtr)drawable);
16382 else
16383 return get_window_pixmap((WindowPtr)drawable);
16385 @@ -244,11 +259,12 @@ struct sna {
16386 #define SNA_NO_VSYNC 0x40
16387 #define SNA_TRIPLE_BUFFER 0x80
16388 #define SNA_TEAR_FREE 0x100
16389 -#define SNA_FORCE_SHADOW 0x200
16390 -#define SNA_FLUSH_GTT 0x400
16391 +#define SNA_WANT_TEAR_FREE 0x200
16392 +#define SNA_FORCE_SHADOW 0x400
16393 +#define SNA_FLUSH_GTT 0x800
16394 #define SNA_PERFORMANCE 0x1000
16395 #define SNA_POWERSAVE 0x2000
16396 -#define SNA_REMOVE_OUTPUTS 0x4000
16397 +#define SNA_NO_DPMS 0x4000
16398 #define SNA_HAS_FLIP 0x10000
16399 #define SNA_HAS_ASYNC_FLIP 0x20000
16400 #define SNA_LINEAR_FB 0x40000
16401 @@ -265,7 +281,13 @@ struct sna {
16402 #define AVX 0x80
16403 #define AVX2 0x100
16405 - unsigned watch_flush;
16406 + bool ignore_copy_area : 1;
16408 + unsigned watch_shm_flush;
16409 + unsigned watch_dri_flush;
16410 + unsigned damage_event;
16411 + bool needs_shm_flush;
16412 + bool needs_dri_flush;
16414 struct timeval timer_tv;
16415 uint32_t timer_expire[NUM_TIMERS];
16416 @@ -284,9 +306,17 @@ struct sna {
16417 struct kgem_bo *shadow;
16418 unsigned front_active;
16419 unsigned shadow_active;
16420 + unsigned rr_active;
16421 unsigned flip_active;
16422 + unsigned hidden;
16423 + bool shadow_enabled;
16424 + bool shadow_wait;
16425 bool dirty;
16427 + struct drm_event_vblank *shadow_events;
16428 + int shadow_nevent;
16429 + int shadow_size;
16431 int max_crtc_width, max_crtc_height;
16432 RegionRec shadow_region;
16433 RegionRec shadow_cancel;
16434 @@ -318,7 +348,8 @@ struct sna {
16435 uint32_t fg, bg;
16436 int size;
16438 - int active;
16439 + bool disable;
16440 + bool active;
16441 int last_x;
16442 int last_y;
16444 @@ -331,8 +362,9 @@ struct sna {
16445 } cursor;
16447 struct sna_dri2 {
16448 - bool available;
16449 - bool open;
16450 + bool available : 1;
16451 + bool enable : 1;
16452 + bool open : 1;
16454 #if HAVE_DRI2
16455 void *flip_pending;
16456 @@ -341,8 +373,11 @@ struct sna {
16457 } dri2;
16459 struct sna_dri3 {
16460 - bool available;
16461 - bool open;
16462 + bool available :1;
16463 + bool override : 1;
16464 + bool enable : 1;
16465 + bool open :1;
16467 #if HAVE_DRI3
16468 SyncScreenCreateFenceFunc create_fence;
16469 struct list pixmaps;
16470 @@ -353,6 +388,9 @@ struct sna {
16471 bool available;
16472 bool open;
16473 #if HAVE_PRESENT
16474 + struct list vblank_queue;
16475 + uint64_t unflip;
16476 + void *freed_info;
16477 #endif
16478 } present;
16480 @@ -364,8 +402,10 @@ struct sna {
16481 EntityInfoPtr pEnt;
16482 const struct intel_device_info *info;
16484 +#if !HAVE_NOTIFY_FD
16485 ScreenBlockHandlerProcPtr BlockHandler;
16486 ScreenWakeupHandlerProcPtr WakeupHandler;
16487 +#endif
16488 CloseScreenProcPtr CloseScreen;
16490 PicturePtr clear;
16491 @@ -383,6 +423,7 @@ struct sna {
16492 struct gen6_render_state gen6;
16493 struct gen7_render_state gen7;
16494 struct gen8_render_state gen8;
16495 + struct gen9_render_state gen9;
16496 } render_state;
16498 /* Broken-out options. */
16499 @@ -420,7 +461,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna);
16500 bool sna_mode_fake_init(struct sna *sna, int num_fake);
16501 bool sna_mode_wants_tear_free(struct sna *sna);
16502 void sna_mode_adjust_frame(struct sna *sna, int x, int y);
16503 -extern void sna_mode_discover(struct sna *sna);
16504 +extern void sna_mode_discover(struct sna *sna, bool tell);
16505 extern void sna_mode_check(struct sna *sna);
16506 extern bool sna_mode_disable(struct sna *sna);
16507 extern void sna_mode_enable(struct sna *sna);
16508 @@ -434,6 +475,7 @@ extern void sna_shadow_unset_crtc(struct sna *sna, xf86CrtcPtr crtc);
16509 extern bool sna_pixmap_discard_shadow_damage(struct sna_pixmap *priv,
16510 const RegionRec *region);
16511 extern void sna_mode_set_primary(struct sna *sna);
16512 +extern bool sna_mode_find_hotplug_connector(struct sna *sna, unsigned id);
16513 extern void sna_mode_close(struct sna *sna);
16514 extern void sna_mode_fini(struct sna *sna);
16516 @@ -444,6 +486,7 @@ extern bool sna_cursors_init(ScreenPtr screen, struct sna *sna);
16517 typedef void (*sna_flip_handler_t)(struct drm_event_vblank *e,
16518 void *data);
16520 +extern bool sna_needs_page_flip(struct sna *sna, struct kgem_bo *bo);
16521 extern int sna_page_flip(struct sna *sna,
16522 struct kgem_bo *bo,
16523 sna_flip_handler_t handler,
16524 @@ -461,6 +504,11 @@ to_sna_from_screen(ScreenPtr screen)
16525 return to_sna(xf86ScreenToScrn(screen));
16528 +pure static inline ScreenPtr to_screen_from_sna(struct sna *sna)
16529 +{
16530 + return xf86ScrnToScreen(sna->scrn);
16531 +}
16533 pure static inline struct sna *
16534 to_sna_from_pixmap(PixmapPtr pixmap)
16536 @@ -498,12 +546,11 @@ to_sna_from_kgem(struct kgem *kgem)
16537 extern xf86CrtcPtr sna_covering_crtc(struct sna *sna,
16538 const BoxRec *box,
16539 xf86CrtcPtr desired);
16540 +extern xf86CrtcPtr sna_primary_crtc(struct sna *sna);
16542 extern bool sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
16543 xf86CrtcPtr crtc, const BoxRec *clip);
16545 -xf86CrtcPtr sna_mode_first_crtc(struct sna *sna);
16547 const struct ust_msc {
16548 uint64_t msc;
16549 int tv_sec;
16550 @@ -536,6 +583,11 @@ static inline uint64_t ust64(int tv_sec, int tv_usec)
16551 return (uint64_t)tv_sec * 1000000 + tv_usec;
16554 +static inline uint64_t swap_ust(const struct ust_msc *swap)
16555 +{
16556 + return ust64(swap->tv_sec, swap->tv_usec);
16557 +}
16559 #if HAVE_DRI2
16560 bool sna_dri2_open(struct sna *sna, ScreenPtr pScreen);
16561 void sna_dri2_page_flip_handler(struct sna *sna, struct drm_event_vblank *event);
16562 @@ -567,20 +619,59 @@ bool sna_present_open(struct sna *sna, ScreenPtr pScreen);
16563 void sna_present_update(struct sna *sna);
16564 void sna_present_close(struct sna *sna, ScreenPtr pScreen);
16565 void sna_present_vblank_handler(struct drm_event_vblank *event);
16566 +void sna_present_cancel_flip(struct sna *sna);
16567 #else
16568 static inline bool sna_present_open(struct sna *sna, ScreenPtr pScreen) { return false; }
16569 static inline void sna_present_update(struct sna *sna) { }
16570 static inline void sna_present_close(struct sna *sna, ScreenPtr pScreen) { }
16571 static inline void sna_present_vblank_handler(struct drm_event_vblank *event) { }
16572 +static inline void sna_present_cancel_flip(struct sna *sna) { }
16573 #endif
16575 -extern bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation);
16576 -extern int sna_crtc_to_pipe(xf86CrtcPtr crtc);
16577 -extern uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc);
16578 -extern uint32_t sna_crtc_id(xf86CrtcPtr crtc);
16579 -extern bool sna_crtc_is_on(xf86CrtcPtr crtc);
16580 +extern unsigned sna_crtc_count_sprites(xf86CrtcPtr crtc);
16581 +extern bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, unsigned idx, uint32_t rotation);
16582 +extern uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc, unsigned idx);
16583 extern bool sna_crtc_is_transformed(xf86CrtcPtr crtc);
16585 +#define CRTC_VBLANK 0x3
16586 +#define CRTC_ON 0x80000000
16588 +uint32_t sna_crtc_id(xf86CrtcPtr crtc);
16590 +static inline unsigned long *sna_crtc_flags(xf86CrtcPtr crtc)
16591 +{
16592 + unsigned long *flags = crtc->driver_private;
16593 + assert(flags);
16594 + return flags;
16595 +}
16597 +static inline unsigned sna_crtc_pipe(xf86CrtcPtr crtc)
16598 +{
16599 + return *sna_crtc_flags(crtc) >> 8 & 0xff;
16600 +}
16602 +static inline bool sna_crtc_is_on(xf86CrtcPtr crtc)
16603 +{
16604 + return *sna_crtc_flags(crtc) & CRTC_ON;
16605 +}
16607 +static inline void sna_crtc_set_vblank(xf86CrtcPtr crtc)
16608 +{
16609 + assert((*sna_crtc_flags(crtc) & CRTC_VBLANK) < 3);
16610 + ++*sna_crtc_flags(crtc);
16611 +}
16613 +static inline void sna_crtc_clear_vblank(xf86CrtcPtr crtc)
16614 +{
16615 + assert(*sna_crtc_flags(crtc) & CRTC_VBLANK);
16616 + --*sna_crtc_flags(crtc);
16617 +}
16619 +static inline bool sna_crtc_has_vblank(xf86CrtcPtr crtc)
16620 +{
16621 + return *sna_crtc_flags(crtc) & CRTC_VBLANK;
16622 +}
16624 CARD32 sna_format_for_depth(int depth);
16625 CARD32 sna_render_format_for_depth(int depth);
16627 @@ -998,15 +1089,14 @@ static inline uint32_t pixmap_size(PixmapPtr pixmap)
16629 bool sna_accel_init(ScreenPtr sreen, struct sna *sna);
16630 void sna_accel_create(struct sna *sna);
16631 -void sna_accel_block_handler(struct sna *sna, struct timeval **tv);
16632 -void sna_accel_wakeup_handler(struct sna *sna);
16633 -void sna_accel_watch_flush(struct sna *sna, int enable);
16634 +void sna_accel_block(struct sna *sna, struct timeval **tv);
16635 void sna_accel_flush(struct sna *sna);
16636 void sna_accel_enter(struct sna *sna);
16637 void sna_accel_leave(struct sna *sna);
16638 void sna_accel_close(struct sna *sna);
16639 void sna_accel_free(struct sna *sna);
16641 +void sna_watch_flush(struct sna *sna, int enable);
16642 void sna_copy_fbcon(struct sna *sna);
16644 bool sna_composite_create(struct sna *sna);
16645 @@ -1127,6 +1217,16 @@ memcpy_blt(const void *src, void *dst, int bpp,
16646 uint16_t width, uint16_t height);
16648 void
16649 +affine_blt(const void *src, void *dst, int bpp,
16650 + int16_t src_x, int16_t src_y,
16651 + int16_t src_width, int16_t src_height,
16652 + int32_t src_stride,
16653 + int16_t dst_x, int16_t dst_y,
16654 + uint16_t dst_width, uint16_t dst_height,
16655 + int32_t dst_stride,
16656 + const struct pixman_f_transform *t);
16658 +void
16659 memmove_box(const void *src, void *dst,
16660 int bpp, int32_t stride,
16661 const BoxRec *box,
16662 @@ -1182,6 +1282,31 @@ box_intersect(BoxPtr a, const BoxRec *b)
16663 return true;
16666 +const BoxRec *
16667 +__find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y);
16668 +inline static const BoxRec *
16669 +find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
16670 +{
16671 + /* Special case for incremental trapezoid clipping */
16672 + if (begin == end)
16673 + return end;
16675 + /* Quick test if scanline is within range of clip boxes */
16676 + if (begin->y2 > y) {
16677 + assert(end == begin + 1 ||
16678 + __find_clip_box_for_y(begin, end, y) == begin);
16679 + return begin;
16680 + }
16681 + if (y >= end[-1].y2) {
16682 + assert(end == begin + 1 ||
16683 + __find_clip_box_for_y(begin, end, y) == end);
16684 + return end;
16685 + }
16687 + /* Otherwise bisect to find the first box crossing y */
16688 + return __find_clip_box_for_y(begin, end, y);
16689 +}
16691 unsigned sna_cpu_detect(void);
16692 char *sna_cpu_features_to_string(unsigned features, char *line);
16694 @@ -1237,4 +1362,17 @@ static inline void sigtrap_put(void)
16695 extern int getline(char **line, size_t *len, FILE *file);
16696 #endif
16698 +static inline void add_shm_flush(struct sna *sna, struct sna_pixmap *priv)
16699 +{
16700 + if (!priv->shm)
16701 + return;
16703 + DBG(("%s: marking handle=%d for SHM flush\n",
16704 + __FUNCTION__, priv->cpu_bo->handle));
16706 + assert(!priv->flush);
16707 + sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
16708 + sna->needs_shm_flush = true;
16709 +}
16711 #endif /* _SNA_H */
16712 diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
16713 index baf5f609..25a075cf 100644
16714 --- a/src/sna/sna_accel.c
16715 +++ b/src/sna/sna_accel.c
16716 @@ -50,8 +50,11 @@
16717 #endif
16718 #include <shmint.h>
16720 +#include <X11/extensions/damageproto.h>
16722 #include <sys/time.h>
16723 #include <sys/mman.h>
16724 +#include <sys/ioctl.h>
16725 #include <unistd.h>
16727 #ifdef HAVE_VALGRIND
16728 @@ -66,7 +69,8 @@
16729 #define FORCE_FLUSH 0
16730 #define FORCE_FULL_SYNC 0 /* https://bugs.freedesktop.org/show_bug.cgi?id=61628 */
16732 -#define DEFAULT_TILING I915_TILING_X
16733 +#define DEFAULT_PIXMAP_TILING I915_TILING_X
16734 +#define DEFAULT_SCANOUT_TILING I915_TILING_X
16736 #define USE_INPLACE 1
16737 #define USE_SPANS 0 /* -1 force CPU, 1 force GPU */
16738 @@ -115,6 +119,11 @@
16739 #define RECTILINEAR 0x4
16740 #define OVERWRITES 0x8
16742 +#if XFONT2_CLIENT_FUNCS_VERSION >= 1
16743 +#define AllocateFontPrivateIndex() xfont2_allocate_font_private_index()
16744 +#define FontSetPrivate(font, idx, data) xfont2_font_set_private(font, idx, data)
16745 +#endif
16747 #if 0
16748 static void __sna_fallback_flush(DrawablePtr d)
16750 @@ -213,6 +222,7 @@ static GCOps sna_gc_ops__tmp;
16751 static const GCFuncs sna_gc_funcs;
16752 static const GCFuncs sna_gc_funcs__cpu;
16754 +static void sna_shm_watch_flush(struct sna *sna, int enable);
16755 static void
16756 sna_poly_fill_rect__gpu(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect);
16758 @@ -527,10 +537,10 @@ sna_pixmap_alloc_cpu(struct sna *sna,
16759 DBG(("%s: allocating CPU buffer (%dx%d)\n", __FUNCTION__,
16760 pixmap->drawable.width, pixmap->drawable.height));
16762 - hint = 0;
16763 - if ((flags & MOVE_ASYNC_HINT) == 0 &&
16764 - ((flags & MOVE_READ) == 0 || (priv->gpu_damage && !priv->clear && !sna->kgem.has_llc)))
16765 - hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE;
16766 + hint = CREATE_CPU_MAP | CREATE_INACTIVE | CREATE_NO_THROTTLE;
16767 + if ((flags & MOVE_ASYNC_HINT) ||
16768 + (priv->gpu_damage && !priv->clear && kgem_bo_is_busy(priv->gpu_bo) && sna->kgem.can_blt_cpu))
16769 + hint = 0;
16771 priv->cpu_bo = kgem_create_cpu_2d(&sna->kgem,
16772 pixmap->drawable.width,
16773 @@ -580,7 +590,7 @@ static void __sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv)
16774 if (priv->cpu_bo->flush) {
16775 assert(!priv->cpu_bo->reusable);
16776 kgem_bo_sync__cpu(&sna->kgem, priv->cpu_bo);
16777 - sna_accel_watch_flush(sna, -1);
16778 + sna_shm_watch_flush(sna, -1);
16780 kgem_bo_destroy(&sna->kgem, priv->cpu_bo);
16781 } else if (!IS_STATIC_PTR(priv->ptr))
16782 @@ -612,9 +622,9 @@ static bool sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv, bool a
16784 static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap)
16786 -#if DEFAULT_TILING == I915_TILING_NONE
16787 +#if DEFAULT_PIXMAP_TILING == I915_TILING_NONE
16788 return I915_TILING_NONE;
16789 -#elif DEFAULT_TILING == I915_TILING_X
16790 +#elif DEFAULT_PIXMAP_TILING == I915_TILING_X
16791 return I915_TILING_X;
16792 #else
16793 /* Try to avoid hitting the Y-tiling GTT mapping bug on 855GM */
16794 @@ -630,15 +640,6 @@ static inline uint32_t default_tiling(struct sna *sna, PixmapPtr pixmap)
16795 pixmap->drawable.height > sna->render.max_3d_size))
16796 return I915_TILING_X;
16798 - if (sna_damage_is_all(&sna_pixmap(pixmap)->cpu_damage,
16799 - pixmap->drawable.width,
16800 - pixmap->drawable.height)) {
16801 - DBG(("%s: entire source is damaged, using Y-tiling\n",
16802 - __FUNCTION__));
16803 - sna_damage_destroy(&sna_pixmap(priv)->gpu_damage);
16804 - return I915_TILING_Y;
16805 - }
16807 return I915_TILING_Y;
16808 #endif
16810 @@ -666,6 +667,7 @@ struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
16811 __FUNCTION__, priv->gpu_bo->tiling, tiling,
16812 pixmap->drawable.width, pixmap->drawable.height));
16813 assert(priv->gpu_damage == NULL || priv->gpu_bo);
16814 + assert(priv->gpu_bo->tiling != tiling);
16816 if (priv->pinned) {
16817 DBG(("%s: can't convert pinned bo\n", __FUNCTION__));
16818 @@ -690,6 +692,12 @@ struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
16819 return NULL;
16822 + if (bo->tiling == priv->gpu_bo->tiling) {
16823 + DBG(("%s: tiling request failed\n", __FUNCTION__));
16824 + kgem_bo_destroy(&sna->kgem, bo);
16825 + return NULL;
16826 + }
16828 box.x1 = box.y1 = 0;
16829 box.x2 = pixmap->drawable.width;
16830 box.y2 = pixmap->drawable.height;
16831 @@ -824,8 +832,8 @@ create_pixmap(struct sna *sna, ScreenPtr screen,
16832 datasize += adjust;
16835 - DBG(("%s: allocating pixmap %dx%d, depth=%d, size=%ld\n",
16836 - __FUNCTION__, width, height, depth, (long)datasize));
16837 + DBG(("%s: allocating pixmap %dx%d, depth=%d/%d, size=%ld\n",
16838 + __FUNCTION__, width, height, depth, bpp, (long)datasize));
16839 pixmap = AllocatePixmap(screen, datasize);
16840 if (!pixmap)
16841 return NullPixmap;
16842 @@ -878,7 +886,11 @@ __pop_freed_pixmap(struct sna *sna)
16843 pixmap = sna->freed_pixmap;
16844 sna->freed_pixmap = pixmap->devPrivate.ptr;
16846 + DBG(("%s: reusing freed pixmap=%ld header\n",
16847 + __FUNCTION__, pixmap->drawable.serialNumber));
16849 assert(pixmap->refcnt == 0);
16850 + assert(pixmap->devKind = 0xdeadbeef);
16851 assert(sna_pixmap(pixmap));
16852 assert(sna_pixmap(pixmap)->header);
16854 @@ -990,7 +1002,7 @@ fallback:
16856 priv->cpu_bo->pitch = pitch;
16857 kgem_bo_mark_unreusable(priv->cpu_bo);
16858 - sna_accel_watch_flush(sna, 1);
16859 + sna_shm_watch_flush(sna, 1);
16860 #ifdef DEBUG_MEMORY
16861 sna->debug_memory.cpu_bo_allocs++;
16862 sna->debug_memory.cpu_bo_bytes += kgem_bo_size(priv->cpu_bo);
16863 @@ -1081,6 +1093,18 @@ sna_pixmap_create_scratch(ScreenPtr screen,
16864 return pixmap;
16867 +static unsigned small_copy(const RegionRec *region)
16868 +{
16869 + if ((region->extents.x2 - region->extents.x1)*(region->extents.y2 - region->extents.y1) < 1024) {
16870 + DBG(("%s: region:%dx%d\n", __FUNCTION__,
16871 + (region->extents.x2 - region->extents.x1),
16872 + (region->extents.y2 - region->extents.y1)));
16873 + return COPY_SMALL;
16874 + }
16876 + return 0;
16877 +}
16879 #ifdef CREATE_PIXMAP_USAGE_SHARED
16880 static Bool
16881 sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle)
16882 @@ -1124,7 +1148,7 @@ sna_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr slave, void **fd_handle)
16883 pixmap->drawable.height,
16884 pixmap->drawable.bitsPerPixel,
16885 I915_TILING_NONE,
16886 - CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT);
16887 + CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT);
16888 if (bo == NULL) {
16889 DBG(("%s: allocation failed\n", __FUNCTION__));
16890 return FALSE;
16891 @@ -1243,7 +1267,7 @@ sna_create_pixmap_shared(struct sna *sna, ScreenPtr screen,
16892 width, height,
16893 pixmap->drawable.bitsPerPixel,
16894 I915_TILING_NONE,
16895 - CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT);
16896 + CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT);
16897 if (priv->gpu_bo == NULL) {
16898 free(priv);
16899 FreePixmap(pixmap);
16900 @@ -1311,7 +1335,7 @@ static PixmapPtr sna_create_pixmap(ScreenPtr screen,
16902 if (unlikely((sna->render.prefer_gpu & PREFER_GPU_RENDER) == 0))
16903 flags &= ~KGEM_CAN_CREATE_GPU;
16904 - if (wedged(sna))
16905 + if (wedged(sna) && usage != SNA_CREATE_FB)
16906 flags &= ~KGEM_CAN_CREATE_GTT;
16908 DBG(("%s: usage=%d, flags=%x\n", __FUNCTION__, usage, flags));
16909 @@ -1417,10 +1441,13 @@ static void __sna_free_pixmap(struct sna *sna,
16910 __sna_pixmap_free_cpu(sna, priv);
16912 if (priv->flush)
16913 - sna_accel_watch_flush(sna, -1);
16914 + sna_watch_flush(sna, -1);
16916 +#if !NDEBUG
16917 + pixmap->devKind = 0xdeadbeef;
16918 +#endif
16919 if (priv->header) {
16920 - assert(pixmap->drawable.pScreen == sna->scrn->pScreen);
16921 + assert(pixmap->drawable.pScreen == to_screen_from_sna(sna));
16922 assert(!priv->shm);
16923 pixmap->devPrivate.ptr = sna->freed_pixmap;
16924 sna->freed_pixmap = pixmap;
16925 @@ -1485,7 +1512,7 @@ static Bool sna_destroy_pixmap(PixmapPtr pixmap)
16926 if (priv->shm && kgem_bo_is_busy(priv->cpu_bo)) {
16927 DBG(("%s: deferring release of active SHM pixmap=%ld\n",
16928 __FUNCTION__, pixmap->drawable.serialNumber));
16929 - sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
16930 + add_shm_flush(sna, priv);
16931 kgem_bo_submit(&sna->kgem, priv->cpu_bo); /* XXX ShmDetach */
16932 } else
16933 __sna_free_pixmap(sna, pixmap, priv);
16934 @@ -1529,7 +1556,7 @@ static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, un
16935 if (!priv->cpu_bo)
16936 return true;
16938 - assert(!priv->cpu_bo->needs_flush);
16939 + assert(!priv->cpu_bo->needs_flush || (flags & MOVE_WRITE) == 0);
16940 assert(priv->pixmap->devKind == priv->cpu_bo->pitch);
16941 return priv->pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu);
16943 @@ -1557,6 +1584,11 @@ static inline bool has_coherent_ptr(struct sna *sna, struct sna_pixmap *priv, un
16944 return true;
16947 + if (priv->pixmap->devPrivate.ptr == MAP(priv->gpu_bo->map__wc)) {
16948 + assert(priv->mapped == MAPPED_GTT);
16949 + return true;
16950 + }
16952 return false;
16955 @@ -1577,6 +1609,16 @@ static inline bool pixmap_inplace(struct sna *sna,
16956 return false;
16958 if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo)) {
16959 + if (priv->clear) {
16960 + DBG(("%s: no, clear GPU bo is busy\n", __FUNCTION__));
16961 + return false;
16962 + }
16964 + if (flags & MOVE_ASYNC_HINT) {
16965 + DBG(("%s: no, async hint and GPU bo is busy\n", __FUNCTION__));
16966 + return false;
16967 + }
16969 if ((flags & (MOVE_WRITE | MOVE_READ)) == (MOVE_WRITE | MOVE_READ)) {
16970 DBG(("%s: no, GPU bo is busy\n", __FUNCTION__));
16971 return false;
16972 @@ -1624,7 +1666,7 @@ static bool sna_pixmap_alloc_gpu(struct sna *sna,
16973 if (pixmap->usage_hint == SNA_CREATE_FB && (sna->flags & SNA_LINEAR_FB) == 0) {
16974 flags |= CREATE_SCANOUT;
16975 tiling = kgem_choose_tiling(&sna->kgem,
16976 - -I915_TILING_X,
16977 + -DEFAULT_SCANOUT_TILING,
16978 pixmap->drawable.width,
16979 pixmap->drawable.height,
16980 pixmap->drawable.bitsPerPixel);
16981 @@ -1861,7 +1903,9 @@ sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
16982 assert(priv->gpu_bo == cow->bo);
16983 assert(cow->refcnt);
16985 - if (flags && (flags & MOVE_WRITE) == 0 && IS_COW_OWNER(priv->cow))
16986 + if (flags && /* flags == 0 => force decouple */
16987 + (flags & MOVE_WRITE) == 0 &&
16988 + (((flags & __MOVE_FORCE) == 0) || IS_COW_OWNER(priv->cow)))
16989 return true;
16991 if (!IS_COW_OWNER(priv->cow))
16992 @@ -1933,7 +1977,7 @@ sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
16993 box.y2 = pixmap->drawable.height;
16995 if (flags & __MOVE_PRIME) {
16996 - create = CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT;
16997 + create = CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT;
16998 tiling = I915_TILING_NONE;
16999 } else {
17000 create = 0;
17001 @@ -2021,6 +2065,10 @@ sna_pixmap_make_cow(struct sna *sna,
17002 cow->bo->handle));
17004 src_priv->cow = MAKE_COW_OWNER(cow);
17005 + if (src_priv->flush & FLUSH_WRITE) {
17006 + assert(!src_priv->shm);
17007 + sna_add_flush_pixmap(sna, src_priv, src_priv->gpu_bo);
17008 + }
17011 if (cow == COW(dst_priv->cow)) {
17012 @@ -2267,6 +2315,7 @@ skip_inplace_map:
17013 (flags & MOVE_WRITE ? (void *)priv->gpu_bo : (void *)priv->gpu_damage) && priv->cpu_damage == NULL &&
17014 priv->gpu_bo->tiling == I915_TILING_NONE &&
17015 (flags & MOVE_READ || kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, flags & MOVE_WRITE)) &&
17016 + (!priv->clear || !kgem_bo_is_busy(priv->gpu_bo)) &&
17017 ((flags & (MOVE_WRITE | MOVE_ASYNC_HINT)) == 0 ||
17018 (!priv->cow && !priv->move_to_gpu && !__kgem_bo_is_busy(&sna->kgem, priv->gpu_bo)))) {
17019 void *ptr;
17020 @@ -2330,7 +2379,9 @@ skip_inplace_map:
17021 pixmap->devKind, pixmap->devKind * pixmap->drawable.height));
17023 if (priv->cpu_bo) {
17024 + kgem_bo_undo(&sna->kgem, priv->cpu_bo);
17025 if ((flags & MOVE_ASYNC_HINT || priv->cpu_bo->exec) &&
17026 + sna->kgem.can_blt_cpu &&
17027 sna->render.fill_one(sna,
17028 pixmap, priv->cpu_bo, priv->clear_color,
17029 0, 0,
17030 @@ -2344,21 +2395,26 @@ skip_inplace_map:
17031 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
17034 - assert(pixmap->devKind);
17035 - if (priv->clear_color == 0 ||
17036 - pixmap->drawable.bitsPerPixel == 8 ||
17037 - priv->clear_color == (1 << pixmap->drawable.depth) - 1) {
17038 - memset(pixmap->devPrivate.ptr, priv->clear_color,
17039 - (size_t)pixmap->devKind * pixmap->drawable.height);
17040 - } else {
17041 - pixman_fill(pixmap->devPrivate.ptr,
17042 - pixmap->devKind/sizeof(uint32_t),
17043 - pixmap->drawable.bitsPerPixel,
17044 - 0, 0,
17045 - pixmap->drawable.width,
17046 - pixmap->drawable.height,
17047 - priv->clear_color);
17048 - }
17049 + if (sigtrap_get() == 0) {
17050 + assert(pixmap->devKind);
17051 + sigtrap_assert_active();
17052 + if (priv->clear_color == 0 ||
17053 + pixmap->drawable.bitsPerPixel == 8 ||
17054 + priv->clear_color == (1 << pixmap->drawable.depth) - 1) {
17055 + memset(pixmap->devPrivate.ptr, priv->clear_color,
17056 + (size_t)pixmap->devKind * pixmap->drawable.height);
17057 + } else {
17058 + pixman_fill(pixmap->devPrivate.ptr,
17059 + pixmap->devKind/sizeof(uint32_t),
17060 + pixmap->drawable.bitsPerPixel,
17061 + 0, 0,
17062 + pixmap->drawable.width,
17063 + pixmap->drawable.height,
17064 + priv->clear_color);
17065 + }
17066 + sigtrap_put();
17067 + } else
17068 + return false;
17070 clear_done:
17071 sna_damage_all(&priv->cpu_damage, pixmap);
17072 @@ -2414,6 +2470,10 @@ done:
17073 DBG(("%s: discarding idle GPU bo\n", __FUNCTION__));
17074 sna_pixmap_free_gpu(sna, priv);
17076 + if (priv->flush) {
17077 + assert(!priv->shm);
17078 + sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
17079 + }
17080 priv->source_count = SOURCE_BIAS;
17083 @@ -2531,6 +2591,9 @@ static bool cpu_clear_boxes(struct sna *sna,
17085 struct sna_fill_op fill;
17087 + if (!sna->kgem.can_blt_cpu)
17088 + return false;
17090 if (!sna_fill_init_blt(&fill, sna,
17091 pixmap, priv->cpu_bo,
17092 GXcopy, priv->clear_color,
17093 @@ -2659,6 +2722,10 @@ sna_drawable_move_region_to_cpu(DrawablePtr drawable,
17096 sna_damage_add_to_pixmap(&priv->cpu_damage, region, pixmap);
17097 + if (priv->flush) {
17098 + assert(!priv->shm);
17099 + sna_add_flush_pixmap(sna, priv, priv->gpu_bo);
17100 + }
17102 if (dx | dy)
17103 RegionTranslate(region, -dx, -dy);
17104 @@ -2904,17 +2971,22 @@ move_to_cpu:
17105 assert(pixmap->devPrivate.ptr == MAP(priv->cpu_bo->map__cpu));
17108 - assert(pixmap->devKind);
17109 - do {
17110 - pixman_fill(pixmap->devPrivate.ptr,
17111 - pixmap->devKind/sizeof(uint32_t),
17112 - pixmap->drawable.bitsPerPixel,
17113 - box->x1, box->y1,
17114 - box->x2 - box->x1,
17115 - box->y2 - box->y1,
17116 - priv->clear_color);
17117 - box++;
17118 - } while (--n);
17119 + if (sigtrap_get() == 0) {
17120 + assert(pixmap->devKind);
17121 + sigtrap_assert_active();
17122 + do {
17123 + pixman_fill(pixmap->devPrivate.ptr,
17124 + pixmap->devKind/sizeof(uint32_t),
17125 + pixmap->drawable.bitsPerPixel,
17126 + box->x1, box->y1,
17127 + box->x2 - box->x1,
17128 + box->y2 - box->y1,
17129 + priv->clear_color);
17130 + box++;
17131 + } while (--n);
17132 + sigtrap_put();
17133 + } else
17134 + return false;
17136 clear_done:
17137 if (flags & MOVE_WRITE ||
17138 @@ -3209,13 +3281,14 @@ __sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags)
17140 struct sna_pixmap *priv;
17142 + assert(flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE));
17143 if ((flags & __MOVE_FORCE) == 0 && wedged(sna))
17144 return NULL;
17146 priv = sna_pixmap(pixmap);
17147 if (priv == NULL) {
17148 DBG(("%s: not attached\n", __FUNCTION__));
17149 - if ((flags & __MOVE_DRI) == 0)
17150 + if ((flags & (__MOVE_DRI | __MOVE_SCANOUT)) == 0)
17151 return NULL;
17153 if (pixmap->usage_hint == -1) {
17154 @@ -3238,6 +3311,44 @@ __sna_pixmap_for_gpu(struct sna *sna, PixmapPtr pixmap, unsigned flags)
17155 return priv;
17158 +inline static void sna_pixmap_unclean(struct sna *sna,
17159 + struct sna_pixmap *priv,
17160 + unsigned flags)
17161 +{
17162 + struct drm_i915_gem_busy busy;
17164 + assert(DAMAGE_IS_ALL(priv->gpu_damage));
17165 + assert(priv->gpu_bo);
17166 + assert(priv->gpu_bo->proxy == NULL);
17167 + assert_pixmap_map(priv->pixmap, priv);
17169 + sna_damage_destroy(&priv->cpu_damage);
17170 + list_del(&priv->flush_list);
17172 + if (flags & (__MOVE_DRI | __MOVE_SCANOUT))
17173 + return;
17175 + if (!priv->flush || priv->gpu_bo->exec)
17176 + return;
17178 + busy.handle = priv->gpu_bo->handle;
17179 + busy.busy = 0;
17180 + ioctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
17182 + DBG(("%s(pixmap=%ld): cleaning foreign bo handle=%u, busy=%x [ring=%d]\n",
17183 + __FUNCTION__,
17184 + priv->pixmap->drawable.serialNumber,
17185 + busy.handle, busy.busy, !!(busy.busy & (0xfffe << 16))));
17187 + if (busy.busy) {
17188 + unsigned mode = KGEM_RENDER;
17189 + if (busy.busy & (0xfffe << 16))
17190 + mode = KGEM_BLT;
17191 + kgem_bo_mark_busy(&sna->kgem, priv->gpu_bo, mode);
17192 + } else
17193 + __kgem_bo_clear_busy(priv->gpu_bo);
17194 +}
17196 struct sna_pixmap *
17197 sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags)
17199 @@ -3287,12 +3398,14 @@ sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int fl
17200 if (priv->cow) {
17201 unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
17203 + assert(cow);
17205 if ((flags & MOVE_READ) == 0) {
17206 if (priv->gpu_damage) {
17207 r.extents = *box;
17208 r.data = NULL;
17209 if (!region_subsumes_damage(&r, priv->gpu_damage))
17210 - cow |= MOVE_READ;
17211 + cow |= MOVE_READ | __MOVE_FORCE;
17213 } else {
17214 if (priv->cpu_damage) {
17215 @@ -3303,22 +3416,18 @@ sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int fl
17219 - if (cow) {
17220 - if (!sna_pixmap_undo_cow(sna, priv, cow))
17221 - return NULL;
17222 + if (!sna_pixmap_undo_cow(sna, priv, cow))
17223 + return NULL;
17225 - if (priv->gpu_bo == NULL)
17226 - sna_damage_destroy(&priv->gpu_damage);
17227 - }
17228 + if (priv->gpu_bo == NULL)
17229 + sna_damage_destroy(&priv->gpu_damage);
17232 if (sna_damage_is_all(&priv->gpu_damage,
17233 pixmap->drawable.width,
17234 pixmap->drawable.height)) {
17235 - assert(priv->gpu_bo);
17236 - assert(priv->gpu_bo->proxy == NULL);
17237 - sna_damage_destroy(&priv->cpu_damage);
17238 - list_del(&priv->flush_list);
17239 + DBG(("%s: already all-damaged\n", __FUNCTION__));
17240 + sna_pixmap_unclean(sna, priv, flags);
17241 goto done;
17244 @@ -3360,10 +3469,7 @@ sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int fl
17245 return priv;
17248 - if (priv->shm) {
17249 - assert(!priv->flush);
17250 - sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
17251 - }
17252 + add_shm_flush(sna, priv);
17254 assert(priv->cpu_damage);
17255 region_set(&r, box);
17256 @@ -3527,7 +3633,8 @@ sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box,
17259 if (priv->cow) {
17260 - unsigned cow = MOVE_WRITE | MOVE_READ;
17261 + unsigned cow = MOVE_WRITE | MOVE_READ | __MOVE_FORCE;
17262 + assert(cow);
17264 if (flags & IGNORE_DAMAGE) {
17265 if (priv->gpu_damage) {
17266 @@ -3717,8 +3824,11 @@ create_gpu_bo:
17267 else
17268 move = MOVE_WRITE | MOVE_READ | MOVE_ASYNC_HINT;
17270 - if (sna_pixmap_move_to_gpu(pixmap, move))
17271 + if (sna_pixmap_move_to_gpu(pixmap, move)) {
17272 + sna_damage_all(&priv->gpu_damage,
17273 + pixmap);
17274 goto use_gpu_bo;
17275 + }
17278 if (DAMAGE_IS_ALL(priv->gpu_damage) ||
17279 @@ -3934,26 +4044,28 @@ prefer_gpu_bo:
17280 goto move_to_gpu;
17283 - if ((priv->cpu_damage == NULL || flags & IGNORE_DAMAGE)) {
17284 - if (priv->gpu_bo && priv->gpu_bo->tiling) {
17285 - DBG(("%s: prefer to use GPU bo for rendering large pixmaps\n", __FUNCTION__));
17286 - goto prefer_gpu_bo;
17287 + if (!priv->shm) {
17288 + if ((priv->cpu_damage == NULL || flags & IGNORE_DAMAGE)) {
17289 + if (priv->gpu_bo && priv->gpu_bo->tiling) {
17290 + DBG(("%s: prefer to use GPU bo for rendering large pixmaps\n", __FUNCTION__));
17291 + goto prefer_gpu_bo;
17292 + }
17294 + if (priv->cpu_bo->pitch >= 4096) {
17295 + DBG(("%s: prefer to use GPU bo for rendering wide pixmaps\n", __FUNCTION__));
17296 + goto prefer_gpu_bo;
17297 + }
17300 - if (priv->cpu_bo->pitch >= 4096) {
17301 - DBG(("%s: prefer to use GPU bo for rendering wide pixmaps\n", __FUNCTION__));
17302 + if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_bo->snoop) {
17303 + DBG(("%s: prefer to use GPU bo for reading from snooped target bo\n", __FUNCTION__));
17304 goto prefer_gpu_bo;
17306 - }
17308 - if ((flags & IGNORE_DAMAGE) == 0 && priv->cpu_bo->snoop) {
17309 - DBG(("%s: prefer to use GPU bo for reading from snooped target bo\n", __FUNCTION__));
17310 - goto prefer_gpu_bo;
17311 - }
17313 - if (!sna->kgem.can_blt_cpu) {
17314 - DBG(("%s: can't render to CPU bo, try to use GPU bo\n", __FUNCTION__));
17315 - goto prefer_gpu_bo;
17316 + if (!sna->kgem.can_blt_cpu) {
17317 + DBG(("%s: can't render to CPU bo, try to use GPU bo\n", __FUNCTION__));
17318 + goto prefer_gpu_bo;
17319 + }
17323 @@ -3967,9 +4079,7 @@ prefer_gpu_bo:
17326 if (priv->shm) {
17327 - assert(!priv->flush);
17328 - sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
17330 + add_shm_flush(sna, priv);
17331 /* As we may have flushed and retired,, recheck for busy bo */
17332 if ((flags & FORCE_GPU) == 0 && !kgem_bo_is_busy(priv->cpu_bo))
17333 return NULL;
17334 @@ -4019,7 +4129,7 @@ sna_pixmap_create_upload(ScreenPtr screen,
17335 assert(width);
17336 assert(height);
17338 - if (depth == 1)
17339 + if (depth < 8)
17340 return create_pixmap(sna, screen, width, height, depth,
17341 CREATE_PIXMAP_USAGE_SCRATCH);
17343 @@ -4121,27 +4231,21 @@ sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
17345 if (priv->cow) {
17346 unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
17347 + assert(cow);
17348 if (flags & MOVE_READ && priv->cpu_damage)
17349 cow |= MOVE_WRITE;
17350 - if (cow) {
17351 - if (!sna_pixmap_undo_cow(sna, priv, cow))
17352 - return NULL;
17353 + if (!sna_pixmap_undo_cow(sna, priv, cow))
17354 + return NULL;
17356 - if (priv->gpu_bo == NULL)
17357 - sna_damage_destroy(&priv->gpu_damage);
17358 - }
17359 + if (priv->gpu_bo == NULL)
17360 + sna_damage_destroy(&priv->gpu_damage);
17363 if (sna_damage_is_all(&priv->gpu_damage,
17364 pixmap->drawable.width,
17365 pixmap->drawable.height)) {
17366 DBG(("%s: already all-damaged\n", __FUNCTION__));
17367 - assert(DAMAGE_IS_ALL(priv->gpu_damage));
17368 - assert(priv->gpu_bo);
17369 - assert(priv->gpu_bo->proxy == NULL);
17370 - assert_pixmap_map(pixmap, priv);
17371 - sna_damage_destroy(&priv->cpu_damage);
17372 - list_del(&priv->flush_list);
17373 + sna_pixmap_unclean(sna, priv, flags);
17374 goto active;
17377 @@ -4206,7 +4310,7 @@ sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
17378 if (flags & MOVE_INPLACE_HINT || (priv->cpu_damage && priv->cpu_bo == NULL))
17379 create = CREATE_GTT_MAP | CREATE_INACTIVE;
17380 if (flags & __MOVE_PRIME)
17381 - create |= CREATE_GTT_MAP | CREATE_PRIME | CREATE_EXACT;
17382 + create |= CREATE_GTT_MAP | CREATE_SCANOUT | CREATE_PRIME | CREATE_EXACT;
17384 sna_pixmap_alloc_gpu(sna, pixmap, priv, create);
17386 @@ -4282,10 +4386,7 @@ sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
17387 goto done;
17390 - if (priv->shm) {
17391 - assert(!priv->flush);
17392 - sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
17393 - }
17394 + add_shm_flush(sna, priv);
17396 n = sna_damage_get_boxes(priv->cpu_damage, &box);
17397 assert(n);
17398 @@ -4534,7 +4635,7 @@ static inline bool box32_trim_and_translate(Box32Rec *box, DrawablePtr d, GCPtr
17399 return box32_clip(box, gc);
17402 -static inline void box_add_pt(BoxPtr box, int16_t x, int16_t y)
17403 +static inline void box_add_xy(BoxPtr box, int16_t x, int16_t y)
17405 if (box->x1 > x)
17406 box->x1 = x;
17407 @@ -4547,6 +4648,11 @@ static inline void box_add_pt(BoxPtr box, int16_t x, int16_t y)
17408 box->y2 = y;
17411 +static inline void box_add_pt(BoxPtr box, const DDXPointRec *pt)
17412 +{
17413 + box_add_xy(box, pt->x, pt->y);
17414 +}
17416 static inline bool box32_to_box16(const Box32Rec *b32, BoxRec *b16)
17418 b16->x1 = b32->x1;
17419 @@ -4864,6 +4970,7 @@ try_upload__inplace(PixmapPtr pixmap, RegionRec *region,
17420 pixmap->devPrivate.ptr = dst;
17421 pixmap->devKind = priv->gpu_bo->pitch;
17422 priv->mapped = dst == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
17423 + priv->cpu &= priv->mapped == MAPPED_CPU;
17424 assert(has_coherent_ptr(sna, priv, MOVE_WRITE));
17426 box = region_rects(region);
17427 @@ -4923,8 +5030,7 @@ done:
17428 sna_damage_all(&priv->gpu_damage, pixmap);
17431 - if (priv->shm)
17432 - sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
17433 + add_shm_flush(sna, priv);
17436 assert(!priv->clear);
17437 @@ -5172,6 +5278,16 @@ static inline uint8_t blt_depth(int depth)
17441 +inline static void blt_done(struct sna *sna)
17442 +{
17443 + sna->blt_state.fill_bo = 0;
17444 + if (sna->kgem.nbatch && __kgem_ring_empty(&sna->kgem)) {
17445 + DBG(("%s: flushing BLT operation on empty ring\n",
17446 + __FUNCTION__));
17447 + _kgem_submit(&sna->kgem);
17448 + }
17449 +}
17451 static bool
17452 sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
17453 int x, int y, int w, int h, char *bits)
17454 @@ -5217,6 +5333,7 @@ sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
17456 kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
17457 assert(kgem_bo_can_blt(&sna->kgem, bo));
17458 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
17460 /* Region is pre-clipped and translated into pixmap space */
17461 box = region_rects(region);
17462 @@ -5238,6 +5355,7 @@ sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
17463 return false;
17464 _kgem_set_mode(&sna->kgem, KGEM_BLT);
17466 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
17468 upload = kgem_create_buffer(&sna->kgem,
17469 bstride*bh,
17470 @@ -5331,7 +5449,7 @@ sna_put_xybitmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
17471 box++;
17472 } while (--n);
17474 - sna->blt_state.fill_bo = 0;
17475 + blt_done(sna);
17476 return true;
17479 @@ -5381,6 +5499,7 @@ sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
17481 kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
17482 assert(kgem_bo_can_blt(&sna->kgem, bo));
17483 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
17485 skip = h * BitmapBytePad(w + left);
17486 for (i = 1 << (gc->depth-1); i; i >>= 1, bits += skip) {
17487 @@ -5408,6 +5527,7 @@ sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
17488 return false;
17489 _kgem_set_mode(&sna->kgem, KGEM_BLT);
17491 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
17493 upload = kgem_create_buffer(&sna->kgem,
17494 bstride*bh,
17495 @@ -5509,7 +5629,7 @@ sna_put_xypixmap_blt(DrawablePtr drawable, GCPtr gc, RegionPtr region,
17496 } while (--n);
17499 - sna->blt_state.fill_bo = 0;
17500 + blt_done(sna);
17501 return true;
17504 @@ -5837,7 +5957,7 @@ sna_self_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
17505 if (!sna->render.copy_boxes(sna, alu,
17506 &pixmap->drawable, priv->gpu_bo, sx, sy,
17507 &pixmap->drawable, priv->gpu_bo, tx, ty,
17508 - box, n, 0)) {
17509 + box, n, small_copy(region))) {
17510 DBG(("%s: fallback - accelerated copy boxes failed\n",
17511 __FUNCTION__));
17512 goto fallback;
17513 @@ -6098,6 +6218,9 @@ sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu,
17515 kgem_bo_sync__cpu_full(&sna->kgem, src_priv->gpu_bo, FORCE_FULL_SYNC);
17517 + if (sigtrap_get())
17518 + return false;
17520 box = region_rects(region);
17521 n = region_num_rects(region);
17522 if (src_priv->gpu_bo->tiling) {
17523 @@ -6137,6 +6260,8 @@ sna_copy_boxes__inplace(struct sna *sna, RegionPtr region, int alu,
17527 + sigtrap_put();
17529 return true;
17531 upload_inplace:
17532 @@ -6234,6 +6359,9 @@ upload_inplace:
17534 assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
17536 + if (sigtrap_get())
17537 + return false;
17539 box = region_rects(region);
17540 n = region_num_rects(region);
17541 if (dst_priv->gpu_bo->tiling) {
17542 @@ -6265,15 +6393,19 @@ upload_inplace:
17543 } while (--n);
17545 if (!dst_priv->shm) {
17546 - assert(ptr == MAP(dst_priv->gpu_bo->map__cpu));
17547 dst_pixmap->devPrivate.ptr = ptr;
17548 dst_pixmap->devKind = dst_priv->gpu_bo->pitch;
17549 - dst_priv->mapped = MAPPED_CPU;
17550 + if (ptr == MAP(dst_priv->gpu_bo->map__cpu)) {
17551 + dst_priv->mapped = MAPPED_CPU;
17552 + dst_priv->cpu = true;
17553 + } else
17554 + dst_priv->mapped = MAPPED_GTT;
17555 assert_pixmap_map(dst_pixmap, dst_priv);
17556 - dst_priv->cpu = true;
17560 + sigtrap_put();
17562 return true;
17565 @@ -6326,6 +6458,16 @@ sna_copy_boxes(DrawablePtr src, DrawablePtr dst, GCPtr gc,
17567 assert(region_num_rects(region));
17569 + if (src_priv &&
17570 + src_priv->gpu_bo == NULL &&
17571 + src_priv->cpu_bo == NULL &&
17572 + src_priv->ptr == NULL) {
17573 + /* Rare but still happens, nothing to copy */
17574 + DBG(("%s: src pixmap=%ld is empty\n",
17575 + __FUNCTION__, src_pixmap->drawable.serialNumber));
17576 + return;
17577 + }
17579 if (src_pixmap == dst_pixmap)
17580 return sna_self_copy_boxes(src, dst, gc,
17581 region, dx, dy,
17582 @@ -6491,15 +6633,14 @@ discard_cow:
17583 sna_damage_all(&dst_priv->gpu_damage, dst_pixmap);
17584 sna_damage_destroy(&dst_priv->cpu_damage);
17585 list_del(&dst_priv->flush_list);
17586 - if (dst_priv->shm)
17587 - sna_add_flush_pixmap(sna, dst_priv, dst_priv->cpu_bo);
17588 + add_shm_flush(sna, dst_priv);
17589 return;
17592 if (!sna->render.copy_boxes(sna, alu,
17593 &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
17594 &dst_pixmap->drawable, bo, 0, 0,
17595 - box, n, 0)) {
17596 + box, n, small_copy(region))) {
17597 DBG(("%s: fallback - accelerated copy boxes failed\n",
17598 __FUNCTION__));
17599 goto fallback;
17600 @@ -6536,7 +6677,7 @@ discard_cow:
17601 if (!sna->render.copy_boxes(sna, alu,
17602 &src_pixmap->drawable, src_priv->gpu_bo, src_dx, src_dy,
17603 &dst_pixmap->drawable, bo, 0, 0,
17604 - box, n, 0)) {
17605 + box, n, small_copy(region))) {
17606 DBG(("%s: fallback - accelerated copy boxes failed\n",
17607 __FUNCTION__));
17608 goto fallback;
17609 @@ -6571,15 +6712,12 @@ discard_cow:
17610 if (replaces && UNDO)
17611 kgem_bo_pair_undo(&sna->kgem, dst_priv->gpu_bo, dst_priv->cpu_bo);
17613 - if (src_priv->shm) {
17614 - assert(!src_priv->flush);
17615 - sna_add_flush_pixmap(sna, src_priv, src_priv->cpu_bo);
17616 - }
17617 + add_shm_flush(sna, src_priv);
17619 if (!sna->render.copy_boxes(sna, alu,
17620 &src_pixmap->drawable, src_priv->cpu_bo, src_dx, src_dy,
17621 &dst_pixmap->drawable, bo, 0, 0,
17622 - box, n, src_priv->shm ? COPY_LAST : 0)) {
17623 + box, n, small_copy(region) | (src_priv->shm ? COPY_LAST : 0))) {
17624 DBG(("%s: fallback - accelerated copy boxes failed\n",
17625 __FUNCTION__));
17626 goto fallback;
17627 @@ -6631,8 +6769,7 @@ discard_cow:
17628 ok = sna->render.copy_boxes(sna, alu,
17629 &src_pixmap->drawable, src_bo, src_dx, src_dy,
17630 &dst_pixmap->drawable, bo, 0, 0,
17631 - box, n, COPY_LAST);
17633 + box, n, small_copy(region) | COPY_LAST);
17634 kgem_bo_sync__cpu(&sna->kgem, src_bo);
17635 assert(src_bo->rq == NULL);
17636 kgem_bo_destroy(&sna->kgem, src_bo);
17637 @@ -6780,18 +6917,22 @@ fallback:
17638 return;
17641 - assert(dst_pixmap->devPrivate.ptr);
17642 - assert(dst_pixmap->devKind);
17643 - do {
17644 - pixman_fill(dst_pixmap->devPrivate.ptr,
17645 - dst_pixmap->devKind/sizeof(uint32_t),
17646 - dst_pixmap->drawable.bitsPerPixel,
17647 - box->x1, box->y1,
17648 - box->x2 - box->x1,
17649 - box->y2 - box->y1,
17650 - src_priv->clear_color);
17651 - box++;
17652 - } while (--n);
17653 + if (sigtrap_get() == 0) {
17654 + assert(dst_pixmap->devPrivate.ptr);
17655 + assert(dst_pixmap->devKind);
17656 + sigtrap_assert_active();
17657 + do {
17658 + pixman_fill(dst_pixmap->devPrivate.ptr,
17659 + dst_pixmap->devKind/sizeof(uint32_t),
17660 + dst_pixmap->drawable.bitsPerPixel,
17661 + box->x1, box->y1,
17662 + box->x2 - box->x1,
17663 + box->y2 - box->y1,
17664 + src_priv->clear_color);
17665 + box++;
17666 + } while (--n);
17667 + sigtrap_put();
17668 + }
17669 } else if (!sna_copy_boxes__inplace(sna, region, alu,
17670 src_pixmap, src_priv,
17671 src_dx, src_dy,
17672 @@ -6848,36 +6989,39 @@ fallback:
17673 ((char *)src_pixmap->devPrivate.ptr +
17674 src_dy * src_stride + src_dx * bpp / 8);
17676 - do {
17677 - DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n",
17678 - __FUNCTION__,
17679 - box->x1, box->y1,
17680 - box->x2 - box->x1,
17681 - box->y2 - box->y1,
17682 - src_dx, src_dy,
17683 - src_stride, dst_stride));
17685 - assert(box->x1 >= 0);
17686 - assert(box->y1 >= 0);
17687 - assert(box->x2 <= dst_pixmap->drawable.width);
17688 - assert(box->y2 <= dst_pixmap->drawable.height);
17690 - assert(box->x1 + src_dx >= 0);
17691 - assert(box->y1 + src_dy >= 0);
17692 - assert(box->x2 + src_dx <= src_pixmap->drawable.width);
17693 - assert(box->y2 + src_dy <= src_pixmap->drawable.height);
17694 - assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
17695 - assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE));
17696 - assert(src_stride);
17697 - assert(dst_stride);
17698 - memcpy_blt(src_bits, dst_bits, bpp,
17699 - src_stride, dst_stride,
17700 - box->x1, box->y1,
17701 - box->x1, box->y1,
17702 - box->x2 - box->x1,
17703 - box->y2 - box->y1);
17704 - box++;
17705 - } while (--n);
17706 + if (sigtrap_get() == 0) {
17707 + do {
17708 + DBG(("%s: memcpy_blt(box=(%d, %d), (%d, %d), src=(%d, %d), pitches=(%d, %d))\n",
17709 + __FUNCTION__,
17710 + box->x1, box->y1,
17711 + box->x2 - box->x1,
17712 + box->y2 - box->y1,
17713 + src_dx, src_dy,
17714 + src_stride, dst_stride));
17716 + assert(box->x1 >= 0);
17717 + assert(box->y1 >= 0);
17718 + assert(box->x2 <= dst_pixmap->drawable.width);
17719 + assert(box->y2 <= dst_pixmap->drawable.height);
17721 + assert(box->x1 + src_dx >= 0);
17722 + assert(box->y1 + src_dy >= 0);
17723 + assert(box->x2 + src_dx <= src_pixmap->drawable.width);
17724 + assert(box->y2 + src_dy <= src_pixmap->drawable.height);
17725 + assert(has_coherent_ptr(sna, src_priv, MOVE_READ));
17726 + assert(has_coherent_ptr(sna, dst_priv, MOVE_WRITE));
17727 + assert(src_stride);
17728 + assert(dst_stride);
17729 + memcpy_blt(src_bits, dst_bits, bpp,
17730 + src_stride, dst_stride,
17731 + box->x1, box->y1,
17732 + box->x1, box->y1,
17733 + box->x2 - box->x1,
17734 + box->y2 - box->y1);
17735 + box++;
17736 + } while (--n);
17737 + sigtrap_put();
17738 + }
17739 } else {
17740 DBG(("%s: fallback -- miCopyRegion\n", __FUNCTION__));
17742 @@ -6931,7 +7075,8 @@ sna_do_copy(DrawablePtr src, DrawablePtr dst, GCPtr gc,
17744 /* Short cut for unmapped windows */
17745 if (dst->type == DRAWABLE_WINDOW && !((WindowPtr)dst)->realized) {
17746 - DBG(("%s: unmapped\n", __FUNCTION__));
17747 + DBG(("%s: unmapped/unrealized dst (pixmap=%ld)\n",
17748 + __FUNCTION__, get_window_pixmap((WindowPtr)dst)));
17749 return NULL;
17752 @@ -7115,19 +7260,28 @@ sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
17753 if (gc->planemask == 0)
17754 return NULL;
17756 - DBG(("%s: src=(%d, %d)x(%d, %d)+(%d, %d) -> dst=(%d, %d)+(%d, %d); alu=%d, pm=%lx, depth=%d\n",
17757 + if (sna->ignore_copy_area)
17758 + return NULL;
17760 + 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",
17761 __FUNCTION__,
17762 + get_drawable_pixmap(src)->drawable.serialNumber,
17763 src_x, src_y, width, height, src->x, src->y,
17764 + get_drawable_pixmap(dst)->drawable.serialNumber,
17765 dst_x, dst_y, dst->x, dst->y,
17766 gc->alu, gc->planemask, gc->depth));
17768 if (FORCE_FALLBACK || !ACCEL_COPY_AREA || wedged(sna) ||
17769 - !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8)
17770 + !PM_IS_SOLID(dst, gc->planemask) || gc->depth < 8) {
17771 + DBG(("%s: fallback copy\n", __FUNCTION__));
17772 copy = sna_fallback_copy_boxes;
17773 - else if (src == dst)
17774 + } else if (src == dst) {
17775 + DBG(("%s: self copy\n", __FUNCTION__));
17776 copy = sna_self_copy_boxes;
17777 - else
17778 + } else {
17779 + DBG(("%s: normal copy\n", __FUNCTION__));
17780 copy = sna_copy_boxes;
17781 + }
17783 return sna_do_copy(src, dst, gc,
17784 src_x, src_y,
17785 @@ -7136,30 +7290,21 @@ sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
17786 copy, 0, NULL);
17789 -static const BoxRec *
17790 -find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
17791 +const BoxRec *
17792 +__find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
17794 - const BoxRec *mid;
17796 - if (end == begin)
17797 - return end;
17799 - if (end - begin == 1) {
17800 + assert(end - begin > 1);
17801 + do {
17802 + const BoxRec *mid = begin + (end - begin) / 2;
17803 + if (mid->y2 > y)
17804 + end = mid;
17805 + else
17806 + begin = mid;
17807 + } while (end > begin + 1);
17808 if (begin->y2 > y)
17809 - return begin;
17810 + return begin;
17811 else
17812 - return end;
17813 - }
17815 - mid = begin + (end - begin) / 2;
17816 - if (mid->y2 > y)
17817 - /* If no box is found in [begin, mid], the function
17818 - * will return @mid, which is then known to be the
17819 - * correct answer.
17820 - */
17821 - return find_clip_box_for_y(begin, mid, y);
17822 - else
17823 - return find_clip_box_for_y(mid, end, y);
17824 + return end;
17827 struct sna_fill_spans {
17828 @@ -8223,6 +8368,8 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
17830 br13 |= blt_depth(drawable->depth) << 24;
17831 br13 |= copy_ROP[gc->alu] << 16;
17832 + DBG(("%s: target-depth=%d, alu=%d, bg=%08x, fg=%08x\n",
17833 + __FUNCTION__, drawable->depth, gc->alu, gc->bgPixel, gc->fgPixel));
17835 kgem_set_mode(&sna->kgem, KGEM_BLT, arg->bo);
17836 assert(kgem_bo_can_blt(&sna->kgem, arg->bo));
17837 @@ -8255,6 +8402,7 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
17838 return; /* XXX fallback? */
17839 _kgem_set_mode(&sna->kgem, KGEM_BLT);
17841 + kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
17843 assert(sna->kgem.mode == KGEM_BLT);
17844 if (sna->kgem.gen >= 0100) {
17845 @@ -8270,8 +8418,8 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
17846 I915_GEM_DOMAIN_RENDER |
17847 KGEM_RELOC_FENCED,
17848 0);
17849 - b[5] = gc->bgPixel;
17850 - b[6] = gc->fgPixel;
17851 + b[6] = gc->bgPixel;
17852 + b[7] = gc->fgPixel;
17854 dst = (uint8_t *)&b[8];
17855 sna->kgem.nbatch += 8 + src_stride;
17856 @@ -8322,6 +8470,7 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
17857 return; /* XXX fallback? */
17858 _kgem_set_mode(&sna->kgem, KGEM_BLT);
17860 + kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
17862 upload = kgem_create_buffer(&sna->kgem,
17863 bstride*bh,
17864 @@ -8408,7 +8557,7 @@ sna_copy_bitmap_blt(DrawablePtr _bitmap, DrawablePtr drawable, GCPtr gc,
17865 sna_damage_add_to_pixmap(arg->damage, region, pixmap);
17867 assert_pixmap_damage(pixmap);
17868 - sna->blt_state.fill_bo = 0;
17869 + blt_done(sna);
17872 static void
17873 @@ -8472,6 +8621,7 @@ sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
17874 return; /* XXX fallback? */
17875 _kgem_set_mode(&sna->kgem, KGEM_BLT);
17877 + kgem_bcs_set_tiling(&sna->kgem, NULL, arg->bo);
17879 upload = kgem_create_buffer(&sna->kgem,
17880 bstride*bh,
17881 @@ -8588,6 +8738,8 @@ sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
17885 + kgem_bcs_set_tiling(&sna->kgem, upload, arg->bo);
17887 assert(sna->kgem.mode == KGEM_BLT);
17888 b = sna->kgem.batch + sna->kgem.nbatch;
17889 if (sna->kgem.gen >= 0100) {
17890 @@ -8641,7 +8793,7 @@ sna_copy_plane_blt(DrawablePtr source, DrawablePtr drawable, GCPtr gc,
17891 sna_damage_add_to_pixmap(arg->damage, region, dst_pixmap);
17893 assert_pixmap_damage(dst_pixmap);
17894 - sna->blt_state.fill_bo = 0;
17895 + blt_done(sna);
17898 static RegionPtr
17899 @@ -8895,36 +9047,11 @@ sna_poly_point_extents(DrawablePtr drawable, GCPtr gc,
17900 last.x += pt->x;
17901 last.y += pt->y;
17902 pt++;
17903 - box_add_pt(&box, last.x, last.y);
17904 + box_add_xy(&box, last.x, last.y);
17906 } else {
17907 - --n; ++pt;
17908 - while (n >= 8) {
17909 - box_add_pt(&box, pt[0].x, pt[0].y);
17910 - box_add_pt(&box, pt[1].x, pt[1].y);
17911 - box_add_pt(&box, pt[2].x, pt[2].y);
17912 - box_add_pt(&box, pt[3].x, pt[3].y);
17913 - box_add_pt(&box, pt[4].x, pt[4].y);
17914 - box_add_pt(&box, pt[5].x, pt[5].y);
17915 - box_add_pt(&box, pt[6].x, pt[6].y);
17916 - box_add_pt(&box, pt[7].x, pt[7].y);
17917 - pt += 8;
17918 - n -= 8;
17919 - }
17920 - if (n & 4) {
17921 - box_add_pt(&box, pt[0].x, pt[0].y);
17922 - box_add_pt(&box, pt[1].x, pt[1].y);
17923 - box_add_pt(&box, pt[2].x, pt[2].y);
17924 - box_add_pt(&box, pt[3].x, pt[3].y);
17925 - pt += 4;
17926 - }
17927 - if (n & 2) {
17928 - box_add_pt(&box, pt[0].x, pt[0].y);
17929 - box_add_pt(&box, pt[1].x, pt[1].y);
17930 - pt += 2;
17931 - }
17932 - if (n & 1)
17933 - box_add_pt(&box, pt[0].x, pt[0].y);
17934 + while (--n)
17935 + box_add_pt(&box, ++pt);
17937 box.x2++;
17938 box.y2++;
17939 @@ -9636,7 +9763,7 @@ sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
17940 y += pt->y;
17941 if (blt)
17942 blt &= pt->x == 0 || pt->y == 0;
17943 - box_add_pt(&box, x, y);
17944 + box_add_xy(&box, x, y);
17946 } else {
17947 int x = box.x1;
17948 @@ -9648,7 +9775,7 @@ sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
17949 x = pt->x;
17950 y = pt->y;
17952 - box_add_pt(&box, pt->x, pt->y);
17953 + box_add_pt(&box, pt);
17956 box.x2++;
17957 @@ -10037,7 +10164,7 @@ out:
17958 RegionUninit(&data.region);
17961 -static inline void box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc)
17962 +static inline bool box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc)
17964 if (seg->x1 == seg->x2) {
17965 if (seg->y1 > seg->y2) {
17966 @@ -10051,6 +10178,9 @@ static inline void box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc)
17967 if (gc->capStyle != CapNotLast)
17968 b->y2++;
17970 + if (b->y1 >= b->y2)
17971 + return false;
17973 b->x1 = seg->x1;
17974 b->x2 = seg->x1 + 1;
17975 } else {
17976 @@ -10065,6 +10195,9 @@ static inline void box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc)
17977 if (gc->capStyle != CapNotLast)
17978 b->x2++;
17980 + if (b->x1 >= b->x2)
17981 + return false;
17983 b->y1 = seg->y1;
17984 b->y2 = seg->y1 + 1;
17986 @@ -10073,6 +10206,7 @@ static inline void box_from_seg(BoxPtr b, const xSegment *seg, GCPtr gc)
17987 __FUNCTION__,
17988 seg->x1, seg->y1, seg->x2, seg->y2,
17989 b->x1, b->y1, b->x2, b->y2));
17990 + return true;
17993 static bool
17994 @@ -10107,12 +10241,13 @@ sna_poly_segment_blt(DrawablePtr drawable,
17995 nbox = ARRAY_SIZE(boxes);
17996 n -= nbox;
17997 do {
17998 - box_from_seg(b, seg++, gc);
17999 - if (b->y2 > b->y1 && b->x2 > b->x1) {
18000 + if (box_from_seg(b, seg++, gc)) {
18001 + assert(!box_empty(b));
18002 b->x1 += dx;
18003 b->x2 += dx;
18004 b->y1 += dy;
18005 b->y2 += dy;
18006 + assert(!box_empty(b));
18007 b++;
18009 } while (--nbox);
18010 @@ -10131,7 +10266,10 @@ sna_poly_segment_blt(DrawablePtr drawable,
18011 nbox = ARRAY_SIZE(boxes);
18012 n -= nbox;
18013 do {
18014 - box_from_seg(b++, seg++, gc);
18015 + if (box_from_seg(b, seg++, gc)) {
18016 + assert(!box_empty(b));
18017 + b++;
18018 + }
18019 } while (--nbox);
18021 if (b != boxes) {
18022 @@ -10156,7 +10294,10 @@ sna_poly_segment_blt(DrawablePtr drawable,
18023 do {
18024 BoxRec box;
18026 - box_from_seg(&box, seg++, gc);
18027 + if (!box_from_seg(&box, seg++, gc))
18028 + continue;
18030 + assert(!box_empty(&box));
18031 box.x1 += drawable->x;
18032 box.x2 += drawable->x;
18033 box.y1 += drawable->y;
18034 @@ -10174,6 +10315,7 @@ sna_poly_segment_blt(DrawablePtr drawable,
18035 b->x2 += dx;
18036 b->y1 += dy;
18037 b->y2 += dy;
18038 + assert(!box_empty(b));
18039 if (++b == last_box) {
18040 fill.boxes(sna, &fill, boxes, last_box-boxes);
18041 if (damage)
18042 @@ -10185,7 +10327,10 @@ sna_poly_segment_blt(DrawablePtr drawable,
18043 } while (--n);
18044 } else {
18045 do {
18046 - box_from_seg(b, seg++, gc);
18047 + if (!box_from_seg(b, seg++, gc))
18048 + continue;
18050 + assert(!box_empty(b));
18051 b->x1 += drawable->x;
18052 b->x2 += drawable->x;
18053 b->y1 += drawable->y;
18054 @@ -10195,6 +10340,7 @@ sna_poly_segment_blt(DrawablePtr drawable,
18055 b->x2 += dx;
18056 b->y1 += dy;
18057 b->y2 += dy;
18058 + assert(!box_empty(b));
18059 if (++b == last_box) {
18060 fill.boxes(sna, &fill, boxes, last_box-boxes);
18061 if (damage)
18062 @@ -10319,8 +10465,11 @@ sna_poly_zero_segment_blt(DrawablePtr drawable,
18064 b->x2++;
18065 b->y2++;
18066 - if (oc1 | oc2)
18067 - box_intersect(b, extents);
18069 + if ((oc1 | oc2) && !box_intersect(b, extents))
18070 + continue;
18072 + assert(!box_empty(b));
18073 if (++b == last_box) {
18074 ret = &&rectangle_continue;
18075 goto *jump;
18076 @@ -10383,6 +10532,7 @@ rectangle_continue:
18077 __FUNCTION__, x1, y1,
18078 b->x1, b->y1, b->x2, b->y2));
18080 + assert(!box_empty(b));
18081 if (++b == last_box) {
18082 ret = &&X_continue;
18083 goto *jump;
18084 @@ -10407,6 +10557,7 @@ X_continue:
18085 b->x2 = x1 + 1;
18086 b->y2 = b->y1 + 1;
18088 + assert(!box_empty(b));
18089 if (++b == last_box) {
18090 ret = &&X2_continue;
18091 goto *jump;
18092 @@ -10468,6 +10619,7 @@ X2_continue:
18093 b->y2 = y1 + 1;
18094 b->x2 = x1 + 1;
18096 + assert(!box_empty(b));
18097 if (++b == last_box) {
18098 ret = &&Y_continue;
18099 goto *jump;
18100 @@ -10491,6 +10643,7 @@ Y_continue:
18101 b->y2 = y1 + 1;
18102 b->x2 = x1 + 1;
18104 + assert(!box_empty(b));
18105 if (++b == last_box) {
18106 ret = &&Y2_continue;
18107 goto *jump;
18108 @@ -11785,14 +11938,29 @@ sna_poly_fill_rect_blt(DrawablePtr drawable,
18109 if (nbox > ARRAY_SIZE(boxes))
18110 nbox = ARRAY_SIZE(boxes);
18111 n -= nbox;
18112 - do {
18113 + while (nbox >= 2) {
18114 + b[0].x1 = rect[0].x + dx;
18115 + b[0].y1 = rect[0].y + dy;
18116 + b[0].x2 = b[0].x1 + rect[0].width;
18117 + b[0].y2 = b[0].y1 + rect[0].height;
18119 + b[1].x1 = rect[1].x + dx;
18120 + b[1].y1 = rect[1].y + dy;
18121 + b[1].x2 = b[1].x1 + rect[1].width;
18122 + b[1].y2 = b[1].y1 + rect[1].height;
18124 + b += 2;
18125 + rect += 2;
18126 + nbox -= 2;
18127 + }
18128 + if (nbox) {
18129 b->x1 = rect->x + dx;
18130 b->y1 = rect->y + dy;
18131 b->x2 = b->x1 + rect->width;
18132 b->y2 = b->y1 + rect->height;
18133 b++;
18134 rect++;
18135 - } while (--nbox);
18136 + }
18137 fill.boxes(sna, &fill, boxes, b-boxes);
18138 b = boxes;
18139 } while (n);
18140 @@ -11802,14 +11970,29 @@ sna_poly_fill_rect_blt(DrawablePtr drawable,
18141 if (nbox > ARRAY_SIZE(boxes))
18142 nbox = ARRAY_SIZE(boxes);
18143 n -= nbox;
18144 - do {
18145 + while (nbox >= 2) {
18146 + b[0].x1 = rect[0].x;
18147 + b[0].y1 = rect[0].y;
18148 + b[0].x2 = b[0].x1 + rect[0].width;
18149 + b[0].y2 = b[0].y1 + rect[0].height;
18151 + b[1].x1 = rect[1].x;
18152 + b[1].y1 = rect[1].y;
18153 + b[1].x2 = b[1].x1 + rect[1].width;
18154 + b[1].y2 = b[1].y1 + rect[1].height;
18156 + b += 2;
18157 + rect += 2;
18158 + nbox -= 2;
18159 + }
18160 + if (nbox) {
18161 b->x1 = rect->x;
18162 b->y1 = rect->y;
18163 b->x2 = b->x1 + rect->width;
18164 b->y2 = b->y1 + rect->height;
18165 b++;
18166 rect++;
18167 - } while (--nbox);
18168 + }
18169 fill.boxes(sna, &fill, boxes, b-boxes);
18170 b = boxes;
18171 } while (n);
18172 @@ -12192,6 +12375,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
18173 return false;
18174 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18176 + kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
18178 get_drawable_deltas(drawable, pixmap, &dx, &dy);
18179 assert(extents->x1 + dx >= 0);
18180 @@ -12335,6 +12519,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
18182 _kgem_submit(&sna->kgem);
18183 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18184 + kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
18185 } while (1);
18186 } else {
18187 RegionRec clip;
18188 @@ -12403,6 +12588,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
18189 if (!kgem_check_batch(&sna->kgem, 3)) {
18190 _kgem_submit(&sna->kgem);
18191 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18192 + kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
18194 unwind_batch = sna->kgem.nbatch;
18195 unwind_reloc = sna->kgem.nreloc;
18196 @@ -12499,6 +12685,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
18197 DBG(("%s: emitting split batch\n", __FUNCTION__));
18198 _kgem_submit(&sna->kgem);
18199 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18200 + kgem_bcs_set_tiling(&sna->kgem, tile_bo, bo);
18202 unwind_batch = sna->kgem.nbatch;
18203 unwind_reloc = sna->kgem.nreloc;
18204 @@ -12572,7 +12759,7 @@ sna_poly_fill_rect_tiled_8x8_blt(DrawablePtr drawable,
18206 done:
18207 assert_pixmap_damage(pixmap);
18208 - sna->blt_state.fill_bo = 0;
18209 + blt_done(sna);
18210 return true;
18213 @@ -13128,6 +13315,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
18214 return false;
18215 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18217 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18219 if (!clipped) {
18220 dx += drawable->x;
18221 @@ -13240,6 +13428,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
18223 _kgem_submit(&sna->kgem);
18224 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18225 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18226 } while (1);
18227 } else {
18228 RegionRec clip;
18229 @@ -13297,6 +13486,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
18230 if (!kgem_check_batch(&sna->kgem, 3)) {
18231 _kgem_submit(&sna->kgem);
18232 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18233 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18235 assert(sna->kgem.mode == KGEM_BLT);
18236 b = sna->kgem.batch + sna->kgem.nbatch;
18237 @@ -13369,6 +13559,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
18238 if (!kgem_check_batch(&sna->kgem, 3)) {
18239 _kgem_submit(&sna->kgem);
18240 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18241 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18243 assert(sna->kgem.mode == KGEM_BLT);
18244 b = sna->kgem.batch + sna->kgem.nbatch;
18245 @@ -13419,7 +13610,7 @@ sna_poly_fill_rect_stippled_8x8_blt(DrawablePtr drawable,
18248 assert_pixmap_damage(pixmap);
18249 - sna->blt_state.fill_bo = 0;
18250 + blt_done(sna);
18251 return true;
18254 @@ -13499,6 +13690,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
18255 get_drawable_deltas(drawable, pixmap, &dx, &dy);
18256 kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
18257 assert(kgem_bo_can_blt(&sna->kgem, bo));
18258 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18260 br00 = 3 << 20;
18261 br13 = bo->pitch;
18262 @@ -13543,6 +13735,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
18263 return false;
18264 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18266 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18268 assert(sna->kgem.mode == KGEM_BLT);
18269 b = sna->kgem.batch + sna->kgem.nbatch;
18270 @@ -13606,6 +13799,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
18271 return false;
18272 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18274 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18276 upload = kgem_create_buffer(&sna->kgem,
18277 bstride*bh,
18278 @@ -13736,6 +13930,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
18279 return false;
18280 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18282 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18284 assert(sna->kgem.mode == KGEM_BLT);
18285 b = sna->kgem.batch + sna->kgem.nbatch;
18286 @@ -13797,6 +13992,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
18287 return false;
18288 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18290 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18292 upload = kgem_create_buffer(&sna->kgem,
18293 bstride*bh,
18294 @@ -13927,6 +14123,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
18295 return false;
18296 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18298 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18300 assert(sna->kgem.mode == KGEM_BLT);
18301 b = sna->kgem.batch + sna->kgem.nbatch;
18302 @@ -13987,6 +14184,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
18303 return false;
18304 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18306 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18308 upload = kgem_create_buffer(&sna->kgem,
18309 bstride*bh,
18310 @@ -14064,7 +14262,7 @@ sna_poly_fill_rect_stippled_1_blt(DrawablePtr drawable,
18314 - sna->blt_state.fill_bo = 0;
18315 + blt_done(sna);
18316 return true;
18319 @@ -14126,6 +14324,7 @@ sna_poly_fill_rect_stippled_n_box__imm(struct sna *sna,
18320 return; /* XXX fallback? */
18321 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18323 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18325 assert(sna->kgem.mode == KGEM_BLT);
18326 b = sna->kgem.batch + sna->kgem.nbatch;
18327 @@ -14251,6 +14450,7 @@ sna_poly_fill_rect_stippled_n_box(struct sna *sna,
18328 return; /* XXX fallback? */
18329 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18331 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18333 assert(sna->kgem.mode == KGEM_BLT);
18334 b = sna->kgem.batch + sna->kgem.nbatch;
18335 @@ -14414,6 +14614,7 @@ sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable,
18336 get_drawable_deltas(drawable, pixmap, &dx, &dy);
18337 kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
18338 assert(kgem_bo_can_blt(&sna->kgem, bo));
18339 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18341 br00 = XY_MONO_SRC_COPY_IMM | 3 << 20;
18342 br13 = bo->pitch;
18343 @@ -14526,7 +14727,7 @@ sna_poly_fill_rect_stippled_n_blt__imm(DrawablePtr drawable,
18346 assert_pixmap_damage(pixmap);
18347 - sna->blt_state.fill_bo = 0;
18348 + blt_done(sna);
18349 return true;
18352 @@ -14559,6 +14760,7 @@ sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable,
18353 get_drawable_deltas(drawable, pixmap, &dx, &dy);
18354 kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
18355 assert(kgem_bo_can_blt(&sna->kgem, bo));
18356 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18358 br00 = XY_MONO_SRC_COPY | 3 << 20;
18359 br13 = bo->pitch;
18360 @@ -14673,7 +14875,7 @@ sna_poly_fill_rect_stippled_n_blt(DrawablePtr drawable,
18361 assert_pixmap_damage(pixmap);
18362 if (tile)
18363 kgem_bo_destroy(&sna->kgem, tile);
18364 - sna->blt_state.fill_bo = 0;
18365 + blt_done(sna);
18366 return true;
18369 @@ -15281,6 +15483,7 @@ sna_glyph_blt(DrawablePtr drawable, GCPtr gc,
18371 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18373 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18375 DBG(("%s: glyph clip box (%d, %d), (%d, %d)\n",
18376 __FUNCTION__,
18377 @@ -15368,6 +15571,7 @@ sna_glyph_blt(DrawablePtr drawable, GCPtr gc,
18378 if (!kgem_check_batch(&sna->kgem, 3+len)) {
18379 _kgem_submit(&sna->kgem);
18380 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18381 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18383 DBG(("%s: new batch, glyph clip box (%d, %d), (%d, %d)\n",
18384 __FUNCTION__,
18385 @@ -15479,7 +15683,7 @@ skip:
18388 assert_pixmap_damage(pixmap);
18389 - sna->blt_state.fill_bo = 0;
18390 + blt_done(sna);
18391 return true;
18394 @@ -16002,6 +16206,7 @@ sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc,
18396 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18398 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18400 unwind_batch = sna->kgem.nbatch;
18401 unwind_reloc = sna->kgem.nreloc;
18402 @@ -16111,6 +16316,7 @@ sna_reversed_glyph_blt(DrawablePtr drawable, GCPtr gc,
18403 if (!kgem_check_batch(&sna->kgem, 3+len)) {
18404 _kgem_submit(&sna->kgem);
18405 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18406 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18408 unwind_batch = sna->kgem.nbatch;
18409 unwind_reloc = sna->kgem.nreloc;
18410 @@ -16229,7 +16435,7 @@ skip:
18413 assert_pixmap_damage(pixmap);
18414 - sna->blt_state.fill_bo = 0;
18415 + blt_done(sna);
18416 return true;
18419 @@ -16450,6 +16656,7 @@ sna_push_pixels_solid_blt(GCPtr gc,
18421 kgem_set_mode(&sna->kgem, KGEM_BLT, bo);
18422 assert(kgem_bo_can_blt(&sna->kgem, bo));
18423 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18425 /* Region is pre-clipped and translated into pixmap space */
18426 box = region_rects(region);
18427 @@ -16471,6 +16678,7 @@ sna_push_pixels_solid_blt(GCPtr gc,
18428 return false;
18429 _kgem_set_mode(&sna->kgem, KGEM_BLT);
18431 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
18433 upload = kgem_create_buffer(&sna->kgem,
18434 bstride*bh,
18435 @@ -16564,7 +16772,7 @@ sna_push_pixels_solid_blt(GCPtr gc,
18436 box++;
18437 } while (--n);
18439 - sna->blt_state.fill_bo = 0;
18440 + blt_done(sna);
18441 return true;
18444 @@ -16754,7 +16962,9 @@ static int sna_create_gc(GCPtr gc)
18446 gc->freeCompClip = 0;
18447 gc->pCompositeClip = 0;
18448 +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,19,99,1,0)
18449 gc->pRotatedPixmap = 0;
18450 +#endif
18452 fb_gc(gc)->bpp = bits_per_pixel(gc->depth);
18454 @@ -16789,7 +16999,8 @@ sna_get_image__inplace(PixmapPtr pixmap,
18455 break;
18458 - if (!kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
18459 + if ((flags & MOVE_INPLACE_HINT) == 0 &&
18460 + !kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC))
18461 return false;
18463 if (idle && __kgem_bo_is_busy(&sna->kgem, priv->gpu_bo))
18464 @@ -16801,11 +17012,19 @@ sna_get_image__inplace(PixmapPtr pixmap,
18465 assert(sna_damage_contains_box(&priv->gpu_damage, &region->extents) == PIXMAN_REGION_IN);
18466 assert(sna_damage_contains_box(&priv->cpu_damage, &region->extents) == PIXMAN_REGION_OUT);
18468 - src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
18469 - if (src == NULL)
18470 - return false;
18471 + if (kgem_bo_can_map__cpu(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC)) {
18472 + src = kgem_bo_map__cpu(&sna->kgem, priv->gpu_bo);
18473 + if (src == NULL)
18474 + return false;
18476 - kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
18477 + kgem_bo_sync__cpu_full(&sna->kgem, priv->gpu_bo, FORCE_FULL_SYNC);
18478 + } else {
18479 + src = kgem_bo_map__wc(&sna->kgem, priv->gpu_bo);
18480 + if (src == NULL)
18481 + return false;
18483 + kgem_bo_sync__gtt(&sna->kgem, priv->gpu_bo);
18484 + }
18486 if (sigtrap_get())
18487 return false;
18488 @@ -16833,12 +17052,11 @@ sna_get_image__inplace(PixmapPtr pixmap,
18489 region->extents.x2 - region->extents.x1,
18490 region->extents.y2 - region->extents.y1);
18491 if (!priv->shm) {
18492 - assert(src == MAP(priv->gpu_bo->map__cpu));
18493 pixmap->devPrivate.ptr = src;
18494 pixmap->devKind = priv->gpu_bo->pitch;
18495 - priv->mapped = MAPPED_CPU;
18496 + priv->mapped = src == MAP(priv->gpu_bo->map__cpu) ? MAPPED_CPU : MAPPED_GTT;
18497 assert_pixmap_map(pixmap, priv);
18498 - priv->cpu = true;
18499 + priv->cpu &= priv->mapped == MAPPED_CPU;
18503 @@ -16930,7 +17148,7 @@ sna_get_image__fast(PixmapPtr pixmap,
18504 if (priv == NULL || priv->gpu_damage == NULL)
18505 return false;
18507 - if (priv->clear) {
18508 + if (priv->clear && sigtrap_get() == 0) {
18509 int w = region->extents.x2 - region->extents.x1;
18510 int h = region->extents.y2 - region->extents.y1;
18511 int pitch = PixmapBytePad(w, pixmap->drawable.depth);
18512 @@ -16939,6 +17157,7 @@ sna_get_image__fast(PixmapPtr pixmap,
18513 __FUNCTION__, priv->clear_color));
18514 assert(DAMAGE_IS_ALL(priv->gpu_damage));
18515 assert(priv->cpu_damage == NULL);
18516 + sigtrap_assert_active();
18518 if (priv->clear_color == 0 ||
18519 pixmap->drawable.bitsPerPixel == 8 ||
18520 @@ -16955,6 +17174,7 @@ sna_get_image__fast(PixmapPtr pixmap,
18521 priv->clear_color);
18524 + sigtrap_put();
18525 return true;
18528 @@ -17001,8 +17221,7 @@ sna_get_image(DrawablePtr drawable,
18529 if (ACCEL_GET_IMAGE &&
18530 !FORCE_FALLBACK &&
18531 format == ZPixmap &&
18532 - drawable->bitsPerPixel >= 8 &&
18533 - PM_IS_SOLID(drawable, mask)) {
18534 + drawable->bitsPerPixel >= 8) {
18535 PixmapPtr pixmap = get_drawable_pixmap(drawable);
18536 int16_t dx, dy;
18538 @@ -17014,7 +17233,7 @@ sna_get_image(DrawablePtr drawable,
18539 region.data = NULL;
18541 if (sna_get_image__fast(pixmap, &region, dst, flags))
18542 - return;
18543 + goto apply_planemask;
18545 if (!sna_drawable_move_region_to_cpu(&pixmap->drawable,
18546 &region, flags))
18547 @@ -17032,6 +17251,16 @@ sna_get_image(DrawablePtr drawable,
18548 region.extents.x1, region.extents.y1, 0, 0, w, h);
18549 sigtrap_put();
18552 +apply_planemask:
18553 + if (!PM_IS_SOLID(drawable, mask)) {
18554 + FbStip pm = fbReplicatePixel(mask, drawable->bitsPerPixel);
18555 + FbStip *d = (FbStip *)dst;
18556 + int i, n = PixmapBytePad(w, drawable->depth) / sizeof(FbStip) * h;
18558 + for (i = 0; i < n; i++)
18559 + d[i] &= pm;
18560 + }
18561 } else {
18562 region.extents.x1 = x + drawable->x;
18563 region.extents.y1 = y + drawable->y;
18564 @@ -17162,17 +17391,19 @@ void sna_accel_flush(struct sna *sna)
18565 __sna_free_pixmap(sna, priv->pixmap, priv);
18567 } else {
18568 + unsigned hints;
18569 DBG(("%s: flushing DRI pixmap=%ld\n", __FUNCTION__,
18570 priv->pixmap->drawable.serialNumber));
18571 assert(priv->flush);
18572 - if (sna_pixmap_move_to_gpu(priv->pixmap,
18573 - MOVE_READ | __MOVE_FORCE)) {
18574 - if (priv->flush & IS_CLIPPED) {
18575 + hints = MOVE_READ | __MOVE_FORCE;
18576 + if (priv->flush & FLUSH_WRITE)
18577 + hints |= MOVE_WRITE;
18578 + if (sna_pixmap_move_to_gpu(priv->pixmap, hints)) {
18579 + if (priv->flush & FLUSH_WRITE) {
18580 kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
18581 sna_damage_all(&priv->gpu_damage, priv->pixmap);
18582 assert(priv->cpu_damage == NULL);
18583 - priv->clear = false;
18584 - priv->cpu = false;
18585 + assert(priv->clear == false);
18589 @@ -17184,10 +17415,46 @@ void sna_accel_flush(struct sna *sna)
18592 static void
18593 -sna_accel_flush_callback(CallbackListPtr *list,
18594 - pointer user_data, pointer call_data)
18595 +sna_shm_flush_callback(CallbackListPtr *list,
18596 + pointer user_data, pointer call_data)
18598 - sna_accel_flush(user_data);
18599 + struct sna *sna = user_data;
18601 + if (!sna->needs_shm_flush)
18602 + return;
18604 + sna_accel_flush(sna);
18605 + sna->needs_shm_flush = false;
18606 +}
18608 +static void
18609 +sna_flush_callback(CallbackListPtr *list, pointer user_data, pointer call_data)
18610 +{
18611 + struct sna *sna = user_data;
18613 + if (!sna->needs_dri_flush)
18614 + return;
18616 + sna_accel_flush(sna);
18617 + sna->needs_dri_flush = false;
18618 +}
18620 +static void
18621 +sna_event_callback(CallbackListPtr *list, pointer user_data, pointer call_data)
18622 +{
18623 + EventInfoRec *eventinfo = call_data;
18624 + struct sna *sna = user_data;
18625 + int i;
18627 + if (sna->needs_dri_flush)
18628 + return;
18630 + for (i = 0; i < eventinfo->count; i++) {
18631 + if (eventinfo->events[i].u.u.type == sna->damage_event) {
18632 + sna->needs_dri_flush = true;
18633 + return;
18634 + }
18635 + }
18638 static struct sna_pixmap *sna_accel_scanout(struct sna *sna)
18639 @@ -17199,6 +17466,7 @@ static struct sna_pixmap *sna_accel_scanout(struct sna *sna)
18641 assert(sna->vblank_interval);
18642 assert(sna->front);
18643 + assert(!sna->mode.hidden);
18645 priv = sna_pixmap(sna->front);
18646 if (priv->gpu_bo == NULL)
18647 @@ -17217,7 +17485,7 @@ static void sna_accel_disarm_timer(struct sna *sna, int id)
18648 static bool has_offload_slaves(struct sna *sna)
18650 #if HAS_PIXMAP_SHARING
18651 - ScreenPtr screen = sna->scrn->pScreen;
18652 + ScreenPtr screen = to_screen_from_sna(sna);
18653 PixmapDirtyUpdatePtr dirty;
18655 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
18656 @@ -17231,11 +17499,14 @@ static bool has_offload_slaves(struct sna *sna)
18658 static bool has_shadow(struct sna *sna)
18660 - DamagePtr damage = sna->mode.shadow_damage;
18661 + DamagePtr damage;
18663 - if (damage == NULL)
18664 + if (!sna->mode.shadow_enabled)
18665 return false;
18667 + damage = sna->mode.shadow_damage;
18668 + assert(damage);
18670 DBG(("%s: has pending damage? %d, outstanding flips: %d\n",
18671 __FUNCTION__,
18672 RegionNotEmpty(DamageRegion(damage)),
18673 @@ -17365,9 +17636,8 @@ static bool sna_accel_do_expire(struct sna *sna)
18674 static void sna_accel_post_damage(struct sna *sna)
18676 #if HAS_PIXMAP_SHARING
18677 - ScreenPtr screen = sna->scrn->pScreen;
18678 + ScreenPtr screen = to_screen_from_sna(sna);
18679 PixmapDirtyUpdatePtr dirty;
18680 - bool flush = false;
18682 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
18683 RegionRec region, *damage;
18684 @@ -17376,8 +17646,6 @@ static void sna_accel_post_damage(struct sna *sna)
18685 int16_t dx, dy;
18686 int n;
18688 - assert(dirty->src == sna->front);
18690 damage = DamageRegion(dirty->damage);
18691 if (RegionNil(damage))
18692 continue;
18693 @@ -17477,7 +17745,14 @@ fallback:
18694 box, n, COPY_LAST))
18695 goto fallback;
18697 - flush = true;
18698 + /* Before signalling the slave via ProcessPending,
18699 + * ensure not only the batch is submitted as the
18700 + * slave may be using the Damage callback to perform
18701 + * its copy, but also that the memory must be coherent
18702 + * - we need to treat it as uncached for the PCI slave
18703 + * will bypass LLC.
18704 + */
18705 + kgem_bo_sync__gtt(&sna->kgem, __sna_pixmap_get_bo(dst));
18708 DamageRegionProcessPending(&dirty->slave_dst->drawable);
18709 @@ -17485,8 +17760,6 @@ skip:
18710 RegionUninit(&region);
18711 DamageEmpty(dirty->damage);
18713 - if (flush)
18714 - kgem_submit(&sna->kgem);
18715 #endif
18718 @@ -17689,6 +17962,7 @@ sna_set_screen_pixmap(PixmapPtr pixmap)
18719 static Bool
18720 sna_create_window(WindowPtr win)
18722 + DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
18723 sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate);
18724 return TRUE;
18726 @@ -17714,6 +17988,7 @@ sna_unmap_window(WindowPtr win)
18727 static Bool
18728 sna_destroy_window(WindowPtr win)
18730 + DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
18731 sna_video_destroy_window(win);
18732 sna_dri2_destroy_window(win);
18733 return TRUE;
18734 @@ -17790,20 +18065,34 @@ static bool sna_option_accel_none(struct sna *sna)
18735 if (wedged(sna))
18736 return true;
18738 - if (xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_DISABLE, FALSE))
18739 + if (!xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_ENABLE, TRUE))
18740 return true;
18742 + if (sna->kgem.gen >= 0120)
18743 + return true;
18745 + if (!intel_option_cast_to_bool(sna->Options,
18746 + OPTION_ACCEL_METHOD,
18747 + !IS_DEFAULT_ACCEL_METHOD(NOACCEL)))
18748 + return false;
18750 +#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
18751 s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
18752 if (s == NULL)
18753 return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
18755 return strcasecmp(s, "none") == 0;
18756 +#else
18757 + return IS_DEFAULT_ACCEL_METHOD(NOACCEL);
18758 +#endif
18761 static bool sna_option_accel_blt(struct sna *sna)
18763 const char *s;
18765 + assert(sna->kgem.gen < 0120);
18767 s = xf86GetOptValString(sna->Options, OPTION_ACCEL_METHOD);
18768 if (s == NULL)
18769 return false;
18770 @@ -17811,6 +18100,13 @@ static bool sna_option_accel_blt(struct sna *sna)
18771 return strcasecmp(s, "blt") == 0;
18774 +#if HAVE_NOTIFY_FD
18775 +static void sna_accel_notify(int fd, int ready, void *data)
18776 +{
18777 + sna_mode_wakeup(data);
18778 +}
18779 +#endif
18781 bool sna_accel_init(ScreenPtr screen, struct sna *sna)
18783 const char *backend;
18784 @@ -17822,7 +18118,7 @@ bool sna_accel_init(ScreenPtr screen, struct sna *sna)
18785 list_init(&sna->flush_pixmaps);
18786 list_init(&sna->active_pixmaps);
18788 - AddGeneralSocket(sna->kgem.fd);
18789 + SetNotifyFd(sna->kgem.fd, sna_accel_notify, X_NOTIFY_READ, sna);
18791 #ifdef DEBUG_MEMORY
18792 sna->timer_expire[DEBUG_MEMORY_TIMER] = GetTimeInMillis()+ 10 * 1000;
18793 @@ -17892,21 +18188,23 @@ bool sna_accel_init(ScreenPtr screen, struct sna *sna)
18794 backend = "disabled";
18795 sna->kgem.wedged = true;
18796 sna_render_mark_wedged(sna);
18797 - } else if (sna_option_accel_blt(sna) || sna->info->gen >= 0110)
18798 + } else if (sna_option_accel_blt(sna))
18799 (void)backend;
18800 - else if (sna->info->gen >= 0100)
18801 + else if (sna->kgem.gen >= 0110)
18802 + backend = gen9_render_init(sna, backend);
18803 + else if (sna->kgem.gen >= 0100)
18804 backend = gen8_render_init(sna, backend);
18805 - else if (sna->info->gen >= 070)
18806 + else if (sna->kgem.gen >= 070)
18807 backend = gen7_render_init(sna, backend);
18808 - else if (sna->info->gen >= 060)
18809 + else if (sna->kgem.gen >= 060)
18810 backend = gen6_render_init(sna, backend);
18811 - else if (sna->info->gen >= 050)
18812 + else if (sna->kgem.gen >= 050)
18813 backend = gen5_render_init(sna, backend);
18814 - else if (sna->info->gen >= 040)
18815 + else if (sna->kgem.gen >= 040)
18816 backend = gen4_render_init(sna, backend);
18817 - else if (sna->info->gen >= 030)
18818 + else if (sna->kgem.gen >= 030)
18819 backend = gen3_render_init(sna, backend);
18820 - else if (sna->info->gen >= 020)
18821 + else if (sna->kgem.gen >= 020)
18822 backend = gen2_render_init(sna, backend);
18824 DBG(("%s(backend=%s, prefer_gpu=%x)\n",
18825 @@ -17924,8 +18222,14 @@ bool sna_accel_init(ScreenPtr screen, struct sna *sna)
18827 void sna_accel_create(struct sna *sna)
18829 + ExtensionEntry *damage;
18831 DBG(("%s\n", __FUNCTION__));
18833 + damage = CheckExtension("DAMAGE");
18834 + if (damage)
18835 + sna->damage_event = damage->eventBase + XDamageNotify;
18837 if (!sna_glyphs_create(sna))
18838 goto fail;
18840 @@ -17943,27 +18247,59 @@ fail:
18841 no_render_init(sna);
18844 -void sna_accel_watch_flush(struct sna *sna, int enable)
18845 +static void sna_shm_watch_flush(struct sna *sna, int enable)
18847 DBG(("%s: enable=%d\n", __FUNCTION__, enable));
18848 assert(enable);
18850 - if (sna->watch_flush == 0) {
18851 + if (sna->watch_shm_flush == 0) {
18852 + DBG(("%s: installing shm watchers\n", __FUNCTION__));
18853 + assert(enable > 0);
18855 + if (!AddCallback(&FlushCallback, sna_shm_flush_callback, sna))
18856 + return;
18858 + sna->watch_shm_flush++;
18859 + }
18861 + sna->watch_shm_flush += enable;
18862 +}
18864 +void sna_watch_flush(struct sna *sna, int enable)
18865 +{
18866 + DBG(("%s: enable=%d\n", __FUNCTION__, enable));
18867 + assert(enable);
18869 + if (sna->watch_dri_flush == 0) {
18870 + int err = 0;
18872 DBG(("%s: installing watchers\n", __FUNCTION__));
18873 assert(enable > 0);
18874 - if (!AddCallback(&FlushCallback, sna_accel_flush_callback, sna)) {
18876 + if (!sna->damage_event)
18877 + return;
18879 + if (!AddCallback(&EventCallback, sna_event_callback, sna))
18880 + err = 1;
18882 + if (!AddCallback(&FlushCallback, sna_flush_callback, sna))
18883 + err = 1;
18885 + if (err) {
18886 xf86DrvMsg(sna->scrn->scrnIndex, X_Error,
18887 "Failed to attach ourselves to the flush callbacks, expect missing synchronisation with DRI clients (e.g a compositor)\n");
18889 - sna->watch_flush++;
18891 + sna->watch_dri_flush++;
18894 - sna->watch_flush += enable;
18895 + sna->watch_dri_flush += enable;
18898 void sna_accel_leave(struct sna *sna)
18900 DBG(("%s\n", __FUNCTION__));
18901 + sna_scanout_flush(sna);
18903 /* as root we always have permission to render */
18904 if (geteuid() == 0)
18905 @@ -17997,13 +18333,15 @@ void sna_accel_close(struct sna *sna)
18907 sna_pixmap_expire(sna);
18909 - DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna);
18910 - RemoveGeneralSocket(sna->kgem.fd);
18911 + DeleteCallback(&FlushCallback, sna_shm_flush_callback, sna);
18912 + DeleteCallback(&FlushCallback, sna_flush_callback, sna);
18913 + DeleteCallback(&EventCallback, sna_event_callback, sna);
18914 + RemoveNotifyFd(sna->kgem.fd);
18916 kgem_cleanup_cache(&sna->kgem);
18919 -void sna_accel_block_handler(struct sna *sna, struct timeval **tv)
18920 +void sna_accel_block(struct sna *sna, struct timeval **tv)
18922 sigtrap_assert_inactive();
18924 @@ -18044,10 +18382,17 @@ restart:
18925 if (sna_accel_do_debug_memory(sna))
18926 sna_accel_debug_memory(sna);
18928 - if (sna->watch_flush == 1) {
18929 - DBG(("%s: removing watchers\n", __FUNCTION__));
18930 - DeleteCallback(&FlushCallback, sna_accel_flush_callback, sna);
18931 - sna->watch_flush = 0;
18932 + if (sna->watch_shm_flush == 1) {
18933 + DBG(("%s: removing shm watchers\n", __FUNCTION__));
18934 + DeleteCallback(&FlushCallback, sna_shm_flush_callback, sna);
18935 + sna->watch_shm_flush = 0;
18936 + }
18938 + if (sna->watch_dri_flush == 1) {
18939 + DBG(("%s: removing dri watchers\n", __FUNCTION__));
18940 + DeleteCallback(&FlushCallback, sna_flush_callback, sna);
18941 + DeleteCallback(&EventCallback, sna_event_callback, sna);
18942 + sna->watch_dri_flush = 0;
18945 if (sna->timer_active & 1) {
18946 @@ -18083,22 +18428,6 @@ set_tv:
18950 -void sna_accel_wakeup_handler(struct sna *sna)
18951 -{
18952 - DBG(("%s: nbatch=%d, need_retire=%d, need_purge=%d\n", __FUNCTION__,
18953 - sna->kgem.nbatch, sna->kgem.need_retire, sna->kgem.need_purge));
18955 - if (!sna->kgem.nbatch)
18956 - return;
18958 - if (kgem_is_idle(&sna->kgem)) {
18959 - DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
18960 - _kgem_submit(&sna->kgem);
18961 - }
18963 - sigtrap_assert_inactive();
18964 -}
18966 void sna_accel_free(struct sna *sna)
18968 DBG(("%s\n", __FUNCTION__));
18969 diff --git a/src/sna/sna_acpi.c b/src/sna/sna_acpi.c
18970 index dcc0287b..643d04af 100644
18971 --- a/src/sna/sna_acpi.c
18972 +++ b/src/sna/sna_acpi.c
18973 @@ -92,7 +92,7 @@ void _sna_acpi_wakeup(struct sna *sna)
18974 DBG(("%s: error [%d], detaching from acpid\n", __FUNCTION__, n));
18976 /* XXX reattach later? */
18977 - RemoveGeneralSocket(sna->acpi.fd);
18978 + RemoveNotifyFd(sna->acpi.fd);
18979 sna_acpi_fini(sna);
18980 return;
18982 @@ -136,6 +136,13 @@ void _sna_acpi_wakeup(struct sna *sna)
18983 } while (n);
18986 +#if HAVE_NOTIFY_FD
18987 +static void sna_acpi_notify(int fd, int read, void *data)
18988 +{
18989 + _sna_acpi_wakeup(data);
18990 +}
18991 +#endif
18993 static int read_power_state(const char *path)
18995 DIR *dir;
18996 @@ -200,7 +207,7 @@ void sna_acpi_init(struct sna *sna)
18998 DBG(("%s: attaching to acpid\n", __FUNCTION__));
19000 - AddGeneralSocket(sna->acpi.fd);
19001 + SetNotifyFd(sna->acpi.fd, sna_acpi_notify, X_NOTIFY_READ, sna);
19002 sna->acpi.remain = sizeof(sna->acpi.event) - 1;
19003 sna->acpi.offset = 0;
19005 diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c
19006 index de8f6ec3..ddd2586d 100644
19007 --- a/src/sna/sna_blt.c
19008 +++ b/src/sna/sna_blt.c
19009 @@ -86,6 +86,11 @@ static const uint8_t fill_ROP[] = {
19010 ROP_1
19011 };
19013 +static void sig_done(struct sna *sna, const struct sna_composite_op *op)
19014 +{
19015 + sigtrap_put();
19016 +}
19018 static void nop_done(struct sna *sna, const struct sna_composite_op *op)
19020 assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem));
19021 @@ -129,7 +134,6 @@ static bool sna_blt_fill_init(struct sna *sna,
19022 struct kgem *kgem = &sna->kgem;
19024 assert(kgem_bo_can_blt (kgem, bo));
19025 - assert(bo->tiling != I915_TILING_Y);
19026 blt->bo[0] = bo;
19028 blt->br13 = bo->pitch;
19029 @@ -183,6 +187,7 @@ static bool sna_blt_fill_init(struct sna *sna,
19030 return false;
19031 _kgem_set_mode(kgem, KGEM_BLT);
19033 + kgem_bcs_set_tiling(kgem, NULL, bo);
19035 assert(sna->kgem.mode == KGEM_BLT);
19036 b = kgem->batch + kgem->nbatch;
19037 @@ -237,17 +242,13 @@ static bool sna_blt_fill_init(struct sna *sna,
19038 return true;
19041 -noinline static void sna_blt_fill_begin(struct sna *sna,
19042 - const struct sna_blt_state *blt)
19043 +noinline static void __sna_blt_fill_begin(struct sna *sna,
19044 + const struct sna_blt_state *blt)
19046 struct kgem *kgem = &sna->kgem;
19047 uint32_t *b;
19049 - if (kgem->nreloc) {
19050 - _kgem_submit(kgem);
19051 - _kgem_set_mode(kgem, KGEM_BLT);
19052 - assert(kgem->nbatch == 0);
19053 - }
19054 + kgem_bcs_set_tiling(&sna->kgem, NULL, blt->bo[0]);
19056 assert(kgem->mode == KGEM_BLT);
19057 b = kgem->batch + kgem->nbatch;
19058 @@ -293,6 +294,21 @@ noinline static void sna_blt_fill_begin(struct sna *sna,
19062 +inline static void sna_blt_fill_begin(struct sna *sna,
19063 + const struct sna_blt_state *blt)
19064 +{
19065 + struct kgem *kgem = &sna->kgem;
19067 + if (kgem->nreloc) {
19068 + _kgem_submit(kgem);
19069 + _kgem_set_mode(kgem, KGEM_BLT);
19070 + kgem_bcs_set_tiling(kgem, NULL, blt->bo[0]);
19071 + assert(kgem->nbatch == 0);
19072 + }
19074 + __sna_blt_fill_begin(sna, blt);
19075 +}
19077 inline static void sna_blt_fill_one(struct sna *sna,
19078 const struct sna_blt_state *blt,
19079 int16_t x, int16_t y,
19080 @@ -330,8 +346,8 @@ static bool sna_blt_copy_init(struct sna *sna,
19082 struct kgem *kgem = &sna->kgem;
19084 - assert(kgem_bo_can_blt (kgem, src));
19085 - assert(kgem_bo_can_blt (kgem, dst));
19086 + assert(kgem_bo_can_blt(kgem, src));
19087 + assert(kgem_bo_can_blt(kgem, dst));
19089 blt->bo[0] = src;
19090 blt->bo[1] = dst;
19091 @@ -370,6 +386,7 @@ static bool sna_blt_copy_init(struct sna *sna,
19092 return false;
19093 _kgem_set_mode(kgem, KGEM_BLT);
19095 + kgem_bcs_set_tiling(&sna->kgem, src, dst);
19097 sna->blt_state.fill_bo = 0;
19098 return true;
19099 @@ -424,6 +441,7 @@ static bool sna_blt_alpha_fixup_init(struct sna *sna,
19100 return false;
19101 _kgem_set_mode(kgem, KGEM_BLT);
19103 + kgem_bcs_set_tiling(&sna->kgem, src, dst);
19105 sna->blt_state.fill_bo = 0;
19106 return true;
19107 @@ -454,6 +472,7 @@ static void sna_blt_alpha_fixup_one(struct sna *sna,
19108 !kgem_check_reloc(kgem, 2)) {
19109 _kgem_submit(kgem);
19110 _kgem_set_mode(kgem, KGEM_BLT);
19111 + kgem_bcs_set_tiling(&sna->kgem, blt->bo[0], blt->bo[1]);
19114 assert(sna->kgem.mode == KGEM_BLT);
19115 @@ -582,6 +601,7 @@ static void sna_blt_copy_one(struct sna *sna,
19116 !kgem_check_reloc(kgem, 2)) {
19117 _kgem_submit(kgem);
19118 _kgem_set_mode(kgem, KGEM_BLT);
19119 + kgem_bcs_set_tiling(&sna->kgem, blt->bo[0], blt->bo[1]);
19122 assert(sna->kgem.mode == KGEM_BLT);
19123 @@ -912,8 +932,27 @@ sna_composite_mask_is_opaque(PicturePtr mask)
19124 return is_solid(mask) && is_white(mask);
19125 else if (!PICT_FORMAT_A(mask->format))
19126 return true;
19127 - else
19128 - return is_solid(mask) && is_opaque_solid(mask);
19129 + else if (mask->pSourcePict) {
19130 + PictSolidFill *fill = (PictSolidFill *) mask->pSourcePict;
19131 + return (fill->color >> 24) == 0xff;
19132 + } else {
19133 + struct sna_pixmap *priv;
19134 + assert(mask->pDrawable);
19136 + if (mask->pDrawable->width == 1 &&
19137 + mask->pDrawable->height == 1 &&
19138 + mask->repeat)
19139 + return pixel_is_opaque(get_pixel(mask), mask->format);
19141 + if (mask->transform)
19142 + return false;
19144 + priv = sna_pixmap_from_drawable(mask->pDrawable);
19145 + if (priv == NULL || !priv->clear)
19146 + return false;
19148 + return pixel_is_opaque(priv->clear_color, mask->format);
19149 + }
19152 fastcall
19153 @@ -971,6 +1010,7 @@ static void blt_composite_fill__cpu(struct sna *sna,
19155 assert(op->dst.pixmap->devPrivate.ptr);
19156 assert(op->dst.pixmap->devKind);
19157 + sigtrap_assert_active();
19158 pixman_fill(op->dst.pixmap->devPrivate.ptr,
19159 op->dst.pixmap->devKind / sizeof(uint32_t),
19160 op->dst.pixmap->drawable.bitsPerPixel,
19161 @@ -990,6 +1030,7 @@ blt_composite_fill_box_no_offset__cpu(struct sna *sna,
19163 assert(op->dst.pixmap->devPrivate.ptr);
19164 assert(op->dst.pixmap->devKind);
19165 + sigtrap_assert_active();
19166 pixman_fill(op->dst.pixmap->devPrivate.ptr,
19167 op->dst.pixmap->devKind / sizeof(uint32_t),
19168 op->dst.pixmap->drawable.bitsPerPixel,
19169 @@ -1010,6 +1051,7 @@ blt_composite_fill_boxes_no_offset__cpu(struct sna *sna,
19171 assert(op->dst.pixmap->devPrivate.ptr);
19172 assert(op->dst.pixmap->devKind);
19173 + sigtrap_assert_active();
19174 pixman_fill(op->dst.pixmap->devPrivate.ptr,
19175 op->dst.pixmap->devKind / sizeof(uint32_t),
19176 op->dst.pixmap->drawable.bitsPerPixel,
19177 @@ -1031,6 +1073,7 @@ blt_composite_fill_box__cpu(struct sna *sna,
19179 assert(op->dst.pixmap->devPrivate.ptr);
19180 assert(op->dst.pixmap->devKind);
19181 + sigtrap_assert_active();
19182 pixman_fill(op->dst.pixmap->devPrivate.ptr,
19183 op->dst.pixmap->devKind / sizeof(uint32_t),
19184 op->dst.pixmap->drawable.bitsPerPixel,
19185 @@ -1052,6 +1095,7 @@ blt_composite_fill_boxes__cpu(struct sna *sna,
19187 assert(op->dst.pixmap->devPrivate.ptr);
19188 assert(op->dst.pixmap->devKind);
19189 + sigtrap_assert_active();
19190 pixman_fill(op->dst.pixmap->devPrivate.ptr,
19191 op->dst.pixmap->devKind / sizeof(uint32_t),
19192 op->dst.pixmap->drawable.bitsPerPixel,
19193 @@ -1159,12 +1203,15 @@ static inline void _sna_blt_maybe_clear(const struct sna_composite_op *op, const
19194 box->y2 - box->y1 >= op->dst.height) {
19195 struct sna_pixmap *priv = sna_pixmap(op->dst.pixmap);
19196 if (op->dst.bo == priv->gpu_bo) {
19197 + sna_damage_all(&priv->gpu_damage, op->dst.pixmap);
19198 + sna_damage_destroy(&priv->cpu_damage);
19199 priv->clear = true;
19200 priv->clear_color = op->u.blt.pixel;
19201 DBG(("%s: pixmap=%ld marking clear [%08x]\n",
19202 __FUNCTION__,
19203 op->dst.pixmap->drawable.serialNumber,
19204 op->u.blt.pixel));
19205 + ((struct sna_composite_op *)op)->damage = NULL;
19209 @@ -1404,6 +1451,7 @@ begin_blt(struct sna *sna,
19210 return false;
19212 _kgem_set_mode(&sna->kgem, KGEM_BLT);
19213 + kgem_bcs_set_tiling(&sna->kgem, NULL, op->dst.bo);
19216 return true;
19217 @@ -1429,6 +1477,7 @@ prepare_blt_clear(struct sna *sna,
19218 DBG(("%s\n", __FUNCTION__));
19220 if (op->dst.bo == NULL) {
19221 + op->u.blt.pixel = 0;
19222 op->blt = blt_composite_fill__cpu;
19223 if (op->dst.x|op->dst.y) {
19224 op->box = blt_composite_fill_box__cpu;
19225 @@ -1439,9 +1488,8 @@ prepare_blt_clear(struct sna *sna,
19226 op->boxes = blt_composite_fill_boxes_no_offset__cpu;
19227 op->thread_boxes = blt_composite_fill_boxes_no_offset__cpu;
19229 - op->done = nop_done;
19230 - op->u.blt.pixel = 0;
19231 - return true;
19232 + op->done = sig_done;
19233 + return sigtrap_get() == 0;
19236 op->blt = blt_composite_fill;
19237 @@ -1484,8 +1532,8 @@ prepare_blt_fill(struct sna *sna,
19238 op->boxes = blt_composite_fill_boxes_no_offset__cpu;
19239 op->thread_boxes = blt_composite_fill_boxes_no_offset__cpu;
19241 - op->done = nop_done;
19242 - return true;
19243 + op->done = sig_done;
19244 + return sigtrap_get() == 0;
19247 op->blt = blt_composite_fill;
19248 @@ -1668,6 +1716,7 @@ static void blt_composite_copy_boxes__thread(struct sna *sna,
19250 _kgem_submit(kgem);
19251 _kgem_set_mode(kgem, KGEM_BLT);
19252 + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
19253 } while (1);
19254 } else {
19255 do {
19256 @@ -1724,6 +1773,7 @@ static void blt_composite_copy_boxes__thread(struct sna *sna,
19258 _kgem_submit(kgem);
19259 _kgem_set_mode(kgem, KGEM_BLT);
19260 + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
19261 } while (1);
19263 sna_vertex_unlock(&sna->render);
19264 @@ -1806,6 +1856,7 @@ static void blt_composite_copy_boxes__thread64(struct sna *sna,
19266 _kgem_submit(kgem);
19267 _kgem_set_mode(kgem, KGEM_BLT);
19268 + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
19269 } while (1);
19270 } else {
19271 do {
19272 @@ -1864,6 +1915,7 @@ static void blt_composite_copy_boxes__thread64(struct sna *sna,
19274 _kgem_submit(kgem);
19275 _kgem_set_mode(kgem, KGEM_BLT);
19276 + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
19277 } while (1);
19279 sna_vertex_unlock(&sna->render);
19280 @@ -1973,6 +2025,7 @@ prepare_blt_copy(struct sna *sna,
19282 _kgem_set_mode(&sna->kgem, KGEM_BLT);
19284 + kgem_bcs_set_tiling(&sna->kgem, bo, op->dst.bo);
19286 DBG(("%s\n", __FUNCTION__));
19288 @@ -2396,6 +2449,9 @@ prepare_blt_put(struct sna *sna,
19289 op->box = blt_put_composite_box;
19290 op->boxes = blt_put_composite_boxes;
19293 + op->done = nop_done;
19294 + return true;
19295 } else {
19296 if (alpha_fixup) {
19297 op->u.blt.pixel = alpha_fixup;
19298 @@ -2407,10 +2463,10 @@ prepare_blt_put(struct sna *sna,
19299 op->box = blt_put_composite_box__cpu;
19300 op->boxes = blt_put_composite_boxes__cpu;
19302 - }
19303 - op->done = nop_done;
19305 - return true;
19306 + op->done = sig_done;
19307 + return sigtrap_get() == 0;
19308 + }
19311 static bool
19312 @@ -2544,6 +2600,7 @@ sna_blt_composite(struct sna *sna,
19313 clear:
19314 if (was_clear && sna_pixmap(tmp->dst.pixmap)->clear_color == 0) {
19315 sna_pixmap(tmp->dst.pixmap)->clear = true;
19316 +nop:
19317 return prepare_blt_nop(sna, tmp);
19320 @@ -2559,6 +2616,7 @@ clear:
19322 tmp->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint,
19323 &dst_box, &tmp->damage);
19324 + assert(!tmp->damage || !DAMAGE_IS_ALL(*tmp->damage));
19325 if (tmp->dst.bo) {
19326 if (!kgem_bo_can_blt(&sna->kgem, tmp->dst.bo)) {
19327 DBG(("%s: can not blit to dst, tiling? %d, pitch? %d\n",
19328 @@ -2567,6 +2625,8 @@ clear:
19330 if (hint & REPLACES)
19331 kgem_bo_undo(&sna->kgem, tmp->dst.bo);
19332 + if (flags & COMPOSITE_UPLOAD)
19333 + return false;
19334 } else {
19335 RegionRec region;
19337 @@ -2590,32 +2650,40 @@ clear:
19339 if (op == PictOpOver && is_opaque_solid(src))
19340 op = PictOpSrc;
19341 - if (op == PictOpAdd && is_white(src))
19342 + if (op == PictOpAdd &&
19343 + PICT_FORMAT_RGB(src->format) == PICT_FORMAT_RGB(dst->format) &&
19344 + is_white(src))
19345 op = PictOpSrc;
19346 if (was_clear && (op == PictOpAdd || op == PictOpOver)) {
19347 if (sna_pixmap(tmp->dst.pixmap)->clear_color == 0)
19348 op = PictOpSrc;
19349 if (op == PictOpOver) {
19350 + unsigned dst_color = solid_color(dst->format, sna_pixmap(tmp->dst.pixmap)->clear_color);
19351 color = over(get_solid_color(src, PICT_a8r8g8b8),
19352 - color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
19353 - dst->format, PICT_a8r8g8b8));
19354 + dst_color);
19355 op = PictOpSrc;
19356 DBG(("%s: precomputing solid OVER (%08x, %08x) -> %08x\n",
19357 __FUNCTION__, get_solid_color(src, PICT_a8r8g8b8),
19358 - color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
19359 - dst->format, PICT_a8r8g8b8),
19360 + solid_color(dst->format, sna_pixmap(tmp->dst.pixmap)->clear_color),
19361 color));
19362 + if (color == dst_color)
19363 + goto nop;
19364 + else
19365 + goto fill;
19367 if (op == PictOpAdd) {
19368 + unsigned dst_color = solid_color(dst->format, sna_pixmap(tmp->dst.pixmap)->clear_color);
19369 color = add(get_solid_color(src, PICT_a8r8g8b8),
19370 - color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
19371 - dst->format, PICT_a8r8g8b8));
19372 + dst_color);
19373 op = PictOpSrc;
19374 DBG(("%s: precomputing solid ADD (%08x, %08x) -> %08x\n",
19375 __FUNCTION__, get_solid_color(src, PICT_a8r8g8b8),
19376 - color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
19377 - dst->format, PICT_a8r8g8b8),
19378 + solid_color(dst->format, sna_pixmap(tmp->dst.pixmap)->clear_color),
19379 color));
19380 + if (color == dst_color)
19381 + goto nop;
19382 + else
19383 + goto fill;
19386 if (op == PictOpOutReverse && is_opaque_solid(src))
19387 @@ -2649,6 +2717,7 @@ fill:
19389 tmp->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint,
19390 &dst_box, &tmp->damage);
19391 + assert(!tmp->damage || !DAMAGE_IS_ALL(*tmp->damage));
19392 if (tmp->dst.bo) {
19393 if (!kgem_bo_can_blt(&sna->kgem, tmp->dst.bo)) {
19394 DBG(("%s: can not blit to dst, tiling? %d, pitch? %d\n",
19395 @@ -2657,6 +2726,8 @@ fill:
19397 if (hint & REPLACES)
19398 kgem_bo_undo(&sna->kgem, tmp->dst.bo);
19399 + if (flags & COMPOSITE_UPLOAD)
19400 + return false;
19401 } else {
19402 RegionRec region;
19404 @@ -2720,8 +2791,8 @@ fill:
19405 if (is_clear(src_pixmap)) {
19406 if (src->repeat ||
19407 (x >= 0 && y >= 0 &&
19408 - x + width < src_pixmap->drawable.width &&
19409 - y + height < src_pixmap->drawable.height)) {
19410 + x + width <= src_pixmap->drawable.width &&
19411 + y + height <= src_pixmap->drawable.height)) {
19412 color = color_convert(sna_pixmap(src_pixmap)->clear_color,
19413 src->format, tmp->dst.format);
19414 goto fill;
19415 @@ -2795,7 +2866,7 @@ fill:
19416 if (src_pixmap->drawable.width <= sna->render.max_3d_size &&
19417 src_pixmap->drawable.height <= sna->render.max_3d_size &&
19418 bo->pitch <= sna->render.max_3d_pitch &&
19419 - (flags & COMPOSITE_FALLBACK) == 0)
19420 + (flags & (COMPOSITE_UPLOAD | COMPOSITE_FALLBACK)) == 0)
19422 return false;
19424 @@ -2817,6 +2888,7 @@ fill:
19426 tmp->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint,
19427 &dst_box, &tmp->damage);
19428 + assert(!tmp->damage || !DAMAGE_IS_ALL(*tmp->damage));
19430 if (tmp->dst.bo && hint & REPLACES) {
19431 struct sna_pixmap *priv = sna_pixmap(tmp->dst.pixmap);
19432 @@ -2846,7 +2918,7 @@ fallback:
19433 DBG(("%s: fallback -- unaccelerated upload\n",
19434 __FUNCTION__));
19435 goto fallback;
19436 - } else {
19437 + } else if ((flags & COMPOSITE_UPLOAD) == 0) {
19438 ret = prepare_blt_copy(sna, tmp, bo, alpha_fixup);
19439 if (!ret)
19440 goto fallback;
19441 @@ -3023,6 +3095,7 @@ sna_blt_composite__convert(struct sna *sna,
19443 _kgem_set_mode(&sna->kgem, KGEM_BLT);
19445 + kgem_bcs_set_tiling(&sna->kgem, tmp->src.bo, tmp->dst.bo);
19447 if (alpha_fixup) {
19448 tmp->blt = blt_composite_copy_with_alpha;
19449 @@ -3062,7 +3135,7 @@ static void sna_blt_fill_op_blt(struct sna *sna,
19450 if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) {
19451 const struct sna_blt_state *blt = &op->base.u.blt;
19453 - sna_blt_fill_begin(sna, blt);
19454 + __sna_blt_fill_begin(sna, blt);
19456 sna->blt_state.fill_bo = blt->bo[0]->unique_id;
19457 sna->blt_state.fill_pixel = blt->pixel;
19458 @@ -3079,7 +3152,7 @@ fastcall static void sna_blt_fill_op_box(struct sna *sna,
19459 if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) {
19460 const struct sna_blt_state *blt = &op->base.u.blt;
19462 - sna_blt_fill_begin(sna, blt);
19463 + __sna_blt_fill_begin(sna, blt);
19465 sna->blt_state.fill_bo = blt->bo[0]->unique_id;
19466 sna->blt_state.fill_pixel = blt->pixel;
19467 @@ -3097,7 +3170,7 @@ fastcall static void sna_blt_fill_op_boxes(struct sna *sna,
19468 if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) {
19469 const struct sna_blt_state *blt = &op->base.u.blt;
19471 - sna_blt_fill_begin(sna, blt);
19472 + __sna_blt_fill_begin(sna, blt);
19474 sna->blt_state.fill_bo = blt->bo[0]->unique_id;
19475 sna->blt_state.fill_pixel = blt->pixel;
19476 @@ -3132,7 +3205,7 @@ fastcall static void sna_blt_fill_op_points(struct sna *sna,
19477 DBG(("%s: %08x x %d\n", __FUNCTION__, blt->pixel, n));
19479 if (sna->blt_state.fill_bo != op->base.u.blt.bo[0]->unique_id) {
19480 - sna_blt_fill_begin(sna, blt);
19481 + __sna_blt_fill_begin(sna, blt);
19483 sna->blt_state.fill_bo = blt->bo[0]->unique_id;
19484 sna->blt_state.fill_pixel = blt->pixel;
19485 @@ -3162,65 +3235,15 @@ fastcall static void sna_blt_fill_op_points(struct sna *sna,
19486 assert(kgem->nbatch < kgem->surface);
19488 if ((dx|dy) == 0) {
19489 - while (n_this_time >= 8) {
19490 - *((uint64_t *)b + 0) = pt_add(cmd, p+0, 0, 0);
19491 - *((uint64_t *)b + 1) = pt_add(cmd, p+1, 0, 0);
19492 - *((uint64_t *)b + 2) = pt_add(cmd, p+2, 0, 0);
19493 - *((uint64_t *)b + 3) = pt_add(cmd, p+3, 0, 0);
19494 - *((uint64_t *)b + 4) = pt_add(cmd, p+4, 0, 0);
19495 - *((uint64_t *)b + 5) = pt_add(cmd, p+5, 0, 0);
19496 - *((uint64_t *)b + 6) = pt_add(cmd, p+6, 0, 0);
19497 - *((uint64_t *)b + 7) = pt_add(cmd, p+7, 0, 0);
19498 - b += 16;
19499 - n_this_time -= 8;
19500 - p += 8;
19501 - }
19502 - if (n_this_time & 4) {
19503 - *((uint64_t *)b + 0) = pt_add(cmd, p+0, 0, 0);
19504 - *((uint64_t *)b + 1) = pt_add(cmd, p+1, 0, 0);
19505 - *((uint64_t *)b + 2) = pt_add(cmd, p+2, 0, 0);
19506 - *((uint64_t *)b + 3) = pt_add(cmd, p+3, 0, 0);
19507 - b += 8;
19508 - p += 4;
19509 - }
19510 - if (n_this_time & 2) {
19511 - *((uint64_t *)b + 0) = pt_add(cmd, p+0, 0, 0);
19512 - *((uint64_t *)b + 1) = pt_add(cmd, p+1, 0, 0);
19513 - b += 4;
19514 - p += 2;
19515 - }
19516 - if (n_this_time & 1)
19517 - *((uint64_t *)b + 0) = pt_add(cmd, p++, 0, 0);
19518 + do {
19519 + *(uint64_t *)b = pt_add(cmd, p++, 0, 0);
19520 + b += 2;
19521 + } while (--n_this_time);
19522 } else {
19523 - while (n_this_time >= 8) {
19524 - *((uint64_t *)b + 0) = pt_add(cmd, p+0, dx, dy);
19525 - *((uint64_t *)b + 1) = pt_add(cmd, p+1, dx, dy);
19526 - *((uint64_t *)b + 2) = pt_add(cmd, p+2, dx, dy);
19527 - *((uint64_t *)b + 3) = pt_add(cmd, p+3, dx, dy);
19528 - *((uint64_t *)b + 4) = pt_add(cmd, p+4, dx, dy);
19529 - *((uint64_t *)b + 5) = pt_add(cmd, p+5, dx, dy);
19530 - *((uint64_t *)b + 6) = pt_add(cmd, p+6, dx, dy);
19531 - *((uint64_t *)b + 7) = pt_add(cmd, p+7, dx, dy);
19532 - b += 16;
19533 - n_this_time -= 8;
19534 - p += 8;
19535 - }
19536 - if (n_this_time & 4) {
19537 - *((uint64_t *)b + 0) = pt_add(cmd, p+0, dx, dy);
19538 - *((uint64_t *)b + 1) = pt_add(cmd, p+1, dx, dy);
19539 - *((uint64_t *)b + 2) = pt_add(cmd, p+2, dx, dy);
19540 - *((uint64_t *)b + 3) = pt_add(cmd, p+3, dx, dy);
19541 - b += 8;
19542 - p += 8;
19543 - }
19544 - if (n_this_time & 2) {
19545 - *((uint64_t *)b + 0) = pt_add(cmd, p+0, dx, dy);
19546 - *((uint64_t *)b + 1) = pt_add(cmd, p+1, dx, dy);
19547 - b += 4;
19548 - p += 2;
19549 - }
19550 - if (n_this_time & 1)
19551 - *((uint64_t *)b + 0) = pt_add(cmd, p++, dx, dy);
19552 + do {
19553 + *(uint64_t *)b = pt_add(cmd, p++, dx, dy);
19554 + b += 2;
19555 + } while (--n_this_time);
19558 if (!n)
19559 @@ -3414,6 +3437,7 @@ static bool sna_blt_fill_box(struct sna *sna, uint8_t alu,
19561 _kgem_set_mode(kgem, KGEM_BLT);
19563 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
19565 assert(kgem_check_batch(kgem, 6));
19566 assert(kgem_check_reloc(kgem, 1));
19567 @@ -3520,6 +3544,8 @@ bool sna_blt_fill_boxes(struct sna *sna, uint8_t alu,
19568 _kgem_set_mode(kgem, KGEM_BLT);
19571 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
19573 assert(sna->kgem.mode == KGEM_BLT);
19574 b = kgem->batch + kgem->nbatch;
19575 if (kgem->gen >= 0100) {
19576 @@ -3608,6 +3634,7 @@ bool sna_blt_fill_boxes(struct sna *sna, uint8_t alu,
19578 _kgem_submit(kgem);
19579 _kgem_set_mode(kgem, KGEM_BLT);
19580 + kgem_bcs_set_tiling(&sna->kgem, NULL, bo);
19582 assert(sna->kgem.mode == KGEM_BLT);
19583 b = kgem->batch + kgem->nbatch;
19584 @@ -3754,6 +3781,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
19586 _kgem_set_mode(kgem, KGEM_BLT);
19588 + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
19590 if ((dst_dx | dst_dy) == 0) {
19591 if (kgem->gen >= 0100) {
19592 @@ -3814,6 +3842,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
19594 _kgem_submit(kgem);
19595 _kgem_set_mode(kgem, KGEM_BLT);
19596 + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
19597 } while (1);
19598 } else {
19599 uint64_t hdr = (uint64_t)br13 << 32 | cmd | 6;
19600 @@ -3871,6 +3900,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
19602 _kgem_submit(kgem);
19603 _kgem_set_mode(kgem, KGEM_BLT);
19604 + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
19605 } while (1);
19607 } else {
19608 @@ -3932,6 +3962,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
19610 _kgem_submit(kgem);
19611 _kgem_set_mode(kgem, KGEM_BLT);
19612 + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
19613 } while (1);
19614 } else {
19615 cmd |= 6;
19616 @@ -3989,6 +4020,7 @@ bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
19618 _kgem_submit(kgem);
19619 _kgem_set_mode(kgem, KGEM_BLT);
19620 + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
19621 } while (1);
19624 @@ -4095,6 +4127,7 @@ bool sna_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu,
19625 !kgem_check_reloc(kgem, 2)) {
19626 _kgem_submit(kgem);
19627 _kgem_set_mode(kgem, KGEM_BLT);
19628 + kgem_bcs_set_tiling(&sna->kgem, src_bo, dst_bo);
19631 assert(sna->kgem.mode == KGEM_BLT);
19632 @@ -4190,6 +4223,7 @@ bool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu,
19633 DBG(("%s: dst == src\n", __FUNCTION__));
19635 if (src_bo->tiling == I915_TILING_Y &&
19636 + !sna->kgem.can_blt_y &&
19637 kgem_bo_blt_pitch_is_ok(&sna->kgem, src_bo)) {
19638 struct kgem_bo *bo;
19640 @@ -4237,6 +4271,7 @@ bool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu,
19642 } else {
19643 if (src_bo->tiling == I915_TILING_Y &&
19644 + !sna->kgem.can_blt_y &&
19645 kgem_bo_blt_pitch_is_ok(&sna->kgem, src_bo)) {
19646 DBG(("%s: src is y-tiled\n", __FUNCTION__));
19647 if (src->type != DRAWABLE_PIXMAP)
19648 @@ -4251,6 +4286,7 @@ bool sna_blt_copy_boxes_fallback(struct sna *sna, uint8_t alu,
19651 if (dst_bo->tiling == I915_TILING_Y &&
19652 + !sna->kgem.can_blt_y &&
19653 kgem_bo_blt_pitch_is_ok(&sna->kgem, dst_bo)) {
19654 DBG(("%s: dst is y-tiled\n", __FUNCTION__));
19655 if (dst->type != DRAWABLE_PIXMAP)
19656 diff --git a/src/sna/sna_composite.c b/src/sna/sna_composite.c
19657 index f01f020e..1da8c291 100644
19658 --- a/src/sna/sna_composite.c
19659 +++ b/src/sna/sna_composite.c
19660 @@ -452,6 +452,8 @@ static void apply_damage(struct sna_composite_op *op, RegionPtr region)
19661 op->damage = NULL;
19662 } else
19663 sna_damage_add(op->damage, region);
19665 + assert(!op->damage || !DAMAGE_IS_ALL(*op->damage));
19668 static inline bool use_cpu(PixmapPtr pixmap, struct sna_pixmap *priv,
19669 @@ -653,8 +655,9 @@ sna_composite(CARD8 op,
19670 RegionRec region;
19671 int dx, dy;
19673 - DBG(("%s(%d src=%ld+(%d, %d), mask=%ld+(%d, %d), dst=%ld+(%d, %d)+(%d, %d), size=(%d, %d)\n",
19674 - __FUNCTION__, op,
19675 + DBG(("%s(pixmap=%ld, op=%d, src=%ld+(%d, %d), mask=%ld+(%d, %d), dst=%ld+(%d, %d)+(%d, %d), size=(%d, %d)\n",
19676 + __FUNCTION__,
19677 + pixmap->drawable.serialNumber, op,
19678 get_picture_id(src), src_x, src_y,
19679 get_picture_id(mask), mask_x, mask_y,
19680 get_picture_id(dst), dst_x, dst_y,
19681 @@ -673,13 +676,6 @@ sna_composite(CARD8 op,
19682 src = sna->clear;
19685 - if (mask && sna_composite_mask_is_opaque(mask)) {
19686 - DBG(("%s: removing opaque %smask\n",
19687 - __FUNCTION__,
19688 - mask->componentAlpha && PICT_FORMAT_RGB(mask->format) ? "CA " : ""));
19689 - mask = NULL;
19690 - }
19692 if (!sna_compute_composite_region(&region,
19693 src, mask, dst,
19694 src_x, src_y,
19695 @@ -688,6 +684,13 @@ sna_composite(CARD8 op,
19696 width, height))
19697 return;
19699 + if (mask && sna_composite_mask_is_opaque(mask)) {
19700 + DBG(("%s: removing opaque %smask\n",
19701 + __FUNCTION__,
19702 + mask->componentAlpha && PICT_FORMAT_RGB(mask->format) ? "CA " : ""));
19703 + mask = NULL;
19704 + }
19706 if (NO_COMPOSITE)
19707 goto fallback;
19709 @@ -756,6 +759,7 @@ sna_composite(CARD8 op,
19710 DBG(("%s: fallback due unhandled composite op\n", __FUNCTION__));
19711 goto fallback;
19713 + assert(!tmp.damage || !DAMAGE_IS_ALL(*tmp.damage));
19715 if (region.data == NULL)
19716 tmp.box(sna, &tmp, &region.extents);
19717 @@ -797,8 +801,10 @@ sna_composite_rectangles(CARD8 op,
19718 int i, num_boxes;
19719 unsigned hint;
19721 - DBG(("%s(op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n",
19722 - __FUNCTION__, op,
19723 + DBG(("%s(pixmap=%ld, op=%d, %08x x %d [(%d, %d)x(%d, %d) ...])\n",
19724 + __FUNCTION__,
19725 + get_drawable_pixmap(dst->pDrawable)->drawable.serialNumber,
19726 + op,
19727 (color->alpha >> 8 << 24) |
19728 (color->red >> 8 << 16) |
19729 (color->green >> 8 << 8) |
19730 @@ -814,38 +820,40 @@ sna_composite_rectangles(CARD8 op,
19731 return;
19734 - if ((color->red|color->green|color->blue|color->alpha) <= 0x00ff) {
19735 - switch (op) {
19736 - case PictOpOver:
19737 - case PictOpOutReverse:
19738 - case PictOpAdd:
19739 - return;
19740 - case PictOpInReverse:
19741 - case PictOpSrc:
19742 - op = PictOpClear;
19743 - break;
19744 - case PictOpAtopReverse:
19745 - op = PictOpOut;
19746 - break;
19747 - case PictOpXor:
19748 - op = PictOpOverReverse;
19749 - break;
19750 - }
19751 - }
19752 if (color->alpha <= 0x00ff) {
19753 - switch (op) {
19754 - case PictOpOver:
19755 - case PictOpOutReverse:
19756 - return;
19757 - case PictOpInReverse:
19758 - op = PictOpClear;
19759 - break;
19760 - case PictOpAtopReverse:
19761 - op = PictOpOut;
19762 - break;
19763 - case PictOpXor:
19764 - op = PictOpOverReverse;
19765 - break;
19766 + if (PICT_FORMAT_TYPE(dst->format) == PICT_TYPE_A ||
19767 + (color->red|color->green|color->blue) <= 0x00ff) {
19768 + switch (op) {
19769 + case PictOpOver:
19770 + case PictOpOutReverse:
19771 + case PictOpAdd:
19772 + return;
19773 + case PictOpInReverse:
19774 + case PictOpSrc:
19775 + op = PictOpClear;
19776 + break;
19777 + case PictOpAtopReverse:
19778 + op = PictOpOut;
19779 + break;
19780 + case PictOpXor:
19781 + op = PictOpOverReverse;
19782 + break;
19783 + }
19784 + } else {
19785 + switch (op) {
19786 + case PictOpOver:
19787 + case PictOpOutReverse:
19788 + return;
19789 + case PictOpInReverse:
19790 + op = PictOpClear;
19791 + break;
19792 + case PictOpAtopReverse:
19793 + op = PictOpOut;
19794 + break;
19795 + case PictOpXor:
19796 + op = PictOpOverReverse;
19797 + break;
19798 + }
19800 } else if (color->alpha >= 0xff00) {
19801 switch (op) {
19802 @@ -863,11 +871,16 @@ sna_composite_rectangles(CARD8 op,
19803 case PictOpXor:
19804 op = PictOpOut;
19805 break;
19806 + case PictOpAdd:
19807 + if (PICT_FORMAT_TYPE(dst->format) == PICT_TYPE_A ||
19808 + (color->red&color->green&color->blue) >= 0xff00)
19809 + op = PictOpSrc;
19810 + break;
19814 /* Avoid reducing overlapping translucent rectangles */
19815 - if (op == PictOpOver &&
19816 + if ((op == PictOpOver || op == PictOpAdd) &&
19817 num_rects == 1 &&
19818 sna_drawable_is_clear(dst->pDrawable))
19819 op = PictOpSrc;
19820 @@ -979,6 +992,9 @@ sna_composite_rectangles(CARD8 op,
19821 bool ok;
19823 if (op == PictOpClear) {
19824 + if (priv->clear_color == 0)
19825 + goto done;
19827 ok = sna_get_pixel_from_rgba(&pixel,
19828 0, 0, 0, 0,
19829 dst->format);
19830 @@ -990,8 +1006,11 @@ sna_composite_rectangles(CARD8 op,
19831 color->alpha,
19832 dst->format);
19834 - if (ok && priv->clear_color == pixel)
19835 + if (ok && priv->clear_color == pixel) {
19836 + DBG(("%s: matches current clear, skipping\n",
19837 + __FUNCTION__));
19838 goto done;
19839 + }
19842 if (region.data == NULL) {
19843 diff --git a/src/sna/sna_damage.h b/src/sna/sna_damage.h
19844 index 272e83bc..d5c727ee 100644
19845 --- a/src/sna/sna_damage.h
19846 +++ b/src/sna/sna_damage.h
19847 @@ -267,7 +267,7 @@ int _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes);
19848 static inline int
19849 sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes)
19851 - assert(damage);
19852 + assert(DAMAGE_PTR(damage));
19854 if (DAMAGE_IS_ALL(damage)) {
19855 *boxes = &DAMAGE_PTR(damage)->extents;
19856 @@ -322,7 +322,8 @@ static inline void sna_damage_destroy(struct sna_damage **damage)
19857 if (*damage == NULL)
19858 return;
19860 - __sna_damage_destroy(DAMAGE_PTR(*damage));
19861 + if (DAMAGE_PTR(*damage))
19862 + __sna_damage_destroy(DAMAGE_PTR(*damage));
19863 *damage = NULL;
19866 diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
19867 index 4b218b70..9b77550e 100644
19868 --- a/src/sna/sna_display.c
19869 +++ b/src/sna/sna_display.c
19870 @@ -39,6 +39,25 @@
19871 #include <errno.h>
19872 #include <poll.h>
19873 #include <ctype.h>
19874 +#include <dirent.h>
19876 +#if HAVE_ALLOCA_H
19877 +#include <alloca.h>
19878 +#elif defined __GNUC__
19879 +#define alloca __builtin_alloca
19880 +#elif defined _AIX
19881 +#define alloca __alloca
19882 +#elif defined _MSC_VER
19883 +#include <malloc.h>
19884 +#define alloca _alloca
19885 +#else
19886 +void *alloca(size_t);
19887 +#endif
19889 +#define _PARSE_EDID_
19890 +/* Jump through a few hoops in order to fixup EDIDs */
19891 +#undef VERSION
19892 +#undef REVISION
19894 #include "sna.h"
19895 #include "sna_reg.h"
19896 @@ -72,6 +91,10 @@
19897 #include <memcheck.h>
19898 #endif
19900 +#define FAIL_CURSOR_IOCTL 0
19902 +#define COLDPLUG_DELAY_MS 2000
19904 /* Minor discrepancy between 32-bit/64-bit ABI in old kernels */
19905 union compat_mode_get_connector{
19906 struct drm_mode_get_connector conn;
19907 @@ -88,6 +111,8 @@ union compat_mode_get_connector{
19908 #define DEFAULT_DPI 96
19909 #endif
19911 +#define OUTPUT_STATUS_CACHE_MS 15000
19913 #define DRM_MODE_PAGE_FLIP_ASYNC 0x02
19915 #define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2
19916 @@ -106,33 +131,87 @@ struct local_mode_obj_get_properties {
19917 };
19918 #define LOCAL_MODE_OBJECT_PLANE 0xeeeeeeee
19920 -#if 0
19921 +struct local_mode_set_plane {
19922 + uint32_t plane_id;
19923 + uint32_t crtc_id;
19924 + uint32_t fb_id; /* fb object contains surface format type */
19925 + uint32_t flags;
19927 + /* Signed dest location allows it to be partially off screen */
19928 + int32_t crtc_x, crtc_y;
19929 + uint32_t crtc_w, crtc_h;
19931 + /* Source values are 16.16 fixed point */
19932 + uint32_t src_x, src_y;
19933 + uint32_t src_h, src_w;
19934 +};
19935 +#define LOCAL_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct local_mode_set_plane)
19937 +struct local_mode_get_plane {
19938 + uint32_t plane_id;
19940 + uint32_t crtc_id;
19941 + uint32_t fb_id;
19943 + uint32_t possible_crtcs;
19944 + uint32_t gamma_size;
19946 + uint32_t count_format_types;
19947 + uint64_t format_type_ptr;
19948 +};
19949 +#define LOCAL_IOCTL_MODE_GETPLANE DRM_IOWR(0xb6, struct local_mode_get_plane)
19951 +struct local_mode_get_plane_res {
19952 + uint64_t plane_id_ptr;
19953 + uint64_t count_planes;
19954 +};
19955 +#define LOCAL_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xb5, struct local_mode_get_plane_res)
19957 +#if 1
19958 #define __DBG DBG
19959 #else
19960 #define __DBG(x)
19961 #endif
19963 +#define DBG_NATIVE_ROTATION ~0 /* minimum RR_Rotate_0 */
19965 extern XF86ConfigPtr xf86configptr;
19967 +struct sna_cursor {
19968 + struct sna_cursor *next;
19969 + uint32_t *image;
19970 + bool transformed;
19971 + Rotation rotation;
19972 + int ref;
19973 + int size;
19974 + int last_width;
19975 + int last_height;
19976 + unsigned handle;
19977 + unsigned serial;
19978 + unsigned alloc;
19979 +};
19981 struct sna_crtc {
19982 + unsigned long flags;
19983 + uint32_t id;
19984 xf86CrtcPtr base;
19985 struct drm_mode_modeinfo kmode;
19986 - int dpms_mode;
19987 PixmapPtr slave_pixmap;
19988 DamagePtr slave_damage;
19989 - struct kgem_bo *bo, *shadow_bo, *client_bo;
19990 + struct kgem_bo *bo, *shadow_bo, *client_bo, *cache_bo;
19991 struct sna_cursor *cursor;
19992 unsigned int last_cursor_size;
19993 uint32_t offset;
19994 bool shadow;
19995 bool fallback_shadow;
19996 bool transform;
19997 + bool cursor_transform;
19998 + bool hwcursor;
19999 bool flip_pending;
20000 - uint8_t id;
20001 - uint8_t pipe;
20003 - RegionRec client_damage; /* XXX overlap with shadow damage? */
20004 + struct pict_f_transform cursor_to_fb, fb_to_cursor;
20006 + RegionRec crtc_damage;
20007 uint16_t shadow_bo_width, shadow_bo_height;
20009 uint32_t rotation;
20010 @@ -143,7 +222,9 @@ struct sna_crtc {
20011 uint32_t supported;
20012 uint32_t current;
20013 } rotation;
20014 - } primary, sprite;
20015 + struct list link;
20016 + } primary;
20017 + struct list sprites;
20019 uint32_t mode_serial, flip_serial;
20021 @@ -173,21 +254,33 @@ struct sna_output {
20023 unsigned int is_panel : 1;
20024 unsigned int add_default_modes : 1;
20025 + int connector_type;
20026 + int connector_type_id;
20028 + uint32_t link_status_idx;
20030 uint32_t edid_idx;
20031 uint32_t edid_blob_id;
20032 uint32_t edid_len;
20033 void *edid_raw;
20034 + xf86MonPtr fake_edid_mon;
20035 + void *fake_edid_raw;
20037 bool has_panel_limits;
20038 int panel_hdisplay;
20039 int panel_vdisplay;
20041 uint32_t dpms_id;
20042 - int dpms_mode;
20043 + uint8_t dpms_mode;
20044 struct backlight backlight;
20045 int backlight_active_level;
20047 + uint32_t last_detect;
20048 + uint32_t status;
20049 + unsigned int hotplug_count;
20050 + bool update_properties;
20051 + bool reprobe;
20053 int num_modes;
20054 struct drm_mode_modeinfo *modes;
20056 @@ -218,13 +311,91 @@ enum { /* XXX copied from hw/xfree86/modes/xf86Crtc.c */
20057 OPTION_DEFAULT_MODES,
20058 };
20060 +static void __sna_output_dpms(xf86OutputPtr output, int dpms, int fixup);
20061 static void sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc);
20062 +static bool sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc,
20063 + struct kgem_bo *bo, int x, int y);
20065 static bool is_zaphod(ScrnInfoPtr scrn)
20067 return xf86IsEntityShared(scrn->entityList[0]);
20070 +static bool
20071 +sna_zaphod_match(struct sna *sna, const char *output)
20072 +{
20073 + const char *s, *colon;
20074 + char t[20];
20075 + unsigned int i = 0;
20077 + s = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
20078 + if (s == NULL)
20079 + return false;
20081 + colon = strchr(s, ':');
20082 + if (colon) /* Skip over the ZaphodPipes */
20083 + s = colon + 1;
20085 + do {
20086 + /* match any outputs in a comma list, stopping at whitespace */
20087 + switch (*s) {
20088 + case '\0':
20089 + t[i] = '\0';
20090 + return strcmp(t, output) == 0;
20092 + case ',':
20093 + t[i] ='\0';
20094 + if (strcmp(t, output) == 0)
20095 + return TRUE;
20096 + i = 0;
20097 + break;
20099 + case ' ':
20100 + case '\t':
20101 + case '\n':
20102 + case '\r':
20103 + break;
20105 + default:
20106 + t[i++] = *s;
20107 + break;
20108 + }
20110 + s++;
20111 + } while (i < sizeof(t));
20113 + return false;
20114 +}
20116 +static unsigned
20117 +get_zaphod_crtcs(struct sna *sna)
20118 +{
20119 + const char *str, *colon;
20120 + unsigned crtcs = 0;
20122 + str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
20123 + if (str == NULL || (colon = strchr(str, ':')) == NULL) {
20124 + DBG(("%s: no zaphod pipes, using screen number: %x\n",
20125 + __FUNCTION__,
20126 + sna->scrn->confScreen->device->screen));
20127 + return 1 << sna->scrn->confScreen->device->screen;
20128 + }
20130 + DBG(("%s: ZaphodHeads='%s'\n", __FUNCTION__, str));
20131 + while (str < colon) {
20132 + char *end;
20133 + unsigned crtc = strtoul(str, &end, 0);
20134 + if (end == str)
20135 + break;
20136 + DBG(("%s: adding CRTC %d to zaphod pipes\n",
20137 + __FUNCTION__, crtc));
20138 + crtcs |= 1 << crtc;
20139 + str = end + 1;
20140 + }
20141 + DBG(("%s: ZaphodPipes=%x\n", __FUNCTION__, crtcs));
20142 + return crtcs;
20143 +}
20145 inline static unsigned count_to_mask(int x)
20147 return (1 << x) - 1;
20148 @@ -247,6 +418,21 @@ static inline struct sna_crtc *to_sna_crtc(xf86CrtcPtr crtc)
20149 return crtc->driver_private;
20152 +static inline unsigned __sna_crtc_pipe(struct sna_crtc *crtc)
20153 +{
20154 + return crtc->flags >> 8 & 0xff;
20155 +}
20157 +static inline unsigned __sna_crtc_id(struct sna_crtc *crtc)
20158 +{
20159 + return crtc->id;
20160 +}
20162 +uint32_t sna_crtc_id(xf86CrtcPtr crtc)
20163 +{
20164 + return __sna_crtc_id(to_sna_crtc(crtc));
20165 +}
20167 static inline bool event_pending(int fd)
20169 struct pollfd pfd;
20170 @@ -268,29 +454,37 @@ static inline uint32_t fb_id(struct kgem_bo *bo)
20171 return bo->delta;
20174 -uint32_t sna_crtc_id(xf86CrtcPtr crtc)
20175 +unsigned sna_crtc_count_sprites(xf86CrtcPtr crtc)
20177 - if (to_sna_crtc(crtc) == NULL)
20178 - return 0;
20179 - return to_sna_crtc(crtc)->id;
20180 -}
20181 + struct plane *sprite;
20182 + unsigned count;
20184 -int sna_crtc_to_pipe(xf86CrtcPtr crtc)
20185 -{
20186 - assert(to_sna_crtc(crtc));
20187 - return to_sna_crtc(crtc)->pipe;
20188 + count = 0;
20189 + list_for_each_entry(sprite, &to_sna_crtc(crtc)->sprites, link)
20190 + count++;
20192 + return count;
20195 -uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc)
20196 +static struct plane *lookup_sprite(struct sna_crtc *crtc, unsigned idx)
20198 - assert(to_sna_crtc(crtc));
20199 - return to_sna_crtc(crtc)->sprite.id;
20200 + struct plane *sprite;
20202 + list_for_each_entry(sprite, &crtc->sprites, link)
20203 + if (idx-- == 0)
20204 + return sprite;
20206 + return NULL;
20209 -bool sna_crtc_is_on(xf86CrtcPtr crtc)
20210 +uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc, unsigned idx)
20212 + struct plane *sprite;
20214 assert(to_sna_crtc(crtc));
20215 - return to_sna_crtc(crtc)->bo != NULL;
20217 + sprite = lookup_sprite(to_sna_crtc(crtc), idx);
20218 + return sprite ? sprite->id : 0;
20221 bool sna_crtc_is_transformed(xf86CrtcPtr crtc)
20222 @@ -299,34 +493,48 @@ bool sna_crtc_is_transformed(xf86CrtcPtr crtc)
20223 return to_sna_crtc(crtc)->transform;
20226 -static inline uint64_t msc64(struct sna_crtc *sna_crtc, uint32_t seq)
20227 +static inline bool msc64(struct sna_crtc *sna_crtc, uint32_t seq, uint64_t *msc)
20229 + bool record = true;
20230 if (seq < sna_crtc->last_seq) {
20231 if (sna_crtc->last_seq - seq > 0x40000000) {
20232 sna_crtc->wrap_seq++;
20233 DBG(("%s: pipe=%d wrapped; was %u, now %u, wraps=%u\n",
20234 - __FUNCTION__, sna_crtc->pipe,
20235 + __FUNCTION__, __sna_crtc_pipe(sna_crtc),
20236 sna_crtc->last_seq, seq, sna_crtc->wrap_seq));
20237 - } else {
20238 - ERR(("%s: pipe=%d msc went backwards; was %u, now %u\n",
20239 - __FUNCTION__, sna_crtc->pipe, sna_crtc->last_seq, seq));
20240 - seq = sna_crtc->last_seq;
20241 + } else {
20242 + DBG(("%s: pipe=%d msc went backwards; was %u, now %u; ignoring for last_swap\n",
20243 + __FUNCTION__, __sna_crtc_pipe(sna_crtc), sna_crtc->last_seq, seq));
20245 + record = false;
20248 - sna_crtc->last_seq = seq;
20249 - return (uint64_t)sna_crtc->wrap_seq << 32 | seq;
20250 + *msc = (uint64_t)sna_crtc->wrap_seq << 32 | seq;
20251 + return record;
20254 uint64_t sna_crtc_record_swap(xf86CrtcPtr crtc,
20255 int tv_sec, int tv_usec, unsigned seq)
20257 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
20258 + uint64_t msc;
20260 assert(sna_crtc);
20261 - DBG(("%s: recording last swap on pipe=%d, frame %d, time %d.%06d\n",
20262 - __FUNCTION__, sna_crtc->pipe, seq, tv_sec, tv_usec));
20263 - sna_crtc->swap.tv_sec = tv_sec;
20264 - sna_crtc->swap.tv_usec = tv_usec;
20265 - return sna_crtc->swap.msc = msc64(sna_crtc, seq);
20267 + if (msc64(sna_crtc, seq, &msc)) {
20268 + DBG(("%s: recording last swap on pipe=%d, frame %d [msc=%08lld], time %d.%06d\n",
20269 + __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc,
20270 + tv_sec, tv_usec));
20271 + sna_crtc->swap.tv_sec = tv_sec;
20272 + sna_crtc->swap.tv_usec = tv_usec;
20273 + sna_crtc->swap.msc = msc;
20274 + } else {
20275 + DBG(("%s: swap event on pipe=%d, frame %d [msc=%08lld], time %d.%06d\n",
20276 + __FUNCTION__, __sna_crtc_pipe(sna_crtc), seq, (long long)msc,
20277 + tv_sec, tv_usec));
20278 + }
20280 + return msc;
20283 const struct ust_msc *sna_crtc_last_swap(xf86CrtcPtr crtc)
20284 @@ -342,15 +550,6 @@ const struct ust_msc *sna_crtc_last_swap(xf86CrtcPtr crtc)
20288 -xf86CrtcPtr sna_mode_first_crtc(struct sna *sna)
20289 -{
20290 - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
20291 - if (sna->mode.num_real_crtc)
20292 - return config->crtc[0];
20293 - else
20294 - return NULL;
20295 -}
20297 #ifndef NDEBUG
20298 static void gem_close(int fd, uint32_t handle);
20299 static void assert_scanout(struct kgem *kgem, struct kgem_bo *bo,
20300 @@ -372,12 +571,24 @@ static void assert_scanout(struct kgem *kgem, struct kgem_bo *bo,
20301 #define assert_scanout(k, b, w, h)
20302 #endif
20304 +static void assert_crtc_fb(struct sna *sna, struct sna_crtc *crtc)
20305 +{
20306 +#ifndef NDEBUG
20307 + struct drm_mode_crtc mode = { .crtc_id = __sna_crtc_id(crtc) };
20308 + drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode);
20309 + assert(mode.fb_id == fb_id(crtc->bo));
20310 +#endif
20311 +}
20313 static unsigned get_fb(struct sna *sna, struct kgem_bo *bo,
20314 int width, int height)
20316 ScrnInfoPtr scrn = sna->scrn;
20317 struct drm_mode_fb_cmd arg;
20319 + if (!kgem_bo_is_fenced(&sna->kgem, bo))
20320 + return 0;
20322 assert(bo->refcnt);
20323 assert(bo->proxy == NULL);
20324 assert(!bo->snoop);
20325 @@ -393,8 +604,9 @@ static unsigned get_fb(struct sna *sna, struct kgem_bo *bo,
20326 DBG(("%s: create fb %dx%d@%d/%d\n",
20327 __FUNCTION__, width, height, scrn->depth, scrn->bitsPerPixel));
20329 - assert(bo->tiling != I915_TILING_Y);
20330 + assert(bo->tiling != I915_TILING_Y || sna->kgem.can_scanout_y);
20331 assert((bo->pitch & 63) == 0);
20332 + assert(scrn->vtSema); /* must be master */
20334 VG_CLEAR(arg);
20335 arg.width = width;
20336 @@ -404,21 +616,83 @@ static unsigned get_fb(struct sna *sna, struct kgem_bo *bo,
20337 arg.depth = scrn->depth;
20338 arg.handle = bo->handle;
20340 - assert(sna->scrn->vtSema); /* must be master */
20341 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_ADDFB, &arg)) {
20342 - xf86DrvMsg(scrn->scrnIndex, X_ERROR,
20343 - "%s: failed to add fb: %dx%d depth=%d, bpp=%d, pitch=%d: %d\n",
20344 - __FUNCTION__, width, height,
20345 - scrn->depth, scrn->bitsPerPixel, bo->pitch, errno);
20346 - return 0;
20347 + /* Try again with the fancy version */
20348 + struct local_mode_fb_cmd2 {
20349 + uint32_t fb_id;
20350 + uint32_t width, height;
20351 + uint32_t pixel_format;
20352 + uint32_t flags;
20354 + uint32_t handles[4];
20355 + uint32_t pitches[4]; /* pitch for each plane */
20356 + uint32_t offsets[4]; /* offset of each plane */
20357 + uint64_t modifiers[4];
20358 + } f;
20359 +#define LOCAL_IOCTL_MODE_ADDFB2 DRM_IOWR(0xb8, struct local_mode_fb_cmd2)
20360 + memset(&f, 0, sizeof(f));
20361 + f.width = width;
20362 + f.height = height;
20363 + /* XXX interlaced */
20364 + f.flags = 1 << 1; /* +modifiers */
20365 + f.handles[0] = bo->handle;
20366 + f.pitches[0] = bo->pitch;
20368 + switch (bo->tiling) {
20369 + case I915_TILING_NONE:
20370 + break;
20371 + case I915_TILING_X:
20372 + /* I915_FORMAT_MOD_X_TILED */
20373 + f.modifiers[0] = (uint64_t)1 << 56 | 1;
20374 + break;
20375 + case I915_TILING_Y:
20376 + /* I915_FORMAT_MOD_X_TILED */
20377 + f.modifiers[0] = (uint64_t)1 << 56 | 2;
20378 + break;
20379 + }
20381 +#define fourcc(a,b,c,d) ((a) | (b) << 8 | (c) << 16 | (d) << 24)
20382 + switch (scrn->depth) {
20383 + default:
20384 + ERR(("%s: unhandled screen format, depth=%d\n",
20385 + __FUNCTION__, scrn->depth));
20386 + goto fail;
20387 + case 8:
20388 + f.pixel_format = fourcc('C', '8', ' ', ' ');
20389 + break;
20390 + case 15:
20391 + f.pixel_format = fourcc('X', 'R', '1', '5');
20392 + break;
20393 + case 16:
20394 + f.pixel_format = fourcc('R', 'G', '1', '6');
20395 + break;
20396 + case 24:
20397 + f.pixel_format = fourcc('X', 'R', '2', '4');
20398 + break;
20399 + case 30:
20400 + f.pixel_format = fourcc('X', 'R', '3', '0');
20401 + break;
20402 + }
20403 +#undef fourcc
20405 + if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_ADDFB2, &f)) {
20406 +fail:
20407 + xf86DrvMsg(scrn->scrnIndex, X_ERROR,
20408 + "%s: failed to add fb: %dx%d depth=%d, bpp=%d, pitch=%d: %d\n",
20409 + __FUNCTION__, width, height,
20410 + scrn->depth, scrn->bitsPerPixel, bo->pitch, errno);
20411 + return 0;
20412 + }
20414 + arg.fb_id = f.fb_id;
20416 assert(arg.fb_id != 0);
20418 + bo->delta = arg.fb_id;
20419 DBG(("%s: attached fb=%d to handle=%d\n",
20420 - __FUNCTION__, arg.fb_id, arg.handle));
20421 + __FUNCTION__, bo->delta, arg.handle));
20423 bo->scanout = true;
20424 - return bo->delta = arg.fb_id;
20425 + return bo->delta;
20428 static uint32_t gem_create(int fd, int size)
20429 @@ -438,6 +712,7 @@ static uint32_t gem_create(int fd, int size)
20430 static void *gem_mmap(int fd, int handle, int size)
20432 struct drm_i915_gem_mmap_gtt mmap_arg;
20433 + struct drm_i915_gem_set_domain set_domain;
20434 void *ptr;
20436 VG_CLEAR(mmap_arg);
20437 @@ -449,6 +724,15 @@ static void *gem_mmap(int fd, int handle, int size)
20438 if (ptr == MAP_FAILED)
20439 return NULL;
20441 + VG_CLEAR(set_domain);
20442 + set_domain.handle = handle;
20443 + set_domain.read_domains = I915_GEM_DOMAIN_GTT;
20444 + set_domain.write_domain = I915_GEM_DOMAIN_GTT;
20445 + if (drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain)) {
20446 + munmap(ptr, size);
20447 + return NULL;
20448 + }
20450 return ptr;
20453 @@ -497,8 +781,6 @@ sna_backlight_uevent(int fd, void *closure)
20454 if (sna_output->dpms_mode != DPMSModeOn)
20455 continue;
20457 - assert(output->randr_output);
20459 val = backlight_get(&sna_output->backlight);
20460 if (val < 0)
20461 continue;
20462 @@ -523,6 +805,7 @@ sna_backlight_uevent(int fd, void *closure)
20463 TRUE, FALSE);
20466 + DBG(("%s: complete\n", __FUNCTION__));
20469 static void sna_backlight_pre_init(struct sna *sna)
20470 @@ -570,6 +853,7 @@ static void sna_backlight_drain_uevents(struct sna *sna)
20471 if (sna->mode.backlight_monitor == NULL)
20472 return;
20474 + DBG(("%s()\n", __FUNCTION__));
20475 sna_backlight_uevent(udev_monitor_get_fd(sna->mode.backlight_monitor),
20476 sna);
20478 @@ -632,9 +916,22 @@ sna_output_backlight_set(struct sna_output *sna_output, int level)
20479 return ret;
20482 +static bool
20483 +has_native_backlight(struct sna_output *sna_output)
20484 +{
20485 + return sna_output->backlight.type == BL_RAW;
20486 +}
20488 static void
20489 sna_output_backlight_off(struct sna_output *sna_output)
20491 + /* Trust the kernel to turn the native backlight off. However, we
20492 + * do explicitly turn the backlight back on (when we wake the output)
20493 + * just in case a third party turns it off!
20494 + */
20495 + if (has_native_backlight(sna_output))
20496 + return;
20498 DBG(("%s(%s)\n", __FUNCTION__, sna_output->base->name));
20499 backlight_off(&sna_output->backlight);
20500 sna_output_backlight_set(sna_output, 0);
20501 @@ -674,7 +971,7 @@ has_user_backlight_override(xf86OutputPtr output)
20502 if (*str == '\0')
20503 return (char *)str;
20505 - if (backlight_exists(str) == BL_NONE) {
20506 + if (!backlight_exists(str)) {
20507 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
20508 "Unrecognised backlight control interface '%s'\n",
20509 str);
20510 @@ -684,6 +981,93 @@ has_user_backlight_override(xf86OutputPtr output)
20511 return strdup(str);
20514 +static int get_device_minor(int fd)
20515 +{
20516 + struct stat st;
20518 + if (fstat(fd, &st) || !S_ISCHR(st.st_mode))
20519 + return -1;
20521 + return st.st_rdev & 0x63;
20522 +}
20524 +static const char * const sysfs_connector_types[] = {
20525 + /* DRM_MODE_CONNECTOR_Unknown */ "Unknown",
20526 + /* DRM_MODE_CONNECTOR_VGA */ "VGA",
20527 + /* DRM_MODE_CONNECTOR_DVII */ "DVI-I",
20528 + /* DRM_MODE_CONNECTOR_DVID */ "DVI-D",
20529 + /* DRM_MODE_CONNECTOR_DVIA */ "DVI-A",
20530 + /* DRM_MODE_CONNECTOR_Composite */ "Composite",
20531 + /* DRM_MODE_CONNECTOR_SVIDEO */ "SVIDEO",
20532 + /* DRM_MODE_CONNECTOR_LVDS */ "LVDS",
20533 + /* DRM_MODE_CONNECTOR_Component */ "Component",
20534 + /* DRM_MODE_CONNECTOR_9PinDIN */ "DIN",
20535 + /* DRM_MODE_CONNECTOR_DisplayPort */ "DP",
20536 + /* DRM_MODE_CONNECTOR_HDMIA */ "HDMI-A",
20537 + /* DRM_MODE_CONNECTOR_HDMIB */ "HDMI-B",
20538 + /* DRM_MODE_CONNECTOR_TV */ "TV",
20539 + /* DRM_MODE_CONNECTOR_eDP */ "eDP",
20540 + /* DRM_MODE_CONNECTOR_VIRTUAL */ "Virtual",
20541 + /* DRM_MODE_CONNECTOR_DSI */ "DSI",
20542 + /* DRM_MODE_CONNECTOR_DPI */ "DPI"
20543 +};
20545 +static char *has_connector_backlight(xf86OutputPtr output)
20546 +{
20547 + struct sna_output *sna_output = output->driver_private;
20548 + struct sna *sna = to_sna(output->scrn);
20549 + char path[1024];
20550 + DIR *dir;
20551 + struct dirent *de;
20552 + int minor, len;
20553 + char *str = NULL;
20555 + if (sna_output->connector_type >= ARRAY_SIZE(sysfs_connector_types))
20556 + return NULL;
20558 + minor = get_device_minor(sna->kgem.fd);
20559 + if (minor < 0)
20560 + return NULL;
20562 + len = snprintf(path, sizeof(path),
20563 + "/sys/class/drm/card%d-%s-%d",
20564 + minor,
20565 + sysfs_connector_types[sna_output->connector_type],
20566 + sna_output->connector_type_id);
20567 + DBG(("%s: lookup %s\n", __FUNCTION__, path));
20569 + dir = opendir(path);
20570 + if (dir == NULL)
20571 + return NULL;
20573 + while ((de = readdir(dir))) {
20574 + struct stat st;
20576 + if (*de->d_name == '.')
20577 + continue;
20579 + snprintf(path + len, sizeof(path) - len,
20580 + "/%s", de->d_name);
20582 + if (stat(path, &st))
20583 + continue;
20585 + if (!S_ISDIR(st.st_mode))
20586 + continue;
20588 + DBG(("%s: testing %s as backlight\n",
20589 + __FUNCTION__, de->d_name));
20591 + if (backlight_exists(de->d_name)) {
20592 + str = strdup(de->d_name); /* leak! */
20593 + break;
20594 + }
20595 + }
20597 + closedir(dir);
20598 + return str;
20599 +}
20601 static void
20602 sna_output_backlight_init(xf86OutputPtr output)
20604 @@ -696,11 +1080,20 @@ sna_output_backlight_init(xf86OutputPtr output)
20605 return;
20606 #endif
20608 - from = X_CONFIG;
20609 - best_iface = has_user_backlight_override(output);
20610 + if (sna_output->is_panel) {
20611 + from = X_CONFIG;
20612 + best_iface = has_user_backlight_override(output);
20613 + if (best_iface)
20614 + goto done;
20615 + }
20617 + best_iface = has_connector_backlight(output);
20618 if (best_iface)
20619 goto done;
20621 + if (!sna_output->is_panel)
20622 + return;
20624 /* XXX detect right backlight for multi-GPU/panels */
20625 from = X_PROBED;
20626 pci = xf86GetPciInfoForEntity(to_sna(output->scrn)->pEnt->index);
20627 @@ -728,6 +1121,38 @@ done:
20628 sna_output->backlight.iface, best_iface, output->name);
20631 +#if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(22, 0)
20632 +static inline int sigio_block(void)
20633 +{
20634 + return 0;
20635 +}
20636 +static inline void sigio_unblock(int was_blocked)
20637 +{
20638 + (void)was_blocked;
20639 +}
20640 +#elif XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
20641 +static inline int sigio_block(void)
20642 +{
20643 + OsBlockSIGIO();
20644 + return 0;
20645 +}
20646 +static inline void sigio_unblock(int was_blocked)
20647 +{
20648 + OsReleaseSIGIO();
20649 + (void)was_blocked;
20650 +}
20651 +#else
20652 +#include <xf86_OSproc.h>
20653 +static inline int sigio_block(void)
20654 +{
20655 + return xf86BlockSIGIO();
20656 +}
20657 +static inline void sigio_unblock(int was_blocked)
20658 +{
20659 + xf86UnblockSIGIO(was_blocked);
20660 +}
20661 +#endif
20663 static char *canonical_kmode_name(const struct drm_mode_modeinfo *kmode)
20665 char tmp[32], *buf;
20666 @@ -781,6 +1206,7 @@ mode_from_kmode(ScrnInfoPtr scrn,
20667 mode->VTotal = kmode->vtotal;
20668 mode->VScan = kmode->vscan;
20670 + mode->VRefresh = kmode->vrefresh;
20671 mode->Flags = kmode->flags;
20672 mode->name = get_kmode_name(kmode);
20674 @@ -814,6 +1240,7 @@ mode_to_kmode(struct drm_mode_modeinfo *kmode, DisplayModePtr mode)
20675 kmode->vtotal = mode->VTotal;
20676 kmode->vscan = mode->VScan;
20678 + kmode->vrefresh = mode->VRefresh;
20679 kmode->flags = mode->Flags;
20680 if (mode->name)
20681 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
20682 @@ -824,11 +1251,12 @@ static void
20683 sna_crtc_force_outputs_on(xf86CrtcPtr crtc)
20685 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
20686 + /* All attached outputs are valid, so update our timestamps */
20687 + unsigned now = GetTimeInMillis();
20688 int i;
20690 assert(to_sna_crtc(crtc));
20691 - DBG(("%s(pipe=%d), currently? %d\n", __FUNCTION__,
20692 - to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->dpms_mode));
20693 + DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc)));
20695 /* DPMS handling by the kernel is inconsistent, so after setting a
20696 * mode on an output presume that we intend for it to be on, or that
20697 @@ -843,10 +1271,11 @@ sna_crtc_force_outputs_on(xf86CrtcPtr crtc)
20698 if (output->crtc != crtc)
20699 continue;
20701 - output->funcs->dpms(output, DPMSModeOn);
20702 + __sna_output_dpms(output, DPMSModeOn, false);
20703 + if (to_sna_output(output)->last_detect)
20704 + to_sna_output(output)->last_detect = now;
20707 - to_sna_crtc(crtc)->dpms_mode = DPMSModeOn;
20708 #if XF86_CRTC_VERSION >= 3
20709 crtc->active = TRUE;
20710 #endif
20711 @@ -859,8 +1288,7 @@ sna_crtc_force_outputs_off(xf86CrtcPtr crtc)
20712 int i;
20714 assert(to_sna_crtc(crtc));
20715 - DBG(("%s(pipe=%d), currently? %d\n", __FUNCTION__,
20716 - to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->dpms_mode));
20717 + DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc)));
20719 /* DPMS handling by the kernel is inconsistent, so after setting a
20720 * mode on an output presume that we intend for it to be on, or that
20721 @@ -875,35 +1303,47 @@ sna_crtc_force_outputs_off(xf86CrtcPtr crtc)
20722 if (output->crtc != crtc)
20723 continue;
20725 - output->funcs->dpms(output, DPMSModeOff);
20726 + __sna_output_dpms(output, DPMSModeOff, false);
20729 - to_sna_crtc(crtc)->dpms_mode = DPMSModeOff;
20732 static unsigned
20733 -rotation_reduce(struct plane *p, unsigned rotation)
20734 +rotation_reflect(unsigned rotation)
20736 - unsigned unsupported_rotations = rotation & ~p->rotation.supported;
20737 + unsigned other_bits;
20739 - if (unsupported_rotations == 0)
20740 - return rotation;
20741 + /* paranoia for future extensions */
20742 + other_bits = rotation & ~RR_Rotate_All;
20744 -#define RR_Reflect_XY (RR_Reflect_X | RR_Reflect_Y)
20745 + /* flip the reflection to compensate for reflecting the rotation */
20746 + other_bits ^= RR_Reflect_X | RR_Reflect_Y;
20748 - if ((unsupported_rotations & RR_Reflect_XY) == RR_Reflect_XY &&
20749 - p->rotation.supported& RR_Rotate_180) {
20750 - rotation &= ~RR_Reflect_XY;
20751 - rotation ^= RR_Rotate_180;
20752 - }
20753 + /* Reflect the screen by rotating the rotation bit,
20754 + * which has to have at least RR_Rotate_0 set. This allows
20755 + * us to reflect any of the rotation bits, not just 0.
20756 + */
20757 + rotation &= RR_Rotate_All;
20758 + assert(rotation);
20759 + rotation <<= 2; /* RR_Rotate_0 -> RR_Rotate_180 etc */
20760 + rotation |= rotation >> 4; /* RR_Rotate_270' to RR_Rotate_90 */
20761 + rotation &= RR_Rotate_All;
20762 + assert(rotation);
20764 - if ((unsupported_rotations & RR_Rotate_180) &&
20765 - (p->rotation.supported& RR_Reflect_XY) == RR_Reflect_XY) {
20766 - rotation ^= RR_Reflect_XY;
20767 - rotation &= ~RR_Rotate_180;
20768 + return rotation | other_bits;
20769 +}
20771 +static unsigned
20772 +rotation_reduce(struct plane *p, unsigned rotation)
20773 +{
20774 + /* If unsupported try exchanging rotation for a reflection */
20775 + if (rotation & ~p->rotation.supported) {
20776 + unsigned new_rotation = rotation_reflect(rotation);
20777 + if ((new_rotation & p->rotation.supported) == new_rotation)
20778 + rotation = new_rotation;
20781 -#undef RR_Reflect_XY
20782 + /* Only one rotation bit should be set */
20783 + assert(is_power_of_two(rotation & RR_Rotate_All));
20785 return rotation;
20787 @@ -923,7 +1363,7 @@ rotation_set(struct sna *sna, struct plane *p, uint32_t desired)
20788 if (desired == p->rotation.current)
20789 return true;
20791 - if ((desired & p->rotation.supported) == 0) {
20792 + if ((desired & p->rotation.supported) != desired) {
20793 errno = EINVAL;
20794 return false;
20796 @@ -956,20 +1396,105 @@ rotation_reset(struct plane *p)
20797 p->rotation.current = 0;
20800 -bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation)
20801 +bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc,
20802 + unsigned idx,
20803 + uint32_t rotation)
20805 + struct plane *sprite;
20806 assert(to_sna_crtc(crtc));
20808 + sprite = lookup_sprite(to_sna_crtc(crtc), idx);
20809 + if (!sprite)
20810 + return false;
20812 DBG(("%s: CRTC:%d [pipe=%d], sprite=%u set-rotation=%x\n",
20813 __FUNCTION__,
20814 - to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->sprite.id,
20815 - rotation));
20816 + sna_crtc_id(crtc), sna_crtc_pipe(crtc),
20817 + sprite->id, rotation));
20819 - return rotation_set(to_sna(crtc->scrn),
20820 - &to_sna_crtc(crtc)->sprite,
20821 - rotation_reduce(&to_sna_crtc(crtc)->sprite, rotation));
20822 + return rotation_set(to_sna(crtc->scrn), sprite,
20823 + rotation_reduce(sprite, rotation));
20826 -static bool
20827 +#if HAS_DEBUG_FULL
20828 +#if !HAS_DEBUG_FULL
20829 +#define LogF ErrorF
20830 +#endif
20831 +struct kmsg {
20832 + int fd;
20833 + int saved_loglevel;
20834 +};
20836 +static int kmsg_get_debug(void)
20837 +{
20838 + FILE *file;
20839 + int v = -1;
20841 + file = fopen("/sys/module/drm/parameters/debug", "r");
20842 + if (file) {
20843 + fscanf(file, "%d", &v);
20844 + fclose(file);
20845 + }
20847 + return v;
20848 +}
20850 +static void kmsg_set_debug(int v)
20851 +{
20852 + FILE *file;
20854 + file = fopen("/sys/module/drm/parameters/debug", "w");
20855 + if (file) {
20856 + fprintf(file, "%d\n", v);
20857 + fclose(file);
20858 + }
20859 +}
20861 +static void kmsg_open(struct kmsg *k)
20862 +{
20863 + k->saved_loglevel = kmsg_get_debug();
20864 + if (k->saved_loglevel != -1)
20865 + kmsg_set_debug(0xff);
20867 + k->fd = open("/dev/kmsg", O_RDONLY | O_NONBLOCK);
20868 + if (k->fd != -1)
20869 + lseek(k->fd, 0, SEEK_END);
20870 +}
20872 +static void kmsg_close(struct kmsg *k, int dump)
20873 +{
20874 + FILE *file;
20876 + file = NULL;
20877 + if (k->fd != -1 && dump)
20878 + file = fdopen(k->fd, "r");
20879 + if (file) {
20880 + size_t len = 0;
20881 + char *line = NULL;
20883 + while (getline(&line, &len, file) != -1) {
20884 + char *start = strchr(line, ';');
20885 + if (start)
20886 + LogF("KMSG: %s", start + 1);
20887 + }
20889 + free(line);
20890 + fclose(file);
20891 + }
20893 + if (k->fd != -1)
20894 + close(k->fd);
20896 + if (k->saved_loglevel != -1)
20897 + kmsg_set_debug(k->saved_loglevel);
20898 +}
20899 +#else
20900 +struct kmsg { int unused; };
20901 +static void kmsg_open(struct kmsg *k) {}
20902 +static void kmsg_close(struct kmsg *k, int dump) {}
20903 +#endif
20905 +static int
20906 sna_crtc_apply(xf86CrtcPtr crtc)
20908 struct sna *sna = to_sna(crtc->scrn);
20909 @@ -978,26 +1503,39 @@ sna_crtc_apply(xf86CrtcPtr crtc)
20910 struct drm_mode_crtc arg;
20911 uint32_t output_ids[32];
20912 int output_count = 0;
20913 - int i;
20914 + int sigio, i;
20915 + struct kmsg kmsg;
20916 + int ret = EINVAL;
20918 - DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->bo->handle));
20919 + DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__,
20920 + __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
20921 + sna_crtc->bo->handle));
20922 if (!sna_crtc->kmode.clock) {
20923 ERR(("%s(CRTC:%d [pipe=%d]): attempted to set an invalid mode\n",
20924 - __FUNCTION__, sna_crtc->id, sna_crtc->pipe));
20925 - return false;
20926 + __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc)));
20927 + return EINVAL;
20930 + kmsg_open(&kmsg);
20931 + sigio = sigio_block();
20933 assert(sna->mode.num_real_output < ARRAY_SIZE(output_ids));
20934 sna_crtc_disable_cursor(sna, sna_crtc);
20936 if (!rotation_set(sna, &sna_crtc->primary, sna_crtc->rotation)) {
20937 + memset(&arg, 0, sizeof(arg));
20938 + arg.crtc_id = __sna_crtc_id(sna_crtc);
20939 + (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg);
20940 + }
20942 + if (!rotation_set(sna, &sna_crtc->primary, sna_crtc->rotation)) {
20943 ERR(("%s: set-primary-rotation failed (rotation-id=%d, rotation=%d) on CRTC:%d [pipe=%d], errno=%d\n",
20944 - __FUNCTION__, sna_crtc->primary.rotation.prop, sna_crtc->rotation, sna_crtc->id, sna_crtc->pipe, errno));
20945 + __FUNCTION__, sna_crtc->primary.rotation.prop, sna_crtc->rotation, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), errno));
20946 sna_crtc->primary.rotation.supported &= ~sna_crtc->rotation;
20947 - return false;
20948 + goto unblock;
20950 DBG(("%s: CRTC:%d [pipe=%d] primary rotation set to %x\n",
20951 - __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->rotation));
20952 + __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), sna_crtc->rotation));
20954 for (i = 0; i < sna->mode.num_real_output; i++) {
20955 xf86OutputPtr output = config->output[i];
20956 @@ -1008,7 +1546,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
20957 * and we lose track of the user settings.
20958 */
20959 if (output->crtc == NULL)
20960 - output->funcs->dpms(output, DPMSModeOff);
20961 + __sna_output_dpms(output, DPMSModeOff, false);
20963 if (output->crtc != crtc)
20964 continue;
20965 @@ -1022,29 +1560,27 @@ sna_crtc_apply(xf86CrtcPtr crtc)
20967 DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n",
20968 __FUNCTION__, output->name, i, to_connector_id(output),
20969 - sna_crtc->id, sna_crtc->pipe,
20970 + __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
20971 (uint32_t)output->possible_crtcs,
20972 (uint32_t)output->possible_clones));
20974 - assert(output->possible_crtcs & (1 << sna_crtc->pipe) ||
20975 + assert(output->possible_crtcs & (1 << __sna_crtc_pipe(sna_crtc)) ||
20976 is_zaphod(crtc->scrn));
20978 output_ids[output_count] = to_connector_id(output);
20979 if (++output_count == ARRAY_SIZE(output_ids)) {
20980 DBG(("%s: too many outputs (%d) for me!\n",
20981 __FUNCTION__, output_count));
20982 - errno = EINVAL;
20983 - return false;
20984 + goto unblock;
20987 if (output_count == 0) {
20988 DBG(("%s: no outputs\n", __FUNCTION__));
20989 - errno = EINVAL;
20990 - return false;
20991 + goto unblock;
20994 VG_CLEAR(arg);
20995 - arg.crtc_id = sna_crtc->id;
20996 + arg.crtc_id = __sna_crtc_id(sna_crtc);
20997 arg.fb_id = fb_id(sna_crtc->bo);
20998 if (sna_crtc->transform || sna_crtc->slave_pixmap) {
20999 arg.x = 0;
21000 @@ -1061,7 +1597,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
21001 arg.mode_valid = 1;
21003 DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d%s%s update to %d outputs [%d...]\n",
21004 - __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
21005 + __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
21006 arg.mode.hdisplay,
21007 arg.mode.vdisplay,
21008 arg.x, arg.y,
21009 @@ -1071,12 +1607,19 @@ sna_crtc_apply(xf86CrtcPtr crtc)
21010 sna_crtc->transform ? " [transformed]" : "",
21011 output_count, output_count ? output_ids[0] : 0));
21013 - if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg))
21014 - return false;
21015 + ret = 0;
21016 + if (unlikely(drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg))) {
21017 + ret = errno;
21018 + goto unblock;
21019 + }
21021 sna_crtc->mode_serial++;
21022 sna_crtc_force_outputs_on(crtc);
21023 - return true;
21025 +unblock:
21026 + sigio_unblock(sigio);
21027 + kmsg_close(&kmsg, ret);
21028 + return ret;
21031 static bool overlap(const BoxRec *a, const BoxRec *b)
21032 @@ -1094,26 +1637,73 @@ static bool overlap(const BoxRec *a, const BoxRec *b)
21033 return true;
21036 +static void defer_event(struct sna *sna, struct drm_event *base)
21037 +{
21038 + if (sna->mode.shadow_nevent == sna->mode.shadow_size) {
21039 + int size = sna->mode.shadow_size * 2;
21040 + void *ptr;
21042 + ptr = realloc(sna->mode.shadow_events,
21043 + sizeof(struct drm_event_vblank)*size);
21044 + if (!ptr)
21045 + return;
21047 + sna->mode.shadow_events = ptr;
21048 + sna->mode.shadow_size = size;
21049 + }
21051 + memcpy(&sna->mode.shadow_events[sna->mode.shadow_nevent++],
21052 + base, sizeof(struct drm_event_vblank));
21053 + DBG(("%s: deferring event count=%d\n",
21054 + __func__, sna->mode.shadow_nevent));
21055 +}
21057 +static void flush_events(struct sna *sna)
21058 +{
21059 + int n;
21061 + if (!sna->mode.shadow_nevent)
21062 + return;
21064 + DBG(("%s: flushing %d events=%d\n", __func__, sna->mode.shadow_nevent));
21066 + for (n = 0; n < sna->mode.shadow_nevent; n++) {
21067 + struct drm_event_vblank *vb = &sna->mode.shadow_events[n];
21069 + if ((uintptr_t)(vb->user_data) & 2)
21070 + sna_present_vblank_handler(vb);
21071 + else
21072 + sna_dri2_vblank_handler(vb);
21073 + }
21075 + sna->mode.shadow_nevent = 0;
21076 +}
21079 static bool wait_for_shadow(struct sna *sna,
21080 struct sna_pixmap *priv,
21081 unsigned flags)
21083 PixmapPtr pixmap = priv->pixmap;
21084 - DamagePtr damage;
21085 struct kgem_bo *bo, *tmp;
21086 int flip_active;
21087 bool ret = true;
21089 - DBG(("%s: flags=%x, flips=%d, handle=%d, shadow=%d\n",
21090 - __FUNCTION__, flags, sna->mode.flip_active,
21091 + DBG(("%s: enabled? %d waiting? %d, flags=%x, flips=%d, pixmap=%ld [front?=%d], handle=%d, shadow=%d\n",
21092 + __FUNCTION__, sna->mode.shadow_enabled, sna->mode.shadow_wait,
21093 + flags, sna->mode.flip_active,
21094 + pixmap->drawable.serialNumber, pixmap == sna->front,
21095 priv->gpu_bo->handle, sna->mode.shadow->handle));
21097 assert(priv->move_to_gpu_data == sna);
21098 assert(sna->mode.shadow != priv->gpu_bo);
21100 - if (flags == 0 || pixmap != sna->front || !sna->mode.shadow_damage)
21101 + if (flags == 0 || pixmap != sna->front || !sna->mode.shadow_enabled)
21102 goto done;
21104 + assert(sna->mode.shadow_damage);
21105 + assert(!sna->mode.shadow_wait);
21107 if ((flags & MOVE_WRITE) == 0) {
21108 if ((flags & __MOVE_SCANOUT) == 0) {
21109 struct sna_crtc *crtc;
21110 @@ -1154,9 +1744,7 @@ static bool wait_for_shadow(struct sna *sna,
21113 assert(sna->mode.shadow_active);
21115 - damage = sna->mode.shadow_damage;
21116 - sna->mode.shadow_damage = NULL;
21117 + sna->mode.shadow_wait = true;
21119 flip_active = sna->mode.flip_active;
21120 if (flip_active) {
21121 @@ -1208,6 +1796,8 @@ static bool wait_for_shadow(struct sna *sna,
21122 bo = sna->mode.shadow;
21125 + assert(sna->mode.shadow_wait);
21126 + sna->mode.shadow_wait = false;
21128 if (bo->refcnt > 1) {
21129 bo = kgem_create_2d(&sna->kgem,
21130 @@ -1230,8 +1820,6 @@ static bool wait_for_shadow(struct sna *sna,
21131 bo = sna->mode.shadow;
21134 - sna->mode.shadow_damage = damage;
21136 RegionSubtract(&sna->mode.shadow_region,
21137 &sna->mode.shadow_region,
21138 &sna->mode.shadow_cancel);
21139 @@ -1269,6 +1857,7 @@ static bool wait_for_shadow(struct sna *sna,
21140 RegionSubtract(&sna->mode.shadow_region, &sna->mode.shadow_region, &region);
21143 + crtc->client_bo->active_scanout--;
21144 kgem_bo_destroy(&sna->kgem, crtc->client_bo);
21145 crtc->client_bo = NULL;
21146 list_del(&crtc->shadow_link);
21147 @@ -1281,12 +1870,13 @@ static bool wait_for_shadow(struct sna *sna,
21148 sna->mode.shadow_region.extents.y1,
21149 sna->mode.shadow_region.extents.x2,
21150 sna->mode.shadow_region.extents.y2));
21151 - ret = sna->render.copy_boxes(sna, GXcopy,
21152 - &pixmap->drawable, priv->gpu_bo, 0, 0,
21153 - &pixmap->drawable, bo, 0, 0,
21154 - region_rects(&sna->mode.shadow_region),
21155 - region_num_rects(&sna->mode.shadow_region),
21156 - 0);
21157 + if (!sna->render.copy_boxes(sna, GXcopy,
21158 + &pixmap->drawable, priv->gpu_bo, 0, 0,
21159 + &pixmap->drawable, bo, 0, 0,
21160 + region_rects(&sna->mode.shadow_region),
21161 + region_num_rects(&sna->mode.shadow_region),
21162 + 0))
21163 + ERR(("%s: copy failed\n", __FUNCTION__));
21166 if (priv->cow)
21167 @@ -1295,11 +1885,13 @@ static bool wait_for_shadow(struct sna *sna,
21168 sna_pixmap_unmap(pixmap, priv);
21170 DBG(("%s: setting front pixmap to handle=%d\n", __FUNCTION__, bo->handle));
21171 + sna->mode.shadow->active_scanout--;
21172 tmp = priv->gpu_bo;
21173 priv->gpu_bo = bo;
21174 if (bo != sna->mode.shadow)
21175 kgem_bo_destroy(&sna->kgem, sna->mode.shadow);
21176 sna->mode.shadow = tmp;
21177 + sna->mode.shadow->active_scanout++;
21179 sna_dri2_pixmap_update_bo(sna, pixmap, bo);
21181 @@ -1311,6 +1903,9 @@ done:
21182 priv->move_to_gpu_data = NULL;
21183 priv->move_to_gpu = NULL;
21185 + assert(!sna->mode.shadow_wait);
21186 + flush_events(sna);
21188 return ret;
21191 @@ -1358,22 +1953,43 @@ bool sna_pixmap_discard_shadow_damage(struct sna_pixmap *priv,
21192 return RegionNil(&sna->mode.shadow_region);
21195 +static void sna_mode_damage(DamagePtr damage, RegionPtr region, void *closure)
21196 +{
21197 + struct sna *sna = closure;
21199 + if (sna->mode.rr_active)
21200 + return;
21202 + /* Throw away the rectangles if the region grows too big */
21203 + region = DamageRegion(damage);
21204 + if (region->data) {
21205 + RegionRec dup;
21207 + dup = *region;
21208 + RegionUninit(&dup);
21210 + region->data = NULL;
21211 + }
21212 +}
21214 static bool sna_mode_enable_shadow(struct sna *sna)
21216 - ScreenPtr screen = sna->scrn->pScreen;
21217 + ScreenPtr screen = to_screen_from_sna(sna);
21219 DBG(("%s\n", __FUNCTION__));
21220 assert(sna->mode.shadow == NULL);
21221 assert(sna->mode.shadow_damage == NULL);
21222 assert(sna->mode.shadow_active == 0);
21223 + assert(!sna->mode.shadow_enabled);
21225 - sna->mode.shadow_damage = DamageCreate(NULL, NULL,
21226 - DamageReportNone, TRUE,
21227 - screen, screen);
21228 + sna->mode.shadow_damage = DamageCreate(sna_mode_damage, NULL,
21229 + DamageReportRawRegion,
21230 + TRUE, screen, sna);
21231 if (!sna->mode.shadow_damage)
21232 return false;
21234 DamageRegister(&sna->front->drawable, sna->mode.shadow_damage);
21235 + sna->mode.shadow_enabled = true;
21236 return true;
21239 @@ -1381,8 +1997,10 @@ static void sna_mode_disable_shadow(struct sna *sna)
21241 struct sna_pixmap *priv;
21243 - if (!sna->mode.shadow_damage)
21244 + if (!sna->mode.shadow_damage) {
21245 + assert(!sna->mode.shadow_enabled);
21246 return;
21247 + }
21249 DBG(("%s\n", __FUNCTION__));
21251 @@ -1393,8 +2011,10 @@ static void sna_mode_disable_shadow(struct sna *sna)
21252 DamageUnregister(&sna->front->drawable, sna->mode.shadow_damage);
21253 DamageDestroy(sna->mode.shadow_damage);
21254 sna->mode.shadow_damage = NULL;
21255 + sna->mode.shadow_enabled = false;
21257 if (sna->mode.shadow) {
21258 + sna->mode.shadow->active_scanout--;
21259 kgem_bo_destroy(&sna->kgem, sna->mode.shadow);
21260 sna->mode.shadow = NULL;
21262 @@ -1413,7 +2033,7 @@ static void sna_crtc_slave_damage(DamagePtr damage, RegionPtr region, void *clos
21263 __FUNCTION__,
21264 region->extents.x1, region->extents.y1, region->extents.x2, region->extents.y2,
21265 region_num_rects(region),
21266 - crtc->pipe, crtc->base->x, crtc->base->y));
21267 + __sna_crtc_pipe(crtc), crtc->base->x, crtc->base->y));
21269 assert(crtc->slave_damage == damage);
21270 assert(sna->mode.shadow_damage);
21271 @@ -1431,7 +2051,7 @@ static bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc)
21272 return true;
21275 - DBG(("%s: enabling for crtc %d\n", __FUNCTION__, crtc->id));
21276 + DBG(("%s: enabling for crtc %d\n", __FUNCTION__, __sna_crtc_id(crtc)));
21278 if (!sna->mode.shadow_active) {
21279 if (!sna_mode_enable_shadow(sna))
21280 @@ -1443,9 +2063,12 @@ static bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc)
21281 if (crtc->slave_pixmap) {
21282 assert(crtc->slave_damage == NULL);
21284 + DBG(("%s: enabling PRIME slave tracking on CRTC %d [pipe=%d], pixmap=%ld\n",
21285 + __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->slave_pixmap->drawable.serialNumber));
21286 crtc->slave_damage = DamageCreate(sna_crtc_slave_damage, NULL,
21287 DamageReportRawRegion, TRUE,
21288 - sna->scrn->pScreen, crtc);
21289 + to_screen_from_sna(sna),
21290 + crtc);
21291 if (crtc->slave_damage == NULL) {
21292 if (!--sna->mode.shadow_active)
21293 sna_mode_disable_shadow(sna);
21294 @@ -1465,6 +2088,9 @@ static void sna_crtc_disable_override(struct sna *sna, struct sna_crtc *crtc)
21295 if (crtc->client_bo == NULL)
21296 return;
21298 + assert(crtc->client_bo->refcnt >= crtc->client_bo->active_scanout);
21299 + crtc->client_bo->active_scanout--;
21301 if (!crtc->transform) {
21302 DrawableRec tmp;
21304 @@ -1489,7 +2115,7 @@ static void sna_crtc_disable_shadow(struct sna *sna, struct sna_crtc *crtc)
21305 if (!crtc->shadow)
21306 return;
21308 - DBG(("%s: disabling for crtc %d\n", __FUNCTION__, crtc->id));
21309 + DBG(("%s: disabling for crtc %d\n", __FUNCTION__, __sna_crtc_id(crtc)));
21310 assert(sna->mode.shadow_active > 0);
21312 if (crtc->slave_damage) {
21313 @@ -1517,14 +2143,24 @@ __sna_crtc_disable(struct sna *sna, struct sna_crtc *sna_crtc)
21314 sna_crtc_disable_shadow(sna, sna_crtc);
21316 if (sna_crtc->bo) {
21317 + DBG(("%s: releasing handle=%d from scanout, active=%d\n",
21318 + __FUNCTION__,sna_crtc->bo->handle, sna_crtc->bo->active_scanout-1));
21319 + assert(sna_crtc->flags & CRTC_ON);
21320 assert(sna_crtc->bo->active_scanout);
21321 assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout);
21322 sna_crtc->bo->active_scanout--;
21323 kgem_bo_destroy(&sna->kgem, sna_crtc->bo);
21324 sna_crtc->bo = NULL;
21325 + sna_crtc->flags &= ~CRTC_ON;
21327 - assert(sna->mode.front_active);
21328 - sna->mode.front_active--;
21329 + if (sna->mode.hidden) {
21330 + sna->mode.hidden--;
21331 + assert(sna->mode.hidden);
21332 + assert(sna->mode.front_active == 0);
21333 + } else {
21334 + assert(sna->mode.front_active);
21335 + sna->mode.front_active--;
21336 + }
21337 sna->mode.dirty = true;
21340 @@ -1532,13 +2168,19 @@ __sna_crtc_disable(struct sna *sna, struct sna_crtc *sna_crtc)
21341 kgem_bo_destroy(&sna->kgem, sna_crtc->shadow_bo);
21342 sna_crtc->shadow_bo = NULL;
21344 - sna_crtc->transform = false;
21345 + if (sna_crtc->transform) {
21346 + assert(sna->mode.rr_active);
21347 + sna->mode.rr_active--;
21348 + sna_crtc->transform = false;
21349 + }
21351 + sna_crtc->cursor_transform = false;
21352 + sna_crtc->hwcursor = true;
21353 assert(!sna_crtc->shadow);
21356 static void
21357 -sna_crtc_disable(xf86CrtcPtr crtc)
21358 +sna_crtc_disable(xf86CrtcPtr crtc, bool force)
21360 struct sna *sna = to_sna(crtc->scrn);
21361 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
21362 @@ -1547,14 +2189,16 @@ sna_crtc_disable(xf86CrtcPtr crtc)
21363 if (sna_crtc == NULL)
21364 return;
21366 - DBG(("%s: disabling crtc [%d, pipe=%d]\n", __FUNCTION__,
21367 - sna_crtc->id, sna_crtc->pipe));
21368 + if (!force && sna_crtc->bo == NULL)
21369 + return;
21371 + DBG(("%s: disabling crtc [%d, pipe=%d], force?=%d\n", __FUNCTION__,
21372 + __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), force));
21374 sna_crtc_force_outputs_off(crtc);
21375 - assert(sna_crtc->dpms_mode == DPMSModeOff);
21377 memset(&arg, 0, sizeof(arg));
21378 - arg.crtc_id = sna_crtc->id;
21379 + arg.crtc_id = __sna_crtc_id(sna_crtc);
21380 (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg);
21382 __sna_crtc_disable(sna, sna_crtc);
21383 @@ -1574,19 +2218,19 @@ static void update_flush_interval(struct sna *sna)
21385 if (!crtc->enabled) {
21386 DBG(("%s: CRTC:%d (pipe %d) disabled\n",
21387 - __FUNCTION__,i, to_sna_crtc(crtc)->pipe));
21388 + __FUNCTION__,i, sna_crtc_pipe(crtc)));
21389 assert(to_sna_crtc(crtc)->bo == NULL);
21390 continue;
21393 - if (to_sna_crtc(crtc)->dpms_mode != DPMSModeOn) {
21394 + if (to_sna_crtc(crtc)->bo == NULL) {
21395 DBG(("%s: CRTC:%d (pipe %d) turned off\n",
21396 - __FUNCTION__,i, to_sna_crtc(crtc)->pipe));
21397 + __FUNCTION__,i, sna_crtc_pipe(crtc)));
21398 continue;
21401 DBG(("%s: CRTC:%d (pipe %d) vrefresh=%f\n",
21402 - __FUNCTION__, i, to_sna_crtc(crtc)->pipe,
21403 + __FUNCTION__, i, sna_crtc_pipe(crtc),
21404 xf86ModeVRefresh(&crtc->mode)));
21405 max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(&crtc->mode));
21407 @@ -1642,7 +2286,7 @@ void sna_copy_fbcon(struct sna *sna)
21408 int dx, dy;
21409 int i;
21411 - if (wedged(sna))
21412 + if (wedged(sna) || isGPU(sna->scrn))
21413 return;
21415 DBG(("%s\n", __FUNCTION__));
21416 @@ -1662,7 +2306,7 @@ void sna_copy_fbcon(struct sna *sna)
21417 assert(crtc != NULL);
21419 VG_CLEAR(mode);
21420 - mode.crtc_id = crtc->id;
21421 + mode.crtc_id = __sna_crtc_id(crtc);
21422 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
21423 continue;
21424 if (!mode.fb_id)
21425 @@ -1726,7 +2370,7 @@ void sna_copy_fbcon(struct sna *sna)
21426 kgem_bo_destroy(&sna->kgem, bo);
21428 #if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(10, 0)
21429 - sna->scrn->pScreen->canDoBGNoneRoot = ok;
21430 + to_screen_from_sna(sna)->canDoBGNoneRoot = ok;
21431 #endif
21434 @@ -1736,7 +2380,6 @@ static bool use_shadow(struct sna *sna, xf86CrtcPtr crtc)
21435 PictTransform crtc_to_fb;
21436 struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc;
21437 unsigned pitch_limit;
21438 - struct sna_pixmap *priv;
21439 BoxRec b;
21441 assert(sna->scrn->virtualX && sna->scrn->virtualY);
21442 @@ -1765,27 +2408,31 @@ static bool use_shadow(struct sna *sna, xf86CrtcPtr crtc)
21443 return true;
21446 - priv = sna_pixmap_force_to_gpu(sna->front, MOVE_READ | __MOVE_SCANOUT);
21447 - if (priv == NULL)
21448 - return true; /* maybe we can create a bo for the scanout? */
21450 - if (sna->kgem.gen == 071)
21451 - pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024;
21452 - else if ((sna->kgem.gen >> 3) > 4)
21453 - pitch_limit = 32 * 1024;
21454 - else if ((sna->kgem.gen >> 3) == 4)
21455 - pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024;
21456 - else if ((sna->kgem.gen >> 3) == 3)
21457 - pitch_limit = priv->gpu_bo->tiling ? 8 * 1024 : 16 * 1024;
21458 - else
21459 - pitch_limit = 8 * 1024;
21460 - 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));
21461 - if (priv->gpu_bo->pitch > pitch_limit)
21462 - return true;
21463 + if (!isGPU(sna->scrn)) {
21464 + struct sna_pixmap *priv;
21466 - if (priv->gpu_bo->tiling && sna->flags & SNA_LINEAR_FB) {
21467 - DBG(("%s: gpu bo is tiled, need linear, forcing shadow\n", __FUNCTION__));
21468 - return true;
21469 + priv = sna_pixmap_force_to_gpu(sna->front, MOVE_READ | __MOVE_SCANOUT);
21470 + if (priv == NULL)
21471 + return true; /* maybe we can create a bo for the scanout? */
21473 + if (sna->kgem.gen == 071)
21474 + pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024;
21475 + else if ((sna->kgem.gen >> 3) > 4)
21476 + pitch_limit = 32 * 1024;
21477 + else if ((sna->kgem.gen >> 3) == 4)
21478 + pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024;
21479 + else if ((sna->kgem.gen >> 3) == 3)
21480 + pitch_limit = priv->gpu_bo->tiling ? 8 * 1024 : 16 * 1024;
21481 + else
21482 + pitch_limit = 8 * 1024;
21483 + 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));
21484 + if (priv->gpu_bo->pitch > pitch_limit)
21485 + return true;
21487 + if (priv->gpu_bo->tiling && sna->flags & SNA_LINEAR_FB) {
21488 + DBG(("%s: gpu bo is tiled, need linear, forcing shadow\n", __FUNCTION__));
21489 + return true;
21490 + }
21493 transform = NULL;
21494 @@ -1800,9 +2447,9 @@ static bool use_shadow(struct sna *sna, xf86CrtcPtr crtc)
21495 bool needs_transform = true;
21496 unsigned rotation = rotation_reduce(&to_sna_crtc(crtc)->primary, crtc->rotation);
21497 DBG(("%s: natively supported rotation? rotation=%x & supported=%x == %d\n",
21498 - __FUNCTION__, crtc->rotation, to_sna_crtc(crtc)->primary.rotation.supported,
21499 - !!(crtc->rotation & to_sna_crtc(crtc)->primary.rotation.supported)));
21500 - if (to_sna_crtc(crtc)->primary.rotation.supported & rotation)
21501 + __FUNCTION__, rotation, to_sna_crtc(crtc)->primary.rotation.supported,
21502 + rotation == (rotation & to_sna_crtc(crtc)->primary.rotation.supported)));
21503 + if ((to_sna_crtc(crtc)->primary.rotation.supported & rotation) == rotation)
21504 needs_transform = RRTransformCompute(crtc->x, crtc->y,
21505 crtc->mode.HDisplay, crtc->mode.VDisplay,
21506 RR_Rotate_0, transform,
21507 @@ -1839,6 +2486,7 @@ static void set_shadow(struct sna *sna, RegionPtr region)
21509 assert(priv->gpu_bo);
21510 assert(sna->mode.shadow);
21511 + assert(sna->mode.shadow->active_scanout);
21513 DBG(("%s: waiting for region %dx[(%d, %d), (%d, %d)], front handle=%d, shadow handle=%d\n",
21514 __FUNCTION__,
21515 @@ -1912,6 +2560,28 @@ get_scanout_bo(struct sna *sna, PixmapPtr pixmap)
21516 return priv->gpu_bo;
21519 +static void shadow_clear(struct sna *sna,
21520 + PixmapPtr front, struct kgem_bo *bo,
21521 + xf86CrtcPtr crtc)
21522 +{
21523 + bool ok = false;
21524 + if (!wedged(sna))
21525 + ok = sna->render.fill_one(sna, front, bo, 0,
21526 + 0, 0, crtc->mode.HDisplay, crtc->mode.VDisplay,
21527 + GXclear);
21528 + if (!ok) {
21529 + void *ptr = kgem_bo_map__gtt(&sna->kgem, bo);
21530 + if (ptr)
21531 + memset(ptr, 0, bo->pitch * crtc->mode.HDisplay);
21532 + }
21533 + sna->mode.shadow_dirty = true;
21534 +}
21536 +static bool rr_active(xf86CrtcPtr crtc)
21537 +{
21538 + return crtc->transformPresent || crtc->rotation != RR_Rotate_0;
21539 +}
21541 static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
21543 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
21544 @@ -1919,10 +2589,15 @@ static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
21545 struct sna *sna = to_sna(scrn);
21546 struct kgem_bo *bo;
21548 - sna_crtc->transform = false;
21549 + if (sna_crtc->transform) {
21550 + assert(sna->mode.rr_active);
21551 + sna_crtc->transform = false;
21552 + sna->mode.rr_active--;
21553 + }
21554 sna_crtc->rotation = RR_Rotate_0;
21556 if (use_shadow(sna, crtc)) {
21557 + PixmapPtr front;
21558 unsigned long tiled_limit;
21559 int tiling;
21561 @@ -1949,6 +2624,10 @@ force_shadow:
21564 tiling = I915_TILING_X;
21565 + if (crtc->rotation & (RR_Rotate_90 | RR_Rotate_270) &&
21566 + sna->kgem.can_scanout_y)
21567 + tiling = I915_TILING_Y;
21569 if (sna->kgem.gen == 071)
21570 tiled_limit = 16 * 1024 * 8;
21571 else if ((sna->kgem.gen >> 3) > 4)
21572 @@ -1977,8 +2656,8 @@ force_shadow:
21573 return NULL;
21576 - if (__sna_pixmap_get_bo(sna->front) && !crtc->transformPresent) {
21577 - DrawableRec tmp;
21578 + front = sna_crtc->slave_pixmap ?: sna->front;
21579 + if (__sna_pixmap_get_bo(front) && !rr_active(crtc)) {
21580 BoxRec b;
21582 b.x1 = crtc->x;
21583 @@ -1986,28 +2665,48 @@ force_shadow:
21584 b.x2 = crtc->x + crtc->mode.HDisplay;
21585 b.y2 = crtc->y + crtc->mode.VDisplay;
21587 - DBG(("%s: copying onto shadow CRTC: (%d, %d)x(%d, %d), handle=%d\n",
21588 - __FUNCTION__,
21589 - b.x1, b.y1,
21590 - b.x2, b.y2,
21591 - bo->handle));
21593 - tmp.width = crtc->mode.HDisplay;
21594 - tmp.height = crtc->mode.VDisplay;
21595 - tmp.depth = sna->front->drawable.depth;
21596 - tmp.bitsPerPixel = sna->front->drawable.bitsPerPixel;
21598 - (void)sna->render.copy_boxes(sna, GXcopy,
21599 - &sna->front->drawable, __sna_pixmap_get_bo(sna->front), 0, 0,
21600 - &tmp, bo, -b.x1, -b.y1,
21601 - &b, 1, 0);
21602 - }
21603 + if (b.x1 < 0)
21604 + b.x1 = 0;
21605 + if (b.y1 < 0)
21606 + b.y1 = 0;
21607 + if (b.x2 > scrn->virtualX)
21608 + b.x2 = scrn->virtualX;
21609 + if (b.y2 > scrn->virtualY)
21610 + b.y2 = scrn->virtualY;
21611 + if (b.x2 - b.x1 < crtc->mode.HDisplay ||
21612 + b.y2 - b.y1 < crtc->mode.VDisplay)
21613 + shadow_clear(sna, front, bo, crtc);
21615 + if (b.y2 > b.y1 && b.x2 > b.x1) {
21616 + DrawableRec tmp;
21618 + DBG(("%s: copying onto shadow CRTC: (%d, %d)x(%d, %d) [fb=%dx%d], handle=%d\n",
21619 + __FUNCTION__,
21620 + b.x1, b.y1,
21621 + b.x2-b.x1, b.y2-b.y1,
21622 + scrn->virtualX, scrn->virtualY,
21623 + bo->handle));
21625 + tmp.width = crtc->mode.HDisplay;
21626 + tmp.height = crtc->mode.VDisplay;
21627 + tmp.depth = front->drawable.depth;
21628 + tmp.bitsPerPixel = front->drawable.bitsPerPixel;
21630 + if (!sna->render.copy_boxes(sna, GXcopy,
21631 + &front->drawable, __sna_pixmap_get_bo(front), 0, 0,
21632 + &tmp, bo, -crtc->x, -crtc->y,
21633 + &b, 1, COPY_LAST))
21634 + shadow_clear(sna, front, bo, crtc);
21635 + }
21636 + } else
21637 + shadow_clear(sna, front, bo, crtc);
21639 sna_crtc->shadow_bo_width = crtc->mode.HDisplay;
21640 sna_crtc->shadow_bo_height = crtc->mode.VDisplay;
21641 sna_crtc->shadow_bo = bo;
21642 out_shadow:
21643 sna_crtc->transform = true;
21644 + sna->mode.rr_active++;
21645 return kgem_bo_reference(bo);
21646 } else {
21647 if (sna_crtc->shadow_bo) {
21648 @@ -2048,26 +2747,26 @@ out_shadow:
21651 if (sna->flags & SNA_TEAR_FREE) {
21652 + RegionRec region;
21654 assert(sna_crtc->slave_pixmap == NULL);
21656 DBG(("%s: enabling TearFree shadow\n", __FUNCTION__));
21657 + region.extents.x1 = 0;
21658 + region.extents.y1 = 0;
21659 + region.extents.x2 = sna->scrn->virtualX;
21660 + region.extents.y2 = sna->scrn->virtualY;
21661 + region.data = NULL;
21663 if (!sna_crtc_enable_shadow(sna, sna_crtc)) {
21664 DBG(("%s: failed to enable crtc shadow\n", __FUNCTION__));
21665 return NULL;
21668 - if (sna->mode.shadow == NULL && !wedged(sna)) {
21669 - RegionRec region;
21670 + if (sna->mode.shadow == NULL) {
21671 struct kgem_bo *shadow;
21673 DBG(("%s: creating TearFree shadow bo\n", __FUNCTION__));
21675 - region.extents.x1 = 0;
21676 - region.extents.y1 = 0;
21677 - region.extents.x2 = sna->scrn->virtualX;
21678 - region.extents.y2 = sna->scrn->virtualY;
21679 - region.data = NULL;
21681 shadow = kgem_create_2d(&sna->kgem,
21682 region.extents.x2,
21683 region.extents.y2,
21684 @@ -2093,9 +2792,12 @@ out_shadow:
21685 goto force_shadow;
21688 + assert(__sna_pixmap_get_bo(sna->front) == NULL ||
21689 + __sna_pixmap_get_bo(sna->front)->pitch == shadow->pitch);
21690 sna->mode.shadow = shadow;
21691 - set_shadow(sna, &region);
21692 + sna->mode.shadow->active_scanout++;
21694 + set_shadow(sna, &region);
21696 sna_crtc_disable_override(sna, sna_crtc);
21697 } else
21698 @@ -2107,6 +2809,37 @@ out_shadow:
21702 +#define SCALING_EPSILON (1./256)
21704 +static bool
21705 +is_affine(const struct pixman_f_transform *t)
21706 +{
21707 + return (fabs(t->m[2][0]) < SCALING_EPSILON &&
21708 + fabs(t->m[2][1]) < SCALING_EPSILON);
21709 +}
21711 +static double determinant(const struct pixman_f_transform *t)
21712 +{
21713 + return t->m[0][0]*t->m[1][1] - t->m[1][0]*t->m[0][1];
21714 +}
21716 +static bool
21717 +affine_is_pixel_exact(const struct pixman_f_transform *t)
21718 +{
21719 + double det = t->m[2][2] * determinant(t);
21720 + if (fabs (det * det - 1.0) < SCALING_EPSILON) {
21721 + if (fabs(t->m[0][1]) < SCALING_EPSILON &&
21722 + fabs(t->m[1][0]) < SCALING_EPSILON)
21723 + return true;
21725 + if (fabs(t->m[0][0]) < SCALING_EPSILON &&
21726 + fabs(t->m[1][1]) < SCALING_EPSILON)
21727 + return true;
21728 + }
21730 + return false;
21731 +}
21733 static void sna_crtc_randr(xf86CrtcPtr crtc)
21735 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
21736 @@ -2152,6 +2885,25 @@ static void sna_crtc_randr(xf86CrtcPtr crtc)
21737 } else
21738 crtc->transform_in_use = sna_crtc->rotation != RR_Rotate_0;
21740 + /* Recompute the cursor after a potential change in transform */
21741 + if (sna_crtc->cursor) {
21742 + assert(sna_crtc->cursor->ref > 0);
21743 + sna_crtc->cursor->ref--;
21744 + sna_crtc->cursor = NULL;
21745 + }
21747 + if (needs_transform) {
21748 + sna_crtc->hwcursor = is_affine(&f_fb_to_crtc);
21749 + sna_crtc->cursor_transform =
21750 + sna_crtc->hwcursor &&
21751 + !affine_is_pixel_exact(&f_fb_to_crtc);
21752 + } else {
21753 + sna_crtc->hwcursor = true;
21754 + sna_crtc->cursor_transform = false;
21755 + }
21756 + DBG(("%s: hwcursor?=%d, cursor_transform?=%d\n",
21757 + __FUNCTION__, sna_crtc->hwcursor, sna_crtc->cursor_transform));
21759 crtc->crtc_to_framebuffer = crtc_to_fb;
21760 crtc->f_crtc_to_framebuffer = f_crtc_to_fb;
21761 crtc->f_framebuffer_to_crtc = f_fb_to_crtc;
21762 @@ -2184,7 +2936,7 @@ static void sna_crtc_randr(xf86CrtcPtr crtc)
21763 static void
21764 sna_crtc_damage(xf86CrtcPtr crtc)
21766 - ScreenPtr screen = crtc->scrn->pScreen;
21767 + ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
21768 struct sna *sna = to_sna(crtc->scrn);
21769 RegionRec region, *damage;
21771 @@ -2200,15 +2952,21 @@ sna_crtc_damage(xf86CrtcPtr crtc)
21772 if (region.extents.y2 > screen->height)
21773 region.extents.y2 = screen->height;
21775 + if (region.extents.x2 <= region.extents.x1 ||
21776 + region.extents.y2 <= region.extents.y1) {
21777 + DBG(("%s: crtc not damaged, all-clipped\n", __FUNCTION__));
21778 + return;
21779 + }
21781 DBG(("%s: marking crtc %d as completely damaged (%d, %d), (%d, %d)\n",
21782 - __FUNCTION__, to_sna_crtc(crtc)->id,
21783 + __FUNCTION__, sna_crtc_id(crtc),
21784 region.extents.x1, region.extents.y1,
21785 region.extents.x2, region.extents.y2));
21786 - to_sna_crtc(crtc)->client_damage = region;
21788 assert(sna->mode.shadow_damage && sna->mode.shadow_active);
21789 damage = DamageRegion(sna->mode.shadow_damage);
21790 RegionUnion(damage, damage, &region);
21791 + to_sna_crtc(crtc)->crtc_damage = region;
21793 DBG(("%s: damage now %dx[(%d, %d), (%d, %d)]\n",
21794 __FUNCTION__,
21795 @@ -2260,6 +3018,21 @@ static const char *reflection_to_str(Rotation rotation)
21799 +static void reprobe_connectors(xf86CrtcPtr crtc)
21800 +{
21801 + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
21802 + struct sna *sna = to_sna(crtc->scrn);
21803 + int i;
21805 + for (i = 0; i < sna->mode.num_real_output; i++) {
21806 + xf86OutputPtr output = config->output[i];
21807 + if (output->crtc == crtc)
21808 + to_sna_output(output)->reprobe = true;
21809 + }
21811 + sna_mode_discover(sna, true);
21812 +}
21814 static Bool
21815 __sna_crtc_set_mode(xf86CrtcPtr crtc)
21817 @@ -2268,11 +3041,19 @@ __sna_crtc_set_mode(xf86CrtcPtr crtc)
21818 struct kgem_bo *saved_bo, *bo;
21819 uint32_t saved_offset;
21820 bool saved_transform;
21821 + bool saved_hwcursor;
21822 + bool saved_cursor_transform;
21823 + int ret;
21825 - DBG(("%s\n", __FUNCTION__));
21826 + DBG(("%s: CRTC=%d, pipe=%d, hidden?=%d\n", __FUNCTION__,
21827 + __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), sna->mode.hidden));
21828 + if (sna->mode.hidden)
21829 + return TRUE;
21831 saved_bo = sna_crtc->bo;
21832 saved_transform = sna_crtc->transform;
21833 + saved_cursor_transform = sna_crtc->cursor_transform;
21834 + saved_hwcursor = sna_crtc->hwcursor;
21835 saved_offset = sna_crtc->offset;
21837 sna_crtc->fallback_shadow = false;
21838 @@ -2285,26 +3066,31 @@ retry: /* Attach per-crtc pixmap or direct */
21841 /* Prevent recursion when enabling outputs during execbuffer */
21842 - if (bo->exec && RQ(bo->rq)->bo == NULL)
21843 + if (bo->exec && RQ(bo->rq)->bo == NULL) {
21844 _kgem_submit(&sna->kgem);
21845 + __kgem_bo_clear_dirty(bo);
21846 + }
21848 sna_crtc->bo = bo;
21849 - if (!sna_crtc_apply(crtc)) {
21850 - int err = errno;
21852 + ret = sna_crtc_apply(crtc);
21853 + if (ret) {
21854 kgem_bo_destroy(&sna->kgem, bo);
21856 - if (!sna_crtc->shadow) {
21857 + if (!sna_crtc->fallback_shadow) {
21858 sna_crtc->fallback_shadow = true;
21859 goto retry;
21862 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
21863 - "failed to set mode: %s [%d]\n", strerror(err), err);
21864 + "failed to set mode: %s [%d]\n", strerror(ret), ret);
21865 goto error;
21868 + sna_crtc->flags |= CRTC_ON;
21869 bo->active_scanout++;
21870 + DBG(("%s: marking handle=%d as active=%d (removing %d from scanout, active=%d)\n",
21871 + __FUNCTION__, bo->handle, bo->active_scanout,
21872 + saved_bo ? saved_bo->handle : 0, saved_bo ? saved_bo->active_scanout - 1: -1));
21873 if (saved_bo) {
21874 assert(saved_bo->active_scanout);
21875 assert(saved_bo->refcnt >= saved_bo->active_scanout);
21876 @@ -2315,17 +3101,34 @@ retry: /* Attach per-crtc pixmap or direct */
21877 sna_crtc_randr(crtc);
21878 if (sna_crtc->transform)
21879 sna_crtc_damage(crtc);
21880 + if (sna_crtc->cursor && /* Reload cursor if RandR maybe changed */
21881 + (!sna_crtc->hwcursor ||
21882 + saved_cursor_transform || sna_crtc->cursor_transform ||
21883 + sna_crtc->cursor->rotation != crtc->rotation))
21884 + sna_crtc_disable_cursor(sna, sna_crtc);
21886 + assert(!sna->mode.hidden);
21887 sna->mode.front_active += saved_bo == NULL;
21888 sna->mode.dirty = true;
21889 - DBG(("%s: front_active=%d\n", __FUNCTION__, sna->mode.front_active));
21890 + DBG(("%s: handle=%d, scanout_active=%d, front_active=%d\n",
21891 + __FUNCTION__, bo->handle, bo->active_scanout, sna->mode.front_active));
21893 return TRUE;
21895 error:
21896 sna_crtc->offset = saved_offset;
21897 + if (sna_crtc->transform) {
21898 + assert(sna->mode.rr_active);
21899 + sna->mode.rr_active--;
21900 + }
21901 + if (saved_transform)
21902 + sna->mode.rr_active++;
21903 sna_crtc->transform = saved_transform;
21904 + sna_crtc->cursor_transform = saved_cursor_transform;
21905 + sna_crtc->hwcursor = saved_hwcursor;
21906 sna_crtc->bo = saved_bo;
21907 - sna_mode_discover(sna);
21909 + reprobe_connectors(crtc);
21910 return FALSE;
21913 @@ -2346,14 +3149,14 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
21914 xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO,
21915 "switch to mode %dx%d@%.1f on %s using pipe %d, position (%d, %d), rotation %s, reflection %s\n",
21916 mode->HDisplay, mode->VDisplay, xf86ModeVRefresh(mode),
21917 - outputs_for_crtc(crtc, outputs, sizeof(outputs)), sna_crtc->pipe,
21918 + outputs_for_crtc(crtc, outputs, sizeof(outputs)), __sna_crtc_pipe(sna_crtc),
21919 x, y, rotation_to_str(rotation), reflection_to_str(rotation));
21921 assert(mode->HDisplay <= sna->mode.max_crtc_width &&
21922 mode->VDisplay <= sna->mode.max_crtc_height);
21924 #if HAS_GAMMA
21925 - drmModeCrtcSetGamma(sna->kgem.fd, sna_crtc->id,
21926 + drmModeCrtcSetGamma(sna->kgem.fd, __sna_crtc_id(sna_crtc),
21927 crtc->gamma_size,
21928 crtc->gamma_red,
21929 crtc->gamma_green,
21930 @@ -2372,17 +3175,10 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
21931 static void
21932 sna_crtc_dpms(xf86CrtcPtr crtc, int mode)
21934 - struct sna_crtc *priv = to_sna_crtc(crtc);
21936 DBG(("%s(pipe %d, dpms mode -> %d):= active=%d\n",
21937 - __FUNCTION__, priv->pipe, mode, mode == DPMSModeOn));
21938 - if (priv->dpms_mode == mode)
21939 - return;
21941 - assert(priv);
21942 - priv->dpms_mode = mode;
21943 + __FUNCTION__, sna_crtc_pipe(crtc), mode, mode == DPMSModeOn));
21945 - if (mode == DPMSModeOn && crtc->enabled && priv->bo == NULL) {
21946 + if (mode == DPMSModeOn && crtc->enabled) {
21947 if (__sna_crtc_set_mode(crtc))
21948 update_flush_interval(to_sna(crtc->scrn));
21949 else
21950 @@ -2390,7 +3186,7 @@ sna_crtc_dpms(xf86CrtcPtr crtc, int mode)
21953 if (mode != DPMSModeOn)
21954 - sna_crtc_disable(crtc);
21955 + sna_crtc_disable(crtc, false);
21958 void sna_mode_adjust_frame(struct sna *sna, int x, int y)
21959 @@ -2426,7 +3222,7 @@ sna_crtc_gamma_set(xf86CrtcPtr crtc,
21961 assert(to_sna_crtc(crtc));
21962 drmModeCrtcSetGamma(to_sna(crtc->scrn)->kgem.fd,
21963 - to_sna_crtc(crtc)->id,
21964 + sna_crtc_id(crtc),
21965 size, red, green, blue);
21968 @@ -2434,10 +3230,14 @@ static void
21969 sna_crtc_destroy(xf86CrtcPtr crtc)
21971 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
21972 + struct plane *sprite, *sn;
21974 if (sna_crtc == NULL)
21975 return;
21977 + list_for_each_entry_safe(sprite, sn, &sna_crtc->sprites, link)
21978 + free(sprite);
21980 free(sna_crtc);
21981 crtc->driver_private = NULL;
21983 @@ -2455,7 +3255,7 @@ sna_crtc_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr pixmap)
21984 return TRUE;
21986 DBG(("%s: CRTC:%d, pipe=%d setting scanout pixmap=%ld\n",
21987 - __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
21988 + __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
21989 pixmap ? pixmap->drawable.serialNumber : 0));
21991 /* Disable first so that we can unregister the damage tracking */
21992 @@ -2576,6 +3376,10 @@ static int plane_details(struct sna *sna, struct plane *p)
21996 + p->rotation.supported &= DBG_NATIVE_ROTATION;
21997 + if (!xf86ReturnOptValBool(sna->Options, OPTION_ROTATION, TRUE))
21998 + p->rotation.supported = RR_Rotate_0;
22000 if (props != (uint32_t *)stack_props)
22001 free(props);
22003 @@ -2583,20 +3387,26 @@ static int plane_details(struct sna *sna, struct plane *p)
22004 return type;
22007 +static void add_sprite_plane(struct sna_crtc *crtc,
22008 + struct plane *details)
22009 +{
22010 + struct plane *sprite = malloc(sizeof(*sprite));
22011 + if (!sprite)
22012 + return;
22014 + memcpy(sprite, details, sizeof(*sprite));
22015 + list_add(&sprite->link, &crtc->sprites);
22016 +}
22018 static void
22019 sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
22021 #define LOCAL_IOCTL_SET_CAP DRM_IOWR(0x0d, struct local_set_cap)
22022 -#define LOCAL_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xb5, struct local_mode_get_plane_res)
22023 -#define LOCAL_IOCTL_MODE_GETPLANE DRM_IOWR(0xb6, struct local_mode_get_plane)
22024 struct local_set_cap {
22025 uint64_t name;
22026 uint64_t value;
22027 } cap;
22028 - struct local_mode_get_plane_res {
22029 - uint64_t plane_id_ptr;
22030 - uint64_t count_planes;
22031 - } r;
22032 + struct local_mode_get_plane_res r;
22033 uint32_t stack_planes[32];
22034 uint32_t *planes = stack_planes;
22035 int i;
22036 @@ -2629,18 +3439,7 @@ sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
22037 VG(VALGRIND_MAKE_MEM_DEFINED(planes, sizeof(uint32_t)*r.count_planes));
22039 for (i = 0; i < r.count_planes; i++) {
22040 - struct local_mode_get_plane {
22041 - uint32_t plane_id;
22043 - uint32_t crtc_id;
22044 - uint32_t fb_id;
22046 - uint32_t possible_crtcs;
22047 - uint32_t gamma_size;
22049 - uint32_t count_format_types;
22050 - uint64_t format_type_ptr;
22051 - } p;
22052 + struct local_mode_get_plane p;
22053 struct plane details;
22055 VG_CLEAR(p);
22056 @@ -2649,11 +3448,11 @@ sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
22057 if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_GETPLANE, &p))
22058 continue;
22060 - if ((p.possible_crtcs & (1 << crtc->pipe)) == 0)
22061 + if ((p.possible_crtcs & (1 << __sna_crtc_pipe(crtc))) == 0)
22062 continue;
22064 DBG(("%s: plane %d is attached to our pipe=%d\n",
22065 - __FUNCTION__, planes[i], crtc->pipe));
22066 + __FUNCTION__, planes[i], __sna_crtc_pipe(crtc)));
22068 details.id = p.plane_id;
22069 details.rotation.prop = 0;
22070 @@ -2672,8 +3471,7 @@ sna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc)
22071 break;
22073 case DRM_PLANE_TYPE_OVERLAY:
22074 - if (crtc->sprite.id == 0)
22075 - crtc->sprite = details;
22076 + add_sprite_plane(crtc, &details);
22077 break;
22080 @@ -2688,7 +3486,6 @@ sna_crtc_init__rotation(struct sna *sna, struct sna_crtc *crtc)
22081 crtc->rotation = RR_Rotate_0;
22082 crtc->primary.rotation.supported = RR_Rotate_0;
22083 crtc->primary.rotation.current = RR_Rotate_0;
22084 - crtc->sprite.rotation = crtc->primary.rotation;
22087 static void
22088 @@ -2698,55 +3495,55 @@ sna_crtc_init__cursor(struct sna *sna, struct sna_crtc *crtc)
22090 VG_CLEAR(arg);
22091 arg.flags = DRM_MODE_CURSOR_BO;
22092 - arg.crtc_id = crtc->id;
22093 + arg.crtc_id = __sna_crtc_id(crtc);
22094 arg.width = arg.height = 0;
22095 arg.handle = 0;
22097 (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg);
22098 + crtc->hwcursor = true;
22101 static bool
22102 -sna_crtc_add(ScrnInfoPtr scrn, int id)
22103 +sna_crtc_add(ScrnInfoPtr scrn, unsigned id)
22105 struct sna *sna = to_sna(scrn);
22106 xf86CrtcPtr crtc;
22107 struct sna_crtc *sna_crtc;
22108 struct drm_i915_get_pipe_from_crtc_id get_pipe;
22110 - DBG(("%s(%d)\n", __FUNCTION__, id));
22111 + DBG(("%s(%d): is-zaphod? %d\n", __FUNCTION__, id, is_zaphod(scrn)));
22113 sna_crtc = calloc(sizeof(struct sna_crtc), 1);
22114 if (sna_crtc == NULL)
22115 return false;
22117 sna_crtc->id = id;
22118 - sna_crtc->dpms_mode = -1;
22120 VG_CLEAR(get_pipe);
22121 get_pipe.pipe = 0;
22122 - get_pipe.crtc_id = sna_crtc->id;
22123 + get_pipe.crtc_id = id;
22124 if (drmIoctl(sna->kgem.fd,
22125 DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID,
22126 &get_pipe)) {
22127 free(sna_crtc);
22128 return false;
22130 - sna_crtc->pipe = get_pipe.pipe;
22131 + assert((unsigned)get_pipe.pipe < 256);
22132 + sna_crtc->flags |= get_pipe.pipe << 8;
22134 if (is_zaphod(scrn) &&
22135 - scrn->confScreen->device->screen != sna_crtc->pipe) {
22136 + (get_zaphod_crtcs(sna) & (1 << get_pipe.pipe)) == 0) {
22137 free(sna_crtc);
22138 return true;
22141 + list_init(&sna_crtc->sprites);
22142 sna_crtc_init__rotation(sna, sna_crtc);
22144 sna_crtc_find_planes(sna, sna_crtc);
22146 - 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",
22147 - __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
22148 - sna_crtc->primary.id, sna_crtc->primary.rotation.supported, sna_crtc->primary.rotation.current,
22149 - sna_crtc->sprite.id, sna_crtc->sprite.rotation.supported, sna_crtc->sprite.rotation.current));
22150 + DBG(("%s: CRTC:%d [pipe=%d], primary id=%x: supported-rotations=%x, current-rotation=%x\n",
22151 + __FUNCTION__, id, get_pipe.pipe,
22152 + sna_crtc->primary.id, sna_crtc->primary.rotation.supported, sna_crtc->primary.rotation.current));
22154 list_init(&sna_crtc->shadow_link);
22156 @@ -2761,7 +3558,7 @@ sna_crtc_add(ScrnInfoPtr scrn, int id)
22157 crtc->driver_private = sna_crtc;
22158 sna_crtc->base = crtc;
22159 DBG(("%s: attached crtc[%d] pipe=%d\n",
22160 - __FUNCTION__, id, sna_crtc->pipe));
22161 + __FUNCTION__, id, __sna_crtc_pipe(sna_crtc)));
22163 return true;
22165 @@ -2798,20 +3595,56 @@ find_property(struct sna *sna, struct sna_output *output, const char *name)
22166 return -1;
22169 +static void update_properties(struct sna *sna, struct sna_output *output)
22170 +{
22171 + union compat_mode_get_connector compat_conn;
22172 + struct drm_mode_modeinfo dummy;
22174 + VG_CLEAR(compat_conn);
22176 + compat_conn.conn.connector_id = output->id;
22177 + compat_conn.conn.count_props = output->num_props;
22178 + compat_conn.conn.props_ptr = (uintptr_t)output->prop_ids;
22179 + compat_conn.conn.prop_values_ptr = (uintptr_t)output->prop_values;
22180 + compat_conn.conn.count_modes = 1; /* skip detect */
22181 + compat_conn.conn.modes_ptr = (uintptr_t)&dummy;
22182 + compat_conn.conn.count_encoders = 0;
22184 + (void)drmIoctl(sna->kgem.fd,
22185 + DRM_IOCTL_MODE_GETCONNECTOR,
22186 + &compat_conn.conn);
22188 + assert(compat_conn.conn.count_props == output->num_props);
22189 + output->update_properties = false;
22190 +}
22192 static xf86OutputStatus
22193 sna_output_detect(xf86OutputPtr output)
22195 struct sna *sna = to_sna(output->scrn);
22196 struct sna_output *sna_output = output->driver_private;
22197 union compat_mode_get_connector compat_conn;
22198 + uint32_t now;
22200 DBG(("%s(%s:%d)\n", __FUNCTION__, output->name, sna_output->id));
22201 + sna_output->update_properties = false;
22203 if (!sna_output->id) {
22204 DBG(("%s(%s) hiding due to lost connection\n", __FUNCTION__, output->name));
22205 return XF86OutputStatusDisconnected;
22208 + /* Cache detections for 15s or hotplug event */
22209 + now = GetTimeInMillis();
22210 + if (sna_output->last_detect != 0 &&
22211 + (int32_t)(now - sna_output->last_detect) <= OUTPUT_STATUS_CACHE_MS) {
22212 + DBG(("%s(%s) reporting cached status (since %dms): %d\n",
22213 + __FUNCTION__, output->name, now - sna_output->last_detect,
22214 + sna_output->status));
22215 + sna_output->update_properties = true;
22216 + return sna_output->status;
22217 + }
22219 VG_CLEAR(compat_conn);
22220 compat_conn.conn.connector_id = sna_output->id;
22221 sna_output->num_modes = compat_conn.conn.count_modes = 0; /* reprobe */
22222 @@ -2854,15 +3687,23 @@ sna_output_detect(xf86OutputPtr output)
22223 DBG(("%s(%s): found %d modes, connection status=%d\n",
22224 __FUNCTION__, output->name, sna_output->num_modes, compat_conn.conn.connection));
22226 + sna_output->reprobe = false;
22227 + sna_output->last_detect = now;
22228 switch (compat_conn.conn.connection) {
22229 case DRM_MODE_CONNECTED:
22230 - return XF86OutputStatusConnected;
22231 + sna_output->status = XF86OutputStatusConnected;
22232 + output->mm_width = compat_conn.conn.mm_width;
22233 + output->mm_height = compat_conn.conn.mm_height;
22234 + break;
22235 case DRM_MODE_DISCONNECTED:
22236 - return XF86OutputStatusDisconnected;
22237 + sna_output->status = XF86OutputStatusDisconnected;
22238 + break;
22239 default:
22240 case DRM_MODE_UNKNOWNCONNECTION:
22241 - return XF86OutputStatusUnknown;
22242 + sna_output->status = XF86OutputStatusUnknown;
22243 + break;
22245 + return sna_output->status;
22248 static Bool
22249 @@ -2895,6 +3736,27 @@ sna_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode)
22250 return MODE_OK;
22253 +static void sna_output_set_parsed_edid(xf86OutputPtr output, xf86MonPtr mon)
22254 +{
22255 + unsigned conn_mm_width, conn_mm_height;
22257 + /* We set the output size based on values from the kernel */
22258 + conn_mm_width = output->mm_width;
22259 + conn_mm_height = output->mm_height;
22261 + xf86OutputSetEDID(output, mon);
22263 + if (output->mm_width != conn_mm_width || output->mm_height != conn_mm_height) {
22264 + DBG(("%s)%s): kernel and Xorg disagree over physical size: kernel=%dx%dmm, Xorg=%dx%dmm\n",
22265 + __FUNCTION__, output->name,
22266 + conn_mm_width, conn_mm_height,
22267 + output->mm_width, output->mm_height));
22268 + }
22270 + output->mm_width = conn_mm_width;
22271 + output->mm_height = conn_mm_height;
22272 +}
22274 static void
22275 sna_output_attach_edid(xf86OutputPtr output)
22277 @@ -2907,6 +3769,13 @@ sna_output_attach_edid(xf86OutputPtr output)
22278 if (sna_output->edid_idx == -1)
22279 return;
22281 + /* Always refresh the blob as the kernel may randomly update the
22282 + * id even if the contents of the blob doesn't change, and a
22283 + * request for the stale id will return nothing.
22284 + */
22285 + if (sna_output->update_properties)
22286 + update_properties(sna, sna_output);
22288 raw = sna_output->edid_raw;
22289 blob.length = sna_output->edid_len;
22291 @@ -2917,8 +3786,12 @@ sna_output_attach_edid(xf86OutputPtr output)
22292 old = NULL;
22294 blob.blob_id = sna_output->prop_values[sna_output->edid_idx];
22295 - DBG(("%s: attaching EDID id=%d, current=%d\n",
22296 - __FUNCTION__, blob.blob_id, sna_output->edid_blob_id));
22297 + if (!blob.blob_id)
22298 + goto done;
22300 + DBG(("%s(%s): attaching EDID id=%d, current=%d\n",
22301 + __FUNCTION__, output->name,
22302 + blob.blob_id, sna_output->edid_blob_id));
22303 if (blob.blob_id == sna_output->edid_blob_id && 0) { /* sigh */
22304 if (output->MonInfo) {
22305 /* XXX the property keeps on disappearing... */
22306 @@ -2936,26 +3809,45 @@ sna_output_attach_edid(xf86OutputPtr output)
22309 blob.data = (uintptr_t)raw;
22310 - if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
22311 - goto done;
22312 + do {
22313 + while (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) {
22314 + update_properties(sna, sna_output);
22315 + if (blob.blob_id == sna_output->prop_values[sna_output->edid_idx]) {
22316 + DBG(("%s(%s): failed to read blob, reusing previous\n",
22317 + __FUNCTION__, output->name));
22318 + goto done;
22319 + }
22320 + blob.blob_id = sna_output->prop_values[sna_output->edid_idx];
22321 + }
22323 - DBG(("%s: retrieving blob id=%d, length=%d\n",
22324 - __FUNCTION__, blob.blob_id, blob.length));
22325 + DBG(("%s(%s): retrieving blob id=%d, length=%d\n",
22326 + __FUNCTION__, output->name, blob.blob_id, blob.length));
22328 - if (blob.length > sna_output->edid_len) {
22329 - raw = realloc(raw, blob.length);
22330 - if (raw == NULL)
22331 + if (blob.length < 128)
22332 goto done;
22334 - VG(memset(raw, 0, blob.length));
22335 - blob.data = (uintptr_t)raw;
22336 - if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
22337 - goto done;
22338 + if (blob.length > sna_output->edid_len) {
22339 + raw = realloc(raw, blob.length);
22340 + if (raw == NULL)
22341 + goto done;
22343 + VG(memset(raw, 0, blob.length));
22344 + blob.data = (uintptr_t)raw;
22345 + }
22346 + } while (blob.length != sna_output->edid_len &&
22347 + drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob));
22349 + if (blob.length & 127) {
22350 + /* Truncated EDID! Make sure no one reads too far */
22351 + *SECTION(NO_EDID, (uint8_t*)raw) = blob.length/128 - 1;
22352 + blob.length &= -128;
22355 if (old &&
22356 blob.length == sna_output->edid_len &&
22357 memcmp(old, raw, blob.length) == 0) {
22358 + DBG(("%s(%s): EDID + MonInfo is unchanged\n",
22359 + __FUNCTION__, output->name));
22360 assert(sna_output->edid_raw == raw);
22361 sna_output->edid_blob_id = blob.blob_id;
22362 RRChangeOutputProperty(output->randr_output,
22363 @@ -2974,31 +3866,186 @@ skip_read:
22364 mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
22367 -done:
22368 - xf86OutputSetEDID(output, mon);
22369 - if (raw) {
22370 - sna_output->edid_raw = raw;
22371 - sna_output->edid_len = blob.length;
22372 - sna_output->edid_blob_id = blob.blob_id;
22373 +done:
22374 + sna_output_set_parsed_edid(output, mon);
22375 + if (raw) {
22376 + sna_output->edid_raw = raw;
22377 + sna_output->edid_len = blob.length;
22378 + sna_output->edid_blob_id = blob.blob_id;
22379 + }
22380 +}
22382 +static void
22383 +sna_output_attach_tile(xf86OutputPtr output)
22384 +{
22385 +#if XF86_OUTPUT_VERSION >= 3
22386 + struct sna *sna = to_sna(output->scrn);
22387 + struct sna_output *sna_output = output->driver_private;
22388 + struct drm_mode_get_blob blob;
22389 + struct xf86CrtcTileInfo tile_info, *set = NULL;
22390 + char *tile;
22391 + int id;
22393 + id = find_property(sna, sna_output, "TILE");
22394 + DBG(("%s: found? TILE=%d\n", __FUNCTION__, id));
22395 + if (id == -1)
22396 + goto out;
22398 + if (sna_output->update_properties)
22399 + update_properties(sna, sna_output);
22401 + VG_CLEAR(blob);
22402 + blob.blob_id = sna_output->prop_values[id];
22403 + blob.length = 0;
22404 + if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
22405 + goto out;
22407 + do {
22408 + id = blob.length;
22409 + tile = alloca(id + 1);
22410 + blob.data = (uintptr_t)tile;
22411 + VG(memset(tile, 0, id));
22412 + DBG(("%s: reading %d bytes for TILE blob\n", __FUNCTION__, id));
22413 + if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
22414 + goto out;
22415 + } while (id != blob.length);
22417 + tile[blob.length] = '\0'; /* paranoia */
22418 + DBG(("%s: TILE='%s'\n", __FUNCTION__, tile));
22419 + if (xf86OutputParseKMSTile(tile, blob.length, &tile_info))
22420 + set = &tile_info;
22421 +out:
22422 + xf86OutputSetTile(output, set);
22423 +#endif
22424 +}
22426 +static bool duplicate_mode(DisplayModePtr modes, DisplayModePtr m)
22427 +{
22428 + if (m == NULL)
22429 + return false;
22431 + while (modes) {
22432 + if (xf86ModesEqual(modes, m))
22433 + return true;
22435 + modes = modes->next;
22436 + }
22438 + return false;
22439 +}
22441 +static struct pixel_count {
22442 + int16_t width, height;
22443 +} common_16_9[] = {
22444 + { 640, 360 },
22445 + { 720, 405 },
22446 + { 864, 486 },
22447 + { 960, 540 },
22448 + { 1024, 576 },
22449 + { 1280, 720 },
22450 + { 1366, 768 },
22451 + { 1600, 900 },
22452 + { 1920, 1080 },
22453 + { 2048, 1152 },
22454 + { 2560, 1440 },
22455 + { 2880, 1620 },
22456 + { 3200, 1800 },
22457 + { 3840, 2160 },
22458 + { 4096, 2304 },
22459 + { 5120, 2880 },
22460 + { 7680, 4320 },
22461 + { 15360, 8640 },
22462 +}, common_16_10[] = {
22463 + { 1280, 800 },
22464 + { 1400, 900 },
22465 + { 1680, 1050 },
22466 + { 1920, 1200 },
22467 + { 2560, 1600 },
22468 +};
22470 +static DisplayModePtr
22471 +default_modes(DisplayModePtr preferred)
22472 +{
22473 + DisplayModePtr modes;
22474 + int n;
22476 +#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0)
22477 + modes = xf86GetDefaultModes();
22478 +#else
22479 + modes = xf86GetDefaultModes(0, 0);
22480 +#endif
22482 + /* XXX O(n^2) mode list generation :( */
22484 +#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,4,99,901,0)
22485 + if (preferred) {
22486 + DisplayModePtr m;
22488 + /* Add a half-resolution mode useful for large panels */
22489 + m = xf86GTFMode(preferred->HDisplay/2,
22490 + preferred->VDisplay/2,
22491 + xf86ModeVRefresh(preferred),
22492 + FALSE, FALSE);
22493 + if (!duplicate_mode(modes, m))
22494 + modes = xf86ModesAdd(modes, m);
22495 + else
22496 + free(m);
22498 + if (preferred->VDisplay * 16 > preferred->HDisplay*9 - preferred->HDisplay/32 &&
22499 + preferred->VDisplay * 16 < preferred->HDisplay*9 + preferred->HDisplay/32) {
22500 + DBG(("Adding 16:9 modes -- %d < %d > %d\n",
22501 + preferred->HDisplay*9 - preferred->HDisplay/32,
22502 + preferred->VDisplay * 16,
22503 + preferred->HDisplay*9 + preferred->HDisplay/32));
22504 + for (n = 0; n < ARRAY_SIZE(common_16_9); n++) {
22505 + if (preferred->HDisplay <= common_16_9[n].width ||
22506 + preferred->VDisplay <= common_16_9[n].height)
22507 + break;
22509 + m = xf86GTFMode(common_16_9[n].width,
22510 + common_16_9[n].height,
22511 + xf86ModeVRefresh(preferred),
22512 + FALSE, FALSE);
22513 + if (!duplicate_mode(modes, m))
22514 + modes = xf86ModesAdd(modes, m);
22515 + else
22516 + free(m);
22517 + }
22518 + }
22520 + if (preferred->VDisplay * 16 > preferred->HDisplay*10 - preferred->HDisplay/32 &&
22521 + preferred->VDisplay * 16 < preferred->HDisplay*10 + preferred->HDisplay/32) {
22522 + DBG(("Adding 16:10 modes -- %d < %d > %d\n",
22523 + preferred->HDisplay*10 - preferred->HDisplay/32,
22524 + preferred->VDisplay * 16,
22525 + preferred->HDisplay*10 + preferred->HDisplay/32));
22526 + for (n = 0; n < ARRAY_SIZE(common_16_10); n++) {
22527 + if (preferred->HDisplay <= common_16_10[n].width ||
22528 + preferred->VDisplay <= common_16_10[n].height)
22529 + break;
22531 + m = xf86GTFMode(common_16_10[n].width,
22532 + common_16_10[n].height,
22533 + xf86ModeVRefresh(preferred),
22534 + FALSE, FALSE);
22535 + if (!duplicate_mode(modes, m))
22536 + modes = xf86ModesAdd(modes, m);
22537 + else
22538 + free(m);
22539 + }
22540 + }
22542 -}
22544 -static DisplayModePtr
22545 -default_modes(void)
22546 -{
22547 -#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0)
22548 - return xf86GetDefaultModes();
22549 -#else
22550 - return xf86GetDefaultModes(0, 0);
22551 #endif
22553 + return modes;
22556 static DisplayModePtr
22557 -sna_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
22558 +sna_output_add_default_modes(xf86OutputPtr output, DisplayModePtr modes)
22560 xf86MonPtr mon = output->MonInfo;
22561 DisplayModePtr i, m, preferred = NULL;
22562 - int max_x = 0, max_y = 0;
22563 + int max_x = 0, max_y = 0, max_clock = 0;
22564 float max_vrefresh = 0.0;
22566 if (mon && GTF_SUPPORTED(mon->features.msc))
22567 @@ -3009,16 +4056,17 @@ sna_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
22568 preferred = m;
22569 max_x = max(max_x, m->HDisplay);
22570 max_y = max(max_y, m->VDisplay);
22571 + max_clock = max(max_clock, m->Clock);
22572 max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
22575 - max_vrefresh = max(max_vrefresh, 60.0);
22576 max_vrefresh *= (1 + SYNC_TOLERANCE);
22578 - m = default_modes();
22579 + m = default_modes(preferred);
22580 xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
22582 for (i = m; i; i = i->next) {
22583 + if (i->Clock > max_clock)
22584 + i->status = MODE_CLOCK_HIGH;
22585 if (xf86ModeVRefresh(i) > max_vrefresh)
22586 i->status = MODE_VSYNC;
22587 if (preferred &&
22588 @@ -3034,28 +4082,47 @@ sna_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
22591 static DisplayModePtr
22592 +sna_output_override_edid(xf86OutputPtr output)
22593 +{
22594 + struct sna_output *sna_output = output->driver_private;
22596 + if (sna_output->fake_edid_mon == NULL)
22597 + return NULL;
22599 + xf86OutputSetEDID(output, sna_output->fake_edid_mon);
22600 + return xf86DDCGetModes(output->scrn->scrnIndex,
22601 + sna_output->fake_edid_mon);
22602 +}
22604 +static DisplayModePtr
22605 sna_output_get_modes(xf86OutputPtr output)
22607 struct sna_output *sna_output = output->driver_private;
22608 - DisplayModePtr Modes = NULL, current = NULL;
22609 + DisplayModePtr Modes, current;
22610 int i;
22612 DBG(("%s(%s:%d)\n", __FUNCTION__, output->name, sna_output->id));
22613 assert(sna_output->id);
22615 + Modes = sna_output_override_edid(output);
22616 + if (Modes)
22617 + return Modes;
22619 sna_output_attach_edid(output);
22620 + sna_output_attach_tile(output);
22622 - if (output->crtc) {
22623 + current = NULL;
22624 + if (output->crtc && !sna_output->hotplug_count) {
22625 struct drm_mode_crtc mode;
22627 VG_CLEAR(mode);
22628 assert(to_sna_crtc(output->crtc));
22629 - mode.crtc_id = to_sna_crtc(output->crtc)->id;
22630 + mode.crtc_id = sna_crtc_id(output->crtc);
22632 if (drmIoctl(to_sna(output->scrn)->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode) == 0) {
22633 DBG(("%s: CRTC:%d, pipe=%d: has mode?=%d\n", __FUNCTION__,
22634 - to_sna_crtc(output->crtc)->id,
22635 - to_sna_crtc(output->crtc)->pipe,
22636 + sna_crtc_id(output->crtc),
22637 + sna_crtc_pipe(output->crtc),
22638 mode.mode_valid && mode.mode.clock));
22640 if (mode.mode_valid && mode.mode.clock) {
22641 @@ -3117,7 +4184,7 @@ sna_output_get_modes(xf86OutputPtr output)
22644 if (sna_output->add_default_modes)
22645 - Modes = sna_output_panel_edid(output, Modes);
22646 + Modes = sna_output_add_default_modes(output, Modes);
22648 return Modes;
22650 @@ -3132,6 +4199,8 @@ sna_output_destroy(xf86OutputPtr output)
22651 return;
22653 free(sna_output->edid_raw);
22654 + free(sna_output->fake_edid_raw);
22656 for (i = 0; i < sna_output->num_props; i++) {
22657 if (sna_output->props[i].kprop == NULL)
22658 continue;
22659 @@ -3155,7 +4224,7 @@ sna_output_destroy(xf86OutputPtr output)
22662 static void
22663 -sna_output_dpms(xf86OutputPtr output, int dpms)
22664 +__sna_output_dpms(xf86OutputPtr output, int dpms, int fixup)
22666 struct sna *sna = to_sna(output->scrn);
22667 struct sna_output *sna_output = output->driver_private;
22668 @@ -3182,8 +4251,9 @@ sna_output_dpms(xf86OutputPtr output, int dpms)
22669 if (sna_output->backlight.iface && dpms != DPMSModeOn) {
22670 if (old_dpms == DPMSModeOn) {
22671 sna_output->backlight_active_level = sna_output_backlight_get(output);
22672 - DBG(("%s: saving current backlight %d\n",
22673 - __FUNCTION__, sna_output->backlight_active_level));
22674 + DBG(("%s(%s:%d): saving current backlight %d\n",
22675 + __FUNCTION__, output->name, sna_output->id,
22676 + sna_output->backlight_active_level));
22678 sna_output->dpms_mode = dpms;
22679 sna_output_backlight_off(sna_output);
22680 @@ -3193,18 +4263,31 @@ sna_output_dpms(xf86OutputPtr output, int dpms)
22681 drmModeConnectorSetProperty(sna->kgem.fd,
22682 sna_output->id,
22683 sna_output->dpms_id,
22684 - dpms))
22685 - dpms = old_dpms;
22686 + dpms)) {
22687 + DBG(("%s(%s:%d): failed to set DPMS to %d (fixup? %d)\n",
22688 + __FUNCTION__, output->name, sna_output->id, dpms, fixup));
22689 + if (fixup && dpms != DPMSModeOn) {
22690 + sna_crtc_disable(output->crtc, false);
22691 + return;
22692 + }
22693 + }
22695 if (sna_output->backlight.iface && dpms == DPMSModeOn) {
22696 - DBG(("%s: restoring previous backlight %d\n",
22697 - __FUNCTION__, sna_output->backlight_active_level));
22698 + DBG(("%s(%d:%d: restoring previous backlight %d\n",
22699 + __FUNCTION__, output->name, sna_output->id,
22700 + sna_output->backlight_active_level));
22701 sna_output_backlight_on(sna_output);
22704 sna_output->dpms_mode = dpms;
22707 +static void
22708 +sna_output_dpms(xf86OutputPtr output, int dpms)
22709 +{
22710 + __sna_output_dpms(output, dpms, true);
22711 +}
22713 static bool
22714 sna_property_ignore(drmModePropertyPtr prop)
22716 @@ -3239,14 +4322,14 @@ sna_output_create_ranged_atom(xf86OutputPtr output, Atom *atom,
22717 err = RRConfigureOutputProperty(output->randr_output, *atom, FALSE,
22718 TRUE, immutable, 2, atom_range);
22719 if (err != 0)
22720 - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
22721 + xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
22722 "RRConfigureOutputProperty error, %d\n", err);
22724 err = RRChangeOutputProperty(output->randr_output, *atom, XA_INTEGER,
22725 32, PropModeReplace, 1, &value,
22726 FALSE, FALSE);
22727 if (err != 0)
22728 - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
22729 + xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
22730 "RRChangeOutputProperty error, %d\n", err);
22733 @@ -3303,7 +4386,7 @@ sna_output_create_resources(xf86OutputPtr output)
22734 p->kprop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
22735 p->num_atoms - 1, (INT32 *)&p->atoms[1]);
22736 if (err != 0) {
22737 - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
22738 + xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
22739 "RRConfigureOutputProperty error, %d\n", err);
22742 @@ -3315,7 +4398,7 @@ sna_output_create_resources(xf86OutputPtr output)
22743 XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1],
22744 FALSE, FALSE);
22745 if (err != 0) {
22746 - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
22747 + xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
22748 "RRChangeOutputProperty error, %d\n", err);
22751 @@ -3385,18 +4468,19 @@ sna_output_set_property(xf86OutputPtr output, Atom property,
22752 if (value->type != XA_INTEGER || value->format != 32 ||
22753 value->size != 1)
22754 return FALSE;
22755 - val = *(uint32_t *)value->data;
22757 + val = *(uint32_t *)value->data;
22758 drmModeConnectorSetProperty(sna->kgem.fd, sna_output->id,
22759 p->kprop->prop_id, (uint64_t)val);
22760 return TRUE;
22761 } else if (p->kprop->flags & DRM_MODE_PROP_ENUM) {
22762 - Atom atom;
22763 - const char *name;
22764 - int j;
22765 + Atom atom;
22766 + const char *name;
22767 + int j;
22769 if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
22770 return FALSE;
22772 memcpy(&atom, value->data, 4);
22773 name = NameForAtom(atom);
22774 if (name == NULL)
22775 @@ -3425,7 +4509,7 @@ static Bool
22776 sna_output_get_property(xf86OutputPtr output, Atom property)
22778 struct sna_output *sna_output = output->driver_private;
22779 - int err;
22780 + int err, i, j;
22782 if (property == backlight_atom || property == backlight_deprecated_atom) {
22783 INT32 val;
22784 @@ -3449,7 +4533,7 @@ sna_output_get_property(xf86OutputPtr output, Atom property)
22785 XA_INTEGER, 32, PropModeReplace, 1, &val,
22786 FALSE, FALSE);
22787 if (err != 0) {
22788 - xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
22789 + xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
22790 "RRChangeOutputProperty error, %d\n", err);
22791 return FALSE;
22793 @@ -3457,6 +4541,40 @@ sna_output_get_property(xf86OutputPtr output, Atom property)
22794 return TRUE;
22797 + for (i = 0; i < sna_output->num_props; i++) {
22798 + struct sna_property *p = &sna_output->props[i];
22800 + if (p->atoms == NULL || p->atoms[0] != property)
22801 + continue;
22803 + if (sna_output->update_properties && output->scrn->vtSema)
22804 + update_properties(to_sna(output->scrn), sna_output);
22806 + err = 0;
22807 + if (p->kprop->flags & DRM_MODE_PROP_RANGE) {
22808 + err = RRChangeOutputProperty(output->randr_output,
22809 + property, XA_INTEGER, 32,
22810 + PropModeReplace, 1,
22811 + &sna_output->prop_values[i],
22812 + FALSE, FALSE);
22813 + } else if (p->kprop->flags & DRM_MODE_PROP_ENUM) {
22814 + for (j = 0; j < p->kprop->count_enums; j++) {
22815 + if (p->kprop->enums[j].value == sna_output->prop_values[i])
22816 + break;
22817 + }
22818 + err = RRChangeOutputProperty(output->randr_output,
22819 + property, XA_ATOM, 32,
22820 + PropModeReplace, 1,
22821 + &p->atoms[j+1],
22822 + FALSE, FALSE);
22823 + }
22825 + if (err != 0)
22826 + xf86DrvMsg(output->scrn->scrnIndex, X_WARNING,
22827 + "RRChangeOutputProperty error, %d\n", err);
22828 + return TRUE;
22829 + }
22831 return FALSE;
22834 @@ -3500,47 +4618,11 @@ static const char * const output_names[] = {
22835 /* DRM_MODE_CONNECTOR_TV */ "TV",
22836 /* DRM_MODE_CONNECTOR_eDP */ "eDP",
22837 /* DRM_MODE_CONNECTOR_VIRTUAL */ "Virtual",
22838 - /* DRM_MODE_CONNECTOR_DSI */ "DSI"
22839 + /* DRM_MODE_CONNECTOR_DSI */ "DSI",
22840 + /* DRM_MODE_CONNECTOR_DPI */ "DPI"
22841 };
22843 static bool
22844 -sna_zaphod_match(const char *s, const char *output)
22845 -{
22846 - char t[20];
22847 - unsigned int i = 0;
22849 - do {
22850 - /* match any outputs in a comma list, stopping at whitespace */
22851 - switch (*s) {
22852 - case '\0':
22853 - t[i] = '\0';
22854 - return strcmp(t, output) == 0;
22856 - case ',':
22857 - t[i] ='\0';
22858 - if (strcmp(t, output) == 0)
22859 - return TRUE;
22860 - i = 0;
22861 - break;
22863 - case ' ':
22864 - case '\t':
22865 - case '\n':
22866 - case '\r':
22867 - break;
22869 - default:
22870 - t[i++] = *s;
22871 - break;
22872 - }
22874 - s++;
22875 - } while (i < sizeof(t));
22877 - return false;
22878 -}
22880 -static bool
22881 output_ignored(ScrnInfoPtr scrn, const char *name)
22883 char monitor_name[64];
22884 @@ -3572,14 +4654,21 @@ gather_encoders(struct sna *sna, uint32_t id, int count,
22885 struct drm_mode_get_encoder enc;
22886 uint32_t *ids = NULL;
22888 + DBG(("%s(%d): expected count=%d\n", __FUNCTION__, id, count));
22890 VG_CLEAR(compat_conn);
22891 + VG_CLEAR(enc);
22892 memset(out, 0, sizeof(*out));
22894 do {
22895 - free(ids);
22896 - ids = malloc(sizeof(*ids) * count);
22897 - if (ids == 0)
22898 + uint32_t *nids;
22900 + nids = realloc(ids, sizeof(*ids) * count);
22901 + if (nids == NULL) {
22902 + free(ids);
22903 return false;
22904 + }
22905 + ids = nids;
22907 compat_conn.conn.connector_id = id;
22908 compat_conn.conn.count_props = 0;
22909 @@ -3593,12 +4682,14 @@ gather_encoders(struct sna *sna, uint32_t id, int count,
22910 compat_conn.conn.count_encoders = count = 0;
22913 + VG(VALGRIND_MAKE_MEM_DEFINED(ids, sizeof(uint32_t)*compat_conn.conn.count_encoders));
22914 if (count == compat_conn.conn.count_encoders)
22915 break;
22917 count = compat_conn.conn.count_encoders;
22918 } while (1);
22920 + DBG(("%s(%d): gathering %d encoders\n", __FUNCTION__, id, count));
22921 for (count = 0; count < compat_conn.conn.count_encoders; count++) {
22922 enc.encoder_id = ids[count];
22923 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETENCODER, &enc)) {
22924 @@ -3606,6 +4697,8 @@ gather_encoders(struct sna *sna, uint32_t id, int count,
22925 count = 0;
22926 break;
22928 + DBG(("%s(%d): encoder=%d, possible_crtcs=%x, possible_clones=%x\n",
22929 + __FUNCTION__, id, enc.encoder_id, enc.possible_crtcs, enc.possible_clones));
22930 out->possible_crtcs |= enc.possible_crtcs;
22931 out->possible_clones |= enc.possible_clones;
22933 @@ -3731,6 +4824,116 @@ static int name_from_path(struct sna *sna,
22934 return 0;
22937 +static char *fake_edid_name(xf86OutputPtr output)
22938 +{
22939 + struct sna *sna = to_sna(output->scrn);
22940 + const char *str, *colon;
22942 +#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
22943 + str = xf86GetOptValString(sna->Options, OPTION_EDID);
22944 +#else
22945 + str = NULL;
22946 +#endif
22947 + if (str == NULL)
22948 + return NULL;
22950 + do {
22951 + colon = strchr(str, ':');
22952 + if (colon == NULL)
22953 + return NULL;
22955 + if (strncmp(str, output->name, colon-str) == 0 &&
22956 + output->name[colon-str] == '\0') {
22957 + char *path;
22958 + int len;
22960 + str = colon + 1;
22961 + colon = strchr(str, ',');
22962 + if (colon)
22963 + len = colon - str;
22964 + else
22965 + len = strlen(str);
22967 + path = malloc(len + 1);
22968 + if (path == NULL)
22969 + return NULL;
22971 + memcpy(path, str, len);
22972 + path[len] = '\0';
22973 + return path;
22974 + }
22976 + str = strchr(colon + 1, ',');
22977 + if (str == NULL)
22978 + return NULL;
22980 + str++;
22981 + } while (1);
22982 +}
22984 +static void
22985 +sna_output_load_fake_edid(xf86OutputPtr output)
22986 +{
22987 + struct sna_output *sna_output = output->driver_private;
22988 + const char *filename;
22989 + FILE *file;
22990 + void *raw;
22991 + int size;
22992 + xf86MonPtr mon;
22994 + filename = fake_edid_name(output);
22995 + if (filename == NULL)
22996 + return;
22998 + file = fopen(filename, "rb");
22999 + if (file == NULL)
23000 + goto err;
23002 + fseek(file, 0, SEEK_END);
23003 + size = ftell(file);
23004 + if (size % 128) {
23005 + fclose(file);
23006 + goto err;
23007 + }
23009 + raw = malloc(size);
23010 + if (raw == NULL) {
23011 + fclose(file);
23012 + free(raw);
23013 + goto err;
23014 + }
23016 + fseek(file, 0, SEEK_SET);
23017 + if (fread(raw, size, 1, file) != 1) {
23018 + fclose(file);
23019 + free(raw);
23020 + goto err;
23021 + }
23022 + fclose(file);
23024 + mon = xf86InterpretEDID(output->scrn->scrnIndex, raw);
23025 + if (mon == NULL) {
23026 + free(raw);
23027 + goto err;
23028 + }
23030 + if (mon && size > 128)
23031 + mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
23033 + sna_output->fake_edid_mon = mon;
23034 + sna_output->fake_edid_raw = raw;
23036 + xf86DrvMsg(output->scrn->scrnIndex, X_CONFIG,
23037 + "Loading EDID from \"%s\" for output %s\n",
23038 + filename, output->name);
23039 + return;
23041 +err:
23042 + xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
23043 + "Could not read EDID file \"%s\" for output %s\n",
23044 + filename, output->name);
23045 +}
23047 static int
23048 sna_output_add(struct sna *sna, unsigned id, unsigned serial)
23050 @@ -3765,6 +4968,7 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
23051 return -1;
23053 assert(compat_conn.conn.connector_id == id);
23054 + DBG(("%s(%d): has %d associated encoders\n", __FUNCTION__, id, compat_conn.conn.count_encoders));
23056 if (compat_conn.conn.connector_type < ARRAY_SIZE(output_names))
23057 output_name = output_names[compat_conn.conn.connector_type];
23058 @@ -3813,34 +5017,43 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
23061 if (is_zaphod(scrn)) {
23062 - const char *str;
23063 + unsigned zaphod_crtcs;
23065 - str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
23066 - if (str && !sna_zaphod_match(str, name)) {
23067 - DBG(("%s: zaphod mismatch, want %s, have %s\n", __FUNCTION__, str, name));
23068 + if (!sna_zaphod_match(sna, name)) {
23069 + DBG(("%s: zaphod mismatch, want %s, have %s\n",
23070 + __FUNCTION__,
23071 + xf86GetOptValString(sna->Options, OPTION_ZAPHOD) ?: "???",
23072 + name));
23073 return 0;
23076 - if ((possible_crtcs & (1 << scrn->confScreen->device->screen)) == 0) {
23077 - if (str) {
23078 - xf86DrvMsg(scrn->scrnIndex, X_ERROR,
23079 - "%s is an invalid output for screen (pipe) %d\n",
23080 - name, scrn->confScreen->device->screen);
23081 - return -1;
23082 - } else
23083 - return 0;
23084 + zaphod_crtcs = get_zaphod_crtcs(sna);
23085 + possible_crtcs &= zaphod_crtcs;
23086 + if (possible_crtcs == 0) {
23087 + xf86DrvMsg(scrn->scrnIndex, X_ERROR,
23088 + "%s is an invalid output for screen %d\n",
23089 + name, scrn->confScreen->device->screen);
23090 + return -1;
23093 - possible_crtcs = 1;
23094 + possible_crtcs >>= ffs(zaphod_crtcs) - 1;
23097 sna_output = calloc(sizeof(struct sna_output), 1);
23098 if (!sna_output)
23099 return -1;
23101 + sna_output->connector_type = compat_conn.conn.connector_type;
23102 + sna_output->connector_type_id = compat_conn.conn.connector_type_id;
23103 sna_output->num_props = compat_conn.conn.count_props;
23104 sna_output->prop_ids = malloc(sizeof(uint32_t)*compat_conn.conn.count_props);
23105 sna_output->prop_values = malloc(sizeof(uint64_t)*compat_conn.conn.count_props);
23106 + if (sna_output->prop_ids == NULL || sna_output->prop_values == NULL) {
23107 + free(sna_output->prop_ids);
23108 + free(sna_output->prop_values);
23109 + free(sna_output);
23110 + return -1;
23111 + }
23113 compat_conn.conn.count_encoders = 0;
23115 @@ -3865,16 +5078,16 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
23116 /* Construct name from topology, and recheck if output is acceptable */
23117 path = name_from_path(sna, sna_output, name);
23118 if (path) {
23119 - const char *str;
23121 if (output_ignored(scrn, name)) {
23122 len = 0;
23123 goto skip;
23126 - str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
23127 - if (str && !sna_zaphod_match(str, name)) {
23128 - DBG(("%s: zaphod mismatch, want %s, have %s\n", __FUNCTION__, str, name));
23129 + if (is_zaphod(scrn) && !sna_zaphod_match(sna, name)) {
23130 + DBG(("%s: zaphod mismatch, want %s, have %s\n",
23131 + __FUNCTION__,
23132 + xf86GetOptValString(sna->Options, OPTION_ZAPHOD) ?: "???",
23133 + name));
23134 len = 0;
23135 goto skip;
23137 @@ -3889,7 +5102,6 @@ sna_output_add(struct sna *sna, unsigned id, unsigned serial)
23138 if (strcmp(output->name, name) == 0) {
23139 assert(output->scrn == scrn);
23140 assert(output->funcs == &sna_output_funcs);
23141 - assert(to_sna_output(output)->id == 0);
23142 sna_output_destroy(output);
23143 goto reset;
23145 @@ -3935,6 +5147,8 @@ reset:
23146 sna_output->id = compat_conn.conn.connector_id;
23147 sna_output->is_panel = is_panel(compat_conn.conn.connector_type);
23148 sna_output->edid_idx = find_property(sna, sna_output, "EDID");
23149 + sna_output->link_status_idx =
23150 + find_property(sna, sna_output, "link-status");
23151 if (find_property(sna, sna_output, "scaling mode") != -1)
23152 sna_output->add_default_modes =
23153 xf86ReturnOptValBool(output->options, OPTION_DEFAULT_MODES, TRUE);
23154 @@ -3945,10 +5159,8 @@ reset:
23155 sna_output->dpms_mode = sna_output->prop_values[i];
23156 DBG(("%s: found 'DPMS' (idx=%d, id=%d), initial value=%d\n",
23157 __FUNCTION__, i, sna_output->dpms_id, sna_output->dpms_mode));
23158 - } else {
23159 - sna_output->dpms_id = -1;
23160 + } else
23161 sna_output->dpms_mode = DPMSModeOff;
23162 - }
23164 sna_output->possible_encoders = possible_encoders;
23165 sna_output->attached_encoders = attached_encoders;
23166 @@ -3963,12 +5175,13 @@ reset:
23167 sna_output->base = output;
23169 backlight_init(&sna_output->backlight);
23170 - if (sna_output->is_panel)
23171 - sna_output_backlight_init(output);
23172 + sna_output_backlight_init(output);
23174 output->possible_crtcs = possible_crtcs & count_to_mask(sna->mode.num_real_crtc);
23175 output->interlaceAllowed = TRUE;
23177 + sna_output_load_fake_edid(output);
23179 if (serial) {
23180 if (output->randr_output == NULL) {
23181 output->randr_output = RROutputCreate(xf86ScrnToScreen(scrn), name, len, output);
23182 @@ -3976,6 +5189,7 @@ reset:
23183 goto cleanup;
23186 + RROutputChanged(output->randr_output, TRUE);
23187 sna_output_create_resources(output);
23188 RRPostPendingProperties(output->randr_output);
23190 @@ -4009,38 +5223,6 @@ skip:
23191 return len;
23194 -static void sna_output_del(xf86OutputPtr output)
23195 -{
23196 - ScrnInfoPtr scrn = output->scrn;
23197 - xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
23198 - int i;
23200 - DBG(("%s(%s)\n", __FUNCTION__, output->name));
23201 - assert(to_sna_output(output));
23203 - RROutputDestroy(output->randr_output);
23204 - sna_output_destroy(output);
23206 - while (output->probed_modes)
23207 - xf86DeleteMode(&output->probed_modes, output->probed_modes);
23209 - free(output);
23211 - for (i = 0; i < config->num_output; i++)
23212 - if (config->output[i] == output)
23213 - break;
23214 - assert(i < to_sna(scrn)->mode.num_real_output);
23215 - DBG(("%s: removing output #%d of %d\n",
23216 - __FUNCTION__, i, to_sna(scrn)->mode.num_real_output));
23218 - for (; i < config->num_output; i++) {
23219 - config->output[i] = config->output[i+1];
23220 - config->output[i]->possible_clones >>= 1;
23221 - }
23222 - config->num_output--;
23223 - to_sna(scrn)->mode.num_real_output--;
23224 -}
23226 static int output_rank(const void *A, const void *B)
23228 const xf86OutputPtr *a = A;
23229 @@ -4058,6 +5240,7 @@ static void sort_config_outputs(struct sna *sna)
23231 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
23232 qsort(config->output, sna->mode.num_real_output, sizeof(*config->output), output_rank);
23233 + config->compat_output = 0; /* make sure it is a sane value */
23234 sna_mode_compute_possible_outputs(sna);
23237 @@ -4080,11 +5263,15 @@ static bool disable_unused_crtc(struct sna *sna)
23238 bool update = false;
23239 int o, c;
23241 + DBG(("%s\n", __FUNCTION__));
23243 for (c = 0; c < sna->mode.num_real_crtc; c++) {
23244 xf86CrtcPtr crtc = config->crtc[c];
23246 - if (!crtc->enabled)
23247 + if (!crtc->enabled) {
23248 + sna_crtc_disable(crtc, false);
23249 continue;
23250 + }
23252 for (o = 0; o < sna->mode.num_real_output; o++) {
23253 xf86OutputPtr output = config->output[o];
23254 @@ -4094,7 +5281,7 @@ static bool disable_unused_crtc(struct sna *sna)
23256 if (o == sna->mode.num_real_output) {
23257 DBG(("%s: CRTC:%d was enabled with no outputs\n",
23258 - __FUNCTION__, to_sna_crtc(crtc)->id));
23259 + __FUNCTION__, sna_crtc_id(crtc)));
23260 crtc->enabled = false;
23261 update = true;
23263 @@ -4108,17 +5295,145 @@ static bool disable_unused_crtc(struct sna *sna)
23264 return update;
23267 -void sna_mode_discover(struct sna *sna)
23268 +bool sna_mode_find_hotplug_connector(struct sna *sna, unsigned id)
23269 +{
23270 + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
23271 + int i;
23273 + for (i = 0; i < sna->mode.num_real_output; i++) {
23274 + struct sna_output *output = to_sna_output(config->output[i]);
23275 + if (output->id == id) {
23276 + output->reprobe = true;
23277 + return true;
23278 + }
23279 + }
23281 + return false;
23282 +}
23284 +static bool
23285 +output_retrain_link(struct sna *sna, struct sna_output *output)
23286 +{
23287 + struct sna_crtc *crtc = to_sna_crtc(output->base->crtc);
23288 + int crtc_x = crtc->offset & 0xffff;
23289 + int crtc_y = crtc->offset >> 16;
23291 + return sna_crtc_flip(sna, crtc, crtc->bo, crtc_x, crtc_y);
23292 +}
23294 +static bool
23295 +output_check_link(struct sna *sna, struct sna_output *output)
23296 +{
23297 + uint64_t link_status;
23299 + if (!output->base->crtc)
23300 + return true;
23302 + if (output->link_status_idx == -1)
23303 + return true;
23305 +#define LINK_STATUS_GOOD 0
23306 + link_status = output->prop_values[output->link_status_idx];
23307 + DBG(("%s: link_status=%d\n", __FUNCTION__, link_status));
23308 + if (link_status == LINK_STATUS_GOOD)
23309 + return true;
23311 + /* Perform a modeset as required for "link-status" = BAD */
23312 + if (!output_retrain_link(sna, output))
23313 + return false;
23315 + /* Query the "link-status" again to confirm the modeset */
23316 + update_properties(sna, output);
23318 + link_status = output->prop_values[output->link_status_idx];
23319 + DBG(("%s: link_status=%d after modeset\n", __FUNCTION__, link_status));
23320 + return link_status == LINK_STATUS_GOOD;
23321 +}
23323 +static bool
23324 +output_check_status(struct sna *sna, struct sna_output *output)
23325 +{
23326 + union compat_mode_get_connector compat_conn;
23327 + struct drm_mode_modeinfo dummy;
23328 + struct drm_mode_get_blob blob;
23329 + xf86OutputStatus status;
23330 + char *edid;
23332 + VG_CLEAR(compat_conn);
23334 + compat_conn.conn.connection = -1;
23335 + compat_conn.conn.connector_id = output->id;
23336 + compat_conn.conn.count_modes = 1; /* skip detect */
23337 + compat_conn.conn.modes_ptr = (uintptr_t)&dummy;
23338 + compat_conn.conn.count_encoders = 0;
23339 + compat_conn.conn.props_ptr = (uintptr_t)output->prop_ids;
23340 + compat_conn.conn.prop_values_ptr = (uintptr_t)output->prop_values;
23341 + compat_conn.conn.count_props = output->num_props;
23343 + if (drmIoctl(sna->kgem.fd,
23344 + DRM_IOCTL_MODE_GETCONNECTOR,
23345 + &compat_conn.conn) == 0)
23346 + output->update_properties = false;
23348 + if (!output_check_link(sna, output))
23349 + return false;
23351 + if (output->reprobe)
23352 + return false;
23354 + switch (compat_conn.conn.connection) {
23355 + case DRM_MODE_CONNECTED:
23356 + status = XF86OutputStatusConnected;
23357 + break;
23358 + case DRM_MODE_DISCONNECTED:
23359 + status = XF86OutputStatusDisconnected;
23360 + break;
23361 + default:
23362 + case DRM_MODE_UNKNOWNCONNECTION:
23363 + status = XF86OutputStatusUnknown;
23364 + break;
23365 + }
23366 + if (output->status != status)
23367 + return false;
23369 + if (status != XF86OutputStatusConnected)
23370 + return true;
23372 + if (output->num_modes != compat_conn.conn.count_modes)
23373 + return false;
23375 + if (output->edid_len == 0)
23376 + return false;
23378 + edid = alloca(output->edid_len);
23380 + VG_CLEAR(blob);
23381 + blob.blob_id = output->prop_values[output->edid_idx];
23382 + blob.length = output->edid_len;
23383 + blob.data = (uintptr_t)edid;
23384 + if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob))
23385 + return false;
23387 + if (blob.length != output->edid_len)
23388 + return false;
23390 + return memcmp(edid, output->edid_raw, output->edid_len) == 0;
23391 +}
23393 +void sna_mode_discover(struct sna *sna, bool tell)
23395 ScreenPtr screen = xf86ScrnToScreen(sna->scrn);
23396 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
23397 + bool force = sna->flags & SNA_REPROBE;
23398 struct drm_mode_card_res res;
23399 - uint32_t connectors[32];
23400 + uint32_t connectors[32], now;
23401 unsigned changed = 0;
23402 unsigned serial;
23403 int i, j;
23405 DBG(("%s()\n", __FUNCTION__));
23406 + sna->flags &= ~SNA_REPROBE;
23408 VG_CLEAR(connectors);
23410 memset(&res, 0, sizeof(res));
23411 @@ -4128,10 +5443,11 @@ void sna_mode_discover(struct sna *sna)
23412 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
23413 return;
23415 - DBG(("%s: now %d (was %d) connectors\n", __FUNCTION__,
23416 - res.count_connectors, sna->mode.num_real_output));
23417 + DBG(("%s: now %d (was %d) connectors, %d encoders, %d crtc\n", __FUNCTION__,
23418 + res.count_connectors, sna->mode.num_real_output,
23419 + res.count_encoders, res.count_crtcs));
23420 if (res.count_connectors > 32)
23421 - return;
23422 + res.count_connectors = 32;
23424 assert(sna->mode.num_real_crtc == res.count_crtcs || is_zaphod(sna->scrn));
23425 assert(sna->mode.max_crtc_width == res.max_width);
23426 @@ -4142,6 +5458,11 @@ void sna_mode_discover(struct sna *sna)
23427 if (serial == 0)
23428 serial = ++sna->mode.serial;
23430 + if (force) {
23431 + changed = 4;
23432 + now = 0;
23433 + } else
23434 + now = GetTimeInMillis();
23435 for (i = 0; i < res.count_connectors; i++) {
23436 DBG(("%s: connector[%d] = %d\n", __FUNCTION__, i, connectors[i]));
23437 for (j = 0; j < sna->mode.num_real_output; j++) {
23438 @@ -4161,32 +5482,42 @@ void sna_mode_discover(struct sna *sna)
23440 for (i = 0; i < sna->mode.num_real_output; i++) {
23441 xf86OutputPtr output = config->output[i];
23442 + struct sna_output *sna_output = to_sna_output(output);
23444 - if (to_sna_output(output)->id == 0)
23445 + if (sna_output->id == 0)
23446 continue;
23448 - if (to_sna_output(output)->serial == serial)
23449 + if (sna_output->serial == serial) {
23450 + if (output_check_status(sna, sna_output)) {
23451 + DBG(("%s: output %s (id=%d), retained state\n",
23452 + __FUNCTION__, output->name, sna_output->id));
23453 + sna_output->last_detect = now;
23454 + } else {
23455 + DBG(("%s: output %s (id=%d), changed state, reprobing\n",
23456 + __FUNCTION__, output->name, sna_output->id));
23457 + sna_output->hotplug_count++;
23458 + sna_output->last_detect = 0;
23459 + changed |= 4;
23460 + }
23461 continue;
23462 + }
23464 DBG(("%s: removing output %s (id=%d), serial=%u [now %u]\n",
23465 - __FUNCTION__, output->name, to_sna_output(output)->id,
23466 - to_sna_output(output)->serial, serial));
23467 + __FUNCTION__, output->name, sna_output->id,
23468 + sna_output->serial, serial));
23470 xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
23471 - "%s output %s\n",
23472 - sna->flags & SNA_REMOVE_OUTPUTS ? "Removed" : "Disabled",
23473 + "Disabled output %s\n",
23474 output->name);
23475 - if (sna->flags & SNA_REMOVE_OUTPUTS) {
23476 - sna_output_del(output);
23477 - i--;
23478 - } else {
23479 - to_sna_output(output)->id = 0;
23480 - output->crtc = NULL;
23481 - }
23482 + sna_output->id = 0;
23483 + sna_output->last_detect = 0;
23484 + output->crtc = NULL;
23485 + RROutputChanged(output->randr_output, TRUE);
23486 changed |= 2;
23489 - if (changed) {
23490 + /* Have the list of available outputs been updated? */
23491 + if (changed & 3) {
23492 DBG(("%s: outputs changed, broadcasting\n", __FUNCTION__));
23494 sna_mode_set_primary(sna);
23495 @@ -4200,6 +5531,51 @@ void sna_mode_discover(struct sna *sna)
23497 xf86RandR12TellChanged(screen);
23500 + /* If anything has changed, refresh the RandR information.
23501 + * Note this could recurse once from udevless RRGetInfo() probes,
23502 + * but only once.
23503 + */
23504 + if (changed && tell)
23505 + RRGetInfo(screen, TRUE);
23506 +}
23508 +/* Since we only probe the current mode on startup, we may not have the full
23509 + * list of modes available until the user explicitly requests them. Fake a
23510 + * hotplug event after a second after starting to fill in any missing modes.
23511 + */
23512 +static CARD32 sna_mode_coldplug(OsTimerPtr timer, CARD32 now, void *data)
23513 +{
23514 + struct sna *sna = data;
23515 + ScreenPtr screen = xf86ScrnToScreen(sna->scrn);
23516 + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
23517 + bool reprobe = false;
23518 + int i;
23520 + DBG(("%s()\n", __FUNCTION__));
23522 + for (i = 0; i < sna->mode.num_real_output; i++) {
23523 + xf86OutputPtr output = config->output[i];
23524 + struct sna_output *sna_output = to_sna_output(output);
23526 + if (sna_output->id == 0)
23527 + continue;
23528 + if (sna_output->last_detect)
23529 + continue;
23530 + if (output->status == XF86OutputStatusDisconnected)
23531 + continue;
23533 + DBG(("%s: output %s connected, needs reprobe\n",
23534 + __FUNCTION__, output->name));
23535 + reprobe = true;
23536 + }
23538 + if (reprobe) {
23539 + RRGetInfo(screen, TRUE);
23540 + RRTellChanged(screen);
23541 + }
23542 + free(timer);
23543 + return 0;
23546 static void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new)
23547 @@ -4208,7 +5584,7 @@ static void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new)
23549 DBG(("%s\n", __FUNCTION__));
23551 - if (wedged(sna))
23552 + if (wedged(sna) || isGPU(sna->scrn))
23553 return;
23555 old_priv = sna_pixmap_force_to_gpu(old, MOVE_READ);
23556 @@ -4220,12 +5596,19 @@ static void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new)
23557 return;
23559 if (old_priv->clear) {
23560 - (void)sna->render.fill_one(sna, new, new_priv->gpu_bo,
23561 - old_priv->clear_color,
23562 - 0, 0,
23563 - new->drawable.width,
23564 - new->drawable.height,
23565 - GXcopy);
23566 + bool ok = false;
23567 + if (!wedged(sna))
23568 + ok = sna->render.fill_one(sna, new, new_priv->gpu_bo,
23569 + old_priv->clear_color,
23570 + 0, 0,
23571 + new->drawable.width,
23572 + new->drawable.height,
23573 + GXcopy);
23574 + if (!ok) {
23575 + void *ptr = kgem_bo_map__gtt(&sna->kgem, new_priv->gpu_bo);
23576 + if (ptr)
23577 + memset(ptr, 0, new_priv->gpu_bo->pitch*new->drawable.height);
23578 + }
23579 new_priv->clear = true;
23580 new_priv->clear_color = old_priv->clear_color;
23581 } else {
23582 @@ -4281,11 +5664,18 @@ static void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new)
23583 __FUNCTION__, box.x2, box.y2, sx, sy, dx, dy));
23585 if (box.x2 != new->drawable.width || box.y2 != new->drawable.height) {
23586 - (void)sna->render.fill_one(sna, new, new_priv->gpu_bo, 0,
23587 - 0, 0,
23588 - new->drawable.width,
23589 - new->drawable.height,
23590 - GXclear);
23591 + bool ok = false;
23592 + if (!wedged(sna))
23593 + ok = sna->render.fill_one(sna, new, new_priv->gpu_bo, 0,
23594 + 0, 0,
23595 + new->drawable.width,
23596 + new->drawable.height,
23597 + GXclear);
23598 + if (!ok) {
23599 + void *ptr = kgem_bo_map__gtt(&sna->kgem, new_priv->gpu_bo);
23600 + if (ptr)
23601 + memset(ptr, 0, new_priv->gpu_bo->pitch*new->drawable.height);
23602 + }
23604 (void)sna->render.copy_boxes(sna, GXcopy,
23605 &old->drawable, old_priv->gpu_bo, sx, sy,
23606 @@ -4302,7 +5692,7 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
23608 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
23609 struct sna *sna = to_sna(scrn);
23610 - ScreenPtr screen = scrn->pScreen;
23611 + ScreenPtr screen = xf86ScrnToScreen(scrn);
23612 PixmapPtr new_front;
23613 int i;
23615 @@ -4337,9 +5727,20 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
23616 for (i = 0; i < sna->mode.num_real_crtc; i++)
23617 sna_crtc_disable_shadow(sna, to_sna_crtc(config->crtc[i]));
23618 assert(sna->mode.shadow_active == 0);
23619 + assert(!sna->mode.shadow_enabled);
23620 assert(sna->mode.shadow_damage == NULL);
23621 assert(sna->mode.shadow == NULL);
23623 + /* Flush pending shadow updates */
23624 + if (sna->mode.flip_active) {
23625 + DBG(("%s: waiting for %d outstanding TearFree flips\n",
23626 + __FUNCTION__, sna->mode.flip_active));
23627 + while (sna->mode.flip_active && sna_mode_wait_for_event(sna))
23628 + sna_mode_wakeup(sna);
23629 + }
23631 + /* Cancel a pending [un]flip (as the pixmaps no longer match) */
23632 + sna_present_cancel_flip(sna);
23633 copy_front(sna, sna->front, new_front);
23635 screen->SetScreenPixmap(new_front);
23636 @@ -4351,14 +5752,6 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
23637 scrn->virtualY = height;
23638 scrn->displayWidth = width;
23640 - /* Flush pending shadow updates */
23641 - if (sna->mode.flip_active) {
23642 - DBG(("%s: waiting for %d outstanding TearFree flips\n",
23643 - __FUNCTION__, sna->mode.flip_active));
23644 - while (sna->mode.flip_active && sna_mode_wait_for_event(sna))
23645 - sna_mode_wakeup(sna);
23646 - }
23648 /* Only update the CRTCs if we are in control */
23649 if (!scrn->vtSema)
23650 return TRUE;
23651 @@ -4371,7 +5764,7 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
23652 continue;
23654 if (!__sna_crtc_set_mode(crtc))
23655 - sna_crtc_disable(crtc);
23656 + sna_crtc_disable(crtc, false);
23659 sna_mode_wakeup(sna);
23660 @@ -4381,19 +5774,6 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
23663 /* cursor handling */
23664 -struct sna_cursor {
23665 - struct sna_cursor *next;
23666 - uint32_t *image;
23667 - Rotation rotation;
23668 - int ref;
23669 - int size;
23670 - int last_width;
23671 - int last_height;
23672 - unsigned handle;
23673 - unsigned serial;
23674 - unsigned alloc;
23675 -};
23677 static void
23678 rotate_coord(Rotation rotation, int size,
23679 int x_dst, int y_dst,
23680 @@ -4429,36 +5809,6 @@ rotate_coord(Rotation rotation, int size,
23681 *y_src = y_dst;
23684 -static void
23685 -rotate_coord_back(Rotation rotation, int size, int *x, int *y)
23686 -{
23687 - int t;
23689 - if (rotation & RR_Reflect_X)
23690 - *x = size - *x - 1;
23691 - if (rotation & RR_Reflect_Y)
23692 - *y = size - *y - 1;
23694 - switch (rotation & 0xf) {
23695 - case RR_Rotate_0:
23696 - break;
23697 - case RR_Rotate_90:
23698 - t = *x;
23699 - *x = *y;
23700 - *y = size - t - 1;
23701 - break;
23702 - case RR_Rotate_180:
23703 - *x = size - *x - 1;
23704 - *y = size - *y - 1;
23705 - break;
23706 - case RR_Rotate_270:
23707 - t = *x;
23708 - *x = size - *y - 1;
23709 - *y = t;
23710 - break;
23711 - }
23712 -}
23714 static struct sna_cursor *__sna_create_cursor(struct sna *sna, int size)
23716 struct sna_cursor *c;
23717 @@ -4519,6 +5869,17 @@ static uint32_t *get_cursor_argb(CursorPtr c)
23718 #endif
23721 +static int __cursor_size(int width, int height)
23722 +{
23723 + int i, size;
23725 + i = MAX(width, height);
23726 + for (size = 64; size < i; size <<= 1)
23727 + ;
23729 + return size;
23730 +}
23732 static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
23734 struct sna_cursor *cursor;
23735 @@ -4526,6 +5887,7 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
23736 const uint32_t *argb;
23737 uint32_t *image;
23738 int width, height, pitch, size, x, y;
23739 + bool transformed;
23740 Rotation rotation;
23742 assert(sna->cursor.ref);
23743 @@ -4537,8 +5899,8 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
23744 cursor ? cursor->serial : 0,
23745 sna->cursor.serial));
23746 if (cursor && cursor->serial == sna->cursor.serial) {
23747 - assert(cursor->size == sna->cursor.size);
23748 - assert(cursor->rotation == crtc->transform_in_use ? crtc->rotation : RR_Rotate_0);
23749 + assert(cursor->size == sna->cursor.size || cursor->transformed);
23750 + assert(cursor->rotation == (!to_sna_crtc(crtc)->cursor_transform && crtc->transform_in_use) ? crtc->rotation : RR_Rotate_0);
23751 assert(cursor->ref);
23752 return cursor;
23754 @@ -4550,22 +5912,81 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
23755 sna->cursor.serial,
23756 get_cursor_argb(sna->cursor.ref) != NULL));
23758 - rotation = crtc->transform_in_use ? crtc->rotation : RR_Rotate_0;
23759 + transformed = to_sna_crtc(crtc)->cursor_transform;
23760 + rotation = (!transformed && crtc->transform_in_use) ? crtc->rotation : RR_Rotate_0;
23762 + if (transformed) {
23763 + struct pixman_box16 box;
23765 + box.x1 = box.y1 = 0;
23766 + box.x2 = sna->cursor.ref->bits->width;
23767 + box.y2 = sna->cursor.ref->bits->height;
23769 - if (sna->cursor.use_gtt) { /* Don't allow phys cursor sharing */
23770 + pixman_f_transform_bounds(&crtc->f_crtc_to_framebuffer, &box);
23771 + size = __cursor_size(box.x2 - box.x1, box.y2 - box.y1);
23772 + __DBG(("%s: transformed cursor %dx%d -> %dx%d\n",
23773 + __FUNCTION__ ,
23774 + sna->cursor.ref->bits->width,
23775 + sna->cursor.ref->bits->height,
23776 + box.x2 - box.x1, box.y2 - box.y1));
23777 + } else
23778 + size = sna->cursor.size;
23780 + if (crtc->transform_in_use) {
23781 + RRTransformPtr T = NULL;
23782 + struct pixman_vector v;
23784 + if (crtc->transformPresent) {
23785 + T = &crtc->transform;
23787 + /* Cancel any translation from this affine
23788 + * transformation. We just want to rotate and scale
23789 + * the cursor image.
23790 + */
23791 + v.vector[0] = 0;
23792 + v.vector[1] = 0;
23793 + v.vector[2] = pixman_fixed_1;
23794 + pixman_transform_point(&crtc->transform.transform, &v);
23795 + }
23797 + RRTransformCompute(0, 0, size, size, crtc->rotation, T, NULL,
23798 + &to_sna_crtc(crtc)->cursor_to_fb,
23799 + &to_sna_crtc(crtc)->fb_to_cursor);
23800 + if (T)
23801 + pixman_f_transform_translate(
23802 + &to_sna_crtc(crtc)->cursor_to_fb,
23803 + &to_sna_crtc(crtc)->fb_to_cursor,
23804 + -pixman_fixed_to_double(v.vector[0]),
23805 + -pixman_fixed_to_double(v.vector[1]));
23807 + __DBG(("%s: cursor_to_fb [%f %f %f, %f %f %f, %f %f %f]\n",
23808 + __FUNCTION__,
23809 + to_sna_crtc(crtc)->cursor_to_fb.m[0][0],
23810 + to_sna_crtc(crtc)->cursor_to_fb.m[0][1],
23811 + to_sna_crtc(crtc)->cursor_to_fb.m[0][2],
23812 + to_sna_crtc(crtc)->cursor_to_fb.m[1][0],
23813 + to_sna_crtc(crtc)->cursor_to_fb.m[1][1],
23814 + to_sna_crtc(crtc)->cursor_to_fb.m[1][2],
23815 + to_sna_crtc(crtc)->cursor_to_fb.m[2][0],
23816 + to_sna_crtc(crtc)->cursor_to_fb.m[2][1],
23817 + to_sna_crtc(crtc)->cursor_to_fb.m[2][2]));
23818 + }
23820 + /* Don't allow phys cursor sharing */
23821 + if (sna->cursor.use_gtt && !transformed) {
23822 for (cursor = sna->cursor.cursors; cursor; cursor = cursor->next) {
23823 - if (cursor->serial == sna->cursor.serial && cursor->rotation == rotation) {
23824 + if (cursor->serial == sna->cursor.serial &&
23825 + cursor->rotation == rotation &&
23826 + !cursor->transformed) {
23827 __DBG(("%s: reusing handle=%d, serial=%d, rotation=%d, size=%d\n",
23828 __FUNCTION__, cursor->handle, cursor->serial, cursor->rotation, cursor->size));
23829 assert(cursor->size == sna->cursor.size);
23830 return cursor;
23834 - cursor = to_sna_crtc(crtc)->cursor;
23837 - size = sna->cursor.size;
23838 + cursor = to_sna_crtc(crtc)->cursor;
23839 if (cursor && cursor->alloc < 4*size*size)
23840 cursor = NULL;
23842 @@ -4577,7 +5998,7 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
23846 - width = sna->cursor.ref->bits->width;
23847 + width = sna->cursor.ref->bits->width;
23848 height = sna->cursor.ref->bits->height;
23849 source = sna->cursor.ref->bits->source;
23850 mask = sna->cursor.ref->bits->mask;
23851 @@ -4585,7 +6006,7 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
23852 pitch = BitmapBytePad(width);
23854 image = cursor->image;
23855 - if (image == NULL) {
23856 + if (image == NULL || transformed) {
23857 image = sna->cursor.scratch;
23858 cursor->last_width = cursor->last_height = size;
23860 @@ -4616,6 +6037,21 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
23861 mask += pitch;
23862 source += pitch;
23864 + if (transformed) {
23865 + __DBG(("%s: Applying affine BLT to bitmap\n", __FUNCTION__));
23866 + affine_blt(image, cursor->image, 32,
23867 + 0, 0, width, height, size * 4,
23868 + 0, 0, size, size, size * 4,
23869 + &to_sna_crtc(crtc)->cursor_to_fb);
23870 + image = cursor->image;
23871 + }
23872 + } else if (transformed) {
23873 + __DBG(("%s: Applying affine BLT to ARGB\n", __FUNCTION__));
23874 + affine_blt(argb, cursor->image, 32,
23875 + 0, 0, width, height, width * 4,
23876 + 0, 0, size, size, size * 4,
23877 + &to_sna_crtc(crtc)->cursor_to_fb);
23878 + image = cursor->image;
23879 } else
23880 memcpy_blt(argb, image, 32,
23881 width * 4, size * 4,
23882 @@ -4662,9 +6098,16 @@ static struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc)
23884 cursor->size = size;
23885 cursor->rotation = rotation;
23886 + cursor->transformed = transformed;
23887 cursor->serial = sna->cursor.serial;
23888 - cursor->last_width = width;
23889 - cursor->last_height = height;
23890 + if (transformed) {
23891 + /* mark the transformed rectangle as dirty, not input */
23892 + cursor->last_width = size;
23893 + cursor->last_height = size;
23894 + } else {
23895 + cursor->last_width = width;
23896 + cursor->last_height = height;
23897 + }
23898 return cursor;
23901 @@ -4674,40 +6117,55 @@ sna_realize_cursor(xf86CursorInfoPtr info, CursorPtr cursor)
23902 return NULL;
23905 -#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0)
23906 -static inline int sigio_block(void)
23907 -{
23908 - OsBlockSIGIO();
23909 - return 0;
23910 -}
23911 -static inline void sigio_unblock(int was_blocked)
23912 +static void enable_fb_access(ScrnInfoPtr scrn, int state)
23914 - OsReleaseSIGIO();
23915 - (void)was_blocked;
23916 -}
23917 + scrn->EnableDisableFBAccess(
23918 +#ifdef XF86_HAS_SCRN_CONV
23919 + scrn,
23920 #else
23921 -#include <xf86_OSproc.h>
23922 -static inline int sigio_block(void)
23923 + scrn->scrnIndex,
23924 +#endif
23925 + state);
23926 +}
23929 +static void __restore_swcursor(ScrnInfoPtr scrn)
23931 - return xf86BlockSIGIO();
23932 + DBG(("%s: attempting to restore SW cursor\n", __FUNCTION__));
23933 + enable_fb_access(scrn, FALSE);
23934 + enable_fb_access(scrn, TRUE);
23936 + RemoveBlockAndWakeupHandlers((void *)__restore_swcursor,
23937 + (void *)NoopDDA,
23938 + scrn);
23940 -static inline void sigio_unblock(int was_blocked)
23942 +static void restore_swcursor(struct sna *sna)
23944 - xf86UnblockSIGIO(was_blocked);
23945 + sna->cursor.info->HideCursor(sna->scrn);
23947 + /* XXX Force the cursor to be restored (avoiding recursion) */
23948 + FreeCursor(sna->cursor.ref, None);
23949 + sna->cursor.ref = NULL;
23951 + RegisterBlockAndWakeupHandlers((void *)__restore_swcursor,
23952 + (void *)NoopDDA,
23953 + sna->scrn);
23955 -#endif
23957 static void
23958 sna_show_cursors(ScrnInfoPtr scrn)
23960 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
23961 struct sna *sna = to_sna(scrn);
23962 + struct kmsg kmsg;
23963 int sigio, c;
23965 DBG(("%s: cursor?=%d\n", __FUNCTION__, sna->cursor.ref != NULL));
23966 if (sna->cursor.ref == NULL)
23967 return;
23969 + kmsg_open(&kmsg);
23970 sigio = sigio_block();
23971 for (c = 0; c < sna->mode.num_real_crtc; c++) {
23972 xf86CrtcPtr crtc = xf86_config->crtc[c];
23973 @@ -4721,7 +6179,7 @@ sna_show_cursors(ScrnInfoPtr scrn)
23975 if (!crtc->cursor_in_range) {
23976 DBG(("%s: skipping cursor outside CRTC (pipe=%d)\n",
23977 - __FUNCTION__, sna_crtc->pipe));
23978 + __FUNCTION__, sna_crtc_pipe(crtc)));
23979 continue;
23982 @@ -4729,20 +6187,21 @@ sna_show_cursors(ScrnInfoPtr scrn)
23983 if (cursor == NULL ||
23984 (sna_crtc->cursor == cursor && sna_crtc->last_cursor_size == cursor->size)) {
23985 DBG(("%s: skipping cursor already show on CRTC (pipe=%d)\n",
23986 - __FUNCTION__, sna_crtc->pipe));
23987 + __FUNCTION__, sna_crtc_pipe(crtc)));
23988 continue;
23991 DBG(("%s: CRTC pipe=%d, handle->%d\n", __FUNCTION__,
23992 - sna_crtc->pipe, cursor->handle));
23993 + sna_crtc_pipe(crtc), cursor->handle));
23995 VG_CLEAR(arg);
23996 arg.flags = DRM_MODE_CURSOR_BO;
23997 - arg.crtc_id = sna_crtc->id;
23998 + arg.crtc_id = __sna_crtc_id(sna_crtc);
23999 arg.width = arg.height = cursor->size;
24000 arg.handle = cursor->handle;
24002 - if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg) == 0) {
24003 + if (!FAIL_CURSOR_IOCTL &&
24004 + drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg) == 0) {
24005 if (sna_crtc->cursor) {
24006 assert(sna_crtc->cursor->ref > 0);
24007 sna_crtc->cursor->ref--;
24008 @@ -4750,10 +6209,18 @@ sna_show_cursors(ScrnInfoPtr scrn)
24009 cursor->ref++;
24010 sna_crtc->cursor = cursor;
24011 sna_crtc->last_cursor_size = cursor->size;
24012 + } else {
24013 + ERR(("%s: failed to show cursor on CRTC:%d [pipe=%d], disabling hwcursor: errno=%d\n",
24014 + __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc), errno));
24015 + sna->cursor.disable = true;
24018 sigio_unblock(sigio);
24019 sna->cursor.active = true;
24020 + kmsg_close(&kmsg, sna->cursor.disable);
24022 + if (unlikely(sna->cursor.disable))
24023 + restore_swcursor(sna);
24026 static void
24027 @@ -4789,24 +6256,45 @@ static void
24028 sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc)
24030 struct drm_mode_cursor arg;
24031 + int sigio;
24033 if (!crtc->cursor)
24034 return;
24036 - DBG(("%s: CRTC:%d, handle=%d\n", __FUNCTION__, crtc->id, crtc->cursor->handle));
24037 - assert(crtc->cursor->ref);
24038 + sigio = sigio_block();
24039 + if (crtc->cursor) {
24040 + DBG(("%s: CRTC:%d, handle=%d\n", __FUNCTION__, __sna_crtc_id(crtc), crtc->cursor->handle));
24041 + assert(crtc->cursor->ref > 0);
24042 + crtc->cursor->ref--;
24043 + crtc->cursor = NULL;
24044 + crtc->last_cursor_size = 0;
24046 - VG_CLEAR(arg);
24047 - arg.flags = DRM_MODE_CURSOR_BO;
24048 - arg.crtc_id = crtc->id;
24049 - arg.width = arg.height = 0;
24050 - arg.handle = 0;
24051 + VG_CLEAR(arg);
24052 + arg.flags = DRM_MODE_CURSOR_BO;
24053 + arg.crtc_id = __sna_crtc_id(crtc);
24054 + arg.width = arg.height = 0;
24055 + arg.handle = 0;
24057 - (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg);
24058 - assert(crtc->cursor->ref > 0);
24059 - crtc->cursor->ref--;
24060 - crtc->cursor = NULL;
24061 - crtc->last_cursor_size = 0;
24062 + (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg);
24063 + }
24064 + sigio_unblock(sigio);
24065 +}
24067 +static void
24068 +sna_disable_cursors(ScrnInfoPtr scrn)
24069 +{
24070 + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
24071 + struct sna *sna = to_sna(scrn);
24072 + int sigio, c;
24074 + DBG(("%s\n", __FUNCTION__));
24076 + sigio = sigio_block();
24077 + for (c = 0; c < sna->mode.num_real_crtc; c++) {
24078 + assert(to_sna_crtc(xf86_config->crtc[c]));
24079 + sna_crtc_disable_cursor(sna, to_sna_crtc(xf86_config->crtc[c]));
24080 + }
24081 + sigio_unblock(sigio);
24084 static void
24085 @@ -4852,6 +6340,7 @@ sna_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
24087 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
24088 struct sna *sna = to_sna(scrn);
24089 + struct kmsg kmsg;
24090 int sigio, c;
24092 __DBG(("%s(%d, %d), cursor? %d\n", __FUNCTION__,
24093 @@ -4859,6 +6348,7 @@ sna_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
24094 if (sna->cursor.ref == NULL)
24095 return;
24097 + kmsg_open(&kmsg);
24098 sigio = sigio_block();
24099 sna->cursor.last_x = x;
24100 sna->cursor.last_y = y;
24101 @@ -4876,27 +6366,37 @@ sna_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
24103 VG_CLEAR(arg);
24104 arg.flags = 0;
24105 - arg.crtc_id = sna_crtc->id;
24106 + arg.crtc_id = __sna_crtc_id(sna_crtc);
24107 arg.handle = 0;
24109 if (sna_crtc->bo == NULL)
24110 goto disable;
24112 + cursor = __sna_get_cursor(sna, crtc);
24113 + if (cursor == NULL)
24114 + cursor = sna_crtc->cursor;
24115 + if (cursor == NULL) {
24116 + __DBG(("%s: failed to grab cursor, disabling\n", __FUNCTION__));
24117 + goto disable;
24118 + }
24120 if (crtc->transform_in_use) {
24121 int xhot = sna->cursor.ref->bits->xhot;
24122 int yhot = sna->cursor.ref->bits->yhot;
24123 - struct pict_f_vector v;
24124 + struct pict_f_vector v, hot;
24126 - v.v[0] = (x + xhot) + 0.5;
24127 - v.v[1] = (y + yhot) + 0.5;
24128 - v.v[2] = 1;
24129 + v.v[0] = x + xhot + .5;
24130 + v.v[1] = y + yhot + .5;
24131 + v.v[2] = 1.;
24132 pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &v);
24134 - rotate_coord_back(crtc->rotation, sna->cursor.size, &xhot, &yhot);
24135 + hot.v[0] = xhot;
24136 + hot.v[1] = yhot;
24137 + hot.v[2] = 1.;
24138 + pixman_f_transform_point(&sna_crtc->fb_to_cursor, &hot);
24140 - /* cursor will have 0.5 added to it already so floor is sufficent */
24141 - arg.x = floor(v.v[0]) - xhot;
24142 - arg.y = floor(v.v[1]) - yhot;
24143 + arg.x = floor(v.v[0] - hot.v[0]);
24144 + arg.y = floor(v.v[1] - hot.v[1]);
24145 } else {
24146 arg.x = x - crtc->x;
24147 arg.y = y - crtc->y;
24148 @@ -4904,15 +6404,6 @@ sna_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
24150 if (arg.x < crtc->mode.HDisplay && arg.x > -sna->cursor.size &&
24151 arg.y < crtc->mode.VDisplay && arg.y > -sna->cursor.size) {
24152 - cursor = __sna_get_cursor(sna, crtc);
24153 - if (cursor == NULL)
24154 - cursor = sna_crtc->cursor;
24155 - if (cursor == NULL) {
24156 - __DBG(("%s: failed to grab cursor, disabling\n",
24157 - __FUNCTION__));
24158 - goto disable;
24159 - }
24161 if (sna_crtc->cursor != cursor || sna_crtc->last_cursor_size != cursor->size) {
24162 arg.flags |= DRM_MODE_CURSOR_BO;
24163 arg.handle = cursor->handle;
24164 @@ -4932,10 +6423,13 @@ disable:
24167 __DBG(("%s: CRTC:%d (%d, %d), handle=%d, flags=%x (old cursor handle=%d), move? %d, update handle? %d\n",
24168 - __FUNCTION__, sna_crtc->id, arg.x, arg.y, arg.handle, arg.flags, sna_crtc->cursor ? sna_crtc->cursor->handle : 0,
24169 + __FUNCTION__, __sna_crtc_id(sna_crtc), arg.x, arg.y, arg.handle, arg.flags, sna_crtc->cursor ? sna_crtc->cursor->handle : 0,
24170 arg.flags & DRM_MODE_CURSOR_MOVE, arg.flags & DRM_MODE_CURSOR_BO));
24172 - if (arg.flags &&
24173 + if (arg.flags == 0)
24174 + continue;
24176 + if (!FAIL_CURSOR_IOCTL &&
24177 drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg) == 0) {
24178 if (arg.flags & DRM_MODE_CURSOR_BO) {
24179 if (sna_crtc->cursor) {
24180 @@ -4949,9 +6443,21 @@ disable:
24181 } else
24182 sna_crtc->last_cursor_size = 0;
24184 + } else {
24185 + ERR(("%s: failed to update cursor on CRTC:%d [pipe=%d], disabling hwcursor: errno=%d\n",
24186 + __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc), errno));
24187 + /* XXX How to force switch back to SW cursor?
24188 + * Right now we just want until the next cursor image
24189 + * change, which is fairly frequent.
24190 + */
24191 + sna->cursor.disable = true;
24194 sigio_unblock(sigio);
24195 + kmsg_close(&kmsg, sna->cursor.disable);
24197 + if (unlikely(sna->cursor.disable))
24198 + restore_swcursor(sna);
24201 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,2)
24202 @@ -4978,17 +6484,6 @@ sna_load_cursor_image(ScrnInfoPtr scrn, unsigned char *src)
24206 -static int __cursor_size(CursorPtr cursor)
24207 -{
24208 - int i, size;
24210 - i = MAX(cursor->bits->width, cursor->bits->height);
24211 - for (size = 64; size < i; size <<= 1)
24212 - ;
24214 - return size;
24215 -}
24217 static bool
24218 sna_cursor_preallocate(struct sna *sna)
24220 @@ -5006,6 +6501,50 @@ sna_cursor_preallocate(struct sna *sna)
24221 return true;
24224 +static bool
24225 +transformable_cursor(struct sna *sna, CursorPtr cursor)
24226 +{
24227 + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
24228 + int i;
24230 + for (i = 0; i < sna->mode.num_real_crtc; i++) {
24231 + xf86CrtcPtr crtc = config->crtc[i];
24232 + struct pixman_box16 box;
24233 + int size;
24235 + if (!to_sna_crtc(crtc)->hwcursor) {
24236 + DBG(("%s: hwcursor disabled on CRTC:%d [pipe=%d]\n",
24237 + __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc)));
24238 + return false;
24239 + }
24241 + if (!sna->cursor.use_gtt || !sna->cursor.scratch) {
24242 + DBG(("%s: unable to use GTT curosor access [%d] or no scratch [%d]\n",
24243 + __FUNCTION__, sna->cursor.use_gtt, sna->cursor.scratch));
24244 + return false;
24245 + }
24247 + box.x1 = box.y1 = 0;
24248 + box.x2 = cursor->bits->width;
24249 + box.y2 = cursor->bits->height;
24251 + if (!pixman_f_transform_bounds(&crtc->f_crtc_to_framebuffer,
24252 + &box)) {
24253 + DBG(("%s: unable to transform bounds\n", __FUNCTION__));
24254 + return false;
24255 + }
24257 + size = __cursor_size(box.x2 - box.x1, box.y2 - box.y1);
24258 + if (size > sna->cursor.max_size) {
24259 + DBG(("%s: transformed cursor size=%d too large, max=%d\n",
24260 + __FUNCTION__, size, sna->cursor.max_size));
24261 + return false;
24262 + }
24263 + }
24265 + return true;
24266 +}
24268 static Bool
24269 sna_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
24271 @@ -5014,6 +6553,9 @@ sna_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
24272 DBG(("%s (%dx%d)?\n", __FUNCTION__,
24273 cursor->bits->width, cursor->bits->height));
24275 + if (sna->cursor.disable)
24276 + return FALSE;
24278 /* cursors are invariant */
24279 if (cursor == sna->cursor.ref)
24280 return TRUE;
24281 @@ -5023,12 +6565,24 @@ sna_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
24282 sna->cursor.ref = NULL;
24285 - sna->cursor.size = __cursor_size(cursor);
24286 - if (sna->cursor.size > sna->cursor.max_size)
24287 + sna->cursor.size =
24288 + __cursor_size(cursor->bits->width, cursor->bits->height);
24289 + if (sna->cursor.size > sna->cursor.max_size) {
24290 + DBG(("%s: cursor size=%d too large, max %d: using sw cursor\n",
24291 + __FUNCTION__, sna->cursor.size, sna->cursor.max_size));
24292 return FALSE;
24293 + }
24295 + if (sna->mode.rr_active && !transformable_cursor(sna, cursor)) {
24296 + DBG(("%s: RandR active [%d] and non-transformable cursor: using sw cursor\n",
24297 + __FUNCTION__, sna->mode.rr_active));
24298 + return FALSE;
24299 + }
24301 - if (!sna_cursor_preallocate(sna))
24302 + if (!sna_cursor_preallocate(sna)) {
24303 + DBG(("%s: cursor preallocation failed: using sw cursor\n", __FUNCTION__));
24304 return FALSE;
24305 + }
24307 sna->cursor.ref = cursor;
24308 cursor->refcnt++;
24309 @@ -5056,8 +6610,12 @@ sna_cursor_pre_init(struct sna *sna)
24310 return;
24312 #define LOCAL_IOCTL_GET_CAP DRM_IOWR(0x0c, struct local_get_cap)
24313 -#define DRM_CAP_CURSOR_WIDTH 8
24314 -#define DRM_CAP_CURSOR_HEIGHT 9
24315 +#ifndef DRM_CAP_CURSOR_WIDTH
24316 +#define DRM_CAP_CURSOR_WIDTH 0x8
24317 +#endif
24318 +#ifndef DRM_CAP_CURSOR_HEIGHT
24319 +#define DRM_CAP_CURSOR_HEIGHT 0x9
24320 +#endif
24322 #define I915_PARAM_HAS_COHERENT_PHYS_GTT 29
24324 @@ -5087,11 +6645,9 @@ sna_cursor_pre_init(struct sna *sna)
24325 DBG(("%s: cursor updates use_gtt?=%d\n",
24326 __FUNCTION__, sna->cursor.use_gtt));
24328 - if (!sna->cursor.use_gtt) {
24329 - sna->cursor.scratch = malloc(sna->cursor.max_size * sna->cursor.max_size * 4);
24330 - if (!sna->cursor.scratch)
24331 - sna->cursor.max_size = 0;
24332 - }
24333 + sna->cursor.scratch = malloc(sna->cursor.max_size * sna->cursor.max_size * 4);
24334 + if (!sna->cursor.scratch && !sna->cursor.use_gtt)
24335 + sna->cursor.max_size = 0;
24337 sna->cursor.num_stash = -sna->mode.num_real_crtc;
24339 @@ -5193,7 +6749,7 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
24340 int output_count = 0;
24341 int i;
24343 - DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, crtc->id, crtc->pipe, bo->handle));
24344 + DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), bo->handle));
24346 assert(sna->mode.num_real_output < ARRAY_SIZE(output_ids));
24347 assert(crtc->bo);
24348 @@ -5207,11 +6763,11 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
24350 DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n",
24351 __FUNCTION__, output->name, i, to_connector_id(output),
24352 - crtc->id, crtc->pipe,
24353 + __sna_crtc_id(crtc), __sna_crtc_pipe(crtc),
24354 (uint32_t)output->possible_crtcs,
24355 (uint32_t)output->possible_clones));
24357 - assert(output->possible_crtcs & (1 << crtc->pipe) ||
24358 + assert(output->possible_crtcs & (1 << __sna_crtc_pipe(crtc)) ||
24359 is_zaphod(sna->scrn));
24361 output_ids[output_count] = to_connector_id(output);
24362 @@ -5221,7 +6777,7 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
24363 assert(output_count);
24365 VG_CLEAR(arg);
24366 - arg.crtc_id = crtc->id;
24367 + arg.crtc_id = __sna_crtc_id(crtc);
24368 arg.fb_id = fb_id(bo);
24369 assert(arg.fb_id);
24370 arg.x = x;
24371 @@ -5231,20 +6787,74 @@ sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x,
24372 arg.mode = crtc->kmode;
24373 arg.mode_valid = 1;
24375 - DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d across %d outputs [%d...]\n",
24376 - __FUNCTION__, crtc->id, crtc->pipe,
24377 - arg.mode.hdisplay,
24378 - arg.mode.vdisplay,
24379 - arg.x, arg.y,
24380 - arg.mode.clock,
24381 - arg.fb_id,
24382 - output_count, output_count ? output_ids[0] : 0));
24383 + DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d across %d outputs [%d...]\n",
24384 + __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc),
24385 + arg.mode.hdisplay,
24386 + arg.mode.vdisplay,
24387 + arg.x, arg.y,
24388 + arg.mode.clock,
24389 + arg.fb_id,
24390 + output_count, output_count ? output_ids[0] : 0));
24392 + if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg))
24393 + return false;
24395 + crtc->offset = y << 16 | x;
24396 + __kgem_bo_clear_dirty(bo);
24397 + return true;
24398 +}
24400 +static void sna_mode_restore(struct sna *sna)
24401 +{
24402 + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
24403 + int error = 0;
24404 + int i;
24406 + assert(!sna->mode.hidden);
24408 + for (i = 0; i < sna->mode.num_real_crtc; i++) {
24409 + xf86CrtcPtr crtc = config->crtc[i];
24411 + assert(to_sna_crtc(crtc) != NULL);
24412 + if (to_sna_crtc(crtc)->bo == NULL)
24413 + continue;
24415 + assert(crtc->enabled);
24416 + if (!__sna_crtc_set_mode(crtc)) {
24417 + sna_crtc_disable(crtc, false);
24418 + error++;
24419 + }
24420 + }
24421 + sna_mode_wakeup(sna);
24422 + while (sna->mode.flip_active && sna_mode_wakeup(sna))
24423 + ;
24424 + update_flush_interval(sna);
24425 + sna_cursors_reload(sna);
24426 + sna->mode.dirty = false;
24428 + if (error)
24429 + xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
24430 + "Failed to restore display configuration\n");
24431 +}
24433 +bool sna_needs_page_flip(struct sna *sna, struct kgem_bo *bo)
24434 +{
24435 + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
24436 + int i;
24438 + for (i = 0; i < sna->mode.num_real_crtc; i++) {
24439 + struct sna_crtc *crtc = config->crtc[i]->driver_private;
24441 + if (crtc->bo == NULL)
24442 + continue;
24444 - if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg))
24445 - return false;
24446 + if (crtc->bo == bo)
24447 + continue;
24449 - crtc->offset = y << 16 | x;
24450 - return true;
24451 + return true;
24452 + }
24454 + return false;
24457 int
24458 @@ -5256,6 +6866,7 @@ sna_page_flip(struct sna *sna,
24459 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
24460 const int width = sna->scrn->virtualX;
24461 const int height = sna->scrn->virtualY;
24462 + int sigio;
24463 int count = 0;
24464 int i;
24466 @@ -5263,23 +6874,26 @@ sna_page_flip(struct sna *sna,
24467 assert(bo->refcnt);
24469 assert((sna->flags & SNA_IS_HOSTED) == 0);
24470 - assert((sna->flags & SNA_TEAR_FREE) == 0);
24471 assert(sna->mode.flip_active == 0);
24472 assert(sna->mode.front_active);
24473 + assert(!sna->mode.hidden);
24474 assert(sna->scrn->vtSema);
24476 if ((sna->flags & (data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP)) == 0)
24477 return 0;
24479 kgem_bo_submit(&sna->kgem, bo);
24480 + __kgem_bo_clear_dirty(bo);
24482 + sigio = sigio_block();
24483 for (i = 0; i < sna->mode.num_real_crtc; i++) {
24484 struct sna_crtc *crtc = config->crtc[i]->driver_private;
24485 struct drm_mode_crtc_page_flip arg;
24486 uint32_t crtc_offset;
24487 + int fixup;
24489 DBG(("%s: crtc %d id=%d, pipe=%d active? %d\n",
24490 - __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo != NULL));
24491 + __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->bo != NULL));
24492 if (crtc->bo == NULL)
24493 continue;
24494 assert(!crtc->transform);
24495 @@ -5288,13 +6902,18 @@ sna_page_flip(struct sna *sna,
24496 assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
24497 assert(crtc->flip_bo == NULL);
24499 - arg.crtc_id = crtc->id;
24500 + assert_crtc_fb(sna, crtc);
24501 + if (data == NULL && crtc->bo == bo)
24502 + goto next_crtc;
24504 + arg.crtc_id = __sna_crtc_id(crtc);
24505 arg.fb_id = get_fb(sna, bo, width, height);
24506 if (arg.fb_id == 0) {
24507 assert(count == 0);
24508 - return 0;
24509 + break;
24512 + fixup = 0;
24513 crtc_offset = crtc->base->y << 16 | crtc->base->x;
24515 if (bo->pitch != crtc->bo->pitch || crtc_offset != crtc->offset) {
24516 @@ -5303,7 +6922,12 @@ sna_page_flip(struct sna *sna,
24517 bo->pitch, crtc->bo->pitch,
24518 crtc_offset, crtc->offset));
24519 fixup_flip:
24520 + fixup = 1;
24521 if (crtc->bo != bo && sna_crtc_flip(sna, crtc, bo, crtc->base->x, crtc->base->y)) {
24522 +update_scanout:
24523 + DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n",
24524 + __FUNCTION__, crtc->bo->handle, crtc->bo->active_scanout,
24525 + bo->handle, bo->active_scanout));
24526 assert(crtc->bo->active_scanout);
24527 assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
24528 crtc->bo->active_scanout--;
24529 @@ -5321,15 +6945,8 @@ fixup_flip:
24530 goto next_crtc;
24532 /* queue a flip in order to send the event */
24533 - } else {
24534 - if (count && !xf86SetDesiredModes(sna->scrn)) {
24535 - xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
24536 - "failed to restore display configuration\n");
24537 - for (; i < sna->mode.num_real_crtc; i++)
24538 - sna_crtc_disable(config->crtc[i]);
24539 - }
24540 - return 0;
24541 - }
24542 + } else
24543 + goto error;
24546 /* Only the reference crtc will finally deliver its page flip
24547 @@ -5346,7 +6963,7 @@ fixup_flip:
24549 retry_flip:
24550 DBG(("%s: crtc %d id=%d, pipe=%d --> fb %d\n",
24551 - __FUNCTION__, i, crtc->id, crtc->pipe, arg.fb_id));
24552 + __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), arg.fb_id));
24553 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
24554 ERR(("%s: pageflip failed with err=%d\n", __FUNCTION__, errno));
24556 @@ -5354,7 +6971,7 @@ retry_flip:
24557 struct drm_mode_crtc mode;
24559 memset(&mode, 0, sizeof(mode));
24560 - mode.crtc_id = crtc->id;
24561 + mode.crtc_id = __sna_crtc_id(crtc);
24562 drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode);
24564 DBG(("%s: crtc=%d, valid?=%d, fb attached?=%d, expected=%d\n",
24565 @@ -5366,7 +6983,7 @@ retry_flip:
24566 goto fixup_flip;
24568 if (count == 0)
24569 - return 0;
24570 + break;
24572 DBG(("%s: throttling on busy flip / waiting for kernel to catch up\n", __FUNCTION__));
24573 drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_THROTTLE, 0);
24574 @@ -5375,15 +6992,25 @@ retry_flip:
24575 goto retry_flip;
24578 + if (!fixup)
24579 + goto fixup_flip;
24581 +error:
24582 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
24583 - "page flipping failed, on CRTC:%d (pipe=%d), disabling %s page flips\n",
24584 - crtc->id, crtc->pipe, data ? "synchronous": "asynchronous");
24585 + "page flipping failed, on CRTC:%d (pipe=%d), disabling %s page flips\n",
24586 + __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), data ? "synchronous": "asynchronous");
24588 + if (count || crtc->bo == bo)
24589 + sna_mode_restore(sna);
24591 sna->flags &= ~(data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP);
24592 - goto fixup_flip;
24593 + count = 0;
24594 + break;
24597 if (data) {
24598 assert(crtc->flip_bo == NULL);
24599 + assert(handler);
24600 crtc->flip_handler = handler;
24601 crtc->flip_data = data;
24602 crtc->flip_bo = kgem_bo_reference(bo);
24603 @@ -5391,11 +7018,15 @@ retry_flip:
24604 crtc->flip_serial = crtc->mode_serial;
24605 crtc->flip_pending = true;
24606 sna->mode.flip_active++;
24607 - }
24609 + DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
24610 + __FUNCTION__, __sna_crtc_id(crtc), crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial));
24611 + } else
24612 + goto update_scanout;
24613 next_crtc:
24614 count++;
24616 + sigio_unblock(sigio);
24618 DBG(("%s: page flipped %d crtcs\n", __FUNCTION__, count));
24619 return count;
24620 @@ -5471,7 +7102,7 @@ static void crtc_init_gamma(xf86CrtcPtr crtc)
24622 assert(sna_crtc);
24624 - lut.crtc_id = sna_crtc->id;
24625 + lut.crtc_id = __sna_crtc_id(sna_crtc);
24626 lut.gamma_size = 256;
24627 lut.red = (uintptr_t)(gamma);
24628 lut.green = (uintptr_t)(gamma + 256);
24629 @@ -5485,7 +7116,7 @@ static void crtc_init_gamma(xf86CrtcPtr crtc)
24632 DBG(("%s: CRTC:%d, pipe=%d: gamma set?=%d\n",
24633 - __FUNCTION__, sna_crtc->id, sna_crtc->pipe,
24634 + __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
24635 gamma_set));
24636 if (!gamma_set) {
24637 int i;
24638 @@ -5502,6 +7133,7 @@ static void crtc_init_gamma(xf86CrtcPtr crtc)
24639 crtc->gamma_red = gamma;
24640 crtc->gamma_green = gamma + 256;
24641 crtc->gamma_blue = gamma + 2*256;
24642 + crtc->gamma_size = 256;
24646 @@ -5528,6 +7160,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
24648 ScrnInfoPtr scrn = sna->scrn;
24649 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
24650 + int crtc_active, crtc_enabled;
24651 int width, height;
24652 int i, j;
24654 @@ -5565,6 +7198,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
24657 /* Copy the existing modes on each CRTCs */
24658 + crtc_active = crtc_enabled = 0;
24659 for (i = 0; i < sna->mode.num_real_crtc; i++) {
24660 xf86CrtcPtr crtc = config->crtc[i];
24661 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
24662 @@ -5577,12 +7211,12 @@ static bool sna_probe_initial_configuration(struct sna *sna)
24664 /* Retrieve the current mode */
24665 VG_CLEAR(mode);
24666 - mode.crtc_id = sna_crtc->id;
24667 + mode.crtc_id = __sna_crtc_id(sna_crtc);
24668 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
24669 continue;
24671 DBG(("%s: CRTC:%d, pipe=%d: has mode?=%d\n", __FUNCTION__,
24672 - sna_crtc->id, sna_crtc->pipe,
24673 + __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc),
24674 mode.mode_valid && mode.mode.clock));
24676 if (!mode.mode_valid || mode.mode.clock == 0)
24677 @@ -5593,6 +7227,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
24678 crtc->desiredX = mode.x;
24679 crtc->desiredY = mode.y;
24680 crtc->desiredTransformPresent = FALSE;
24681 + crtc_active++;
24684 /* Reconstruct outputs pointing to active CRTC */
24685 @@ -5604,6 +7239,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
24687 crtc_id = (uintptr_t)output->crtc;
24688 output->crtc = NULL;
24689 + output->status = XF86OutputStatusUnknown;
24690 if (sna->flags & SNA_IS_SLAVED)
24691 continue;
24693 @@ -5623,7 +7259,7 @@ static bool sna_probe_initial_configuration(struct sna *sna)
24694 xf86CrtcPtr crtc = config->crtc[j];
24696 assert(to_sna_crtc(crtc));
24697 - if (to_sna_crtc(crtc)->id != crtc_id)
24698 + if (sna_crtc_id(crtc) != crtc_id)
24699 continue;
24701 if (crtc->desiredMode.status == MODE_OK) {
24702 @@ -5641,18 +7277,30 @@ static bool sna_probe_initial_configuration(struct sna *sna)
24703 "Output %s using initial mode %s on pipe %d\n",
24704 output->name,
24705 crtc->desiredMode.name,
24706 - to_sna_crtc(crtc)->pipe);
24707 + sna_crtc_pipe(crtc));
24709 output->crtc = crtc;
24710 + output->status = XF86OutputStatusConnected;
24711 crtc->enabled = TRUE;
24712 + crtc_enabled++;
24714 + output_set_gamma(output, crtc);
24716 + if (output->conf_monitor) {
24717 + output->mm_width = output->conf_monitor->mon_width;
24718 + output->mm_height = output->conf_monitor->mon_height;
24719 + }
24721 +#if 0
24722 + sna_output_attach_edid(output);
24723 + sna_output_attach_tile(output);
24724 +#endif
24726 if (output->mm_width == 0 || output->mm_height == 0) {
24727 output->mm_height = (crtc->desiredMode.VDisplay * 254) / (10*DEFAULT_DPI);
24728 output->mm_width = (crtc->desiredMode.HDisplay * 254) / (10*DEFAULT_DPI);
24731 - output_set_gamma(output, crtc);
24733 M = calloc(1, sizeof(DisplayModeRec));
24734 if (M) {
24735 *M = crtc->desiredMode;
24736 @@ -5673,6 +7321,12 @@ static bool sna_probe_initial_configuration(struct sna *sna)
24740 + if (crtc_active != crtc_enabled) {
24741 + DBG(("%s: only enabled %d out of %d active CRTC, forcing a reconfigure\n",
24742 + __FUNCTION__, crtc_enabled, crtc_active));
24743 + return false;
24744 + }
24746 width = height = 0;
24747 for (i = 0; i < sna->mode.num_real_crtc; i++) {
24748 xf86CrtcPtr crtc = config->crtc[i];
24749 @@ -5707,8 +7361,8 @@ static bool sna_probe_initial_configuration(struct sna *sna)
24750 if (sna_output->num_modes == 0)
24751 continue;
24753 - width = sna_output->modes[0].hdisplay;
24754 - height= sna_output->modes[0].vdisplay;
24755 + width = sna_output->modes[0].hdisplay;
24756 + height = sna_output->modes[0].vdisplay;
24758 DBG(("%s: panel '%s' is %dx%d\n",
24759 __FUNCTION__, output->name, width, height));
24760 @@ -5788,7 +7442,7 @@ probe_capabilities(struct sna *sna)
24761 sna->flags &= ~(SNA_HAS_FLIP | SNA_HAS_ASYNC_FLIP);
24762 if (has_flip(sna))
24763 sna->flags |= SNA_HAS_FLIP;
24764 - if (has_flip__async(sna))
24765 + if (has_flip__async(sna) && (sna->flags & SNA_TEAR_FREE) == 0)
24766 sna->flags |= SNA_HAS_ASYNC_FLIP;
24767 DBG(("%s: page flips? %s, async? %s\n", __FUNCTION__,
24768 sna->flags & SNA_HAS_FLIP ? "enabled" : "disabled",
24769 @@ -5813,12 +7467,25 @@ sna_crtc_config_notify(ScreenPtr screen)
24770 return;
24773 + /* Flush any events completed by the modeset */
24774 + sna_mode_wakeup(sna);
24776 update_flush_interval(sna);
24777 + sna->cursor.disable = false; /* Reset HW cursor until the next fail */
24778 sna_cursors_reload(sna);
24780 probe_capabilities(sna);
24781 sna_present_update(sna);
24783 + /* Allow TearFree to come back on when everything is off */
24784 + if (!sna->mode.front_active && sna->flags & SNA_WANT_TEAR_FREE) {
24785 + if ((sna->flags & SNA_TEAR_FREE) == 0)
24786 + DBG(("%s: enable TearFree next modeset\n",
24787 + __FUNCTION__));
24789 + sna->flags |= SNA_TEAR_FREE;
24790 + }
24792 sna->mode.dirty = false;
24795 @@ -5840,6 +7507,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
24798 probe_capabilities(sna);
24799 + sna->mode.hidden = 1;
24801 if (!xf86GetOptValInteger(sna->Options, OPTION_VIRTUAL, &num_fake))
24802 num_fake = 1;
24803 @@ -5855,6 +7523,9 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
24804 if (res) {
24805 xf86CrtcConfigPtr xf86_config;
24807 + DBG(("%s: found %d CRTC, %d encoders, %d connectors\n",
24808 + __FUNCTION__, res->count_crtcs, res->count_encoders, res->count_connectors));
24810 assert(res->count_crtcs);
24811 assert(res->count_connectors);
24813 @@ -5862,6 +7533,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
24815 xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
24816 xf86_config->xf86_crtc_notify = sna_crtc_config_notify;
24817 + xf86_config->compat_output = 0;
24819 for (i = 0; i < res->count_crtcs; i++)
24820 if (!sna_crtc_add(scrn, res->crtcs[i]))
24821 @@ -5900,6 +7572,11 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
24822 if (!sna_mode_fake_init(sna, num_fake))
24823 return false;
24825 + sna->mode.shadow_size = 256;
24826 + sna->mode.shadow_events = malloc(sna->mode.shadow_size * sizeof(struct drm_event_vblank));
24827 + if (!sna->mode.shadow_events)
24828 + return false;
24830 if (!sna_probe_initial_configuration(sna)) {
24831 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
24833 @@ -5912,6 +7589,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
24836 sort_config_outputs(sna);
24837 + TimerSet(NULL, 0, COLDPLUG_DELAY_MS, sna_mode_coldplug, sna);
24839 sna_setup_provider(scrn);
24840 return scrn->modes != NULL;
24841 @@ -5921,18 +7599,58 @@ bool
24842 sna_mode_wants_tear_free(struct sna *sna)
24844 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
24845 + bool found = false;
24846 + FILE *file;
24847 int i;
24849 + file = fopen("/sys/module/i915/parameters/enable_fbc", "r");
24850 + if (file) {
24851 + int fbc_enabled = 0;
24852 + int value;
24854 + if (fscanf(file, "%d", &value) == 1)
24855 + fbc_enabled = value > 0;
24856 + fclose(file);
24858 + DBG(("%s: module parameter 'enable_fbc' enabled? %d\n",
24859 + __FUNCTION__, fbc_enabled));
24861 + if (fbc_enabled)
24862 + return true;
24863 + }
24865 for (i = 0; i < sna->mode.num_real_output; i++) {
24866 struct sna_output *output = to_sna_output(config->output[i]);
24867 int id = find_property(sna, output, "Panel Self-Refresh");
24868 - if (id !=-1 && output->prop_values[id] != -1) {
24869 + if (id == -1)
24870 + continue;
24872 + found = true;
24873 + if (output->prop_values[id] != -1) {
24874 DBG(("%s: Panel Self-Refresh detected on %s\n",
24875 __FUNCTION__, config->output[i]->name));
24876 return true;
24880 + if (!found) {
24881 + file = fopen("/sys/module/i915/parameters/enable_psr", "r");
24882 + if (file) {
24883 + int psr_enabled = 0;
24884 + int value;
24886 + if (fscanf(file, "%d", &value) == 1)
24887 + psr_enabled = value > 0;
24888 + fclose(file);
24890 + DBG(("%s: module parameter 'enable_psr' enabled? %d\n",
24891 + __FUNCTION__, psr_enabled));
24893 + if (psr_enabled)
24894 + return true;
24895 + }
24896 + }
24898 return false;
24901 @@ -5955,7 +7673,7 @@ sna_mode_set_primary(struct sna *sna)
24903 DBG(("%s: setting PrimaryOutput %s\n", __FUNCTION__, output->name));
24904 rr->primaryOutput = output->randr_output;
24905 - RROutputChanged(rr->primaryOutput, 0);
24906 + RROutputChanged(rr->primaryOutput, FALSE);
24907 rr->layoutChanged = TRUE;
24908 break;
24910 @@ -5974,12 +7692,9 @@ sna_mode_disable(struct sna *sna)
24911 if (!sna->scrn->vtSema)
24912 return false;
24914 - /* XXX we will cause previously hidden cursors to be reshown, but
24915 - * this should be a rare fixup case for severe fragmentation.
24916 - */
24917 - sna_hide_cursors(sna->scrn);
24918 + sna_disable_cursors(sna->scrn);
24919 for (i = 0; i < sna->mode.num_real_crtc; i++)
24920 - sna_crtc_disable(config->crtc[i]);
24921 + sna_crtc_disable(config->crtc[i], false);
24922 assert(sna->mode.front_active == 0);
24924 sna_mode_wakeup(sna);
24925 @@ -6001,6 +7716,11 @@ sna_mode_enable(struct sna *sna)
24926 if (!sna->scrn->vtSema)
24927 return;
24929 + if (sna->mode.hidden) {
24930 + DBG(("%s: hidden outputs\n", __FUNCTION__));
24931 + return;
24932 + }
24934 for (i = 0; i < sna->mode.num_real_crtc; i++) {
24935 xf86CrtcPtr crtc = config->crtc[i];
24937 @@ -6016,13 +7736,30 @@ sna_mode_enable(struct sna *sna)
24940 update_flush_interval(sna);
24941 - sna_show_cursors(sna->scrn);
24942 + sna_cursors_reload(sna);
24943 sna->mode.dirty = false;
24946 +static void sna_randr_close(struct sna *sna)
24947 +{
24948 + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
24949 + int n;
24951 + /* The RR structs are freed early during CloseScreen as they
24952 + * are tracked as Resources. However, we may be tempted to
24953 + * access them during shutdown so decouple them now.
24954 + */
24955 + for (n = 0; n < config->num_output; n++)
24956 + config->output[n]->randr_output = NULL;
24958 + for (n = 0; n < config->num_crtc; n++)
24959 + config->crtc[n]->randr_crtc = NULL;
24960 +}
24962 void
24963 sna_mode_close(struct sna *sna)
24965 + sna_randr_close(sna);
24966 sna_mode_wakeup(sna);
24968 if (sna->flags & SNA_IS_HOSTED)
24969 @@ -6077,15 +7814,22 @@ xf86CrtcPtr
24970 sna_covering_crtc(struct sna *sna, const BoxRec *box, xf86CrtcPtr desired)
24972 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
24973 - xf86CrtcPtr best_crtc;
24974 - int best_coverage, c;
24975 + xf86CrtcPtr best_crtc = NULL;
24976 + int best_coverage = -1, c;
24978 if (sna->flags & SNA_IS_HOSTED)
24979 return NULL;
24981 /* If we do not own the VT, we do not own the CRTC either */
24982 - if (!sna->scrn->vtSema)
24983 + if (!sna->scrn->vtSema) {
24984 + DBG(("%s: none, VT switched\n", __FUNCTION__));
24985 + return NULL;
24986 + }
24988 + if (sna->mode.hidden) {
24989 + DBG(("%s: none, hidden outputs\n", __FUNCTION__));
24990 return NULL;
24991 + }
24993 DBG(("%s for box=(%d, %d), (%d, %d)\n",
24994 __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
24995 @@ -6107,10 +7851,10 @@ sna_covering_crtc(struct sna *sna, const BoxRec *box, xf86CrtcPtr desired)
24996 cover_box.x2, cover_box.y2));
24997 return desired;
24999 + best_crtc = desired;
25000 + best_coverage = 0;
25003 - best_crtc = NULL;
25004 - best_coverage = 0;
25005 for (c = 0; c < sna->mode.num_real_crtc; c++) {
25006 xf86CrtcPtr crtc = config->crtc[c];
25007 BoxRec cover_box;
25008 @@ -6156,6 +7900,38 @@ sna_covering_crtc(struct sna *sna, const BoxRec *box, xf86CrtcPtr desired)
25009 return best_crtc;
25012 +static xf86CrtcPtr first_active_crtc(struct sna *sna)
25013 +{
25014 + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
25015 + int n;
25017 + for (n = 0; n < sna->mode.num_real_crtc; n++) {
25018 + xf86CrtcPtr crtc = config->crtc[n];
25019 + if (to_sna_crtc(crtc)->bo)
25020 + return crtc;
25021 + }
25023 + /* No active, use the first as a placeholder */
25024 + if (sna->mode.num_real_crtc)
25025 + return config->crtc[0];
25027 + return NULL;
25028 +}
25030 +xf86CrtcPtr sna_primary_crtc(struct sna *sna)
25031 +{
25032 + rrScrPrivPtr rr = rrGetScrPriv(xf86ScrnToScreen(sna->scrn));
25033 + if (rr && rr->primaryOutput) {
25034 + xf86OutputPtr output = rr->primaryOutput->devPrivate;
25035 + if (output->crtc &&
25036 + output->scrn == sna->scrn &&
25037 + to_sna_crtc(output->crtc))
25038 + return output->crtc;
25039 + }
25041 + return first_active_crtc(sna);
25042 +}
25044 #define MI_LOAD_REGISTER_IMM (0x22<<23)
25046 static bool sna_emit_wait_for_scanline_hsw(struct sna *sna,
25047 @@ -6433,7 +8209,7 @@ sna_wait_for_scanline(struct sna *sna,
25048 y2 /= 2;
25051 - pipe = sna_crtc_to_pipe(crtc);
25052 + pipe = sna_crtc_pipe(crtc);
25053 DBG(("%s: pipe=%d, y1=%d, y2=%d, full_height?=%d\n",
25054 __FUNCTION__, pipe, y1, y2, full_height));
25056 @@ -6457,19 +8233,101 @@ sna_wait_for_scanline(struct sna *sna,
25057 return ret;
25060 +static bool sna_mode_shutdown_crtc(xf86CrtcPtr crtc)
25061 +{
25062 + struct sna *sna = to_sna(crtc->scrn);
25063 + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
25064 + bool disabled = false;
25065 + int o;
25067 + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
25068 + "%s: invalid state found on pipe %d, disabling CRTC:%d\n",
25069 + __FUNCTION__,
25070 + __sna_crtc_pipe(to_sna_crtc(crtc)),
25071 + __sna_crtc_id(to_sna_crtc(crtc)));
25072 + sna_crtc_disable(crtc, true);
25073 +#if XF86_CRTC_VERSION >= 3
25074 + crtc->active = FALSE;
25075 +#endif
25076 + if (crtc->enabled) {
25077 + crtc->enabled = FALSE;
25078 + disabled = true;
25079 + }
25081 + for (o = 0; o < sna->mode.num_real_output; o++) {
25082 + xf86OutputPtr output = config->output[o];
25084 + if (output->crtc != crtc)
25085 + continue;
25087 + output->funcs->dpms(output, DPMSModeOff);
25088 + output->crtc = NULL;
25089 + }
25091 + return disabled;
25092 +}
25094 +static bool
25095 +sna_mode_disable_secondary_planes(struct sna *sna)
25096 +{
25097 + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
25098 + bool disabled = false;
25099 + int c;
25101 + /* Disable all secondary planes on our CRTCs, just in case
25102 + * other userspace left garbage in them.
25103 + */
25104 + for (c = 0; c < sna->mode.num_real_crtc; c++) {
25105 + xf86CrtcPtr crtc = config->crtc[c];
25106 + struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
25107 + struct plane *plane;
25109 + list_for_each_entry(plane, &sna_crtc->sprites, link) {
25110 + struct local_mode_get_plane p;
25111 + struct local_mode_set_plane s;
25113 + VG_CLEAR(p);
25114 + p.plane_id = plane->id;
25115 + p.count_format_types = 0;
25116 + if (drmIoctl(sna->kgem.fd,
25117 + LOCAL_IOCTL_MODE_GETPLANE,
25118 + &p))
25119 + continue;
25121 + if (p.fb_id == 0 || p.crtc_id == 0)
25122 + continue;
25124 + memset(&s, 0, sizeof(s));
25125 + s.plane_id = p.plane_id;
25126 + s.crtc_id = p.crtc_id;
25127 + if (drmIoctl(sna->kgem.fd,
25128 + LOCAL_IOCTL_MODE_SETPLANE,
25129 + &s))
25130 + disabled |= sna_mode_shutdown_crtc(crtc);
25131 + }
25132 + }
25134 + return disabled;
25135 +}
25137 void sna_mode_check(struct sna *sna)
25139 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
25140 - int i;
25141 + bool disabled;
25142 + int c, o;
25144 if (sna->flags & SNA_IS_HOSTED)
25145 return;
25147 - DBG(("%s\n", __FUNCTION__));
25148 + DBG(("%s: hidden?=%d\n", __FUNCTION__, sna->mode.hidden));
25149 + if (sna->mode.hidden)
25150 + return;
25152 + disabled = sna_mode_disable_secondary_planes(sna);
25154 /* Validate CRTC attachments and force consistency upon the kernel */
25155 - for (i = 0; i < sna->mode.num_real_crtc; i++) {
25156 - xf86CrtcPtr crtc = config->crtc[i];
25157 + for (c = 0; c < sna->mode.num_real_crtc; c++) {
25158 + xf86CrtcPtr crtc = config->crtc[c];
25159 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
25160 struct drm_mode_crtc mode;
25161 uint32_t expected[2];
25162 @@ -6483,7 +8341,7 @@ void sna_mode_check(struct sna *sna)
25163 expected[1] = sna_crtc->flip_bo ? fb_id(sna_crtc->flip_bo) : -1;
25165 VG_CLEAR(mode);
25166 - mode.crtc_id = sna_crtc->id;
25167 + mode.crtc_id = __sna_crtc_id(sna_crtc);
25168 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
25169 continue;
25171 @@ -6492,16 +8350,12 @@ void sna_mode_check(struct sna *sna)
25172 mode.crtc_id, mode.mode_valid,
25173 mode.fb_id, expected[0], expected[1]));
25175 - if (mode.fb_id != expected[0] && mode.fb_id != expected[1]) {
25176 - xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
25177 - "%s: invalid state found on pipe %d, disabling CRTC:%d\n",
25178 - __FUNCTION__, sna_crtc->pipe, sna_crtc->id);
25179 - sna_crtc_disable(crtc);
25180 - }
25181 + if (mode.fb_id != expected[0] && mode.fb_id != expected[1])
25182 + disabled |= sna_mode_shutdown_crtc(crtc);
25185 - for (i = 0; i < config->num_output; i++) {
25186 - xf86OutputPtr output = config->output[i];
25187 + for (o = 0; o < config->num_output; o++) {
25188 + xf86OutputPtr output = config->output[o];
25189 struct sna_output *sna_output;
25191 if (output->crtc)
25192 @@ -6515,26 +8369,16 @@ void sna_mode_check(struct sna *sna)
25195 update_flush_interval(sna);
25197 + if (disabled)
25198 + xf86RandR12TellChanged(xf86ScrnToScreen(sna->scrn));
25201 static bool
25202 sna_crtc_hide_planes(struct sna *sna, struct sna_crtc *crtc)
25204 -#define LOCAL_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct local_mode_set_plane)
25205 - struct local_mode_set_plane {
25206 - uint32_t plane_id;
25207 - uint32_t crtc_id;
25208 - uint32_t fb_id; /* fb object contains surface format type */
25209 - uint32_t flags;
25211 - /* Signed dest location allows it to be partially off screen */
25212 - int32_t crtc_x, crtc_y;
25213 - uint32_t crtc_w, crtc_h;
25215 - /* Source values are 16.16 fixed point */
25216 - uint32_t src_x, src_y;
25217 - uint32_t src_h, src_w;
25218 - } s;
25219 + struct local_mode_set_plane s;
25220 + struct plane *plane;
25222 if (crtc->primary.id == 0)
25223 return false;
25224 @@ -6544,8 +8388,10 @@ sna_crtc_hide_planes(struct sna *sna, struct sna_crtc *crtc)
25225 if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s))
25226 return false;
25228 - s.plane_id = crtc->sprite.id;
25229 - (void)drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s);
25230 + list_for_each_entry(plane, &crtc->sprites, link) {
25231 + s.plane_id = plane->id;
25232 + (void)drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s);
25233 + }
25235 __sna_crtc_disable(sna, crtc);
25236 return true;
25237 @@ -6561,21 +8407,22 @@ void sna_mode_reset(struct sna *sna)
25239 DBG(("%s\n", __FUNCTION__));
25241 - sna_hide_cursors(sna->scrn);
25242 + sna_disable_cursors(sna->scrn);
25243 for (i = 0; i < sna->mode.num_real_crtc; i++)
25244 if (!sna_crtc_hide_planes(sna, to_sna_crtc(config->crtc[i])))
25245 - sna_crtc_disable(config->crtc[i]);
25246 + sna_crtc_disable(config->crtc[i], true);
25247 assert(sna->mode.front_active == 0);
25249 for (i = 0; i < sna->mode.num_real_crtc; i++) {
25250 struct sna_crtc *sna_crtc = to_sna_crtc(config->crtc[i]);
25251 + struct plane *plane;
25253 assert(sna_crtc != NULL);
25254 - sna_crtc->dpms_mode = -1;
25256 /* Force the rotation property to be reset on next use */
25257 rotation_reset(&sna_crtc->primary);
25258 - rotation_reset(&sna_crtc->sprite);
25259 + list_for_each_entry(plane, &sna_crtc->sprites, link)
25260 + rotation_reset(plane);
25263 /* VT switching, likely to be fbcon so make the backlight usable */
25264 @@ -6641,9 +8488,10 @@ sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
25266 int16_t sx, sy;
25267 struct sna *sna = to_sna(crtc->scrn);
25268 - ScreenPtr screen = sna->scrn->pScreen;
25269 + ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
25270 DrawablePtr draw = crtc_source(crtc, &sx, &sy);
25271 PictFormatPtr format;
25272 + PictTransform T;
25273 PicturePtr src, dst;
25274 PixmapPtr pixmap;
25275 int depth, error;
25276 @@ -6664,6 +8512,14 @@ sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
25277 __FUNCTION__, format->format, depth, draw->bitsPerPixel,
25278 bo->pitch, crtc->mode.HDisplay, crtc->mode.VDisplay));
25280 + if (sx | sy)
25281 + RegionTranslate(region, sx, sy);
25282 + error = !sna_drawable_move_region_to_cpu(draw, region, MOVE_READ);
25283 + if (sx | sy)
25284 + RegionTranslate(region, -sx, -sy);
25285 + if (error)
25286 + return;
25288 ptr = kgem_bo_map__gtt(&sna->kgem, bo);
25289 if (ptr == NULL)
25290 return;
25291 @@ -6683,9 +8539,37 @@ sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
25292 if (!src)
25293 goto free_pixmap;
25295 - error = SetPictureTransform(src, &crtc->crtc_to_framebuffer);
25296 - if (error)
25297 - goto free_src;
25298 + pixman_transform_init_translate(&T, sx << 16, sy << 16);
25299 + pixman_transform_multiply(&T, &T, &crtc->crtc_to_framebuffer);
25300 + if (!sna_transform_is_integer_translation(&T, &sx, &sy)) {
25301 +#define f2d(x) (((double)(x))/65536.)
25302 + DBG(("%s: transform=[[%f %f %f], [%f %f %f], [%f %f %f]] (raw [[%x %x %x], [%x %x %x], [%x %x %x]])\n",
25303 + __FUNCTION__,
25304 + f2d(T.matrix[0][0]),
25305 + f2d(T.matrix[0][1]),
25306 + f2d(T.matrix[0][2]),
25307 + f2d(T.matrix[1][0]),
25308 + f2d(T.matrix[1][1]),
25309 + f2d(T.matrix[1][2]),
25310 + f2d(T.matrix[2][0]),
25311 + f2d(T.matrix[2][1]),
25312 + f2d(T.matrix[2][2]),
25313 + T.matrix[0][0],
25314 + T.matrix[0][1],
25315 + T.matrix[0][2],
25316 + T.matrix[1][0],
25317 + T.matrix[1][1],
25318 + T.matrix[1][2],
25319 + T.matrix[2][0],
25320 + T.matrix[2][1],
25321 + T.matrix[2][2]));
25322 +#undef f2d
25324 + error = SetPictureTransform(src, &T);
25325 + if (error)
25326 + goto free_src;
25327 + sx = sy = 0;
25328 + }
25330 if (crtc->filter && crtc->transform_in_use)
25331 SetPicturePictFilter(src, crtc->filter,
25332 @@ -6733,10 +8617,11 @@ sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
25334 int16_t sx, sy;
25335 struct sna *sna = to_sna(crtc->scrn);
25336 - ScreenPtr screen = crtc->scrn->pScreen;
25337 + ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
25338 DrawablePtr draw = crtc_source(crtc, &sx, &sy);
25339 struct sna_composite_op tmp;
25340 PictFormatPtr format;
25341 + PictTransform T;
25342 PicturePtr src, dst;
25343 PixmapPtr pixmap;
25344 const BoxRec *b;
25345 @@ -6777,9 +8662,14 @@ sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
25346 if (!src)
25347 goto free_pixmap;
25349 - error = SetPictureTransform(src, &crtc->crtc_to_framebuffer);
25350 - if (error)
25351 - goto free_src;
25352 + pixman_transform_init_translate(&T, sx << 16, sy << 16);
25353 + pixman_transform_multiply(&T, &T, &crtc->crtc_to_framebuffer);
25354 + if (!sna_transform_is_integer_translation(&T, &sx, &sy)) {
25355 + error = SetPictureTransform(src, &T);
25356 + if (error)
25357 + goto free_src;
25358 + sx = sy = 0;
25359 + }
25361 if (crtc->filter && crtc->transform_in_use)
25362 SetPicturePictFilter(src, crtc->filter,
25363 @@ -6793,36 +8683,38 @@ sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
25364 ValidatePicture(src);
25365 ValidatePicture(dst);
25367 - if (!sna->render.composite(sna,
25368 - PictOpSrc, src, NULL, dst,
25369 - sx, sy,
25370 - 0, 0,
25371 - 0, 0,
25372 - crtc->mode.HDisplay, crtc->mode.VDisplay,
25373 - COMPOSITE_PARTIAL, memset(&tmp, 0, sizeof(tmp)))) {
25374 - DBG(("%s: unsupported operation!\n", __FUNCTION__));
25375 - sna_crtc_redisplay__fallback(crtc, region, bo);
25376 - goto free_dst;
25377 - }
25379 + /* Composite each box individually as if we are dealing with a rotation
25380 + * on a large display, we may have to perform intermediate copies. We
25381 + * can then minimise the overdraw by looking at individual boxes rather
25382 + * than the bbox.
25383 + */
25384 n = region_num_rects(region);
25385 b = region_rects(region);
25386 do {
25387 - BoxRec box;
25389 - box = *b++;
25390 + BoxRec box = *b;
25391 transformed_box(&box, crtc);
25393 DBG(("%s: (%d, %d)x(%d, %d) -> (%d, %d), (%d, %d)\n",
25394 __FUNCTION__,
25395 - b[-1].x1, b[-1].y1, b[-1].x2-b[-1].x1, b[-1].y2-b[-1].y1,
25396 + b->x1, b->y1, b->x2-b->x1, b->y2-b->y1,
25397 box.x1, box.y1, box.x2, box.y2));
25399 - tmp.box(sna, &tmp, &box);
25400 - } while (--n);
25401 - tmp.done(sna, &tmp);
25402 + if (!sna->render.composite(sna,
25403 + PictOpSrc, src, NULL, dst,
25404 + sx + box.x1, sy + box.y1,
25405 + 0, 0,
25406 + box.x1, box.y1,
25407 + box.x2 - box.x1, box.y2 - box.y1,
25408 + 0, memset(&tmp, 0, sizeof(tmp)))) {
25409 + DBG(("%s: unsupported operation!\n", __FUNCTION__));
25410 + sna_crtc_redisplay__fallback(crtc, region, bo);
25411 + break;
25412 + } else {
25413 + tmp.box(sna, &tmp, &box);
25414 + tmp.done(sna, &tmp);
25415 + }
25416 + } while (b++, --n);
25418 -free_dst:
25419 FreePicture(dst, None);
25420 free_src:
25421 FreePicture(src, None);
25422 @@ -6839,7 +8731,7 @@ sna_crtc_redisplay(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo *bo)
25423 struct sna_pixmap *priv = sna_pixmap((PixmapPtr)draw);
25425 DBG(("%s: crtc %d [pipe=%d], damage (%d, %d), (%d, %d) x %d\n",
25426 - __FUNCTION__, to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe,
25427 + __FUNCTION__, sna_crtc_id(crtc), sna_crtc_pipe(crtc),
25428 region->extents.x1, region->extents.y1,
25429 region->extents.x2, region->extents.y2,
25430 region_num_rects(region)));
25431 @@ -6898,7 +8790,10 @@ sna_crtc_redisplay(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo *bo)
25432 static void shadow_flip_handler(struct drm_event_vblank *e,
25433 void *data)
25435 - sna_mode_redisplay(data);
25436 + struct sna *sna = data;
25438 + if (!sna->mode.shadow_wait)
25439 + sna_mode_redisplay(sna);
25442 void sna_shadow_set_crtc(struct sna *sna,
25443 @@ -6908,18 +8803,23 @@ void sna_shadow_set_crtc(struct sna *sna,
25444 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
25445 struct sna_pixmap *priv;
25447 + assert(sna_crtc);
25448 DBG(("%s: setting shadow override for CRTC:%d to handle=%d\n",
25449 - __FUNCTION__, sna_crtc->id, bo->handle));
25450 + __FUNCTION__, __sna_crtc_id(sna_crtc), bo->handle));
25452 assert(sna->flags & SNA_TEAR_FREE);
25453 - assert(sna_crtc);
25454 assert(!sna_crtc->transform);
25456 if (sna_crtc->client_bo != bo) {
25457 - if (sna_crtc->client_bo)
25458 + if (sna_crtc->client_bo) {
25459 + assert(sna_crtc->client_bo->refcnt >= sna_crtc->client_bo->active_scanout);
25460 + sna_crtc->client_bo->active_scanout--;
25461 kgem_bo_destroy(&sna->kgem, sna_crtc->client_bo);
25462 + }
25464 sna_crtc->client_bo = kgem_bo_reference(bo);
25465 + sna_crtc->client_bo->active_scanout++;
25466 + assert(sna_crtc->client_bo->refcnt >= sna_crtc->client_bo->active_scanout);
25467 sna_crtc_damage(crtc);
25470 @@ -6969,11 +8869,13 @@ void sna_shadow_unset_crtc(struct sna *sna,
25471 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
25473 DBG(("%s: clearin shadow override for CRTC:%d\n",
25474 - __FUNCTION__, sna_crtc->id));
25475 + __FUNCTION__, __sna_crtc_id(sna_crtc)));
25477 if (sna_crtc->client_bo == NULL)
25478 return;
25480 + assert(sna_crtc->client_bo->refcnt >= sna_crtc->client_bo->active_scanout);
25481 + sna_crtc->client_bo->active_scanout--;
25482 kgem_bo_destroy(&sna->kgem, sna_crtc->client_bo);
25483 sna_crtc->client_bo = NULL;
25484 list_del(&sna_crtc->shadow_link);
25485 @@ -6982,15 +8884,57 @@ void sna_shadow_unset_crtc(struct sna *sna,
25486 sna_crtc_damage(crtc);
25489 +static bool move_crtc_to_gpu(struct sna *sna)
25490 +{
25491 + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
25492 + int i;
25494 + for (i = 0; i < sna->mode.num_real_crtc; i++) {
25495 + struct sna_crtc *crtc = to_sna_crtc(config->crtc[i]);
25496 + unsigned hint;
25498 + assert(crtc);
25500 + if (crtc->bo == NULL)
25501 + continue;
25503 + if (crtc->slave_pixmap)
25504 + continue;
25506 + if (crtc->client_bo)
25507 + continue;
25509 + if (crtc->shadow_bo)
25510 + continue;
25512 + hint = MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT;
25513 + if (sna->flags & SNA_TEAR_FREE)
25514 + hint |= __MOVE_FORCE;
25516 + DBG(("%s: CRTC %d [pipe=%d] requires frontbuffer\n",
25517 + __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc)));
25518 + return sna_pixmap_move_to_gpu(sna->front, hint);
25519 + }
25521 + return true;
25522 +}
25524 void sna_mode_redisplay(struct sna *sna)
25526 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
25527 RegionPtr region;
25528 int i;
25530 - if (!sna->mode.shadow_damage)
25531 + if (sna->mode.hidden) {
25532 + DBG(("%s: hidden outputs, skipping\n", __FUNCTION__));
25533 + return;
25534 + }
25536 + if (!sna->mode.shadow_enabled)
25537 return;
25539 + assert(sna->mode.shadow_damage);
25541 DBG(("%s: posting shadow damage? %d (flips pending? %d, mode reconfiguration pending? %d)\n",
25542 __FUNCTION__,
25543 !RegionNil(DamageRegion(sna->mode.shadow_damage)),
25544 @@ -7012,21 +8956,23 @@ void sna_mode_redisplay(struct sna *sna)
25545 region->extents.x2, region->extents.y2));
25547 if (sna->mode.flip_active) {
25548 - DamagePtr damage;
25550 - damage = sna->mode.shadow_damage;
25551 - sna->mode.shadow_damage = NULL;
25552 + DBG(("%s: checking for %d outstanding flip completions\n",
25553 + __FUNCTION__, sna->mode.flip_active));
25555 + sna->mode.dirty = true;
25556 while (sna->mode.flip_active && sna_mode_wakeup(sna))
25558 + sna->mode.dirty = false;
25560 - sna->mode.shadow_damage = damage;
25561 + DBG(("%s: now %d outstanding flip completions (enabled? %d)\n",
25562 + __FUNCTION__,
25563 + sna->mode.flip_active,
25564 + sna->mode.shadow_enabled));
25565 + if (sna->mode.flip_active || !sna->mode.shadow_enabled)
25566 + return;
25569 - if (sna->mode.flip_active)
25570 - return;
25572 - if (wedged(sna) || !sna_pixmap_move_to_gpu(sna->front, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT)) {
25573 + if (!move_crtc_to_gpu(sna)) {
25574 DBG(("%s: forcing scanout update using the CPU\n", __FUNCTION__));
25575 if (!sna_pixmap_move_to_cpu(sna->front, MOVE_READ))
25576 return;
25577 @@ -7047,90 +8993,14 @@ void sna_mode_redisplay(struct sna *sna)
25578 damage.data = NULL;
25579 RegionIntersect(&damage, &damage, region);
25580 if (!box_empty(&damage.extents)) {
25581 - struct kgem_bo *bo = NULL;
25583 DBG(("%s: fallback intersects pipe=%d [(%d, %d), (%d, %d)]\n",
25584 - __FUNCTION__, sna_crtc->pipe,
25585 + __FUNCTION__, __sna_crtc_pipe(sna_crtc),
25586 damage.extents.x1, damage.extents.y1,
25587 damage.extents.x2, damage.extents.y2));
25589 - if (sna->flags & SNA_TEAR_FREE) {
25590 - RegionRec new_damage;
25592 - RegionNull(&new_damage);
25593 - RegionCopy(&new_damage, &damage);
25595 - bo = sna_crtc->client_bo;
25596 - if (bo == NULL) {
25597 - damage.extents = crtc->bounds;
25598 - damage.data = NULL;
25599 - bo = kgem_create_2d(&sna->kgem,
25600 - crtc->mode.HDisplay,
25601 - crtc->mode.VDisplay,
25602 - crtc->scrn->bitsPerPixel,
25603 - sna_crtc->bo->tiling,
25604 - CREATE_SCANOUT);
25605 - } else
25606 - RegionUnion(&damage, &damage, &sna_crtc->client_damage);
25608 - DBG(("%s: TearFree fallback, shadow handle=%d, crtc handle=%d\n", __FUNCTION__, bo->handle, sna_crtc->bo->handle));
25610 - sna_crtc->client_damage = new_damage;
25611 - }
25613 - if (bo == NULL)
25614 - bo = sna_crtc->bo;
25615 - sna_crtc_redisplay__fallback(crtc, &damage, bo);
25617 - if (bo != sna_crtc->bo) {
25618 - struct drm_mode_crtc_page_flip arg;
25620 - arg.crtc_id = sna_crtc->id;
25621 - arg.fb_id = get_fb(sna, bo,
25622 - crtc->mode.HDisplay,
25623 - crtc->mode.VDisplay);
25625 - arg.user_data = (uintptr_t)sna_crtc;
25626 - arg.flags = DRM_MODE_PAGE_FLIP_EVENT;
25627 - arg.reserved = 0;
25629 - if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
25630 - if (sna_crtc_flip(sna, sna_crtc, bo, 0, 0)) {
25631 - assert(sna_crtc->bo->active_scanout);
25632 - assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout);
25633 - sna_crtc->bo->active_scanout--;
25634 - kgem_bo_destroy(&sna->kgem, sna_crtc->bo);
25636 - sna_crtc->bo = bo;
25637 - sna_crtc->bo->active_scanout++;
25638 - sna_crtc->client_bo = NULL;
25639 - } else {
25640 - DBG(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
25641 - __FUNCTION__, arg.fb_id, i, sna_crtc->id, sna_crtc->pipe, errno));
25642 - xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
25643 - "Page flipping failed, disabling TearFree\n");
25644 - sna->flags &= ~SNA_TEAR_FREE;
25646 - damage.extents = crtc->bounds;
25647 - damage.data = NULL;
25648 - sna_crtc_redisplay__fallback(crtc, &damage, sna_crtc->bo);
25650 - kgem_bo_destroy(&sna->kgem, bo);
25651 - sna_crtc->client_bo = NULL;
25652 - }
25653 - } else {
25654 - sna->mode.flip_active++;
25656 - assert(sna_crtc->flip_bo == NULL);
25657 - sna_crtc->flip_handler = shadow_flip_handler;
25658 - sna_crtc->flip_data = sna;
25659 - sna_crtc->flip_bo = bo;
25660 - sna_crtc->flip_bo->active_scanout++;
25661 - sna_crtc->flip_serial = sna_crtc->mode_serial;
25663 - sna_crtc->client_bo = kgem_bo_reference(sna_crtc->bo);
25664 - }
25665 - }
25666 + sna_crtc_redisplay__fallback(crtc,
25667 + &damage,
25668 + sna_crtc->bo);
25670 RegionUninit(&damage);
25672 @@ -7171,6 +9041,7 @@ void sna_mode_redisplay(struct sna *sna)
25673 xf86CrtcPtr crtc = config->crtc[i];
25674 struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
25675 RegionRec damage;
25676 + int sigio;
25678 assert(sna_crtc != NULL);
25679 DBG(("%s: crtc[%d] transformed? %d\n",
25680 @@ -7192,30 +9063,38 @@ void sna_mode_redisplay(struct sna *sna)
25681 region_num_rects(&damage),
25682 damage.extents.x1, damage.extents.y1,
25683 damage.extents.x2, damage.extents.y2));
25684 + sigio = sigio_block();
25685 if (!box_empty(&damage.extents)) {
25686 if (sna->flags & SNA_TEAR_FREE) {
25687 + RegionRec new_damage;
25688 struct drm_mode_crtc_page_flip arg;
25689 struct kgem_bo *bo;
25691 - RegionUninit(&damage);
25692 - damage.extents = crtc->bounds;
25693 - damage.data = NULL;
25694 + RegionNull(&new_damage);
25695 + RegionCopy(&new_damage, &damage);
25697 - bo = sna_crtc->client_bo;
25698 - if (bo == NULL)
25699 + bo = sna_crtc->cache_bo;
25700 + if (bo == NULL) {
25701 + damage.extents = crtc->bounds;
25702 + damage.data = NULL;
25703 bo = kgem_create_2d(&sna->kgem,
25704 crtc->mode.HDisplay,
25705 crtc->mode.VDisplay,
25706 crtc->scrn->bitsPerPixel,
25707 sna_crtc->bo->tiling,
25708 CREATE_SCANOUT);
25709 - if (bo == NULL)
25710 - goto disable1;
25711 + if (bo == NULL)
25712 + continue;
25713 + } else
25714 + RegionUnion(&damage, &damage, &sna_crtc->crtc_damage);
25715 + sna_crtc->crtc_damage = new_damage;
25717 sna_crtc_redisplay(crtc, &damage, bo);
25718 kgem_bo_submit(&sna->kgem, bo);
25719 + __kgem_bo_clear_dirty(bo);
25721 - arg.crtc_id = sna_crtc->id;
25722 + assert_crtc_fb(sna, sna_crtc);
25723 + arg.crtc_id = __sna_crtc_id(sna_crtc);
25724 arg.fb_id = get_fb(sna, bo,
25725 crtc->mode.HDisplay,
25726 crtc->mode.VDisplay);
25727 @@ -7228,6 +9107,9 @@ void sna_mode_redisplay(struct sna *sna)
25729 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
25730 if (sna_crtc_flip(sna, sna_crtc, bo, 0, 0)) {
25731 + DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n",
25732 + __FUNCTION__, sna_crtc->bo->handle, sna_crtc->bo->active_scanout - 1,
25733 + bo->handle, bo->active_scanout));
25734 assert(sna_crtc->bo->active_scanout);
25735 assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout);
25736 sna_crtc->bo->active_scanout--;
25737 @@ -7235,13 +9117,12 @@ void sna_mode_redisplay(struct sna *sna)
25739 sna_crtc->bo = kgem_bo_reference(bo);
25740 sna_crtc->bo->active_scanout++;
25741 - sna_crtc->client_bo = kgem_bo_reference(bo);
25742 } else {
25743 BoxRec box;
25744 DrawableRec tmp;
25746 DBG(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
25747 - __FUNCTION__, arg.fb_id, i, sna_crtc->id, sna_crtc->pipe, errno));
25748 + __FUNCTION__, arg.fb_id, i, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc), errno));
25749 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
25750 "Page flipping failed, disabling TearFree\n");
25751 sna->flags &= ~SNA_TEAR_FREE;
25752 @@ -7260,13 +9141,13 @@ disable1:
25753 &box, 1, COPY_LAST)) {
25754 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
25755 "%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n",
25756 - __FUNCTION__, sna_crtc->id, sna_crtc->pipe);
25757 - sna_crtc_disable(crtc);
25758 + __FUNCTION__, __sna_crtc_id(sna_crtc), __sna_crtc_pipe(sna_crtc));
25759 + sna_crtc_disable(crtc, false);
25762 - kgem_bo_destroy(&sna->kgem, bo);
25763 - sna_crtc->client_bo = NULL;
25766 + kgem_bo_destroy(&sna->kgem, bo);
25767 + sna_crtc->cache_bo = NULL;
25768 continue;
25770 sna->mode.flip_active++;
25771 @@ -7279,13 +9160,20 @@ disable1:
25772 sna_crtc->flip_serial = sna_crtc->mode_serial;
25773 sna_crtc->flip_pending = true;
25775 - sna_crtc->client_bo = kgem_bo_reference(sna_crtc->bo);
25776 + if (sna_crtc->bo != sna->mode.shadow) {
25777 + assert_scanout(&sna->kgem, sna_crtc->bo,
25778 + crtc->mode.HDisplay, crtc->mode.VDisplay);
25779 + sna_crtc->cache_bo = kgem_bo_reference(sna_crtc->bo);
25780 + }
25781 + DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
25782 + __FUNCTION__, __sna_crtc_id(sna_crtc), sna_crtc->flip_bo->handle, sna_crtc->flip_bo->active_scanout, sna_crtc->flip_serial));
25783 } else {
25784 sna_crtc_redisplay(crtc, &damage, sna_crtc->bo);
25785 kgem_scanout_flush(&sna->kgem, sna_crtc->bo);
25788 RegionUninit(&damage);
25789 + sigio_unblock(sigio);
25791 if (sna_crtc->slave_damage)
25792 DamageEmpty(sna_crtc->slave_damage);
25793 @@ -7296,6 +9184,7 @@ disable1:
25794 struct kgem_bo *old = sna->mode.shadow;
25795 struct drm_mode_crtc_page_flip arg;
25796 uint32_t fb = 0;
25797 + int sigio;
25799 DBG(("%s: flipping TearFree outputs, current scanout handle=%d [active?=%d], new handle=%d [active=%d]\n",
25800 __FUNCTION__, old->handle, old->active_scanout, new->handle, new->active_scanout));
25801 @@ -7307,7 +9196,9 @@ disable1:
25802 arg.reserved = 0;
25804 kgem_bo_submit(&sna->kgem, new);
25805 + __kgem_bo_clear_dirty(new);
25807 + sigio = sigio_block();
25808 for (i = 0; i < sna->mode.num_real_crtc; i++) {
25809 struct sna_crtc *crtc = config->crtc[i]->driver_private;
25810 struct kgem_bo *flip_bo;
25811 @@ -7315,20 +9206,20 @@ disable1:
25813 assert(crtc != NULL);
25814 DBG(("%s: crtc %d [%d, pipe=%d] active? %d, transformed? %d\n",
25815 - __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo ? crtc->bo->handle : 0, crtc->transform));
25816 + __FUNCTION__, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->bo ? crtc->bo->handle : 0, crtc->transform));
25817 if (crtc->bo == NULL || crtc->transform)
25818 continue;
25820 assert(config->crtc[i]->enabled);
25821 - assert(crtc->dpms_mode <= DPMSModeOn);
25822 assert(crtc->flip_bo == NULL);
25823 + assert_crtc_fb(sna, crtc);
25825 - arg.crtc_id = crtc->id;
25826 + arg.crtc_id = __sna_crtc_id(crtc);
25827 arg.user_data = (uintptr_t)crtc;
25829 if (crtc->client_bo) {
25830 DBG(("%s: apply shadow override bo for CRTC:%d on pipe=%d, handle=%d\n",
25831 - __FUNCTION__, crtc->id, crtc->pipe, crtc->client_bo->handle));
25832 + __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), crtc->client_bo->handle));
25833 arg.fb_id = get_fb(sna, crtc->client_bo,
25834 crtc->base->mode.HDisplay,
25835 crtc->base->mode.VDisplay);
25836 @@ -7356,6 +9247,7 @@ fixup_shadow:
25840 + sigio_unblock(sigio);
25841 return;
25844 @@ -7365,8 +9257,12 @@ fixup_shadow:
25845 y = crtc->base->y;
25848 - if (crtc->bo == flip_bo)
25849 + if (crtc->bo == flip_bo) {
25850 + assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
25851 + DBG(("%s: flip handle=%d is already on the CRTC\n",
25852 + __FUNCTION__, flip_bo->handle));
25853 continue;
25854 + }
25856 if (flip_bo->pitch != crtc->bo->pitch || (y << 16 | x) != crtc->offset) {
25857 DBG(("%s: changing pitch (new %d =?= old %d) or offset (new %x =?= old %x)\n",
25858 @@ -7375,6 +9271,9 @@ fixup_shadow:
25859 y << 16 | x, crtc->offset));
25860 fixup_flip:
25861 if (sna_crtc_flip(sna, crtc, flip_bo, x, y)) {
25862 + DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n",
25863 + __FUNCTION__, crtc->bo->handle, crtc->bo->active_scanout-1,
25864 + flip_bo->handle, flip_bo->active_scanout));
25865 assert(flip_bo != crtc->bo);
25866 assert(crtc->bo->active_scanout);
25867 assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
25868 @@ -7389,9 +9288,11 @@ fixup_flip:
25869 crtc->bo = kgem_bo_reference(flip_bo);
25870 crtc->bo->active_scanout++;
25871 } else {
25872 - xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
25873 - "Failed to prepare CRTC for page flipping, disabling TearFree\n");
25874 - sna->flags &= ~SNA_TEAR_FREE;
25875 + if (sna->flags & SNA_TEAR_FREE) {
25876 + xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
25877 + "Failed to prepare CRTC for page flipping, disabling TearFree\n");
25878 + sna->flags &= ~SNA_TEAR_FREE;
25879 + }
25881 if (sna->mode.flip_active == 0) {
25882 DBG(("%s: abandoning flip attempt\n", __FUNCTION__));
25883 @@ -7400,15 +9301,15 @@ fixup_flip:
25885 xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
25886 "%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n",
25887 - __FUNCTION__, crtc->id, crtc->pipe);
25888 - sna_crtc_disable(crtc->base);
25889 + __FUNCTION__, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc));
25890 + sna_crtc_disable(crtc->base, false);
25892 continue;
25895 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
25896 ERR(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
25897 - __FUNCTION__, arg.fb_id, i, crtc->id, crtc->pipe, errno));
25898 + __FUNCTION__, arg.fb_id, i, __sna_crtc_id(crtc), __sna_crtc_pipe(crtc), errno));
25899 goto fixup_flip;
25901 sna->mode.flip_active++;
25902 @@ -7421,6 +9322,9 @@ fixup_flip:
25903 crtc->flip_serial = crtc->mode_serial;
25904 crtc->flip_pending = true;
25906 + DBG(("%s: recording flip on CRTC:%d handle=%d, active_scanout=%d, serial=%d\n",
25907 + __FUNCTION__, __sna_crtc_id(crtc), crtc->flip_bo->handle, crtc->flip_bo->active_scanout, crtc->flip_serial));
25910 struct drm_i915_gem_busy busy = { flip_bo->handle };
25911 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy) == 0) {
25912 @@ -7435,6 +9339,7 @@ fixup_flip:
25916 + sigio_unblock(sigio);
25918 DBG(("%s: flipped %d outputs, shadow active? %d\n",
25919 __FUNCTION__,
25920 @@ -7486,7 +9391,9 @@ again:
25921 struct drm_event *e = (struct drm_event *)&buffer[i];
25922 switch (e->type) {
25923 case DRM_EVENT_VBLANK:
25924 - if (((uintptr_t)((struct drm_event_vblank *)e)->user_data) & 2)
25925 + if (sna->mode.shadow_wait)
25926 + defer_event(sna, e);
25927 + else if (((uintptr_t)((struct drm_event_vblank *)e)->user_data) & 2)
25928 sna_present_vblank_handler((struct drm_event_vblank *)e);
25929 else
25930 sna_dri2_vblank_handler((struct drm_event_vblank *)e);
25931 @@ -7495,13 +9402,19 @@ again:
25933 struct drm_event_vblank *vbl = (struct drm_event_vblank *)e;
25934 struct sna_crtc *crtc = (void *)(uintptr_t)vbl->user_data;
25935 + uint64_t msc;
25937 /* Beware Zaphod! */
25938 sna = to_sna(crtc->base->scrn);
25940 - crtc->swap.tv_sec = vbl->tv_sec;
25941 - crtc->swap.tv_usec = vbl->tv_usec;
25942 - crtc->swap.msc = msc64(crtc, vbl->sequence);
25943 + if (msc64(crtc, vbl->sequence, &msc)) {
25944 + DBG(("%s: recording last swap on pipe=%d, frame %d [%08llx], time %d.%06d\n",
25945 + __FUNCTION__, __sna_crtc_pipe(crtc), vbl->sequence, (long long)msc, vbl->tv_sec, vbl->tv_usec));
25946 + crtc->swap.tv_sec = vbl->tv_sec;
25947 + crtc->swap.tv_usec = vbl->tv_usec;
25948 + crtc->swap.msc = msc;
25949 + }
25950 + assert(crtc->flip_pending);
25951 crtc->flip_pending = false;
25953 assert(crtc->flip_bo);
25954 @@ -7509,10 +9422,12 @@ again:
25955 assert(crtc->flip_bo->refcnt >= crtc->flip_bo->active_scanout);
25957 if (crtc->flip_serial == crtc->mode_serial) {
25958 - DBG(("%s: removing handle=%d from scanout, installing handle=%d\n",
25959 - __FUNCTION__, crtc->bo->handle, crtc->flip_bo->handle));
25960 + DBG(("%s: removing handle=%d [active_scanout=%d] from scanout, installing handle=%d [active_scanout=%d]\n",
25961 + __FUNCTION__, crtc->bo->handle, crtc->bo->active_scanout - 1,
25962 + crtc->flip_bo->handle, crtc->flip_bo->active_scanout));
25963 assert(crtc->bo->active_scanout);
25964 assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
25966 crtc->bo->active_scanout--;
25967 kgem_bo_destroy(&sna->kgem, crtc->bo);
25969 @@ -7523,6 +9438,8 @@ again:
25971 crtc->bo = crtc->flip_bo;
25972 crtc->flip_bo = NULL;
25974 + assert_crtc_fb(sna, crtc);
25975 } else {
25976 crtc->flip_bo->active_scanout--;
25977 kgem_bo_destroy(&sna->kgem, crtc->flip_bo);
25978 @@ -7531,8 +9448,10 @@ again:
25980 DBG(("%s: flip complete, pending? %d\n", __FUNCTION__, sna->mode.flip_active));
25981 assert(sna->mode.flip_active);
25982 - if (--sna->mode.flip_active == 0)
25983 + if (--sna->mode.flip_active == 0) {
25984 + assert(crtc->flip_handler);
25985 crtc->flip_handler(vbl, crtc->flip_data);
25986 + }
25988 break;
25989 default:
25990 diff --git a/src/sna/sna_display_fake.c b/src/sna/sna_display_fake.c
25991 index 4d74c38d..fa26bda1 100644
25992 --- a/src/sna/sna_display_fake.c
25993 +++ b/src/sna/sna_display_fake.c
25994 @@ -96,12 +96,6 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
25997 static void
25998 -sna_crtc_gamma_set(xf86CrtcPtr crtc,
25999 - CARD16 *red, CARD16 *green, CARD16 *blue, int size)
26000 -{
26001 -}
26003 -static void
26004 sna_crtc_destroy(xf86CrtcPtr crtc)
26007 @@ -109,7 +103,6 @@ sna_crtc_destroy(xf86CrtcPtr crtc)
26008 static const xf86CrtcFuncsRec sna_crtc_funcs = {
26009 .dpms = sna_crtc_dpms,
26010 .set_mode_major = sna_crtc_set_mode_major,
26011 - .gamma_set = sna_crtc_gamma_set,
26012 .destroy = sna_crtc_destroy,
26013 };
26015 @@ -192,7 +185,7 @@ static const xf86OutputFuncsRec sna_output_funcs = {
26016 static Bool
26017 sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
26019 - ScreenPtr screen = scrn->pScreen;
26020 + ScreenPtr screen = xf86ScrnToScreen(scrn);
26021 PixmapPtr new_front;
26023 DBG(("%s (%d, %d) -> (%d, %d)\n", __FUNCTION__,
26024 @@ -262,6 +255,7 @@ static bool add_fake_output(struct sna *sna, bool late)
26025 output->mm_height = 0;
26026 output->interlaceAllowed = FALSE;
26027 output->subpixel_order = SubPixelNone;
26028 + output->status = XF86OutputStatusDisconnected;
26030 output->possible_crtcs = ~((1 << sna->mode.num_real_crtc) - 1);
26031 output->possible_clones = ~((1 << sna->mode.num_real_output) - 1);
26032 @@ -297,6 +291,8 @@ static bool add_fake_output(struct sna *sna, bool late)
26034 RRCrtcSetRotations(crtc->randr_crtc,
26035 RR_Rotate_All | RR_Reflect_All);
26036 + if (!RRCrtcGammaSetSize(crtc->randr_crtc, 256))
26037 + goto err;
26040 sna->mode.num_fake++;
26041 @@ -312,13 +308,16 @@ err:
26042 continue;
26044 xf86OutputDestroy(output);
26045 + i--;
26048 for (i = 0; i < xf86_config->num_crtc; i++) {
26049 crtc = xf86_config->crtc[i];
26050 if (crtc->driver_private)
26051 continue;
26053 xf86CrtcDestroy(crtc);
26054 + i--;
26056 sna->mode.num_fake = -1;
26057 return false;
26058 diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
26059 index e5c4d53e..d89525cc 100644
26060 --- a/src/sna/sna_dri2.c
26061 +++ b/src/sna/sna_dri2.c
26062 @@ -82,12 +82,23 @@ get_private(void *buffer)
26063 return (struct sna_dri2_private *)((DRI2Buffer2Ptr)buffer+1);
26066 +pure static inline DRI2BufferPtr sna_pixmap_get_buffer(PixmapPtr pixmap)
26067 +{
26068 + assert(pixmap->refcnt);
26069 + return ((void **)__get_private(pixmap, sna_pixmap_key))[2];
26070 +}
26072 +static inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr)
26073 +{
26074 + assert(pixmap->refcnt);
26075 + ((void **)__get_private(pixmap, sna_pixmap_key))[2] = ptr;
26076 +}
26078 #if DRI2INFOREC_VERSION >= 4
26079 enum event_type {
26080 WAITMSC = 0,
26081 SWAP,
26082 - SWAP_WAIT,
26083 - SWAP_THROTTLE,
26084 + SWAP_COMPLETE,
26085 FLIP,
26086 FLIP_THROTTLE,
26087 FLIP_COMPLETE,
26088 @@ -98,6 +109,7 @@ struct dri_bo {
26089 struct list link;
26090 struct kgem_bo *bo;
26091 uint32_t name;
26092 + unsigned flags;
26093 };
26095 struct sna_dri2_event {
26096 @@ -108,6 +120,8 @@ struct sna_dri2_event {
26097 xf86CrtcPtr crtc;
26098 int pipe;
26099 bool queued;
26100 + bool sync;
26101 + bool chained;
26103 /* for swaps & flips only */
26104 DRI2SwapEventPtr event_complete;
26105 @@ -116,35 +130,146 @@ struct sna_dri2_event {
26106 DRI2BufferPtr back;
26107 struct kgem_bo *bo;
26109 + struct copy {
26110 + struct kgem_bo *bo;
26111 + unsigned flags;
26112 + uint32_t name;
26113 + uint32_t size;
26114 + } pending;
26116 struct sna_dri2_event *chain;
26118 - struct list cache;
26119 struct list link;
26121 - int mode;
26122 + int flip_continue;
26123 + int keepalive;
26124 + int signal;
26125 };
26127 +#if DRI2INFOREC_VERSION < 10
26128 +#undef USE_ASYNC_SWAP
26129 +#endif
26131 +#if USE_ASYNC_SWAP
26132 +#define KEEPALIVE 8 /* wait ~100ms before discarding swap caches */
26133 +#define APPLY_DAMAGE 0
26134 +#else
26135 +#define USE_ASYNC_SWAP 0
26136 +#define KEEPALIVE 1
26137 +#define APPLY_DAMAGE 1
26138 +#endif
26140 static void sna_dri2_flip_event(struct sna_dri2_event *flip);
26141 +inline static DRI2BufferPtr dri2_window_get_front(WindowPtr win);
26143 +static struct kgem_bo *
26144 +__sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
26145 + DRI2BufferPtr src, DRI2BufferPtr dst,
26146 + unsigned flags);
26148 +inline static void
26149 +__sna_dri2_copy_event(struct sna_dri2_event *info, unsigned flags)
26150 +{
26151 + DBG(("%s: flags = %x\n", __FUNCTION__, flags));
26152 + assert(info->front != info->back);
26153 + info->bo = __sna_dri2_copy_region(info->sna, info->draw, NULL,
26154 + info->back, info->front,
26155 + flags);
26156 + info->front->flags = info->back->flags;
26157 +}
26159 +static int front_pitch(DrawablePtr draw)
26160 +{
26161 + DRI2BufferPtr buffer;
26163 + buffer = NULL;
26164 + if (draw->type != DRAWABLE_PIXMAP)
26165 + buffer = dri2_window_get_front((WindowPtr)draw);
26166 + if (buffer == NULL)
26167 + buffer = sna_pixmap_get_buffer(get_drawable_pixmap(draw));
26169 + return buffer ? buffer->pitch : 0;
26170 +}
26172 +struct dri2_window {
26173 + DRI2BufferPtr front;
26174 + struct sna_dri2_event *chain;
26175 + xf86CrtcPtr crtc;
26176 + int64_t msc_delta;
26177 + struct list cache;
26178 + uint32_t cache_size;
26179 + int scanout;
26180 +};
26182 +static struct dri2_window *dri2_window(WindowPtr win)
26183 +{
26184 + assert(win->drawable.type != DRAWABLE_PIXMAP);
26185 + return ((void **)__get_private(win, sna_window_key))[1];
26186 +}
26188 +static bool use_scanout(struct sna *sna,
26189 + DrawablePtr draw,
26190 + struct dri2_window *priv)
26191 +{
26192 + if (priv->front)
26193 + return true;
26195 + if (priv->scanout < 0)
26196 + priv->scanout =
26197 + (sna->flags & (SNA_LINEAR_FB | SNA_NO_WAIT | SNA_NO_FLIP)) == 0 &&
26198 + draw->width == sna->front->drawable.width &&
26199 + draw->height == sna->front->drawable.height &&
26200 + draw->bitsPerPixel == sna->front->drawable.bitsPerPixel;
26202 + return priv->scanout;
26203 +}
26205 static void
26206 sna_dri2_get_back(struct sna *sna,
26207 DrawablePtr draw,
26208 - DRI2BufferPtr back,
26209 - struct sna_dri2_event *info)
26210 + DRI2BufferPtr back)
26212 + struct dri2_window *priv = dri2_window((WindowPtr)draw);
26213 + uint32_t size;
26214 struct kgem_bo *bo;
26215 + struct dri_bo *c;
26216 uint32_t name;
26217 + int flags;
26218 bool reuse;
26220 - DBG(("%s: draw size=%dx%d, buffer size=%dx%d\n",
26221 + DBG(("%s: draw size=%dx%d, back buffer handle=%d size=%dx%d, is-scanout? %d, active?=%d, pitch=%d, front pitch=%d\n",
26222 __FUNCTION__, draw->width, draw->height,
26223 - get_private(back)->size & 0xffff, get_private(back)->size >> 16));
26224 - reuse = (draw->height << 16 | draw->width) == get_private(back)->size;
26225 + get_private(back)->bo->handle,
26226 + get_private(back)->size & 0xffff, get_private(back)->size >> 16,
26227 + get_private(back)->bo->scanout,
26228 + get_private(back)->bo->active_scanout,
26229 + back->pitch, front_pitch(draw)));
26230 + assert(priv);
26232 + size = draw->height << 16 | draw->width;
26233 + if (size != priv->cache_size) {
26234 + while (!list_is_empty(&priv->cache)) {
26235 + c = list_first_entry(&priv->cache, struct dri_bo, link);
26236 + list_del(&c->link);
26238 + DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
26239 + assert(c->bo);
26240 + kgem_bo_destroy(&sna->kgem, c->bo);
26242 + free(c);
26243 + }
26244 + priv->cache_size = size;
26245 + }
26247 + reuse = size == get_private(back)->size;
26248 + if (reuse)
26249 + reuse = get_private(back)->bo->scanout == use_scanout(sna, draw, priv);
26250 + DBG(("%s: reuse backbuffer? %d\n", __FUNCTION__, reuse));
26251 if (reuse) {
26252 bo = get_private(back)->bo;
26253 assert(bo->refcnt);
26254 - DBG(("%s: back buffer handle=%d, scanout?=%d, refcnt=%d\n",
26255 - __FUNCTION__, bo->handle, bo->active_scanout, get_private(back)->refcnt));
26256 + DBG(("%s: back buffer handle=%d, active?=%d, refcnt=%d\n",
26257 + __FUNCTION__, bo->handle, bo->active_scanout, get_private(back)->refcnt));
26258 if (bo->active_scanout == 0) {
26259 DBG(("%s: reuse unattached back\n", __FUNCTION__));
26260 get_private(back)->stale = false;
26261 @@ -153,24 +278,37 @@ sna_dri2_get_back(struct sna *sna,
26264 bo = NULL;
26265 - if (info) {
26266 - struct dri_bo *c;
26267 - list_for_each_entry(c, &info->cache, link) {
26268 - if (c->bo && c->bo->scanout == 0) {
26269 - bo = c->bo;
26270 - name = c->name;
26271 - DBG(("%s: reuse cache handle=%d\n", __FUNCTION__, bo->handle));
26272 - list_move_tail(&c->link, &info->cache);
26273 - c->bo = NULL;
26274 + list_for_each_entry(c, &priv->cache, link) {
26275 + DBG(("%s: cache: handle=%d, active=%d\n",
26276 + __FUNCTION__, c->bo ? c->bo->handle : 0, c->bo ? c->bo->active_scanout : -1));
26277 + assert(c->bo);
26278 + if (c->bo->active_scanout == 0) {
26279 + _list_del(&c->link);
26280 + if (c->bo == NULL) {
26281 + free(c);
26282 + goto out;
26284 + bo = c->bo;
26285 + name = c->name;
26286 + flags = c->flags;
26287 + DBG(("%s: reuse cache handle=%d, name=%d, flags=%d\n", __FUNCTION__, bo->handle, name, flags));
26288 + c->bo = NULL;
26289 + break;
26292 if (bo == NULL) {
26293 DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
26294 + flags = CREATE_EXACT;
26296 + if (use_scanout(sna, draw, priv)) {
26297 + DBG(("%s: requesting scanout compatible back\n", __FUNCTION__));
26298 + flags |= CREATE_SCANOUT;
26299 + }
26301 bo = kgem_create_2d(&sna->kgem,
26302 draw->width, draw->height, draw->bitsPerPixel,
26303 get_private(back)->bo->tiling,
26304 - get_private(back)->bo->scanout ? CREATE_SCANOUT : 0);
26305 + flags);
26306 if (bo == NULL)
26307 return;
26309 @@ -179,30 +317,42 @@ sna_dri2_get_back(struct sna *sna,
26310 kgem_bo_destroy(&sna->kgem, bo);
26311 return;
26314 + flags = 0;
26315 + if (USE_ASYNC_SWAP && back->flags) {
26316 + BoxRec box;
26318 + box.x1 = 0;
26319 + box.y1 = 0;
26320 + box.x2 = draw->width;
26321 + box.y2 = draw->height;
26323 + DBG(("%s: filling new buffer with old back\n", __FUNCTION__));
26324 + if (sna->render.copy_boxes(sna, GXcopy,
26325 + draw, get_private(back)->bo, 0, 0,
26326 + draw, bo, 0, 0,
26327 + &box, 1, COPY_LAST | COPY_DRI))
26328 + flags = back->flags;
26329 + }
26331 assert(bo->active_scanout == 0);
26333 - if (info && reuse) {
26334 - bool found = false;
26335 - struct dri_bo *c;
26337 - list_for_each_entry_reverse(c, &info->cache, link) {
26338 - if (c->bo == NULL) {
26339 - found = true;
26340 - _list_del(&c->link);
26341 - break;
26342 - }
26343 - }
26344 - if (!found)
26345 + if (reuse && get_private(back)->bo->refcnt == 1 + get_private(back)->bo->active_scanout) {
26346 + if (&c->link == &priv->cache)
26347 c = malloc(sizeof(*c));
26348 if (c != NULL) {
26349 c->bo = ref(get_private(back)->bo);
26350 c->name = back->name;
26351 - list_add(&c->link, &info->cache);
26352 - DBG(("%s: cacheing handle=%d (name=%d)\n", __FUNCTION__, c->bo->handle, c->name));
26353 + c->flags = back->flags;
26354 + list_add(&c->link, &priv->cache);
26355 + 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));
26357 + } else {
26358 + if (&c->link != &priv->cache)
26359 + free(c);
26362 + assert(bo->active_scanout == 0);
26363 assert(bo != get_private(back)->bo);
26364 kgem_bo_destroy(&sna->kgem, get_private(back)->bo);
26366 @@ -210,21 +360,13 @@ sna_dri2_get_back(struct sna *sna,
26367 get_private(back)->size = draw->height << 16 | draw->width;
26368 back->pitch = bo->pitch;
26369 back->name = name;
26370 + back->flags = flags;
26372 - get_private(back)->stale = false;
26373 -}
26375 -struct dri2_window {
26376 - DRI2BufferPtr front;
26377 - struct sna_dri2_event *chain;
26378 - xf86CrtcPtr crtc;
26379 - int64_t msc_delta;
26380 -};
26381 + assert(back->pitch);
26382 + assert(back->name);
26384 -static struct dri2_window *dri2_window(WindowPtr win)
26385 -{
26386 - assert(win->drawable.type != DRAWABLE_PIXMAP);
26387 - return ((void **)__get_private(win, sna_window_key))[1];
26388 +out:
26389 + get_private(back)->stale = false;
26392 static struct sna_dri2_event *
26393 @@ -232,21 +374,25 @@ dri2_chain(DrawablePtr d)
26395 struct dri2_window *priv = dri2_window((WindowPtr)d);
26396 assert(priv != NULL);
26397 + assert(priv->chain == NULL || priv->chain->chained);
26398 return priv->chain;
26400 inline static DRI2BufferPtr dri2_window_get_front(WindowPtr win)
26402 struct dri2_window *priv = dri2_window(win);
26403 + assert(priv->front == NULL || get_private(priv->front)->bo->active_scanout);
26404 return priv ? priv->front : NULL;
26406 #else
26407 inline static void *dri2_window_get_front(WindowPtr win) { return NULL; }
26408 +#define APPLY_DAMAGE 1
26409 #endif
26411 #if DRI2INFOREC_VERSION < 6
26413 #define xorg_can_triple_buffer() 0
26414 #define swap_limit(d, l) false
26415 +#define mark_stale(b)
26417 #else
26419 @@ -273,6 +419,8 @@ mark_stale(DRI2BufferPtr back)
26420 * stale frame. (This is mostly useful for tracking down
26421 * driver bugs!)
26422 */
26423 + DBG(("%s(handle=%d) => %d\n", __FUNCTION__,
26424 + get_private(back)->bo->handle, xorg_can_triple_buffer()));
26425 get_private(back)->stale = xorg_can_triple_buffer();
26428 @@ -286,21 +434,29 @@ sna_dri2_swap_limit_validate(DrawablePtr draw, int swap_limit)
26429 static void
26430 sna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
26432 + struct sna *sna = to_sna_from_drawable(draw);
26434 DBG(("%s: reusing buffer pixmap=%ld, attachment=%d, handle=%d, name=%d\n",
26435 __FUNCTION__, get_drawable_pixmap(draw)->drawable.serialNumber,
26436 buffer->attachment, get_private(buffer)->bo->handle, buffer->name));
26437 assert(get_private(buffer)->refcnt);
26438 - assert(get_private(buffer)->bo->refcnt > get_private(buffer)->bo->active_scanout);
26439 + assert(get_private(buffer)->bo->refcnt >= get_private(buffer)->bo->active_scanout);
26440 + assert(kgem_bo_flink(&sna->kgem, get_private(buffer)->bo) == buffer->name);
26442 if (buffer->attachment == DRI2BufferBackLeft &&
26443 draw->type != DRAWABLE_PIXMAP) {
26444 - DBG(("%s: replacing back buffer\n", __FUNCTION__));
26445 - sna_dri2_get_back(to_sna_from_drawable(draw), draw, buffer, dri2_chain(draw));
26446 + DBG(("%s: replacing back buffer on window %ld\n", __FUNCTION__, draw->id));
26447 + sna_dri2_get_back(sna, draw, buffer);
26449 - assert(kgem_bo_flink(&to_sna_from_drawable(draw)->kgem, get_private(buffer)->bo) == buffer->name);
26450 assert(get_private(buffer)->bo->refcnt);
26451 assert(get_private(buffer)->bo->active_scanout == 0);
26452 + assert(kgem_bo_flink(&sna->kgem, get_private(buffer)->bo) == buffer->name);
26453 + DBG(("%s: reusing back buffer handle=%d, name=%d, pitch=%d, age=%d\n",
26454 + __FUNCTION__, get_private(buffer)->bo->handle,
26455 + buffer->name, buffer->pitch, buffer->flags));
26458 + kgem_bo_submit(&sna->kgem, get_private(buffer)->bo);
26461 static bool swap_limit(DrawablePtr draw, int limit)
26462 @@ -314,11 +470,6 @@ static bool swap_limit(DrawablePtr draw, int limit)
26464 #endif
26466 -#if DRI2INFOREC_VERSION < 10
26467 -#undef USE_ASYNC_SWAP
26468 -#define USE_ASYNC_SWAP 0
26469 -#endif
26471 #define COLOR_PREFER_TILING_Y 0
26473 /* Prefer to enable TILING_Y if this buffer will never be a
26474 @@ -328,6 +479,9 @@ static uint32_t color_tiling(struct sna *sna, DrawablePtr draw)
26476 uint32_t tiling;
26478 + if (!sna->kgem.can_fence)
26479 + return I915_TILING_NONE;
26481 if (COLOR_PREFER_TILING_Y &&
26482 (draw->width != sna->front->drawable.width ||
26483 draw->height != sna->front->drawable.height))
26484 @@ -355,7 +509,6 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
26485 PixmapPtr pixmap)
26487 struct sna_pixmap *priv;
26488 - int tiling;
26490 DBG(("%s: attaching DRI client to pixmap=%ld\n",
26491 __FUNCTION__, pixmap->drawable.serialNumber));
26492 @@ -373,31 +526,29 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
26493 return NULL;
26496 - assert(priv->flush == false);
26497 + assert(priv->flush == false || priv->pinned & PIN_DRI3);
26498 + assert(priv->gpu_bo->flush == false || priv->pinned & PIN_DRI3);
26499 assert(priv->cpu_damage == NULL);
26500 assert(priv->gpu_bo);
26501 assert(priv->gpu_bo->proxy == NULL);
26502 - assert(priv->gpu_bo->flush == false);
26504 - tiling = color_tiling(sna, &pixmap->drawable);
26505 - if (tiling < 0)
26506 - tiling = -tiling;
26507 - if (priv->gpu_bo->tiling != tiling)
26508 - sna_pixmap_change_tiling(pixmap, tiling);
26510 - return priv->gpu_bo;
26511 -}
26512 + if (!kgem_bo_is_fenced(&sna->kgem, priv->gpu_bo)) {
26513 + if (priv->gpu_bo->tiling &&
26514 + !sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) {
26515 + DBG(("%s: failed to discard tiling (%d) for DRI2 protocol\n", __FUNCTION__, priv->gpu_bo->tiling));
26516 + return NULL;
26517 + }
26518 + } else {
26519 + int tiling = color_tiling(sna, &pixmap->drawable);
26520 + if (tiling < 0)
26521 + tiling = -tiling;
26522 + if (priv->gpu_bo->tiling < tiling && !priv->gpu_bo->scanout)
26523 + sna_pixmap_change_tiling(pixmap, tiling);
26524 + }
26526 -pure static inline void *sna_pixmap_get_buffer(PixmapPtr pixmap)
26527 -{
26528 - assert(pixmap->refcnt);
26529 - return ((void **)__get_private(pixmap, sna_pixmap_key))[2];
26530 -}
26531 + priv->gpu_bo->active_scanout++;
26533 -static inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr)
26534 -{
26535 - assert(pixmap->refcnt);
26536 - ((void **)__get_private(pixmap, sna_pixmap_key))[2] = ptr;
26537 + return priv->gpu_bo;
26540 void
26541 @@ -422,13 +573,18 @@ sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap, struct kgem_bo *bo)
26542 if (private->bo == bo)
26543 return;
26545 + assert(private->bo->active_scanout > 0);
26546 + private->bo->active_scanout--;
26548 DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle));
26549 private->bo->flush = false;
26550 kgem_bo_destroy(&sna->kgem, private->bo);
26553 buffer->name = kgem_bo_flink(&sna->kgem, bo);
26554 buffer->pitch = bo->pitch;
26555 private->bo = ref(bo);
26556 + bo->active_scanout++;
26558 DBG(("%s: adding flush hint to handle=%d\n", __FUNCTION__, bo->handle));
26559 bo->flush = true;
26560 @@ -449,9 +605,9 @@ sna_dri2_create_buffer(DrawablePtr draw,
26561 struct sna_dri2_private *private;
26562 PixmapPtr pixmap;
26563 struct kgem_bo *bo;
26564 - unsigned flags = 0;
26565 + unsigned bpp = format ?: draw->bitsPerPixel;
26566 + unsigned flags = CREATE_EXACT;
26567 uint32_t size;
26568 - int bpp;
26570 DBG(("%s pixmap=%ld, (attachment=%d, format=%d, drawable=%dx%d), window?=%d\n",
26571 __FUNCTION__,
26572 @@ -468,11 +624,11 @@ sna_dri2_create_buffer(DrawablePtr draw,
26573 if (draw->type != DRAWABLE_PIXMAP)
26574 buffer = dri2_window_get_front((WindowPtr)draw);
26575 if (buffer == NULL)
26576 - buffer = sna_pixmap_get_buffer(pixmap);
26577 + buffer = (DRI2Buffer2Ptr)sna_pixmap_get_buffer(pixmap);
26578 if (buffer) {
26579 private = get_private(buffer);
26581 - DBG(("%s: reusing front buffer attachment, win=%lu %dx%d, pixmap=%ld [%ld] %dx%d, handle=%d, name=%d\n",
26582 + DBG(("%s: reusing front buffer attachment, win=%lu %dx%d, pixmap=%ld [%ld] %dx%d, handle=%d, name=%d, active_scanout=%d\n",
26583 __FUNCTION__,
26584 draw->type != DRAWABLE_PIXMAP ? (long)draw->id : (long)0,
26585 draw->width, draw->height,
26586 @@ -480,12 +636,22 @@ sna_dri2_create_buffer(DrawablePtr draw,
26587 private->pixmap->drawable.serialNumber,
26588 pixmap->drawable.width,
26589 pixmap->drawable.height,
26590 - private->bo->handle, buffer->name));
26591 + private->bo->handle, buffer->name,
26592 + private->bo->active_scanout));
26594 + assert(buffer->attachment == DRI2BufferFrontLeft);
26595 assert(private->pixmap == pixmap);
26596 assert(sna_pixmap(pixmap)->flush);
26597 assert(sna_pixmap(pixmap)->pinned & PIN_DRI2);
26598 assert(kgem_bo_flink(&sna->kgem, private->bo) == buffer->name);
26599 + assert(private->bo->pitch == buffer->pitch);
26600 + assert(private->bo->active_scanout);
26602 + sna_pixmap_move_to_gpu(pixmap,
26603 + MOVE_READ |
26604 + __MOVE_FORCE |
26605 + __MOVE_DRI);
26606 + kgem_bo_submit(&sna->kgem, private->bo);
26608 private->refcnt++;
26609 return buffer;
26610 @@ -498,7 +664,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
26611 assert(sna_pixmap(pixmap) != NULL);
26613 bo = ref(bo);
26614 - bpp = pixmap->drawable.bitsPerPixel;
26615 if (pixmap == sna->front && !(sna->flags & SNA_LINEAR_FB))
26616 flags |= CREATE_SCANOUT;
26617 DBG(("%s: attaching to front buffer %dx%d [%p:%d], scanout? %d\n",
26618 @@ -506,6 +671,7 @@ sna_dri2_create_buffer(DrawablePtr draw,
26619 pixmap->drawable.width, pixmap->drawable.height,
26620 pixmap, pixmap->refcnt, flags & CREATE_SCANOUT));
26621 size = (uint32_t)pixmap->drawable.height << 16 | pixmap->drawable.width;
26622 + bpp = pixmap->drawable.bitsPerPixel;
26623 break;
26625 case DRI2BufferBackLeft:
26626 @@ -514,6 +680,7 @@ sna_dri2_create_buffer(DrawablePtr draw,
26627 flags |= CREATE_SCANOUT;
26628 if (draw->width == sna->front->drawable.width &&
26629 draw->height == sna->front->drawable.height &&
26630 + draw->bitsPerPixel == bpp &&
26631 (sna->flags & (SNA_LINEAR_FB | SNA_NO_WAIT | SNA_NO_FLIP)) == 0)
26632 flags |= CREATE_SCANOUT;
26634 @@ -521,7 +688,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
26635 case DRI2BufferFrontRight:
26636 case DRI2BufferFakeFrontLeft:
26637 case DRI2BufferFakeFrontRight:
26638 - bpp = draw->bitsPerPixel;
26639 DBG(("%s: creating back buffer %dx%d, suitable for scanout? %d\n",
26640 __FUNCTION__,
26641 draw->width, draw->height,
26642 @@ -530,7 +696,7 @@ sna_dri2_create_buffer(DrawablePtr draw,
26643 bo = kgem_create_2d(&sna->kgem,
26644 draw->width,
26645 draw->height,
26646 - draw->bitsPerPixel,
26647 + bpp,
26648 color_tiling(sna, draw),
26649 flags);
26650 break;
26651 @@ -558,7 +724,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
26652 * not understand W tiling and the GTT is incapable of
26653 * W fencing.
26654 */
26655 - bpp = format ? format : draw->bitsPerPixel;
26656 bpp *= 2;
26657 bo = kgem_create_2d(&sna->kgem,
26658 ALIGN(draw->width, 64),
26659 @@ -570,7 +735,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
26660 case DRI2BufferDepthStencil:
26661 case DRI2BufferHiz:
26662 case DRI2BufferAccum:
26663 - bpp = format ? format : draw->bitsPerPixel,
26664 bo = kgem_create_2d(&sna->kgem,
26665 draw->width, draw->height, bpp,
26666 other_tiling(sna, draw),
26667 @@ -614,7 +778,7 @@ sna_dri2_create_buffer(DrawablePtr draw,
26668 pixmap->refcnt++;
26670 priv = sna_pixmap(pixmap);
26671 - assert(priv->flush == false);
26672 + assert(priv->flush == false || priv->pinned & PIN_DRI3);
26673 assert((priv->pinned & PIN_DRI2) == 0);
26675 /* Don't allow this named buffer to be replaced */
26676 @@ -630,17 +794,17 @@ sna_dri2_create_buffer(DrawablePtr draw,
26677 if (priv->gpu_bo->exec)
26678 sna->kgem.flush = 1;
26680 - priv->flush |= 1;
26681 + priv->flush |= FLUSH_READ;
26682 if (draw->type == DRAWABLE_PIXMAP) {
26683 /* DRI2 renders directly into GLXPixmaps, treat as hostile */
26684 kgem_bo_unclean(&sna->kgem, priv->gpu_bo);
26685 sna_damage_all(&priv->gpu_damage, pixmap);
26686 priv->clear = false;
26687 priv->cpu = false;
26688 - priv->flush |= 2;
26689 + priv->flush |= FLUSH_WRITE;
26692 - sna_accel_watch_flush(sna, 1);
26693 + sna_watch_flush(sna, 1);
26696 return buffer;
26697 @@ -651,16 +815,80 @@ err:
26698 return NULL;
26701 -static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
26702 +static void
26703 +sna_dri2_cache_bo(struct sna *sna,
26704 + DrawablePtr draw,
26705 + struct kgem_bo *bo,
26706 + uint32_t name,
26707 + uint32_t size,
26708 + uint32_t flags)
26709 +{
26710 + struct dri_bo *c;
26712 + DBG(("%s(handle=%d, name=%d)\n", __FUNCTION__, bo->handle, name));
26714 + if (draw == NULL) {
26715 + DBG(("%s: no draw, releasing handle=%d\n",
26716 + __FUNCTION__, bo->handle));
26717 + goto err;
26718 + }
26720 + if (draw->type == DRAWABLE_PIXMAP) {
26721 + DBG(("%s: not a window, releasing handle=%d\n",
26722 + __FUNCTION__, bo->handle));
26723 + goto err;
26724 + }
26726 + if (bo->refcnt > 1 + bo->active_scanout) {
26727 + DBG(("%s: multiple references [%d], releasing handle\n",
26728 + __FUNCTION__, bo->refcnt, bo->handle));
26729 + goto err;
26730 + }
26732 + if ((draw->height << 16 | draw->width) != size) {
26733 + DBG(("%s: wrong size [%dx%d], releasing handle\n",
26734 + __FUNCTION__,
26735 + size & 0xffff, size >> 16,
26736 + bo->handle));
26737 + goto err;
26738 + }
26740 + if (bo->scanout && front_pitch(draw) != bo->pitch) {
26741 + DBG(("%s: scanout with pitch change [%d != %d], releasing handle\n",
26742 + __FUNCTION__, bo->pitch, front_pitch(draw), bo->handle));
26743 + goto err;
26744 + }
26746 + c = malloc(sizeof(*c));
26747 + if (!c)
26748 + goto err;
26750 + DBG(("%s: caching handle=%d (name=%d, flags=%d, active_scanout=%d)\n", __FUNCTION__, bo->handle, name, flags, bo->active_scanout));
26752 + c->bo = bo;
26753 + c->name = name;
26754 + c->flags = flags;
26755 + list_add(&c->link, &dri2_window((WindowPtr)draw)->cache);
26756 + return;
26758 +err:
26759 + kgem_bo_destroy(&sna->kgem, bo);
26760 +}
26762 +static void _sna_dri2_destroy_buffer(struct sna *sna,
26763 + DrawablePtr draw,
26764 + DRI2Buffer2Ptr buffer)
26766 struct sna_dri2_private *private = get_private(buffer);
26768 if (buffer == NULL)
26769 return;
26771 - DBG(("%s: %p [handle=%d] -- refcnt=%d, pixmap=%ld\n",
26772 + DBG(("%s: %p [handle=%d] -- refcnt=%d, draw=%ld, pixmap=%ld, proxy?=%d\n",
26773 __FUNCTION__, buffer, private->bo->handle, private->refcnt,
26774 - private->pixmap ? private->pixmap->drawable.serialNumber : 0));
26775 + draw ? draw->id : 0,
26776 + private->pixmap ? private->pixmap->drawable.serialNumber : 0,
26777 + private->proxy != NULL));
26778 assert(private->refcnt > 0);
26779 if (--private->refcnt)
26780 return;
26781 @@ -669,7 +897,10 @@ static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
26783 if (private->proxy) {
26784 DBG(("%s: destroying proxy\n", __FUNCTION__));
26785 - _sna_dri2_destroy_buffer(sna, private->proxy);
26786 + assert(private->bo->active_scanout > 0);
26787 + private->bo->active_scanout--;
26789 + _sna_dri2_destroy_buffer(sna, draw, private->proxy);
26790 private->pixmap = NULL;
26793 @@ -683,6 +914,11 @@ static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
26794 assert(priv->pinned & PIN_DRI2);
26795 assert(priv->flush);
26797 + DBG(("%s: removing active_scanout=%d from pixmap handle=%d\n",
26798 + __FUNCTION__, priv->gpu_bo->active_scanout, priv->gpu_bo->handle));
26799 + assert(priv->gpu_bo->active_scanout > 0);
26800 + priv->gpu_bo->active_scanout--;
26802 /* Undo the DRI markings on this pixmap */
26803 DBG(("%s: releasing last DRI pixmap=%ld, scanout?=%d\n",
26804 __FUNCTION__,
26805 @@ -692,28 +928,34 @@ static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
26806 list_del(&priv->flush_list);
26808 DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, private->bo->handle));
26809 - priv->gpu_bo->flush = false;
26810 priv->pinned &= ~PIN_DRI2;
26812 - priv->flush = false;
26813 - sna_accel_watch_flush(sna, -1);
26814 + if ((priv->pinned & PIN_DRI3) == 0) {
26815 + priv->gpu_bo->flush = false;
26816 + priv->flush = false;
26817 + }
26818 + sna_watch_flush(sna, -1);
26820 sna_pixmap_set_buffer(pixmap, NULL);
26821 pixmap->drawable.pScreen->DestroyPixmap(pixmap);
26823 - assert(private->bo->flush == false);
26825 - kgem_bo_destroy(&sna->kgem, private->bo);
26826 + sna_dri2_cache_bo(sna, draw,
26827 + private->bo,
26828 + buffer->name,
26829 + private->size,
26830 + buffer->flags);
26831 free(buffer);
26834 static void sna_dri2_destroy_buffer(DrawablePtr draw, DRI2Buffer2Ptr buffer)
26836 - _sna_dri2_destroy_buffer(to_sna_from_drawable(draw), buffer);
26837 + _sna_dri2_destroy_buffer(to_sna_from_drawable(draw), draw, buffer);
26840 static DRI2BufferPtr sna_dri2_reference_buffer(DRI2BufferPtr buffer)
26842 + assert(get_private(buffer)->refcnt > 0);
26843 get_private(buffer)->refcnt++;
26844 return buffer;
26846 @@ -746,10 +988,9 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
26848 struct sna *sna = to_sna_from_pixmap(pixmap);
26849 struct sna_pixmap *priv = sna_pixmap(pixmap);
26850 - RegionRec region;
26852 - DBG(("%s: pixmap=%ld, handle=%d\n",
26853 - __FUNCTION__, pixmap->drawable.serialNumber, bo->handle));
26854 + DBG(("%s: pixmap=%ld, handle=%d (old handle=%d)\n",
26855 + __FUNCTION__, pixmap->drawable.serialNumber, bo->handle, priv->gpu_bo->handle));
26857 assert(pixmap->drawable.width * pixmap->drawable.bitsPerPixel <= 8*bo->pitch);
26858 assert(pixmap->drawable.height * bo->pitch <= kgem_bo_size(bo));
26859 @@ -758,21 +999,34 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
26860 assert((priv->pinned & (PIN_PRIME | PIN_DRI3)) == 0);
26861 assert(priv->flush);
26863 - /* Post damage on the new front buffer so that listeners, such
26864 - * as DisplayLink know take a copy and shove it over the USB,
26865 - * also for software cursors and the like.
26866 - */
26867 - region.extents.x1 = region.extents.y1 = 0;
26868 - region.extents.x2 = pixmap->drawable.width;
26869 - region.extents.y2 = pixmap->drawable.height;
26870 - region.data = NULL;
26871 - DamageRegionAppend(&pixmap->drawable, &region);
26872 + if (APPLY_DAMAGE) {
26873 + RegionRec region;
26875 + /* Post damage on the new front buffer so that listeners, such
26876 + * as DisplayLink know take a copy and shove it over the USB,
26877 + * also for software cursors and the like.
26878 + */
26879 + region.extents.x1 = region.extents.y1 = 0;
26880 + region.extents.x2 = pixmap->drawable.width;
26881 + region.extents.y2 = pixmap->drawable.height;
26882 + region.data = NULL;
26884 + /*
26885 + * Eeek, beware the sw cursor copying to the old bo
26886 + * causing recursion and mayhem.
26887 + */
26888 + DBG(("%s: marking whole pixmap as damaged\n", __FUNCTION__));
26889 + sna->ignore_copy_area = sna->flags & SNA_TEAR_FREE;
26890 + DamageRegionAppend(&pixmap->drawable, &region);
26891 + }
26893 damage(pixmap, priv, NULL);
26895 assert(bo->refcnt);
26896 - if (priv->move_to_gpu)
26897 + if (priv->move_to_gpu) {
26898 + DBG(("%s: applying final/discard move-to-gpu\n", __FUNCTION__));
26899 priv->move_to_gpu(sna, priv, 0);
26900 + }
26901 if (priv->gpu_bo != bo) {
26902 DBG(("%s: dropping flush hint from handle=%d\n", __FUNCTION__, priv->gpu_bo->handle));
26903 priv->gpu_bo->flush = false;
26904 @@ -792,8 +1046,27 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
26905 bo->domain = DOMAIN_NONE;
26906 assert(bo->flush);
26908 - DamageRegionProcessPending(&pixmap->drawable);
26909 + if (APPLY_DAMAGE) {
26910 + sna->ignore_copy_area = false;
26911 + DamageRegionProcessPending(&pixmap->drawable);
26912 + }
26913 +}
26915 +#if defined(__GNUC__)
26916 +#define popcount(x) __builtin_popcount(x)
26917 +#else
26918 +static int popcount(unsigned int x)
26919 +{
26920 + int count = 0;
26922 + while (x) {
26923 + count += x&1;
26924 + x >>= 1;
26925 + }
26927 + return count;
26929 +#endif
26931 static void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kgem_bo *src, bool sync)
26933 @@ -823,6 +1096,12 @@ static void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kg
26934 return;
26937 + if (sna->render_state.gt < 2 && sna->kgem.has_semaphores) {
26938 + DBG(("%s: small GT [%d], not forcing selection\n",
26939 + __FUNCTION__, sna->render_state.gt));
26940 + return;
26941 + }
26943 VG_CLEAR(busy);
26944 busy.handle = src->handle;
26945 if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy))
26946 @@ -860,9 +1139,11 @@ static void sna_dri2_select_mode(struct sna *sna, struct kgem_bo *dst, struct kg
26947 * the cost of the query.
26948 */
26949 mode = KGEM_RENDER;
26950 - if (busy.busy & (0xfffe << 16))
26951 + if ((busy.busy & 0xffff) == I915_EXEC_BLT)
26952 mode = KGEM_BLT;
26953 - kgem_bo_mark_busy(&sna->kgem, busy.handle == src->handle ? src : dst, mode);
26954 + kgem_bo_mark_busy(&sna->kgem,
26955 + busy.handle == src->handle ? src : dst,
26956 + mode);
26957 _kgem_set_mode(&sna->kgem, mode);
26960 @@ -871,10 +1152,13 @@ static bool is_front(int attachment)
26961 return attachment == DRI2BufferFrontLeft;
26964 +#define DRI2_SYNC 0x1
26965 +#define DRI2_DAMAGE 0x2
26966 +#define DRI2_BO 0x4
26967 static struct kgem_bo *
26968 __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
26969 DRI2BufferPtr src, DRI2BufferPtr dst,
26970 - bool sync)
26971 + unsigned flags)
26973 PixmapPtr pixmap = get_drawable_pixmap(draw);
26974 DrawableRec scratch, *src_draw = &pixmap->drawable, *dst_draw = &pixmap->drawable;
26975 @@ -886,7 +1170,7 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
26976 struct kgem_bo *dst_bo;
26977 const BoxRec *boxes;
26978 int16_t dx, dy, sx, sy;
26979 - unsigned flags;
26980 + unsigned hint;
26981 int n;
26983 /* To hide a stale DRI2Buffer, one may choose to substitute
26984 @@ -962,8 +1246,9 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
26987 } else
26988 - sync = false;
26989 + flags &= ~DRI2_SYNC;
26991 + scratch.pScreen = draw->pScreen;
26992 scratch.x = scratch.y = 0;
26993 scratch.width = scratch.height = 0;
26994 scratch.depth = draw->depth;
26995 @@ -971,6 +1256,7 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
26997 src_bo = src_priv->bo;
26998 assert(src_bo->refcnt);
26999 + kgem_bo_unclean(&sna->kgem, src_bo);
27000 if (is_front(src->attachment)) {
27001 struct sna_pixmap *priv;
27003 @@ -987,11 +1273,12 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
27004 scratch.height = src_priv->size >> 16;
27005 src_draw = &scratch;
27007 - DBG(("%s: source size %dx%d, region size %dx%d\n",
27008 + DBG(("%s: source size %dx%d, region size %dx%d, src offset %dx%d\n",
27009 __FUNCTION__,
27010 scratch.width, scratch.height,
27011 clip.extents.x2 - clip.extents.x1,
27012 - clip.extents.y2 - clip.extents.y1));
27013 + clip.extents.y2 - clip.extents.y1,
27014 + -sx, -sy));
27016 source.extents.x1 = -sx;
27017 source.extents.y1 = -sy;
27018 @@ -1002,6 +1289,10 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
27019 assert(region == NULL || region == &clip);
27020 pixman_region_intersect(&clip, &clip, &source);
27022 + if (!pixman_region_not_empty(&clip)) {
27023 + DBG(("%s: region doesn't overlap pixmap\n", __FUNCTION__));
27024 + return NULL;
27025 + }
27028 dst_bo = dst_priv->bo;
27029 @@ -1013,12 +1304,12 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
27030 /* Preserve the CRTC shadow overrides */
27031 sna_shadow_steal_crtcs(sna, &shadow);
27033 - flags = MOVE_WRITE | __MOVE_FORCE;
27034 + hint = MOVE_WRITE | __MOVE_FORCE;
27035 if (clip.data)
27036 - flags |= MOVE_READ;
27037 + hint |= MOVE_READ;
27039 assert(region == NULL || region == &clip);
27040 - priv = sna_pixmap_move_area_to_gpu(pixmap, &clip.extents, flags);
27041 + priv = sna_pixmap_move_area_to_gpu(pixmap, &clip.extents, hint);
27042 if (priv) {
27043 damage(pixmap, priv, region);
27044 dst_bo = priv->gpu_bo;
27045 @@ -1050,20 +1341,20 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
27046 assert(region == NULL || region == &clip);
27047 pixman_region_intersect(&clip, &clip, &target);
27049 - sync = false;
27050 + flags &= ~DRI2_SYNC;
27053 if (!wedged(sna)) {
27054 xf86CrtcPtr crtc;
27056 crtc = NULL;
27057 - if (sync && sna_pixmap_is_scanout(sna, pixmap))
27058 + if (flags & DRI2_SYNC && sna_pixmap_is_scanout(sna, pixmap))
27059 crtc = sna_covering_crtc(sna, &clip.extents, NULL);
27060 sna_dri2_select_mode(sna, dst_bo, src_bo, crtc != NULL);
27062 - sync = (crtc != NULL&&
27063 - sna_wait_for_scanline(sna, pixmap, crtc,
27064 - &clip.extents));
27065 + if (crtc == NULL ||
27066 + !sna_wait_for_scanline(sna, pixmap, crtc, &clip.extents))
27067 + flags &= ~DRI2_SYNC;
27070 if (region) {
27071 @@ -1075,8 +1366,11 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
27072 boxes = &clip.extents;
27073 n = 1;
27075 - DamageRegionAppend(&pixmap->drawable, region);
27077 + if (APPLY_DAMAGE || flags & DRI2_DAMAGE) {
27078 + DBG(("%s: marking region as damaged\n", __FUNCTION__));
27079 + sna->ignore_copy_area = sna->flags & SNA_TEAR_FREE;
27080 + DamageRegionAppend(&pixmap->drawable, region);
27081 + }
27083 DBG(("%s: copying [(%d, %d), (%d, %d)]x%d src=(%d, %d), dst=(%d, %d)\n",
27084 __FUNCTION__,
27085 @@ -1084,29 +1378,36 @@ __sna_dri2_copy_region(struct sna *sna, DrawablePtr draw, RegionPtr region,
27086 boxes[0].x2, boxes[0].y2,
27087 n, sx, sy, dx, dy));
27089 - flags = COPY_LAST;
27090 - if (sync)
27091 - flags |= COPY_SYNC;
27092 + hint = COPY_LAST | COPY_DRI;
27093 + if (flags & DRI2_SYNC)
27094 + hint |= COPY_SYNC;
27095 if (!sna->render.copy_boxes(sna, GXcopy,
27096 src_draw, src_bo, sx, sy,
27097 dst_draw, dst_bo, dx, dy,
27098 - boxes, n, flags))
27099 + boxes, n, hint))
27100 memcpy_copy_boxes(sna, GXcopy,
27101 src_draw, src_bo, sx, sy,
27102 dst_draw, dst_bo, dx, dy,
27103 - boxes, n, flags);
27105 - DBG(("%s: flushing? %d\n", __FUNCTION__, sync));
27106 - if (sync) { /* STAT! */
27107 - struct kgem_request *rq = sna->kgem.next_request;
27108 - kgem_submit(&sna->kgem);
27109 - if (rq->bo) {
27110 - bo = ref(rq->bo);
27111 - DBG(("%s: recording sync fence handle=%d\n", __FUNCTION__, bo->handle));
27112 + boxes, n, hint);
27114 + sna->needs_dri_flush = true;
27115 + if (flags & (DRI2_SYNC | DRI2_BO)) { /* STAT! */
27116 + struct kgem_request *rq = RQ(dst_bo->rq);
27117 + if (rq && rq != (void *)&sna->kgem) {
27118 + if (rq->bo == NULL)
27119 + kgem_submit(&sna->kgem);
27120 + if (rq->bo) { /* Becareful in case the gpu is wedged */
27121 + bo = ref(rq->bo);
27122 + DBG(("%s: recording sync fence handle=%d\n",
27123 + __FUNCTION__, bo->handle));
27124 + }
27128 - DamageRegionProcessPending(&pixmap->drawable);
27129 + if (APPLY_DAMAGE || flags & DRI2_DAMAGE) {
27130 + sna->ignore_copy_area = false;
27131 + DamageRegionProcessPending(&pixmap->drawable);
27132 + }
27134 if (clip.data)
27135 pixman_region_fini(&clip);
27136 @@ -1142,6 +1443,8 @@ sna_dri2_copy_region(DrawablePtr draw,
27137 assert(get_private(src)->refcnt);
27138 assert(get_private(dst)->refcnt);
27140 + assert(get_private(src)->bo != get_private(dst)->bo);
27142 assert(get_private(src)->bo->refcnt);
27143 assert(get_private(dst)->bo->refcnt);
27145 @@ -1151,7 +1454,7 @@ sna_dri2_copy_region(DrawablePtr draw,
27146 region->extents.x2, region->extents.y2,
27147 region_num_rects(region)));
27149 - __sna_dri2_copy_region(sna, draw, region, src, dst, false);
27150 + __sna_dri2_copy_region(sna, draw, region, src, dst, DRI2_DAMAGE);
27153 inline static uint32_t pipe_select(int pipe)
27154 @@ -1161,6 +1464,7 @@ inline static uint32_t pipe_select(int pipe)
27155 * we can safely ignore the capability check - if we have more
27156 * than two pipes, we can assume that they are fully supported.
27157 */
27158 + assert(pipe < _DRM_VBLANK_HIGH_CRTC_MASK);
27159 if (pipe > 1)
27160 return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
27161 else if (pipe > 0)
27162 @@ -1169,15 +1473,53 @@ inline static uint32_t pipe_select(int pipe)
27163 return 0;
27166 -static inline int sna_wait_vblank(struct sna *sna, union drm_wait_vblank *vbl, int pipe)
27167 +static inline bool sna_next_vblank(struct sna_dri2_event *info)
27169 - DBG(("%s(pipe=%d, waiting until seq=%u%s)\n",
27170 - __FUNCTION__, pipe, vbl->request.sequence,
27171 - vbl->request.type & DRM_VBLANK_RELATIVE ? " [relative]" : ""));
27172 - assert(pipe != -1);
27173 + union drm_wait_vblank vbl;
27175 - vbl->request.type |= pipe_select(pipe);
27176 - return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl);
27177 + DBG(("%s(pipe=%d, waiting until next vblank)\n",
27178 + __FUNCTION__, info->pipe));
27179 + assert(info->pipe != -1);
27181 + VG_CLEAR(vbl);
27182 + vbl.request.type =
27183 + DRM_VBLANK_RELATIVE |
27184 + DRM_VBLANK_EVENT |
27185 + pipe_select(info->pipe);
27186 + vbl.request.sequence = 1;
27187 + vbl.request.signal = (uintptr_t)info;
27189 + assert(!info->queued);
27190 + if (drmIoctl(info->sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, &vbl))
27191 + return false;
27193 + info->queued = true;
27194 + return true;
27195 +}
27197 +static inline bool sna_wait_vblank(struct sna_dri2_event *info,
27198 + unsigned seq)
27199 +{
27200 + union drm_wait_vblank vbl;
27202 + DBG(("%s(pipe=%d, waiting until vblank %u)\n",
27203 + __FUNCTION__, info->pipe, seq));
27204 + assert(info->pipe != -1);
27206 + VG_CLEAR(vbl);
27207 + vbl.request.type =
27208 + DRM_VBLANK_ABSOLUTE |
27209 + DRM_VBLANK_EVENT |
27210 + pipe_select(info->pipe);
27211 + vbl.request.sequence = seq;
27212 + vbl.request.signal = (uintptr_t)info;
27214 + assert(!info->queued);
27215 + if (drmIoctl(info->sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, &vbl))
27216 + return false;
27218 + info->queued = true;
27219 + return true;
27222 #if DRI2INFOREC_VERSION >= 4
27223 @@ -1195,6 +1537,7 @@ draw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc)
27225 struct dri2_window *priv;
27227 + assert(draw);
27228 if (draw->type != DRAWABLE_WINDOW)
27229 return msc;
27231 @@ -1206,6 +1549,9 @@ draw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc)
27232 priv->crtc = crtc;
27233 priv->msc_delta = 0;
27234 priv->chain = NULL;
27235 + priv->scanout = -1;
27236 + priv->cache_size = 0;
27237 + list_init(&priv->cache);
27238 dri2_window_attach((WindowPtr)draw, priv);
27240 } else {
27241 @@ -1214,8 +1560,8 @@ draw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc)
27242 const struct ust_msc *this = sna_crtc_last_swap(crtc);
27243 DBG(("%s: Window transferring from pipe=%d [msc=%llu] to pipe=%d [msc=%llu], delta now %lld\n",
27244 __FUNCTION__,
27245 - sna_crtc_to_pipe(priv->crtc), (long long)last->msc,
27246 - sna_crtc_to_pipe(crtc), (long long)this->msc,
27247 + sna_crtc_pipe(priv->crtc), (long long)last->msc,
27248 + sna_crtc_pipe(crtc), (long long)this->msc,
27249 (long long)(priv->msc_delta + this->msc - last->msc)));
27250 priv->msc_delta += this->msc - last->msc;
27251 priv->crtc = crtc;
27252 @@ -1248,57 +1594,119 @@ sna_dri2_get_crtc(DrawablePtr draw)
27253 NULL);
27256 -static void
27257 -sna_dri2_remove_event(WindowPtr win, struct sna_dri2_event *info)
27258 +static void frame_swap_complete(struct sna_dri2_event *frame, int type)
27260 - struct dri2_window *priv;
27261 - struct sna_dri2_event *chain;
27263 - assert(win->drawable.type == DRAWABLE_WINDOW);
27264 - DBG(("%s: remove[%p] from window %ld, active? %d\n",
27265 - __FUNCTION__, info, (long)win->drawable.id, info->draw != NULL));
27266 + const struct ust_msc *swap;
27268 - priv = dri2_window(win);
27269 - assert(priv);
27270 - assert(priv->chain != NULL);
27271 + assert(frame->signal);
27272 + frame->signal = false;
27274 - if (priv->chain == info) {
27275 - priv->chain = info->chain;
27276 + if (frame->client == NULL) {
27277 + DBG(("%s: client already gone\n", __FUNCTION__));
27278 return;
27281 - chain = priv->chain;
27282 - while (chain->chain != info)
27283 - chain = chain->chain;
27284 - assert(chain != info);
27285 - assert(info->chain != chain);
27286 - chain->chain = info->chain;
27287 + assert(frame->draw);
27289 + swap = sna_crtc_last_swap(frame->crtc);
27290 + DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc=%lld], tv=%d.%06d\n",
27291 + __FUNCTION__, type, (long)frame->draw->id, frame->pipe,
27292 + (long long)swap->msc,
27293 + (long long)draw_current_msc(frame->draw, frame->crtc, swap->msc),
27294 + swap->tv_sec, swap->tv_usec));
27296 + DRI2SwapComplete(frame->client, frame->draw,
27297 + draw_current_msc(frame->draw, frame->crtc, swap->msc),
27298 + swap->tv_sec, swap->tv_usec,
27299 + type, frame->event_complete, frame->event_data);
27302 -static void
27303 -sna_dri2_event_free(struct sna_dri2_event *info)
27304 +static void fake_swap_complete(struct sna *sna, ClientPtr client,
27305 + DrawablePtr draw, xf86CrtcPtr crtc,
27306 + int type, DRI2SwapEventPtr func, void *data)
27308 - DrawablePtr draw = info->draw;
27309 + const struct ust_msc *swap;
27311 - DBG(("%s(draw?=%d)\n", __FUNCTION__, draw != NULL));
27312 - if (draw && draw->type == DRAWABLE_WINDOW)
27313 - sna_dri2_remove_event((WindowPtr)draw, info);
27314 + assert(draw);
27316 - _sna_dri2_destroy_buffer(info->sna, info->front);
27317 - _sna_dri2_destroy_buffer(info->sna, info->back);
27318 + if (crtc == NULL)
27319 + crtc = sna_primary_crtc(sna);
27321 - while (!list_is_empty(&info->cache)) {
27322 - struct dri_bo *c;
27323 + swap = sna_crtc_last_swap(crtc);
27324 + DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n",
27325 + __FUNCTION__, type, (long)draw->id, crtc ? sna_crtc_pipe(crtc) : -1,
27326 + (long long)swap->msc,
27327 + (long long)draw_current_msc(draw, crtc, swap->msc),
27328 + swap->tv_sec, swap->tv_usec));
27330 - c = list_first_entry(&info->cache, struct dri_bo, link);
27331 - list_del(&c->link);
27332 + DRI2SwapComplete(client, draw,
27333 + draw_current_msc(draw, crtc, swap->msc),
27334 + swap->tv_sec, swap->tv_usec,
27335 + type, func, data);
27336 +}
27338 - DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
27339 - if (c->bo)
27340 - kgem_bo_destroy(&info->sna->kgem, c->bo);
27341 +static void
27342 +sna_dri2_remove_event(struct sna_dri2_event *info)
27343 +{
27344 + WindowPtr win = (WindowPtr)info->draw;
27345 + struct dri2_window *priv;
27347 - free(c);
27348 + assert(win->drawable.type == DRAWABLE_WINDOW);
27349 + DBG(("%s: remove[%p] from window %ld, active? %d\n",
27350 + __FUNCTION__, info, (long)win->drawable.id, info->draw != NULL));
27351 + assert(!info->signal);
27353 + priv = dri2_window(win);
27354 + assert(priv);
27355 + assert(priv->chain != NULL);
27356 + assert(info->chained);
27357 + info->chained = false;
27359 + if (priv->chain != info) {
27360 + struct sna_dri2_event *chain = priv->chain;
27361 + while (chain->chain != info) {
27362 + assert(chain->chained);
27363 + chain = chain->chain;
27364 + }
27365 + assert(chain != info);
27366 + assert(info->chain != chain);
27367 + chain->chain = info->chain;
27368 + return;
27369 + }
27371 + priv->chain = info->chain;
27372 + if (priv->chain == NULL) {
27373 + struct dri_bo *c, *tmp;
27375 + c = list_entry(priv->cache.next->next, struct dri_bo, link);
27376 + list_for_each_entry_safe_from(c, tmp, &priv->cache, link) {
27377 + list_del(&c->link);
27379 + DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
27380 + assert(c->bo);
27381 + kgem_bo_destroy(&info->sna->kgem, c->bo);
27382 + free(c);
27383 + }
27385 +}
27387 +static void
27388 +sna_dri2_event_free(struct sna_dri2_event *info)
27389 +{
27390 + DBG(("%s(draw?=%d)\n", __FUNCTION__, info->draw != NULL));
27391 + assert(!info->queued);
27392 + assert(!info->signal);
27393 + assert(info->pending.bo == NULL);
27395 + if (info->sna->dri2.flip_pending == info)
27396 + info->sna->dri2.flip_pending = NULL;
27397 + assert(info->sna->dri2.flip_pending != info);
27398 + if (info->chained)
27399 + sna_dri2_remove_event(info);
27401 + assert((info->front == NULL && info->back == NULL) || info->front != info->back);
27402 + _sna_dri2_destroy_buffer(info->sna, info->draw, info->front);
27403 + _sna_dri2_destroy_buffer(info->sna, info->draw, info->back);
27405 if (info->bo) {
27406 DBG(("%s: releasing batch handle=%d\n", __FUNCTION__, info->bo->handle));
27407 @@ -1331,15 +1739,26 @@ sna_dri2_client_gone(CallbackListPtr *list, void *closure, void *data)
27409 event = list_first_entry(&priv->events, struct sna_dri2_event, link);
27410 assert(event->client == client);
27411 + list_del(&event->link);
27412 + event->signal = false;
27414 - if (event->queued) {
27415 - if (event->draw)
27416 - sna_dri2_remove_event((WindowPtr)event->draw,
27417 - event);
27418 - event->client = NULL;
27419 - event->draw = NULL;
27420 - list_del(&event->link);
27421 - } else
27422 + if (event->pending.bo) {
27423 + assert(event->pending.bo->active_scanout > 0);
27424 + event->pending.bo->active_scanout--;
27426 + kgem_bo_destroy(&sna->kgem, event->pending.bo);
27427 + event->pending.bo = NULL;
27428 + }
27430 + if (event->chained)
27431 + sna_dri2_remove_event(event);
27433 + event->client = NULL;
27434 + event->draw = NULL;
27435 + event->keepalive = 1;
27436 + assert(!event->signal);
27438 + if (!event->queued)
27439 sna_dri2_event_free(event);
27442 @@ -1365,11 +1784,15 @@ static bool add_event_to_client(struct sna_dri2_event *info, struct sna *sna, Cl
27445 static struct sna_dri2_event *
27446 -sna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client)
27447 +sna_dri2_add_event(struct sna *sna,
27448 + DrawablePtr draw,
27449 + ClientPtr client,
27450 + xf86CrtcPtr crtc)
27452 struct dri2_window *priv;
27453 struct sna_dri2_event *info, *chain;
27455 + assert(draw != NULL);
27456 assert(draw->type == DRAWABLE_WINDOW);
27457 DBG(("%s: adding event to window %ld)\n",
27458 __FUNCTION__, (long)draw->id));
27459 @@ -1382,11 +1805,11 @@ sna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client)
27460 if (info == NULL)
27461 return NULL;
27463 - list_init(&info->cache);
27464 info->sna = sna;
27465 info->draw = draw;
27466 - info->crtc = priv->crtc;
27467 - info->pipe = sna_crtc_to_pipe(priv->crtc);
27468 + info->crtc = crtc;
27469 + info->pipe = sna_crtc_pipe(crtc);
27470 + info->keepalive = 1;
27472 if (!add_event_to_client(info, sna, client)) {
27473 free(info);
27474 @@ -1394,6 +1817,7 @@ sna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client)
27477 assert(priv->chain != info);
27478 + info->chained = true;
27480 if (priv->chain == NULL) {
27481 priv->chain = info;
27482 @@ -1409,6 +1833,66 @@ sna_dri2_add_event(struct sna *sna, DrawablePtr draw, ClientPtr client)
27483 return info;
27486 +static void decouple_window(WindowPtr win,
27487 + struct dri2_window *priv,
27488 + struct sna *sna,
27489 + bool signal)
27490 +{
27491 + if (priv->front) {
27492 + DBG(("%s: decouple private front\n", __FUNCTION__));
27493 + assert(priv->crtc);
27494 + sna_shadow_unset_crtc(sna, priv->crtc);
27496 + _sna_dri2_destroy_buffer(sna, NULL, priv->front);
27497 + priv->front = NULL;
27498 + }
27500 + if (priv->chain) {
27501 + struct sna_dri2_event *info, *chain;
27503 + DBG(("%s: freeing chain\n", __FUNCTION__));
27505 + chain = priv->chain;
27506 + while ((info = chain)) {
27507 + DBG(("%s: freeing event, pending signal? %d, pending swap? handle=%d\n",
27508 + __FUNCTION__, info->signal,
27509 + info->pending.bo ? info->pending.bo->handle : 0));
27510 + assert(info->draw == &win->drawable);
27512 + if (info->pending.bo) {
27513 + if (signal) {
27514 + bool was_signalling = info->signal;
27515 + info->signal = true;
27516 + frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE);
27517 + info->signal = was_signalling;
27518 + }
27519 + assert(info->pending.bo->active_scanout > 0);
27520 + info->pending.bo->active_scanout--;
27522 + kgem_bo_destroy(&sna->kgem, info->pending.bo);
27523 + info->pending.bo = NULL;
27524 + }
27526 + if (info->signal && signal)
27527 + frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE);
27528 + info->signal = false;
27529 + info->draw = NULL;
27530 + info->keepalive = 1;
27531 + assert(!info->signal);
27532 + list_del(&info->link);
27534 + chain = info->chain;
27535 + info->chain = NULL;
27536 + info->chained = false;
27538 + if (!info->queued)
27539 + sna_dri2_event_free(info);
27540 + }
27542 + priv->chain = NULL;
27543 + }
27544 +}
27546 void sna_dri2_decouple_window(WindowPtr win)
27548 struct dri2_window *priv;
27549 @@ -1418,50 +1902,34 @@ void sna_dri2_decouple_window(WindowPtr win)
27550 return;
27552 DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
27553 + decouple_window(win, priv, to_sna_from_drawable(&win->drawable), true);
27555 - if (priv->front) {
27556 - struct sna *sna = to_sna_from_drawable(&win->drawable);
27557 - assert(priv->crtc);
27558 - sna_shadow_unset_crtc(sna, priv->crtc);
27559 - _sna_dri2_destroy_buffer(sna, priv->front);
27560 - priv->front = NULL;
27561 - }
27562 + priv->scanout = -1;
27565 void sna_dri2_destroy_window(WindowPtr win)
27567 struct dri2_window *priv;
27568 + struct sna *sna;
27570 priv = dri2_window(win);
27571 if (priv == NULL)
27572 return;
27574 DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.id));
27575 + sna = to_sna_from_drawable(&win->drawable);
27576 + decouple_window(win, priv, sna, false);
27578 - if (priv->front) {
27579 - struct sna *sna = to_sna_from_drawable(&win->drawable);
27580 - assert(priv->crtc);
27581 - sna_shadow_unset_crtc(sna, priv->crtc);
27582 - _sna_dri2_destroy_buffer(sna, priv->front);
27583 - }
27585 - if (priv->chain) {
27586 - struct sna_dri2_event *info, *chain;
27588 - DBG(("%s: freeing chain\n", __FUNCTION__));
27590 - chain = priv->chain;
27591 - while ((info = chain)) {
27592 - info->draw = NULL;
27593 - info->client = NULL;
27594 - list_del(&info->link);
27595 + while (!list_is_empty(&priv->cache)) {
27596 + struct dri_bo *c;
27598 - chain = info->chain;
27599 - info->chain = NULL;
27600 + c = list_first_entry(&priv->cache, struct dri_bo, link);
27601 + list_del(&c->link);
27603 - if (!info->queued)
27604 - sna_dri2_event_free(info);
27605 - }
27606 + DBG(("%s: releasing cached handle=%d\n", __FUNCTION__, c->bo ? c->bo->handle : 0));
27607 + assert(c->bo);
27608 + kgem_bo_destroy(&sna->kgem, c->bo);
27609 + free(c);
27612 free(priv);
27613 @@ -1479,19 +1947,30 @@ sna_dri2_flip(struct sna_dri2_event *info)
27615 struct kgem_bo *bo = get_private(info->back)->bo;
27616 struct kgem_bo *tmp_bo;
27617 - uint32_t tmp_name;
27618 + uint32_t tmp_name, tmp_flags;
27619 int tmp_pitch;
27621 DBG(("%s(type=%d)\n", __FUNCTION__, info->type));
27623 assert(sna_pixmap_get_buffer(info->sna->front) == info->front);
27624 assert(get_drawable_pixmap(info->draw)->drawable.height * bo->pitch <= kgem_bo_size(bo));
27625 + assert(get_private(info->front)->size == get_private(info->back)->size);
27626 assert(bo->refcnt);
27628 + if (info->sna->mode.flip_active) {
27629 + DBG(("%s: %d flips still active, aborting\n",
27630 + __FUNCTION__, info->sna->mode.flip_active));
27631 + return false;
27632 + }
27634 + assert(!info->queued);
27635 if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler,
27636 info->type == FLIP_ASYNC ? NULL : info))
27637 return false;
27639 + DBG(("%s: queued flip=%p\n", __FUNCTION__, info->type == FLIP_ASYNC ? NULL : info));
27640 + assert(info->signal || info->type != FLIP_THROTTLE);
27642 assert(info->sna->dri2.flip_pending == NULL ||
27643 info->sna->dri2.flip_pending == info);
27644 if (info->type != FLIP_ASYNC)
27645 @@ -1505,13 +1984,21 @@ sna_dri2_flip(struct sna_dri2_event *info)
27646 tmp_bo = get_private(info->front)->bo;
27647 tmp_name = info->front->name;
27648 tmp_pitch = info->front->pitch;
27649 + tmp_flags = info->front->flags;
27651 + assert(tmp_bo->active_scanout > 0);
27652 + tmp_bo->active_scanout--;
27654 set_bo(info->sna->front, bo);
27656 + info->front->flags = info->back->flags;
27657 info->front->name = info->back->name;
27658 info->front->pitch = info->back->pitch;
27659 get_private(info->front)->bo = bo;
27660 + bo->active_scanout++;
27661 + assert(bo->active_scanout <= bo->refcnt);
27663 + info->back->flags = tmp_flags;
27664 info->back->name = tmp_name;
27665 info->back->pitch = tmp_pitch;
27666 get_private(info->back)->bo = tmp_bo;
27667 @@ -1521,6 +2008,7 @@ sna_dri2_flip(struct sna_dri2_event *info)
27668 assert(get_private(info->back)->bo->refcnt);
27669 assert(get_private(info->front)->bo != get_private(info->back)->bo);
27671 + info->keepalive = KEEPALIVE;
27672 info->queued = true;
27673 return true;
27675 @@ -1549,15 +2037,16 @@ can_flip(struct sna * sna,
27678 assert(sna->scrn->vtSema);
27679 + assert(!sna->mode.hidden);
27681 if ((sna->flags & (SNA_HAS_FLIP | SNA_HAS_ASYNC_FLIP)) == 0) {
27682 DBG(("%s: no, pageflips disabled\n", __FUNCTION__));
27683 return false;
27686 - if (front->format != back->format) {
27687 + if (front->cpp != back->cpp) {
27688 DBG(("%s: no, format mismatch, front = %d, back = %d\n",
27689 - __FUNCTION__, front->format, back->format));
27690 + __FUNCTION__, front->cpp, back->cpp));
27691 return false;
27694 @@ -1567,7 +2056,7 @@ can_flip(struct sna * sna,
27697 if (!sna_crtc_is_on(crtc)) {
27698 - DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_to_pipe(crtc)));
27699 + DBG(("%s: ref-pipe=%d is disabled\n", __FUNCTION__, sna_crtc_pipe(crtc)));
27700 return false;
27703 @@ -1581,7 +2070,7 @@ can_flip(struct sna * sna,
27704 if (sna_pixmap_get_buffer(pixmap) != front) {
27705 DBG(("%s: no, DRI2 drawable is no longer attached (old name=%d, new name=%d) to pixmap=%ld\n",
27706 __FUNCTION__, front->name,
27707 - sna_pixmap_get_buffer(pixmap) ? ((DRI2BufferPtr)sna_pixmap_get_buffer(pixmap))->name : 0,
27708 + sna_pixmap_get_buffer(pixmap) ? sna_pixmap_get_buffer(pixmap)->name : 0,
27709 pixmap->drawable.serialNumber));
27710 return false;
27712 @@ -1661,7 +2150,6 @@ can_flip(struct sna * sna,
27715 DBG(("%s: yes, pixmap=%ld\n", __FUNCTION__, pixmap->drawable.serialNumber));
27716 - assert(dri2_window(win)->front == NULL);
27717 return true;
27720 @@ -1680,9 +2168,9 @@ can_xchg(struct sna *sna,
27721 if (draw->type == DRAWABLE_PIXMAP)
27722 return false;
27724 - if (front->format != back->format) {
27725 + if (front->cpp != back->cpp) {
27726 DBG(("%s: no, format mismatch, front = %d, back = %d\n",
27727 - __FUNCTION__, front->format, back->format));
27728 + __FUNCTION__, front->cpp, back->cpp));
27729 return false;
27732 @@ -1714,6 +2202,8 @@ can_xchg(struct sna *sna,
27733 return false;
27736 + DBG(("%s: back size=%x, front size=%x\n",
27737 + __FUNCTION__, get_private(back)->size, get_private(front)->size));
27738 if (get_private(back)->size != get_private(front)->size) {
27739 DBG(("%s: no, back buffer %dx%d does not match front buffer %dx%d\n",
27740 __FUNCTION__,
27741 @@ -1766,9 +2256,9 @@ overlaps_other_crtc(struct sna *sna, xf86CrtcPtr desired)
27742 static bool
27743 can_xchg_crtc(struct sna *sna,
27744 DrawablePtr draw,
27745 + xf86CrtcPtr crtc,
27746 DRI2BufferPtr front,
27747 - DRI2BufferPtr back,
27748 - xf86CrtcPtr crtc)
27749 + DRI2BufferPtr back)
27751 WindowPtr win = (WindowPtr)draw;
27752 PixmapPtr pixmap;
27753 @@ -1785,9 +2275,9 @@ can_xchg_crtc(struct sna *sna,
27754 if (draw->type == DRAWABLE_PIXMAP)
27755 return false;
27757 - if (front->format != back->format) {
27758 + if (front->cpp != back->cpp) {
27759 DBG(("%s: no, format mismatch, front = %d, back = %d\n",
27760 - __FUNCTION__, front->format, back->format));
27761 + __FUNCTION__, front->cpp, back->cpp));
27762 return false;
27765 @@ -1866,20 +2356,21 @@ sna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
27767 back_bo = get_private(back)->bo;
27768 front_bo = get_private(front)->bo;
27769 - assert(front_bo != back_bo);
27771 - DBG(("%s: win=%ld, exchange front=%d/%d and back=%d/%d, pixmap=%ld %dx%d\n",
27772 + DBG(("%s: win=%ld, exchange front=%d/%d,ref=%d and back=%d/%d,ref=%d, pixmap=%ld %dx%d\n",
27773 __FUNCTION__, win->drawable.id,
27774 - front_bo->handle, front->name,
27775 - back_bo->handle, back->name,
27776 + front_bo->handle, front->name, get_private(front)->refcnt,
27777 + back_bo->handle, back->name, get_private(back)->refcnt,
27778 pixmap->drawable.serialNumber,
27779 pixmap->drawable.width,
27780 pixmap->drawable.height));
27782 - DBG(("%s: back_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
27783 - __FUNCTION__, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt, back_bo->active_scanout));
27784 - DBG(("%s: front_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
27785 - __FUNCTION__, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt, front_bo->active_scanout));
27786 + DBG(("%s: back_bo handle=%d, pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
27787 + __FUNCTION__, back_bo->handle, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt, back_bo->active_scanout));
27788 + DBG(("%s: front_bo handle=%d, pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
27789 + __FUNCTION__, front_bo->handle, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt, front_bo->active_scanout));
27791 + assert(front_bo != back_bo);
27792 assert(front_bo->refcnt);
27793 assert(back_bo->refcnt);
27795 @@ -1894,6 +2385,11 @@ sna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
27796 get_private(back)->bo = front_bo;
27797 mark_stale(back);
27799 + assert(front_bo->active_scanout > 0);
27800 + front_bo->active_scanout--;
27801 + back_bo->active_scanout++;
27802 + assert(back_bo->active_scanout <= back_bo->refcnt);
27804 tmp = front->name;
27805 front->name = back->name;
27806 back->name = tmp;
27807 @@ -1902,17 +2398,23 @@ sna_dri2_xchg(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
27808 front->pitch = back->pitch;
27809 back->pitch = tmp;
27811 + tmp = front->flags;
27812 + front->flags = back->flags;
27813 + back->flags = tmp;
27815 assert(front_bo->refcnt);
27816 assert(back_bo->refcnt);
27818 + assert(front_bo->pitch == get_private(front)->bo->pitch);
27819 + assert(back_bo->pitch == get_private(back)->bo->pitch);
27821 assert(get_private(front)->bo == sna_pixmap(pixmap)->gpu_bo);
27824 static void sna_dri2_xchg_crtc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc, DRI2BufferPtr front, DRI2BufferPtr back)
27826 WindowPtr win = (WindowPtr)draw;
27827 - DRI2Buffer2Ptr tmp;
27828 - struct kgem_bo *bo;
27829 + struct dri2_window *priv = dri2_window(win);
27831 DBG(("%s: exchange front=%d/%d and back=%d/%d, win id=%lu, pixmap=%ld %dx%d\n",
27832 __FUNCTION__,
27833 @@ -1922,162 +2424,130 @@ static void sna_dri2_xchg_crtc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr cr
27834 get_window_pixmap(win)->drawable.serialNumber,
27835 get_window_pixmap(win)->drawable.width,
27836 get_window_pixmap(win)->drawable.height));
27837 + assert(can_xchg_crtc(sna, draw, crtc, front, back));
27839 - DamageRegionAppend(&win->drawable, &win->clipList);
27840 + if (APPLY_DAMAGE) {
27841 + DBG(("%s: marking drawable as damaged\n", __FUNCTION__));
27842 + sna->ignore_copy_area = sna->flags & SNA_TEAR_FREE;
27843 + DamageRegionAppend(&win->drawable, &win->clipList);
27844 + }
27845 sna_shadow_set_crtc(sna, crtc, get_private(back)->bo);
27846 - DamageRegionProcessPending(&win->drawable);
27847 + if (APPLY_DAMAGE) {
27848 + sna->ignore_copy_area = false;
27849 + DamageRegionProcessPending(&win->drawable);
27850 + }
27852 - assert(dri2_window(win)->front == NULL);
27853 + if (priv->front == NULL) {
27854 + DRI2Buffer2Ptr tmp;
27856 - tmp = calloc(1, sizeof(*tmp) + sizeof(struct sna_dri2_private));
27857 - if (tmp == NULL) {
27858 - back->attachment = -1;
27859 - if (get_private(back)->proxy == NULL) {
27860 - get_private(back)->pixmap = get_window_pixmap(win);
27861 - get_private(back)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(get_private(back)->pixmap));
27862 + tmp = calloc(1, sizeof(*tmp) + sizeof(struct sna_dri2_private));
27863 + if (tmp == NULL) {
27864 + sna_shadow_unset_crtc(sna, crtc);
27865 + return;
27867 - dri2_window(win)->front = sna_dri2_reference_buffer(back);
27868 - return;
27869 - }
27871 - *tmp = *back;
27872 - tmp->attachment = DRI2BufferFrontLeft;
27873 - tmp->driverPrivate = tmp + 1;
27874 - get_private(tmp)->refcnt = 1;
27875 - get_private(tmp)->bo = get_private(back)->bo;
27876 - get_private(tmp)->size = get_private(back)->size;
27877 - get_private(tmp)->pixmap = get_window_pixmap(win);
27878 - get_private(tmp)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(get_private(tmp)->pixmap));
27879 - dri2_window(win)->front = tmp;
27881 - DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
27882 - back->name = 0;
27883 - bo = kgem_create_2d(&sna->kgem,
27884 - draw->width, draw->height, draw->bitsPerPixel,
27885 - get_private(back)->bo->tiling,
27886 - CREATE_SCANOUT);
27887 - if (bo != NULL) {
27888 - get_private(back)->bo = bo;
27889 - back->pitch = bo->pitch;
27890 - back->name = kgem_bo_flink(&sna->kgem, bo);
27891 - }
27892 - if (back->name == 0) {
27893 - if (bo != NULL)
27894 - kgem_bo_destroy(&sna->kgem, bo);
27895 - get_private(back)->bo = NULL;
27896 - back->attachment = -1;
27897 + tmp->attachment = DRI2BufferFrontLeft;
27898 + tmp->driverPrivate = tmp + 1;
27899 + tmp->cpp = back->cpp;
27900 + tmp->format = back->format;
27902 + get_private(tmp)->refcnt = 1;
27903 + get_private(tmp)->bo = kgem_create_2d(&sna->kgem,
27904 + draw->width, draw->height, draw->bitsPerPixel,
27905 + get_private(back)->bo->tiling,
27906 + CREATE_SCANOUT | CREATE_EXACT);
27907 + if (get_private(tmp)->bo != NULL) {
27908 + tmp->pitch = get_private(tmp)->bo->pitch;
27909 + tmp->name = kgem_bo_flink(&sna->kgem, get_private(tmp)->bo);
27910 + }
27911 + if (tmp->name == 0) {
27912 + if (get_private(tmp)->bo != NULL)
27913 + kgem_bo_destroy(&sna->kgem, get_private(tmp)->bo);
27914 + sna_shadow_unset_crtc(sna, crtc);
27915 + return;
27916 + }
27917 + get_private(tmp)->size = get_private(back)->size;
27918 + get_private(tmp)->pixmap = get_private(front)->pixmap;
27919 + get_private(tmp)->proxy = sna_dri2_reference_buffer(front);
27920 + get_private(tmp)->bo->active_scanout++;
27922 + priv->front = front = tmp;
27924 -}
27925 + assert(front == priv->front);
27927 -static void frame_swap_complete(struct sna_dri2_event *frame, int type)
27928 -{
27929 - const struct ust_msc *swap;
27930 + {
27931 + struct kgem_bo *front_bo = get_private(front)->bo;
27932 + struct kgem_bo *back_bo = get_private(back)->bo;
27933 + unsigned tmp;
27935 - if (frame->draw == NULL)
27936 - return;
27937 + assert(front_bo->refcnt);
27938 + assert(back_bo->refcnt);
27940 - assert(frame->client);
27941 + get_private(back)->bo = front_bo;
27942 + get_private(front)->bo = back_bo;
27943 + mark_stale(back);
27945 - swap = sna_crtc_last_swap(frame->crtc);
27946 - DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc=%lld], tv=%d.%06d\n",
27947 - __FUNCTION__, type, (long)frame->draw, frame->pipe,
27948 - (long long)swap->msc,
27949 - (long long)draw_current_msc(frame->draw, frame->crtc, swap->msc),
27950 - swap->tv_sec, swap->tv_usec));
27951 + assert(front_bo->active_scanout > 0);
27952 + front_bo->active_scanout--;
27953 + back_bo->active_scanout++;
27954 + assert(back_bo->active_scanout <= back_bo->refcnt);
27956 - DRI2SwapComplete(frame->client, frame->draw,
27957 - draw_current_msc(frame->draw, frame->crtc, swap->msc),
27958 - swap->tv_sec, swap->tv_usec,
27959 - type, frame->event_complete, frame->event_data);
27960 -}
27961 + tmp = front->name;
27962 + front->name = back->name;
27963 + back->name = tmp;
27965 -static void fake_swap_complete(struct sna *sna, ClientPtr client,
27966 - DrawablePtr draw, xf86CrtcPtr crtc,
27967 - int type, DRI2SwapEventPtr func, void *data)
27968 -{
27969 - const struct ust_msc *swap;
27971 - swap = sna_crtc_last_swap(crtc);
27972 - DBG(("%s(type=%d): draw=%ld, pipe=%d, frame=%lld [msc %lld], tv=%d.%06d\n",
27973 - __FUNCTION__, type, (long)draw->id, crtc ? sna_crtc_to_pipe(crtc) : -1,
27974 - (long long)swap->msc,
27975 - (long long)draw_current_msc(draw, crtc, swap->msc),
27976 - swap->tv_sec, swap->tv_usec));
27977 + tmp = front->pitch;
27978 + front->pitch = back->pitch;
27979 + back->pitch = tmp;
27981 - DRI2SwapComplete(client, draw,
27982 - draw_current_msc(draw, crtc, swap->msc),
27983 - swap->tv_sec, swap->tv_usec,
27984 - type, func, data);
27985 + tmp = front->flags;
27986 + front->flags = back->flags;
27987 + back->flags = tmp;
27988 + }
27991 static void chain_swap(struct sna_dri2_event *chain)
27993 - union drm_wait_vblank vbl;
27994 + DBG(("%s: draw=%ld, queued?=%d, type=%d\n",
27995 + __FUNCTION__, (long)chain->draw->id, chain->queued, chain->type));
27997 + if (chain->queued) /* too early! */
27998 + return;
28000 if (chain->draw == NULL) {
28001 sna_dri2_event_free(chain);
28002 return;
28005 - if (chain->queued) /* too early! */
28006 - return;
28008 assert(chain == dri2_chain(chain->draw));
28009 - DBG(("%s: chaining draw=%ld, type=%d\n",
28010 - __FUNCTION__, (long)chain->draw->id, chain->type));
28011 - chain->queued = true;
28012 + assert(chain->signal);
28014 switch (chain->type) {
28015 - case SWAP_THROTTLE:
28016 + case SWAP_COMPLETE:
28017 DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
28018 - if (chain->sna->mode.shadow &&
28019 - !chain->sna->mode.shadow_damage) {
28020 - /* recursed from wait_for_shadow(), simply requeue */
28021 - DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__));
28022 - VG_CLEAR(vbl);
28023 - vbl.request.type =
28024 - DRM_VBLANK_RELATIVE |
28025 - DRM_VBLANK_EVENT;
28026 - vbl.request.sequence = 1;
28027 - vbl.request.signal = (uintptr_t)chain;
28029 - if (!sna_wait_vblank(chain->sna, &vbl, chain->pipe))
28030 - return;
28032 - DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno));
28033 - }
28035 if (can_xchg(chain->sna, chain->draw, chain->front, chain->back)) {
28036 sna_dri2_xchg(chain->draw, chain->front, chain->back);
28037 - } else if (can_xchg_crtc(chain->sna, chain->draw, chain->front, chain->back, chain->crtc)) {
28038 - sna_dri2_xchg_crtc(chain->sna, chain->draw, chain->crtc, chain->front, chain->back);
28039 + } else if (can_xchg_crtc(chain->sna, chain->draw, chain->crtc,
28040 + chain->front, chain->back)) {
28041 + sna_dri2_xchg_crtc(chain->sna, chain->draw, chain->crtc,
28042 + chain->front, chain->back);
28043 } else {
28044 - assert(chain->queued);
28045 - chain->bo = __sna_dri2_copy_region(chain->sna, chain->draw, NULL,
28046 - chain->back, chain->front,
28047 - true);
28048 + __sna_dri2_copy_event(chain, chain->sync | DRI2_BO);
28050 + assert(get_private(chain->back)->bo != get_private(chain->front)->bo);
28051 case SWAP:
28052 break;
28053 default:
28054 return;
28057 - VG_CLEAR(vbl);
28058 - vbl.request.type =
28059 - DRM_VBLANK_RELATIVE |
28060 - DRM_VBLANK_EVENT;
28061 - vbl.request.sequence = 1;
28062 - vbl.request.signal = (uintptr_t)chain;
28063 - if (sna_wait_vblank(chain->sna, &vbl, chain->pipe)) {
28064 + if ((chain->type == SWAP_COMPLETE &&
28065 + !swap_limit(chain->draw, 2 + !chain->sync) &&
28066 + !chain->sync) ||
28067 + !sna_next_vblank(chain)) {
28068 DBG(("%s: vblank wait failed, unblocking client\n", __FUNCTION__));
28069 frame_swap_complete(chain, DRI2_BLIT_COMPLETE);
28070 sna_dri2_event_free(chain);
28071 - } else {
28072 - if (chain->type == SWAP_THROTTLE && !swap_limit(chain->draw, 2)) {
28073 - DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
28074 - frame_swap_complete(chain, DRI2_BLIT_COMPLETE);
28075 - }
28079 @@ -2086,40 +2556,27 @@ static inline bool rq_is_busy(struct kgem *kgem, struct kgem_bo *bo)
28080 if (bo == NULL)
28081 return false;
28083 - DBG(("%s: handle=%d, domain: %d exec? %d, rq? %d\n", __FUNCTION__,
28084 - bo->handle, bo->domain, bo->exec != NULL, bo->rq != NULL));
28085 - assert(bo->refcnt);
28087 - if (bo->exec)
28088 - return true;
28090 - if (bo->rq == NULL)
28091 - return false;
28093 - return __kgem_busy(kgem, bo->handle);
28094 + return __kgem_bo_is_busy(kgem, bo);
28097 -static bool sna_dri2_blit_complete(struct sna *sna,
28098 - struct sna_dri2_event *info)
28099 +static bool sna_dri2_blit_complete(struct sna_dri2_event *info)
28101 - if (rq_is_busy(&sna->kgem, info->bo)) {
28102 - union drm_wait_vblank vbl;
28103 + if (!info->bo)
28104 + return true;
28106 + if (__kgem_bo_is_busy(&info->sna->kgem, info->bo)) {
28107 DBG(("%s: vsync'ed blit is still busy, postponing\n",
28108 __FUNCTION__));
28110 - VG_CLEAR(vbl);
28111 - vbl.request.type =
28112 - DRM_VBLANK_RELATIVE |
28113 - DRM_VBLANK_EVENT;
28114 - vbl.request.sequence = 1;
28115 - vbl.request.signal = (uintptr_t)info;
28116 - assert(info->queued);
28117 - if (!sna_wait_vblank(sna, &vbl, info->pipe))
28118 + if (sna_next_vblank(info))
28119 return false;
28121 + kgem_bo_sync__gtt(&info->sna->kgem, info->bo);
28124 DBG(("%s: blit finished\n", __FUNCTION__));
28125 + kgem_bo_destroy(&info->sna->kgem, info->bo);
28126 + info->bo = NULL;
28128 return true;
28131 @@ -2128,11 +2585,12 @@ void sna_dri2_vblank_handler(struct drm_event_vblank *event)
28132 struct sna_dri2_event *info = (void *)(uintptr_t)event->user_data;
28133 struct sna *sna = info->sna;
28134 DrawablePtr draw;
28135 - union drm_wait_vblank vbl;
28136 uint64_t msc;
28138 - DBG(("%s(type=%d, sequence=%d)\n", __FUNCTION__, info->type, event->sequence));
28139 + DBG(("%s(type=%d, sequence=%d, draw=%ld)\n", __FUNCTION__, info->type, event->sequence, info->draw ? info->draw->serialNumber : 0));
28140 assert(info->queued);
28141 + info->queued = false;
28143 msc = sna_crtc_record_event(info->crtc, event);
28145 draw = info->draw;
28146 @@ -2141,68 +2599,120 @@ void sna_dri2_vblank_handler(struct drm_event_vblank *event)
28147 goto done;
28150 + assert((info->front == NULL && info->back == NULL) || info->front != info->back);
28151 switch (info->type) {
28152 case FLIP:
28153 /* If we can still flip... */
28154 + assert(info->signal);
28155 if (can_flip(sna, draw, info->front, info->back, info->crtc) &&
28156 sna_dri2_flip(info))
28157 return;
28159 /* else fall through to blit */
28160 case SWAP:
28161 - assert(info->queued);
28162 - if (sna->mode.shadow && !sna->mode.shadow_damage) {
28163 - /* recursed from wait_for_shadow(), simply requeue */
28164 - DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__));
28166 - } else if (can_xchg(info->sna, draw, info->front, info->back)) {
28167 + assert(info->signal);
28168 + if (can_xchg(info->sna, draw, info->front, info->back)) {
28169 sna_dri2_xchg(draw, info->front, info->back);
28170 - info->type = SWAP_WAIT;
28171 - } else if (can_xchg_crtc(sna, draw, info->front, info->back, info->crtc)) {
28172 - sna_dri2_xchg_crtc(sna, draw, info->crtc, info->front, info->back);
28173 - info->type = SWAP_WAIT;
28174 + info->type = SWAP_COMPLETE;
28175 + } else if (can_xchg_crtc(sna, draw, info->crtc,
28176 + info->front, info->back)) {
28177 + sna_dri2_xchg_crtc(sna, draw, info->crtc,
28178 + info->front, info->back);
28179 + info->type = SWAP_COMPLETE;
28180 } else {
28181 - assert(info->queued);
28182 - info->bo = __sna_dri2_copy_region(sna, draw, NULL,
28183 - info->back, info->front, true);
28184 - info->type = SWAP_WAIT;
28185 + __sna_dri2_copy_event(info, DRI2_BO | DRI2_SYNC);
28186 + info->type = SWAP_COMPLETE;
28189 - VG_CLEAR(vbl);
28190 - vbl.request.type =
28191 - DRM_VBLANK_RELATIVE |
28192 - DRM_VBLANK_EVENT;
28193 - vbl.request.sequence = 1;
28194 - vbl.request.signal = (uintptr_t)info;
28196 - assert(info->queued);
28197 - if (!sna_wait_vblank(sna, &vbl, info->pipe))
28198 + if (sna_next_vblank(info))
28199 return;
28201 DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno));
28202 + assert(info->pending.bo == NULL);
28203 + assert(info->keepalive == 1);
28204 /* fall through to SwapComplete */
28205 - case SWAP_WAIT:
28206 - if (!sna_dri2_blit_complete(sna, info))
28207 - return;
28209 - DBG(("%s: swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
28210 - event->sequence, event->tv_sec, event->tv_usec));
28211 - frame_swap_complete(info, DRI2_BLIT_COMPLETE);
28212 - break;
28214 - case SWAP_THROTTLE:
28215 + case SWAP_COMPLETE:
28216 DBG(("%s: %d complete, frame=%d tv=%d.%06d\n",
28217 __FUNCTION__, info->type,
28218 event->sequence, event->tv_sec, event->tv_usec));
28220 - if (xorg_can_triple_buffer()) {
28221 - if (!sna_dri2_blit_complete(sna, info))
28222 + if (info->signal) {
28223 + if (!sna_dri2_blit_complete(info))
28224 return;
28226 DBG(("%s: triple buffer swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
28227 event->sequence, event->tv_sec, event->tv_usec));
28228 frame_swap_complete(info, DRI2_BLIT_COMPLETE);
28231 + if (info->pending.bo) {
28232 + struct copy current_back;
28234 + DBG(("%s: swapping back handle=%d [name=%d, active=%d] for pending handle=%d [name=%d, active=%d], front handle=%d [name=%d, active=%d]\n",
28235 + __FUNCTION__,
28236 + get_private(info->back)->bo->handle, info->back->name, get_private(info->back)->bo->active_scanout,
28237 + info->pending.bo->handle, info->pending.name, info->pending.bo->active_scanout,
28238 + get_private(info->front)->bo->handle, info->front->name, get_private(info->front)->bo->active_scanout));
28240 + assert(info->pending.bo->active_scanout > 0);
28241 + info->pending.bo->active_scanout--;
28243 + current_back.bo = get_private(info->back)->bo;
28244 + current_back.size = get_private(info->back)->size;
28245 + current_back.name = info->back->name;
28246 + current_back.flags = info->back->flags;
28248 + get_private(info->back)->bo = info->pending.bo;
28249 + get_private(info->back)->size = info->pending.size;
28250 + info->back->name = info->pending.name;
28251 + info->back->pitch = info->pending.bo->pitch;
28252 + info->back->flags = info->pending.flags;
28253 + info->pending.bo = NULL;
28255 + assert(get_private(info->back)->bo != get_private(info->front)->bo);
28257 + if (can_xchg(info->sna, info->draw, info->front, info->back))
28258 + sna_dri2_xchg(info->draw, info->front, info->back);
28259 + else if (can_xchg_crtc(info->sna, info->draw, info->crtc,
28260 + info->front, info->back))
28261 + sna_dri2_xchg_crtc(info->sna, info->draw, info->crtc,
28262 + info->front, info->back);
28263 + else
28264 + __sna_dri2_copy_event(info, info->sync | DRI2_BO);
28266 + sna_dri2_cache_bo(info->sna, info->draw,
28267 + get_private(info->back)->bo,
28268 + info->back->name,
28269 + get_private(info->back)->size,
28270 + info->back->flags);
28272 + get_private(info->back)->bo = current_back.bo;
28273 + get_private(info->back)->size = current_back.size;
28274 + info->back->name = current_back.name;
28275 + info->back->pitch = current_back.bo->pitch;
28276 + info->back->flags = current_back.flags;
28278 + DBG(("%s: restored current back handle=%d [name=%d, active=%d], active=%d], front handle=%d [name=%d, active=%d]\n",
28279 + __FUNCTION__,
28280 + get_private(info->back)->bo->handle, info->back->name, get_private(info->back)->bo->active_scanout,
28281 + get_private(info->front)->bo->handle, info->front->name, get_private(info->front)->bo->active_scanout));
28283 + assert(info->draw);
28284 + assert(!info->signal);
28285 + info->keepalive++;
28286 + info->signal = true;
28287 + }
28289 + if (--info->keepalive) {
28290 + if (sna_next_vblank(info))
28291 + return;
28293 + if (info->signal) {
28294 + DBG(("%s: triple buffer swap complete, unblocking client (frame=%d, tv=%d.%06d)\n", __FUNCTION__,
28295 + event->sequence, event->tv_sec, event->tv_usec));
28296 + frame_swap_complete(info, DRI2_BLIT_COMPLETE);
28297 + }
28298 + }
28299 break;
28301 case WAITMSC:
28302 @@ -2218,11 +2728,11 @@ void sna_dri2_vblank_handler(struct drm_event_vblank *event)
28305 if (info->chain) {
28306 + DBG(("%s: continuing chain\n", __FUNCTION__));
28307 assert(info->chain != info);
28308 assert(info->draw == draw);
28309 - sna_dri2_remove_event((WindowPtr)draw, info);
28310 + sna_dri2_remove_event(info);
28311 chain_swap(info->chain);
28312 - info->draw = NULL;
28315 done:
28316 @@ -2230,101 +2740,148 @@ done:
28317 DBG(("%s complete\n", __FUNCTION__));
28320 -static bool
28321 +static void
28322 sna_dri2_immediate_blit(struct sna *sna,
28323 struct sna_dri2_event *info,
28324 - bool sync, bool event)
28325 + bool sync)
28327 - DrawablePtr draw = info->draw;
28328 - bool ret = false;
28329 + struct sna_dri2_event *chain = dri2_chain(info->draw);
28331 if (sna->flags & SNA_NO_WAIT)
28332 sync = false;
28334 - DBG(("%s: emitting immediate blit, throttling client, synced? %d, chained? %d, send-event? %d\n",
28335 - __FUNCTION__, sync, dri2_chain(draw) != info,
28336 - event));
28337 + DBG(("%s: emitting immediate blit, throttling client, synced? %d, chained? %d, pipe %d\n",
28338 + __FUNCTION__, sync, chain != info, info->pipe));
28339 + assert(chain);
28341 - info->type = SWAP_THROTTLE;
28342 - if (!sync || dri2_chain(draw) == info) {
28343 - DBG(("%s: no pending blit, starting chain\n",
28344 - __FUNCTION__));
28345 + info->type = SWAP_COMPLETE;
28346 + info->sync = sync;
28347 + info->keepalive = KEEPALIVE;
28349 - info->queued = true;
28350 - info->bo = __sna_dri2_copy_region(sna, draw, NULL,
28351 - info->back,
28352 - info->front,
28353 - sync);
28354 - if (event) {
28355 - if (sync) {
28356 - union drm_wait_vblank vbl;
28358 - VG_CLEAR(vbl);
28359 - vbl.request.type =
28360 - DRM_VBLANK_RELATIVE |
28361 - DRM_VBLANK_EVENT;
28362 - vbl.request.sequence = 1;
28363 - vbl.request.signal = (uintptr_t)info;
28364 - ret = !sna_wait_vblank(sna, &vbl, info->pipe);
28365 - if (ret)
28366 - event = !swap_limit(draw, 2);
28367 - }
28368 - if (event) {
28369 - DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
28370 - frame_swap_complete(info, DRI2_BLIT_COMPLETE);
28371 - }
28372 + if (chain == info) {
28373 + DBG(("%s: no pending blit, starting chain\n", __FUNCTION__));
28375 + assert(info->front != info->back);
28376 + if (can_xchg(info->sna, info->draw, info->front, info->back)) {
28377 + sna_dri2_xchg(info->draw, info->front, info->back);
28378 + } else if (can_xchg_crtc(info->sna, info->draw, info->crtc,
28379 + info->front, info->back)) {
28380 + sna_dri2_xchg_crtc(info->sna, info->draw, info->crtc,
28381 + info->front, info->back);
28382 + } else
28383 + __sna_dri2_copy_event(info, sync | DRI2_BO);
28385 + assert(info->signal);
28387 + if ((!swap_limit(info->draw, 2 + !sync) && !sync) ||
28388 + !sna_next_vblank(info)) {
28389 + DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
28390 + frame_swap_complete(info, DRI2_BLIT_COMPLETE);
28391 + sna_dri2_event_free(info);
28392 + }
28393 + return;
28394 + }
28396 + DBG(("%s: current event front=%d [name=%d, active?=%d], back=%d [name=%d, active?=%d]\n", __FUNCTION__,
28397 + get_private(chain->front)->bo->handle, chain->front->name, get_private(chain->front)->bo->active_scanout,
28398 + get_private(chain->back)->bo->handle, chain->back->name, get_private(chain->back)->bo->active_scanout));
28400 + if (chain->type == SWAP_COMPLETE && chain->front == info->front) {
28401 + assert(chain->draw == info->draw);
28402 + assert(chain->client == info->client);
28403 + assert(chain->event_complete == info->event_complete);
28404 + assert(chain->event_data == info->event_data);
28405 + assert(chain->queued);
28407 + if ((!sync || !chain->sync) && chain->pending.bo) {
28408 + bool signal = chain->signal;
28410 + DBG(("%s: swap elision, unblocking client\n", __FUNCTION__));
28411 + assert(chain->draw);
28412 + chain->signal = true;
28413 + frame_swap_complete(chain, DRI2_EXCHANGE_COMPLETE);
28414 + chain->signal = signal;
28416 + assert(chain->pending.bo->active_scanout > 0);
28417 + chain->pending.bo->active_scanout--;
28419 + sna_dri2_cache_bo(chain->sna, chain->draw,
28420 + chain->pending.bo,
28421 + chain->pending.name,
28422 + chain->pending.size,
28423 + chain->pending.flags);
28424 + chain->pending.bo = NULL;
28425 + }
28427 + if (chain->pending.bo == NULL && swap_limit(info->draw, 2 + !sync)) {
28428 + DBG(("%s: setting handle=%d as pending blit (current event front=%d, back=%d)\n", __FUNCTION__,
28429 + get_private(info->back)->bo->handle,
28430 + get_private(chain->front)->bo->handle,
28431 + get_private(chain->back)->bo->handle));
28432 + chain->pending.bo = ref(get_private(info->back)->bo);
28433 + chain->pending.size = get_private(info->back)->size;
28434 + chain->pending.name = info->back->name;
28435 + chain->pending.flags = info->back->flags;
28436 + chain->sync = sync;
28437 + info->signal = false; /* transfer signal to pending */
28439 + /* Prevent us from handing it back on next GetBuffers */
28440 + chain->pending.bo->active_scanout++;
28442 + sna_dri2_event_free(info);
28443 + return;
28445 - } else {
28446 - DBG(("%s: pending blit, chained\n", __FUNCTION__));
28447 - ret = true;
28450 - DBG(("%s: continue? %d\n", __FUNCTION__, ret));
28451 - return ret;
28452 + DBG(("%s: pending blit, chained\n", __FUNCTION__));
28455 static bool
28456 sna_dri2_flip_continue(struct sna_dri2_event *info)
28458 - DBG(("%s(mode=%d)\n", __FUNCTION__, info->mode));
28459 + struct kgem_bo *bo = get_private(info->front)->bo;
28461 - if (info->mode > 0){
28462 - struct kgem_bo *bo = get_private(info->front)->bo;
28463 + DBG(("%s(mode=%d)\n", __FUNCTION__, info->flip_continue));
28464 + assert(info->flip_continue > 0);
28465 + info->type = info->flip_continue;
28466 + info->flip_continue = 0;
28468 - info->type = info->mode;
28469 + assert(!info->signal);
28470 + info->signal = info->type == FLIP_THROTTLE && info->draw;
28472 - if (bo != sna_pixmap(info->sna->front)->gpu_bo)
28473 - return false;
28474 + if (info->sna->mode.front_active == 0)
28475 + return false;
28477 - if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler, info))
28478 - return false;
28479 + if (bo != sna_pixmap(info->sna->front)->gpu_bo)
28480 + return false;
28482 - assert(info->sna->dri2.flip_pending == NULL ||
28483 - info->sna->dri2.flip_pending == info);
28484 - info->sna->dri2.flip_pending = info;
28485 - assert(info->queued);
28486 - } else {
28487 - info->type = -info->mode;
28488 + assert(!info->queued);
28489 + if (!sna_page_flip(info->sna, bo, sna_dri2_flip_handler, info))
28490 + return false;
28492 - if (!info->draw)
28493 - return false;
28494 + DBG(("%s: queued flip=%p\n", __FUNCTION__, info));
28495 + assert(info->sna->dri2.flip_pending == NULL ||
28496 + info->sna->dri2.flip_pending == info);
28497 + info->sna->dri2.flip_pending = info;
28498 + info->queued = true;
28500 - if (!can_flip(info->sna, info->draw, info->front, info->back, info->crtc))
28501 - return false;
28502 + return true;
28503 +}
28505 - assert(sna_pixmap_get_buffer(get_drawable_pixmap(info->draw)) == info->front);
28506 - if (!sna_dri2_flip(info))
28507 - return false;
28508 +static bool
28509 +sna_dri2_flip_keepalive(struct sna_dri2_event *info)
28510 +{
28511 + DBG(("%s(keepalive?=%d)\n", __FUNCTION__, info->keepalive-1));
28512 + assert(info->keepalive > 0);
28513 + if (!--info->keepalive)
28514 + return false;
28516 - if (!xorg_can_triple_buffer()) {
28517 - sna_dri2_get_back(info->sna, info->draw, info->back, info);
28518 - DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
28519 - frame_swap_complete(info, DRI2_FLIP_COMPLETE);
28520 - }
28521 - }
28522 + if (info->draw == NULL)
28523 + return false;
28525 - info->mode = 0;
28526 - return true;
28527 + DBG(("%s: marking next flip as complete\n", __FUNCTION__));
28528 + info->flip_continue = FLIP_COMPLETE;
28529 + return sna_dri2_flip_continue(info);
28532 static void chain_flip(struct sna *sna)
28533 @@ -2332,8 +2889,8 @@ static void chain_flip(struct sna *sna)
28534 struct sna_dri2_event *chain = sna->dri2.flip_pending;
28536 assert(chain->type == FLIP);
28537 - DBG(("%s: chaining type=%d, cancelled?=%d\n",
28538 - __FUNCTION__, chain->type, chain->draw == NULL));
28539 + DBG(("%s: chaining type=%d, cancelled?=%d window=%ld\n",
28540 + __FUNCTION__, chain->type, chain->draw == NULL, chain->draw ? chain->draw->id : 0));
28542 sna->dri2.flip_pending = NULL;
28543 if (chain->draw == NULL) {
28544 @@ -2343,31 +2900,18 @@ static void chain_flip(struct sna *sna)
28546 assert(chain == dri2_chain(chain->draw));
28547 assert(!chain->queued);
28548 - chain->queued = true;
28550 if (can_flip(sna, chain->draw, chain->front, chain->back, chain->crtc) &&
28551 sna_dri2_flip(chain)) {
28552 DBG(("%s: performing chained flip\n", __FUNCTION__));
28553 } else {
28554 DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
28555 - chain->bo = __sna_dri2_copy_region(sna, chain->draw, NULL,
28556 - chain->back, chain->front,
28557 - true);
28558 + __sna_dri2_copy_event(chain, DRI2_SYNC);
28560 if (xorg_can_triple_buffer()) {
28561 - union drm_wait_vblank vbl;
28563 - VG_CLEAR(vbl);
28565 - chain->type = SWAP_WAIT;
28566 - vbl.request.type =
28567 - DRM_VBLANK_RELATIVE |
28568 - DRM_VBLANK_EVENT;
28569 - vbl.request.sequence = 1;
28570 - vbl.request.signal = (uintptr_t)chain;
28572 - assert(chain->queued);
28573 - if (!sna_wait_vblank(sna, &vbl, chain->pipe))
28574 + chain->type = SWAP_COMPLETE;
28575 + assert(chain->signal);
28576 + if (sna_next_vblank(chain))
28577 return;
28580 @@ -2381,8 +2925,10 @@ static void sna_dri2_flip_event(struct sna_dri2_event *flip)
28582 struct sna *sna = flip->sna;
28584 - DBG(("%s(pipe=%d, event=%d)\n", __FUNCTION__, flip->pipe, flip->type));
28585 - assert(flip->queued);
28586 + DBG(("%s flip=%p (pipe=%d, event=%d, queued?=%d)\n", __FUNCTION__, flip, flip->pipe, flip->type, flip->queued));
28587 + if (!flip->queued) /* pageflip died whilst being queued */
28588 + return;
28589 + flip->queued = false;
28591 if (sna->dri2.flip_pending == flip)
28592 sna->dri2.flip_pending = NULL;
28593 @@ -2390,8 +2936,10 @@ static void sna_dri2_flip_event(struct sna_dri2_event *flip)
28594 /* We assume our flips arrive in order, so we don't check the frame */
28595 switch (flip->type) {
28596 case FLIP:
28597 - DBG(("%s: swap complete, unblocking client\n", __FUNCTION__));
28598 - frame_swap_complete(flip, DRI2_FLIP_COMPLETE);
28599 + if (flip->signal) {
28600 + DBG(("%s: swap complete, unblocking client\n", __FUNCTION__));
28601 + frame_swap_complete(flip, DRI2_FLIP_COMPLETE);
28602 + }
28603 sna_dri2_event_free(flip);
28605 if (sna->dri2.flip_pending)
28606 @@ -2399,27 +2947,35 @@ static void sna_dri2_flip_event(struct sna_dri2_event *flip)
28607 break;
28609 case FLIP_THROTTLE:
28610 - DBG(("%s: triple buffer swap complete, unblocking client\n", __FUNCTION__));
28611 - frame_swap_complete(flip, DRI2_FLIP_COMPLETE);
28612 + if (flip->signal) {
28613 + DBG(("%s: triple buffer swap complete, unblocking client\n", __FUNCTION__));
28614 + frame_swap_complete(flip, DRI2_FLIP_COMPLETE);
28615 + }
28616 case FLIP_COMPLETE:
28617 + assert(!flip->signal);
28618 if (sna->dri2.flip_pending) {
28619 + DBG(("%s: pending flip\n", __FUNCTION__));
28620 sna_dri2_event_free(flip);
28621 chain_flip(sna);
28622 - } else if (!flip->mode) {
28623 + } else if (!flip->flip_continue) {
28624 DBG(("%s: flip chain complete\n", __FUNCTION__));
28625 + if (!sna_dri2_flip_keepalive(flip)) {
28626 + if (flip->chain) {
28627 + sna_dri2_remove_event(flip);
28628 + chain_swap(flip->chain);
28629 + }
28631 - if (flip->chain) {
28632 - sna_dri2_remove_event((WindowPtr)flip->draw,
28633 - flip);
28634 - chain_swap(flip->chain);
28635 - flip->draw = NULL;
28636 + sna_dri2_event_free(flip);
28639 - sna_dri2_event_free(flip);
28640 } else if (!sna_dri2_flip_continue(flip)) {
28641 DBG(("%s: no longer able to flip\n", __FUNCTION__));
28642 - if (flip->draw == NULL || !sna_dri2_immediate_blit(sna, flip, false, flip->mode < 0))
28643 - sna_dri2_event_free(flip);
28644 + if (flip->draw != NULL)
28645 + __sna_dri2_copy_event(flip, 0);
28646 + if (flip->signal) {
28647 + DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
28648 + frame_swap_complete(flip, DRI2_BLIT_COMPLETE);
28649 + }
28650 + sna_dri2_event_free(flip);
28652 break;
28654 @@ -2433,17 +2989,27 @@ static void sna_dri2_flip_event(struct sna_dri2_event *flip)
28658 +static int
28659 +sna_query_vblank(struct sna *sna, xf86CrtcPtr crtc, union drm_wait_vblank *vbl)
28660 +{
28661 + VG_CLEAR(*vbl);
28662 + vbl->request.type =
28663 + _DRM_VBLANK_RELATIVE | pipe_select(sna_crtc_pipe(crtc));
28664 + vbl->request.sequence = 0;
28666 + return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl);
28667 +}
28669 static uint64_t
28670 get_current_msc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc)
28672 union drm_wait_vblank vbl;
28673 - uint64_t ret = -1;
28674 + uint64_t ret;
28676 - VG_CLEAR(vbl);
28677 - vbl.request.type = _DRM_VBLANK_RELATIVE;
28678 - vbl.request.sequence = 0;
28679 - if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0)
28680 + if (sna_query_vblank(sna, crtc, &vbl) == 0)
28681 ret = sna_crtc_record_vblank(crtc, &vbl);
28682 + else
28683 + ret = sna_crtc_last_swap(crtc)->msc;
28685 return draw_current_msc(draw, crtc, ret);
28687 @@ -2494,12 +3060,18 @@ static int use_triple_buffer(struct sna *sna, ClientPtr client, bool async)
28690 static bool immediate_swap(struct sna *sna,
28691 - uint64_t target_msc,
28692 - uint64_t divisor,
28693 DrawablePtr draw,
28694 xf86CrtcPtr crtc,
28695 + uint64_t *target_msc,
28696 + uint64_t divisor,
28697 + uint64_t remainder,
28698 uint64_t *current_msc)
28700 + /*
28701 + * If divisor is zero, or current_msc is smaller than target_msc
28702 + * we just need to make sure target_msc passes before initiating
28703 + * the swap.
28704 + */
28705 if (divisor == 0) {
28706 *current_msc = -1;
28708 @@ -2508,72 +3080,97 @@ static bool immediate_swap(struct sna *sna,
28709 return true;
28712 - if (target_msc)
28713 + if (*target_msc)
28714 *current_msc = get_current_msc(sna, draw, crtc);
28716 DBG(("%s: current_msc=%ld, target_msc=%ld -- %s\n",
28717 - __FUNCTION__, (long)*current_msc, (long)target_msc,
28718 - (*current_msc >= target_msc - 1) ? "yes" : "no"));
28719 - return *current_msc >= target_msc - 1;
28720 + __FUNCTION__, (long)*current_msc, (long)*target_msc,
28721 + (*current_msc >= *target_msc - 1) ? "yes" : "no"));
28722 + return *current_msc >= *target_msc - 1;
28725 DBG(("%s: explicit waits requests, divisor=%ld\n",
28726 __FUNCTION__, (long)divisor));
28727 *current_msc = get_current_msc(sna, draw, crtc);
28728 - return false;
28729 + if (*current_msc >= *target_msc) {
28730 + DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
28731 + __FUNCTION__,
28732 + (long long)*current_msc,
28733 + (long long)*target_msc,
28734 + (long long)divisor,
28735 + (long long)remainder));
28737 + *target_msc = *current_msc + remainder - *current_msc % divisor;
28738 + if (*target_msc <= *current_msc)
28739 + *target_msc += divisor;
28740 + }
28742 + DBG(("%s: target_msc=%lld, current_msc=%lld, immediate?=%d\n",
28743 + __FUNCTION__, (long long)*target_msc, (long long)*current_msc,
28744 + *current_msc >= *target_msc - 1));
28745 + return *current_msc >= *target_msc - 1;
28748 static bool
28749 sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
28750 DRI2BufferPtr front, DRI2BufferPtr back,
28751 - CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
28752 + bool immediate, CARD64 *target_msc, CARD64 current_msc,
28753 DRI2SwapEventPtr func, void *data)
28755 struct sna *sna = to_sna_from_drawable(draw);
28756 struct sna_dri2_event *info;
28757 - uint64_t current_msc;
28759 - if (immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc)) {
28760 - int type;
28762 + if (immediate) {
28763 + bool signal = false;
28764 info = sna->dri2.flip_pending;
28765 DBG(("%s: performing immediate swap on pipe %d, pending? %d, mode: %d, continuation? %d\n",
28766 - __FUNCTION__, sna_crtc_to_pipe(crtc),
28767 - info != NULL, info ? info->mode : 0,
28768 + __FUNCTION__, sna_crtc_pipe(crtc),
28769 + info != NULL, info ? info->flip_continue : 0,
28770 info && info->draw == draw));
28772 if (info && info->draw == draw) {
28773 assert(info->type != FLIP);
28774 - assert(info->front == front);
28775 + assert(info->queued);
28776 + assert(info->front != info->back);
28777 + if (info->front != front) {
28778 + assert(info->front != NULL);
28779 + _sna_dri2_destroy_buffer(sna, draw, info->front);
28780 + info->front = sna_dri2_reference_buffer(front);
28781 + }
28782 if (info->back != back) {
28783 - _sna_dri2_destroy_buffer(sna, info->back);
28784 + assert(info->back != NULL);
28785 + _sna_dri2_destroy_buffer(sna, draw, info->back);
28786 info->back = sna_dri2_reference_buffer(back);
28788 - if (info->mode || current_msc >= *target_msc) {
28789 - DBG(("%s: executing xchg of pending flip\n",
28790 - __FUNCTION__));
28791 - sna_dri2_xchg(draw, front, back);
28792 - info->mode = type = FLIP_COMPLETE;
28793 - goto new_back;
28794 - } else {
28795 + assert(info->front != info->back);
28796 + 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));
28797 + sna_dri2_xchg(draw, front, back);
28798 + info->keepalive = KEEPALIVE;
28799 + if (xorg_can_triple_buffer() &&
28800 + current_msc < *target_msc) {
28801 DBG(("%s: chaining flip\n", __FUNCTION__));
28802 - type = FLIP_THROTTLE;
28803 - if (xorg_can_triple_buffer())
28804 - info->mode = -type;
28805 - else
28806 - info->mode = -FLIP_COMPLETE;
28807 + info->flip_continue = FLIP_THROTTLE;
28808 goto out;
28809 + } else {
28810 + info->flip_continue = FLIP_COMPLETE;
28811 + signal = info->signal;
28812 + assert(info->draw);
28813 + info->signal = true;
28814 + goto new_back;
28818 - info = sna_dri2_add_event(sna, draw, client);
28819 + info = sna_dri2_add_event(sna, draw, client, crtc);
28820 if (info == NULL)
28821 return false;
28823 assert(info->crtc == crtc);
28824 info->event_complete = func;
28825 info->event_data = data;
28826 + assert(info->draw);
28827 + info->signal = true;
28829 + assert(front != back);
28830 info->front = sna_dri2_reference_buffer(front);
28831 info->back = sna_dri2_reference_buffer(back);
28833 @@ -2584,26 +3181,33 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
28834 */
28835 DBG(("%s: queueing flip after pending completion\n",
28836 __FUNCTION__));
28837 - info->type = type = FLIP;
28838 + info->type = FLIP;
28839 sna->dri2.flip_pending = info;
28840 - assert(info->queued);
28841 current_msc++;
28842 + } else if (sna->mode.flip_active) {
28843 + DBG(("%s: %d outstanding flips from old client, queueing\n",
28844 + __FUNCTION__, sna->mode.flip_active));
28845 + goto queue;
28846 } else {
28847 - info->type = type = use_triple_buffer(sna, client, *target_msc == 0);
28848 + info->type = use_triple_buffer(sna, client, *target_msc == 0);
28849 if (!sna_dri2_flip(info)) {
28850 DBG(("%s: flip failed, falling back\n", __FUNCTION__));
28851 + info->signal = false;
28852 sna_dri2_event_free(info);
28853 return false;
28855 + assert(get_private(info->front)->bo->active_scanout);
28858 - swap_limit(draw, 1 + (type == FLIP_THROTTLE));
28859 - if (type >= FLIP_COMPLETE) {
28860 + swap_limit(draw, 1 + (info->type == FLIP_THROTTLE));
28861 + if (info->type >= FLIP_COMPLETE) {
28862 new_back:
28863 if (!xorg_can_triple_buffer())
28864 - sna_dri2_get_back(sna, draw, back, info);
28865 + sna_dri2_get_back(sna, draw, back);
28866 DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
28867 frame_swap_complete(info, DRI2_EXCHANGE_COMPLETE);
28868 + assert(info->draw);
28869 + info->signal = signal;
28870 if (info->type == FLIP_ASYNC)
28871 sna_dri2_event_free(info);
28873 @@ -2613,57 +3217,34 @@ out:
28874 return true;
28877 - info = sna_dri2_add_event(sna, draw, client);
28878 +queue:
28879 + if (KEEPALIVE > 1 && sna->dri2.flip_pending) {
28880 + info = sna->dri2.flip_pending;
28881 + info->keepalive = 1;
28882 + }
28884 + info = sna_dri2_add_event(sna, draw, client, crtc);
28885 if (info == NULL)
28886 return false;
28888 assert(info->crtc == crtc);
28889 info->event_complete = func;
28890 info->event_data = data;
28891 + assert(info->draw);
28892 + info->signal = true;
28893 info->type = FLIP;
28895 + assert(front != back);
28896 info->front = sna_dri2_reference_buffer(front);
28897 info->back = sna_dri2_reference_buffer(back);
28899 - /*
28900 - * If divisor is zero, or current_msc is smaller than target_msc
28901 - * we just need to make sure target_msc passes before initiating
28902 - * the swap.
28903 - */
28904 - if (divisor && current_msc >= *target_msc) {
28905 - DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
28906 - __FUNCTION__,
28907 - (long long)current_msc,
28908 - (long long)*target_msc,
28909 - (long long)divisor,
28910 - (long long)remainder));
28912 - *target_msc = current_msc + remainder - current_msc % divisor;
28913 - if (*target_msc <= current_msc)
28914 - *target_msc += divisor;
28915 - }
28917 - if (*target_msc <= current_msc + 1) {
28918 - if (!sna_dri2_flip(info)) {
28919 - sna_dri2_event_free(info);
28920 - return false;
28921 - }
28922 + if (*target_msc <= current_msc + 1 && sna_dri2_flip(info)) {
28923 *target_msc = current_msc + 1;
28924 } else {
28925 - union drm_wait_vblank vbl;
28927 - VG_CLEAR(vbl);
28929 - vbl.request.type =
28930 - DRM_VBLANK_ABSOLUTE |
28931 - DRM_VBLANK_EVENT;
28933 /* Account for 1 frame extra pageflip delay */
28934 - vbl.reply.sequence = draw_target_seq(draw, *target_msc - 1);
28935 - vbl.request.signal = (uintptr_t)info;
28937 - info->queued = true;
28938 - if (sna_wait_vblank(sna, &vbl, info->pipe)) {
28939 + if (!sna_wait_vblank(info,
28940 + draw_target_seq(draw, *target_msc - 1))) {
28941 + info->signal = false;
28942 sna_dri2_event_free(info);
28943 return false;
28945 @@ -2674,128 +3255,6 @@ out:
28946 return true;
28949 -static bool
28950 -sna_dri2_schedule_xchg(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
28951 - DRI2BufferPtr front, DRI2BufferPtr back,
28952 - CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
28953 - DRI2SwapEventPtr func, void *data)
28954 -{
28955 - struct sna *sna = to_sna_from_drawable(draw);
28956 - uint64_t current_msc;
28957 - bool sync, event;
28959 - if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc))
28960 - return false;
28962 - sync = current_msc < *target_msc;
28963 - event = dri2_chain(draw) == NULL;
28964 - if (!sync || event) {
28965 - DBG(("%s: performing immediate xchg on pipe %d\n",
28966 - __FUNCTION__, sna_crtc_to_pipe(crtc)));
28967 - sna_dri2_xchg(draw, front, back);
28968 - }
28969 - if (sync) {
28970 - struct sna_dri2_event *info;
28972 - info = sna_dri2_add_event(sna, draw, client);
28973 - if (!info)
28974 - goto complete;
28976 - info->event_complete = func;
28977 - info->event_data = data;
28979 - info->front = sna_dri2_reference_buffer(front);
28980 - info->back = sna_dri2_reference_buffer(back);
28981 - info->type = SWAP_THROTTLE;
28983 - if (event) {
28984 - union drm_wait_vblank vbl;
28986 - VG_CLEAR(vbl);
28987 - vbl.request.type =
28988 - DRM_VBLANK_RELATIVE |
28989 - DRM_VBLANK_EVENT;
28990 - vbl.request.sequence = 1;
28991 - vbl.request.signal = (uintptr_t)info;
28993 - info->queued = true;
28994 - if (sna_wait_vblank(sna, &vbl, info->pipe)) {
28995 - sna_dri2_event_free(info);
28996 - goto complete;
28997 - }
28999 - swap_limit(draw, 2);
29000 - }
29001 - } else {
29002 -complete:
29003 - fake_swap_complete(sna, client, draw, crtc, DRI2_EXCHANGE_COMPLETE, func, data);
29004 - }
29006 - *target_msc = current_msc + 1;
29007 - return true;
29008 -}
29010 -static bool
29011 -sna_dri2_schedule_xchg_crtc(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
29012 - DRI2BufferPtr front, DRI2BufferPtr back,
29013 - CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
29014 - DRI2SwapEventPtr func, void *data)
29015 -{
29016 - struct sna *sna = to_sna_from_drawable(draw);
29017 - uint64_t current_msc;
29018 - bool sync, event;
29020 - if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc))
29021 - return false;
29023 - sync = current_msc < *target_msc;
29024 - event = dri2_chain(draw) == NULL;
29025 - if (!sync || event) {
29026 - DBG(("%s: performing immediate xchg only on pipe %d\n",
29027 - __FUNCTION__, sna_crtc_to_pipe(crtc)));
29028 - sna_dri2_xchg_crtc(sna, draw, crtc, front, back);
29029 - }
29030 - if (sync) {
29031 - struct sna_dri2_event *info;
29033 - info = sna_dri2_add_event(sna, draw, client);
29034 - if (!info)
29035 - goto complete;
29037 - info->event_complete = func;
29038 - info->event_data = data;
29040 - info->front = sna_dri2_reference_buffer(front);
29041 - info->back = sna_dri2_reference_buffer(back);
29042 - info->type = SWAP_THROTTLE;
29044 - if (event) {
29045 - union drm_wait_vblank vbl;
29047 - VG_CLEAR(vbl);
29048 - vbl.request.type =
29049 - DRM_VBLANK_RELATIVE |
29050 - DRM_VBLANK_EVENT;
29051 - vbl.request.sequence = 1;
29052 - vbl.request.signal = (uintptr_t)info;
29054 - info->queued = true;
29055 - if (sna_wait_vblank(sna, &vbl, info->pipe)) {
29056 - sna_dri2_event_free(info);
29057 - goto complete;
29058 - }
29060 - swap_limit(draw, 2);
29061 - }
29062 - } else {
29063 -complete:
29064 - fake_swap_complete(sna, client, draw, crtc, DRI2_EXCHANGE_COMPLETE, func, data);
29065 - }
29067 - *target_msc = current_msc + 1;
29068 - return true;
29069 -}
29071 static bool has_pending_events(struct sna *sna)
29073 struct pollfd pfd;
29074 @@ -2830,11 +3289,11 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
29075 CARD64 remainder, DRI2SwapEventPtr func, void *data)
29077 struct sna *sna = to_sna_from_drawable(draw);
29078 - union drm_wait_vblank vbl;
29079 xf86CrtcPtr crtc = NULL;
29080 struct sna_dri2_event *info = NULL;
29081 int type = DRI2_EXCHANGE_COMPLETE;
29082 CARD64 current_msc;
29083 + bool immediate;
29085 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",
29086 __FUNCTION__,
29087 @@ -2860,6 +3319,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
29088 assert(get_private(front)->refcnt);
29089 assert(get_private(back)->refcnt);
29091 + assert(get_private(back)->bo != get_private(front)->bo);
29092 assert(get_private(front)->bo->refcnt);
29093 assert(get_private(back)->bo->refcnt);
29095 @@ -2876,17 +3336,17 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
29096 goto skip;
29099 - assert(sna_pixmap_from_drawable(draw)->flush);
29101 if (draw->type != DRAWABLE_PIXMAP) {
29102 WindowPtr win = (WindowPtr)draw;
29103 struct dri2_window *priv = dri2_window(win);
29105 if (priv->front) {
29106 - assert(front == priv->front);
29107 - assert(get_private(priv->front)->refcnt > 1);
29108 - get_private(priv->front)->refcnt--;
29109 - priv->front = NULL;
29110 + front = priv->front;
29111 + assert(front->attachment == DRI2BufferFrontLeft);
29112 + assert(get_private(front)->refcnt);
29113 + assert(get_private(front)->pixmap == get_drawable_pixmap(draw));
29116 if (win->clipList.extents.x2 <= win->clipList.extents.x1 ||
29117 win->clipList.extents.y2 <= win->clipList.extents.y1) {
29118 DBG(("%s: window clipped (%d, %d), (%d, %d)\n",
29119 @@ -2899,6 +3359,10 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
29123 + DBG(("%s: using front handle=%d, active_scanout?=%d, flush?=%d\n", __FUNCTION__, get_private(front)->bo->handle, get_private(front)->bo->active_scanout, sna_pixmap_from_drawable(draw)->flush));
29124 + assert(get_private(front)->bo->active_scanout);
29125 + assert(sna_pixmap_from_drawable(draw)->flush);
29127 /* Drawable not displayed... just complete the swap */
29128 if ((sna->flags & SNA_NO_WAIT) == 0)
29129 crtc = sna_dri2_get_crtc(draw);
29130 @@ -2914,109 +3378,112 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
29131 sna_mode_wakeup(sna);
29134 - if (can_xchg(sna, draw, front, back) &&
29135 - sna_dri2_schedule_xchg(client, draw, crtc, front, back,
29136 + immediate = immediate_swap(sna, draw, crtc,
29137 target_msc, divisor, remainder,
29138 - func, data))
29139 - return TRUE;
29141 - if (can_xchg_crtc(sna, draw, front, back, crtc) &&
29142 - sna_dri2_schedule_xchg_crtc(client, draw, crtc, front, back,
29143 - target_msc, divisor, remainder,
29144 - func, data))
29145 - return TRUE;
29146 + &current_msc);
29148 if (can_flip(sna, draw, front, back, crtc) &&
29149 sna_dri2_schedule_flip(client, draw, crtc, front, back,
29150 - target_msc, divisor, remainder,
29151 + immediate, target_msc, current_msc,
29152 func, data))
29153 return TRUE;
29155 - VG_CLEAR(vbl);
29157 - info = sna_dri2_add_event(sna, draw, client);
29158 + info = sna_dri2_add_event(sna, draw, client, crtc);
29159 if (!info)
29160 goto blit;
29162 assert(info->crtc == crtc);
29163 info->event_complete = func;
29164 info->event_data = data;
29165 + assert(info->draw);
29166 + info->signal = true;
29168 + assert(front != back);
29169 info->front = sna_dri2_reference_buffer(front);
29170 info->back = sna_dri2_reference_buffer(back);
29172 - if (immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc)) {
29173 + if (immediate) {
29174 bool sync = current_msc < *target_msc;
29175 - if (!sna_dri2_immediate_blit(sna, info, sync, true))
29176 - sna_dri2_event_free(info);
29177 + sna_dri2_immediate_blit(sna, info, sync);
29178 *target_msc = current_msc + sync;
29179 + DBG(("%s: reported target_msc=%llu\n",
29180 + __FUNCTION__, *target_msc));
29181 return TRUE;
29184 - vbl.request.type =
29185 - DRM_VBLANK_ABSOLUTE |
29186 - DRM_VBLANK_EVENT;
29187 - vbl.request.signal = (uintptr_t)info;
29189 - /*
29190 - * If divisor is zero, or current_msc is smaller than target_msc
29191 - * we just need to make sure target_msc passes before initiating
29192 - * the swap.
29193 - */
29194 info->type = SWAP;
29195 - info->queued = true;
29196 - if (divisor && current_msc >= *target_msc) {
29197 - DBG(("%s: missed target, queueing event for next: current=%lld, target=%lld, divisor=%lld, remainder=%lld\n",
29198 - __FUNCTION__,
29199 - (long long)current_msc,
29200 - (long long)*target_msc,
29201 - (long long)divisor,
29202 - (long long)remainder));
29204 - *target_msc = current_msc + remainder - current_msc % divisor;
29205 - if (*target_msc <= current_msc)
29206 - *target_msc += divisor;
29207 - }
29208 - vbl.request.sequence = draw_target_seq(draw, *target_msc - 1);
29209 if (*target_msc <= current_msc + 1) {
29210 DBG(("%s: performing blit before queueing\n", __FUNCTION__));
29211 - assert(info->queued);
29212 - info->bo = __sna_dri2_copy_region(sna, draw, NULL,
29213 - back, front,
29214 - true);
29215 - info->type = SWAP_WAIT;
29217 - vbl.request.type =
29218 - DRM_VBLANK_RELATIVE |
29219 - DRM_VBLANK_EVENT;
29220 - vbl.request.sequence = 1;
29221 + __sna_dri2_copy_event(info, DRI2_SYNC);
29222 + info->type = SWAP_COMPLETE;
29223 + if (!sna_next_vblank(info))
29224 + goto fake;
29226 + DBG(("%s: reported target_msc=%llu\n",
29227 + __FUNCTION__, *target_msc));
29228 *target_msc = current_msc + 1;
29229 - }
29230 + swap_limit(draw, 2);
29231 + } else {
29232 + if (!sna_wait_vblank(info,
29233 + draw_target_seq(draw, *target_msc - 1)))
29234 + goto blit;
29236 - assert(info->queued);
29237 - if (sna_wait_vblank(sna, &vbl, info->pipe))
29238 - goto blit;
29239 + DBG(("%s: reported target_msc=%llu (in)\n",
29240 + __FUNCTION__, *target_msc));
29241 + swap_limit(draw, 1);
29242 + }
29244 - DBG(("%s: reported target_msc=%llu\n", __FUNCTION__, *target_msc));
29245 - swap_limit(draw, 1 + (info->type == SWAP_WAIT));
29246 return TRUE;
29248 blit:
29249 DBG(("%s -- blit\n", __FUNCTION__));
29250 - if (info)
29251 - sna_dri2_event_free(info);
29252 if (can_xchg(sna, draw, front, back)) {
29253 sna_dri2_xchg(draw, front, back);
29254 } else {
29255 - __sna_dri2_copy_region(sna, draw, NULL, back, front, false);
29256 + __sna_dri2_copy_region(sna, draw, NULL, back, front, 0);
29257 + front->flags = back->flags;
29258 type = DRI2_BLIT_COMPLETE;
29260 + if (draw->type == DRAWABLE_PIXMAP)
29261 + goto fake;
29262 skip:
29263 DBG(("%s: unable to show frame, unblocking client\n", __FUNCTION__));
29264 - if (crtc == NULL)
29265 - crtc = sna_mode_first_crtc(sna);
29266 - fake_swap_complete(sna, client, draw, crtc, type, func, data);
29267 - *target_msc = 0; /* offscreen, so zero out target vblank count */
29268 + if (crtc == NULL && (sna->flags & SNA_NO_WAIT) == 0)
29269 + crtc = sna_primary_crtc(sna);
29270 + if (crtc && sna_crtc_is_on(crtc)) {
29271 + if (info == NULL)
29272 + info = sna_dri2_add_event(sna, draw, client, crtc);
29273 + if (info != dri2_chain(draw))
29274 + goto fake;
29276 + assert(info->crtc == crtc);
29278 + info->type = SWAP_COMPLETE;
29279 + info->event_complete = func;
29280 + info->event_data = data;
29281 + assert(info->draw);
29282 + info->signal = true;
29284 + if (info->front == NULL)
29285 + info->front = sna_dri2_reference_buffer(front);
29286 + if (info->back == NULL)
29287 + info->back = sna_dri2_reference_buffer(back);
29289 + if (!sna_next_vblank(info))
29290 + goto fake;
29292 + swap_limit(draw, 1);
29293 + } else {
29294 +fake:
29295 + /* XXX Use a Timer to throttle the client? */
29296 + fake_swap_complete(sna, client, draw, crtc, type, func, data);
29297 + if (info) {
29298 + assert(info->draw);
29299 + info->signal = false;
29300 + sna_dri2_event_free(info);
29301 + }
29302 + }
29303 + DBG(("%s: reported target_msc=%llu (in)\n", __FUNCTION__, *target_msc));
29304 return TRUE;
29307 @@ -3030,27 +3497,25 @@ sna_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
29308 struct sna *sna = to_sna_from_drawable(draw);
29309 xf86CrtcPtr crtc = sna_dri2_get_crtc(draw);
29310 const struct ust_msc *swap;
29311 + union drm_wait_vblank vbl;
29313 DBG(("%s(draw=%ld, pipe=%d)\n", __FUNCTION__, draw->id,
29314 - crtc ? sna_crtc_to_pipe(crtc) : -1));
29315 + crtc ? sna_crtc_pipe(crtc) : -1));
29317 - if (crtc != NULL) {
29318 - union drm_wait_vblank vbl;
29319 + /* Drawable not displayed, make up a *monotonic* value */
29320 + if (crtc == NULL)
29321 + crtc = sna_primary_crtc(sna);
29322 + if (crtc == NULL)
29323 + return FALSE;
29325 - VG_CLEAR(vbl);
29326 - vbl.request.type = _DRM_VBLANK_RELATIVE;
29327 - vbl.request.sequence = 0;
29328 - if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(crtc)) == 0)
29329 - sna_crtc_record_vblank(crtc, &vbl);
29330 - } else
29331 - /* Drawable not displayed, make up a *monotonic* value */
29332 - crtc = sna_mode_first_crtc(sna);
29333 + if (sna_query_vblank(sna, crtc, &vbl) == 0)
29334 + sna_crtc_record_vblank(crtc, &vbl);
29336 swap = sna_crtc_last_swap(crtc);
29337 *msc = draw_current_msc(draw, crtc, swap->msc);
29338 *ust = ust64(swap->tv_sec, swap->tv_usec);
29339 - DBG(("%s: msc=%llu, ust=%llu\n", __FUNCTION__,
29340 - (long long)*msc, (long long)*ust));
29341 + DBG(("%s: msc=%llu [raw=%llu], ust=%llu\n", __FUNCTION__,
29342 + (long long)*msc, swap->msc, (long long)*ust));
29343 return TRUE;
29346 @@ -3068,32 +3533,22 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
29347 struct sna_dri2_event *info = NULL;
29348 xf86CrtcPtr crtc;
29349 CARD64 current_msc;
29350 - union drm_wait_vblank vbl;
29351 const struct ust_msc *swap;
29352 - int pipe;
29354 crtc = sna_dri2_get_crtc(draw);
29355 DBG(("%s(pipe=%d, target_msc=%llu, divisor=%llu, rem=%llu)\n",
29356 - __FUNCTION__, crtc ? sna_crtc_to_pipe(crtc) : -1,
29357 + __FUNCTION__, crtc ? sna_crtc_pipe(crtc) : -1,
29358 (long long)target_msc,
29359 (long long)divisor,
29360 (long long)remainder));
29362 /* Drawable not visible, return immediately */
29363 if (crtc == NULL)
29364 - goto out_complete;
29366 - pipe = sna_crtc_to_pipe(crtc);
29368 - VG_CLEAR(vbl);
29370 - /* Get current count */
29371 - vbl.request.type = _DRM_VBLANK_RELATIVE;
29372 - vbl.request.sequence = 0;
29373 - if (sna_wait_vblank(sna, &vbl, pipe))
29374 - goto out_complete;
29375 + crtc = sna_primary_crtc(sna);
29376 + if (crtc == NULL)
29377 + return FALSE;
29379 - current_msc = draw_current_msc(draw, crtc, sna_crtc_record_vblank(crtc, &vbl));
29380 + current_msc = get_current_msc(sna, draw, crtc);
29382 /* If target_msc already reached or passed, set it to
29383 * current_msc to ensure we return a reasonable value back
29384 @@ -3104,15 +3559,13 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
29385 if (divisor == 0 && current_msc >= target_msc)
29386 goto out_complete;
29388 - info = sna_dri2_add_event(sna, draw, client);
29389 + info = sna_dri2_add_event(sna, draw, client, crtc);
29390 if (!info)
29391 goto out_complete;
29393 assert(info->crtc == crtc);
29394 info->type = WAITMSC;
29396 - vbl.request.signal = (uintptr_t)info;
29397 - vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
29398 /*
29399 * If divisor is zero, or current_msc is smaller than target_msc,
29400 * we just need to make sure target_msc passes before waking up the
29401 @@ -3129,10 +3582,8 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
29402 if (target_msc <= current_msc)
29403 target_msc += divisor;
29405 - vbl.request.sequence = draw_target_seq(draw, target_msc);
29407 - info->queued = true;
29408 - if (sna_wait_vblank(sna, &vbl, pipe))
29409 + if (!sna_wait_vblank(info, draw_target_seq(draw, target_msc)))
29410 goto out_free_info;
29412 DRI2BlockClient(client, draw);
29413 @@ -3141,8 +3592,6 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
29414 out_free_info:
29415 sna_dri2_event_free(info);
29416 out_complete:
29417 - if (crtc == NULL)
29418 - crtc = sna_mode_first_crtc(sna);
29419 swap = sna_crtc_last_swap(crtc);
29420 DRI2WaitMSCComplete(client, draw,
29421 draw_current_msc(draw, crtc, swap->msc),
29422 @@ -3231,9 +3680,18 @@ static bool is_level(const char **str)
29423 return false;
29426 +static const char *options_get_dri(struct sna *sna)
29427 +{
29428 +#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
29429 + return xf86GetOptValString(sna->Options, OPTION_DRI);
29430 +#else
29431 + return NULL;
29432 +#endif
29433 +}
29435 static const char *dri_driver_name(struct sna *sna)
29437 - const char *s = xf86GetOptValString(sna->Options, OPTION_DRI);
29438 + const char *s = options_get_dri(sna);
29440 if (is_level(&s)) {
29441 if (sna->kgem.gen < 030)
29442 @@ -3259,7 +3717,7 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
29444 if (wedged(sna)) {
29445 xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
29446 - "loading DRI2 whilst the GPU is wedged.\n");
29447 + "loading DRI2 whilst acceleration is disabled.\n");
29450 if (xf86LoaderCheckSymbol("DRI2Version"))
29451 @@ -3274,7 +3732,7 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
29452 memset(&info, '\0', sizeof(info));
29453 info.fd = sna->kgem.fd;
29454 info.driverName = dri_driver_name(sna);
29455 - info.deviceName = intel_get_client_name(sna->dev);
29456 + info.deviceName = intel_get_master_name(sna->dev);
29458 DBG(("%s: loading dri driver '%s' [gen=%d] for device '%s'\n",
29459 __FUNCTION__, info.driverName, sna->kgem.gen, info.deviceName));
29460 @@ -3299,11 +3757,12 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
29461 info.numDrivers = 2;
29462 info.driverNames = driverNames;
29463 driverNames[0] = info.driverName;
29464 - driverNames[1] = info.driverName;
29465 + driverNames[1] = "va_gl";
29466 #endif
29468 #if DRI2INFOREC_VERSION >= 6
29469 if (xorg_can_triple_buffer()) {
29470 + DBG(("%s: enabling Xorg triple buffering\n", __FUNCTION__));
29471 info.version = 6;
29472 info.SwapLimitValidate = sna_dri2_swap_limit_validate;
29473 info.ReuseBufferNotify = sna_dri2_reuse_buffer;
29474 @@ -3311,8 +3770,10 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
29475 #endif
29477 #if USE_ASYNC_SWAP
29478 + DBG(("%s: enabled async swap and buffer age\n", __FUNCTION__));
29479 info.version = 10;
29480 info.scheduleSwap0 = 1;
29481 + info.bufferAge = 1;
29482 #endif
29484 return DRI2ScreenInit(screen, &info);
29485 diff --git a/src/sna/sna_dri3.c b/src/sna/sna_dri3.c
29486 index f586e242..ce4970ae 100644
29487 --- a/src/sna/sna_dri3.c
29488 +++ b/src/sna/sna_dri3.c
29489 @@ -55,11 +55,14 @@ static inline void mark_dri3_pixmap(struct sna *sna, struct sna_pixmap *priv, st
29490 if (bo->exec)
29491 sna->kgem.flush = 1;
29492 if (bo == priv->gpu_bo)
29493 - priv->flush |= 3;
29494 + priv->flush |= FLUSH_READ | FLUSH_WRITE;
29495 else
29496 priv->shm = true;
29498 - sna_accel_watch_flush(sna, 1);
29499 + sna_watch_flush(sna, 1);
29501 + kgem_bo_submit(&sna->kgem, bo);
29502 + kgem_bo_unclean(&sna->kgem, bo);
29505 static void sna_sync_flush(struct sna *sna, struct sna_pixmap *priv)
29506 @@ -270,6 +273,8 @@ static PixmapPtr sna_dri3_pixmap_from_fd(ScreenPtr screen,
29507 priv->ptr = MAKE_STATIC_PTR(pixmap->devPrivate.ptr);
29508 } else {
29509 assert(priv->gpu_bo == bo);
29510 + priv->create = kgem_can_create_2d(&sna->kgem,
29511 + width, height, depth);
29512 priv->pinned |= PIN_DRI3;
29514 list_add(&priv->cow_list, &sna->dri3.pixmaps);
29515 @@ -325,6 +330,15 @@ static int sna_dri3_fd_from_pixmap(ScreenPtr screen,
29516 return -1;
29519 + if (bo->tiling && !sna->kgem.can_fence) {
29520 + if (!sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) {
29521 + DBG(("%s: unable to discard GPU tiling (%d) for DRI3 protocol\n",
29522 + __FUNCTION__, bo->tiling));
29523 + return -1;
29524 + }
29525 + bo = priv->gpu_bo;
29526 + }
29528 fd = kgem_bo_export_to_prime(&sna->kgem, bo);
29529 if (fd == -1) {
29530 DBG(("%s: exporting handle=%d to fd failed\n", __FUNCTION__, bo->handle));
29531 diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
29532 index 8a3599c7..1b4015de 100644
29533 --- a/src/sna/sna_driver.c
29534 +++ b/src/sna/sna_driver.c
29535 @@ -57,6 +57,13 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
29536 #include <mi.h>
29537 #include <micmap.h>
29539 +#if defined(HAVE_X11_EXTENSIONS_DPMSCONST_H)
29540 +#include <X11/extensions/dpmsconst.h>
29541 +#else
29542 +#define DPMSModeOn 0
29543 +#define DPMSModeOff 3
29544 +#endif
29546 #include <sys/ioctl.h>
29547 #include <sys/fcntl.h>
29548 #include <sys/poll.h>
29549 @@ -69,6 +76,8 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
29551 #if HAVE_DOT_GIT
29552 #include "git_version.h"
29553 +#else
29554 +#define git_version "not compiled from git"
29555 #endif
29557 #ifdef TEARFREE
29558 @@ -185,12 +194,12 @@ sna_set_fallback_mode(ScrnInfoPtr scrn)
29560 xf86DisableUnusedFunctions(scrn);
29561 #ifdef RANDR_12_INTERFACE
29562 - if (get_root_window(scrn->pScreen))
29563 - xf86RandR12TellChanged(scrn->pScreen);
29564 + if (get_root_window(xf86ScrnToScreen(scrn)))
29565 + xf86RandR12TellChanged(xf86ScrnToScreen(scrn));
29566 #endif
29569 -static Bool sna_set_desired_mode(struct sna *sna)
29570 +static void sna_set_desired_mode(struct sna *sna)
29572 ScrnInfoPtr scrn = sna->scrn;
29574 @@ -203,7 +212,6 @@ static Bool sna_set_desired_mode(struct sna *sna)
29577 sna_mode_check(sna);
29578 - return TRUE;
29581 /**
29582 @@ -222,7 +230,7 @@ static Bool sna_create_screen_resources(ScreenPtr screen)
29583 screen->width, screen->height, screen->rootDepth));
29585 assert(sna->scrn == xf86ScreenToScrn(screen));
29586 - assert(sna->scrn->pScreen == screen);
29587 + assert(to_screen_from_sna(sna) == screen);
29589 /* free the data used during miInitScreen */
29590 free(screen->devPrivate);
29591 @@ -273,33 +281,89 @@ static Bool sna_create_screen_resources(ScreenPtr screen)
29592 if (serverGeneration == 1 && (sna->flags & SNA_IS_HOSTED) == 0)
29593 sna_copy_fbcon(sna);
29595 - (void)sna_set_desired_mode(sna);
29596 + sna_set_desired_mode(sna);
29599 return TRUE;
29602 -static Bool sna_save_screen(ScreenPtr screen, int mode)
29603 +static void sna_dpms_set(ScrnInfoPtr scrn, int mode, int flags)
29605 - ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
29606 + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
29607 + struct sna *sna = to_sna(scrn);
29608 + bool changed = false;
29609 + int i;
29611 - DBG(("%s(mode=%d)\n", __FUNCTION__, mode));
29612 + DBG(("%s(mode=%d, flags=%d), vtSema=%d => off?=%d\n",
29613 + __FUNCTION__, mode, flags, scrn->vtSema, mode!=DPMSModeOn));
29614 if (!scrn->vtSema)
29615 - return FALSE;
29616 + return;
29618 - xf86SaveScreen(screen, mode);
29619 - sna_crtc_config_notify(screen);
29620 - return TRUE;
29621 + /* Opencoded version of xf86DPMSSet().
29622 + *
29623 + * The principle difference is to skip calling crtc->dpms() when
29624 + * turning off the display. This (on recent enough kernels at
29625 + * least) should be equivalent in power consumption, but require
29626 + * less work (hence quicker and less likely to fail) when switching
29627 + * back on.
29628 + */
29629 + if (mode != DPMSModeOn) {
29630 + if (sna->mode.hidden == 0 && !(sna->flags & SNA_NO_DPMS)) {
29631 + DBG(("%s: hiding %d outputs\n",
29632 + __FUNCTION__, config->num_output));
29633 + for (i = 0; i < config->num_output; i++) {
29634 + xf86OutputPtr output = config->output[i];
29635 + if (output->crtc != NULL)
29636 + output->funcs->dpms(output, mode);
29637 + }
29638 + sna->mode.hidden = sna->mode.front_active + 1;
29639 + sna->mode.front_active = 0;
29640 + changed = true;
29641 + }
29642 + } else {
29643 + /* Re-enable CRTC that have been forced off via other means */
29644 + if (sna->mode.hidden != 0) {
29645 + DBG(("%s: unhiding %d crtc, %d outputs\n",
29646 + __FUNCTION__, config->num_crtc, config->num_output));
29647 + sna->mode.front_active = sna->mode.hidden - 1;
29648 + sna->mode.hidden = 0;
29649 + for (i = 0; i < config->num_crtc; i++) {
29650 + xf86CrtcPtr crtc = config->crtc[i];
29651 + if (crtc->enabled)
29652 + crtc->funcs->dpms(crtc, mode);
29653 + }
29655 + for (i = 0; i < config->num_output; i++) {
29656 + xf86OutputPtr output = config->output[i];
29657 + if (output->crtc != NULL)
29658 + output->funcs->dpms(output, mode);
29659 + }
29660 + changed = true;
29661 + }
29662 + }
29664 + DBG(("%s: hiding outputs? %d, front active? %d, changed? %d\n",
29665 + __FUNCTION__, sna->mode.hidden, sna->mode.front_active, changed));
29667 + if (changed)
29668 + sna_crtc_config_notify(xf86ScrnToScreen(scrn));
29671 -static void sna_dpms_set(ScrnInfoPtr scrn, int mode, int flags)
29672 +static Bool sna_save_screen(ScreenPtr screen, int mode)
29674 - DBG(("%s(mode=%d, flags=%d)\n", __FUNCTION__, mode));
29675 - if (!scrn->vtSema)
29676 - return;
29677 + ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
29679 + DBG(("%s(mode=%d [unblank=%d])\n",
29680 + __FUNCTION__, mode, xf86IsUnblank(mode)));
29682 - xf86DPMSSet(scrn, mode, flags);
29683 - sna_crtc_config_notify(xf86ScrnToScreen(scrn));
29684 + /* We have to unroll xf86SaveScreen() here as it is called
29685 + * by DPMSSet() nullifying our special handling crtc->dpms()
29686 + * in sna_dpms_set().
29687 + */
29688 + sna_dpms_set(scrn,
29689 + xf86IsUnblank(mode) ? DPMSModeOn : DPMSModeOff,
29690 + 0);
29691 + return TRUE;
29694 static void sna_selftest(void)
29695 @@ -330,107 +394,6 @@ static void sna_setup_capabilities(ScrnInfoPtr scrn, int fd)
29696 #endif
29699 -static int
29700 -namecmp(const char *s1, const char *s2)
29701 -{
29702 - char c1, c2;
29704 - if (!s1 || *s1 == 0) {
29705 - if (!s2 || *s2 == 0)
29706 - return 0;
29707 - else
29708 - return 1;
29709 - }
29711 - while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
29712 - s1++;
29714 - while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
29715 - s2++;
29717 - c1 = isupper(*s1) ? tolower(*s1) : *s1;
29718 - c2 = isupper(*s2) ? tolower(*s2) : *s2;
29719 - while (c1 == c2) {
29720 - if (c1 == '\0')
29721 - return 0;
29723 - s1++;
29724 - while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
29725 - s1++;
29727 - s2++;
29728 - while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
29729 - s2++;
29731 - c1 = isupper(*s1) ? tolower(*s1) : *s1;
29732 - c2 = isupper(*s2) ? tolower(*s2) : *s2;
29733 - }
29735 - return c1 - c2;
29736 -}
29738 -static Bool sna_option_cast_to_bool(struct sna *sna, int id, Bool val)
29739 -{
29740 - const char *str = xf86GetOptValString(sna->Options, id);
29742 - if (str == NULL)
29743 - return val;
29745 - if (*str == '\0')
29746 - return TRUE;
29748 - if (namecmp(str, "1") == 0)
29749 - return TRUE;
29750 - if (namecmp(str, "on") == 0)
29751 - return TRUE;
29752 - if (namecmp(str, "true") == 0)
29753 - return TRUE;
29754 - if (namecmp(str, "yes") == 0)
29755 - return TRUE;
29757 - if (namecmp(str, "0") == 0)
29758 - return FALSE;
29759 - if (namecmp(str, "off") == 0)
29760 - return FALSE;
29761 - if (namecmp(str, "false") == 0)
29762 - return FALSE;
29763 - if (namecmp(str, "no") == 0)
29764 - return FALSE;
29766 - return val;
29767 -}
29769 -static unsigned sna_option_cast_to_unsigned(struct sna *sna, int id, unsigned val)
29770 -{
29771 - const char *str = xf86GetOptValString(sna->Options, id);
29772 - unsigned v;
29774 - if (str == NULL || *str == '\0')
29775 - return val;
29777 - if (namecmp(str, "on") == 0)
29778 - return val;
29779 - if (namecmp(str, "true") == 0)
29780 - return val;
29781 - if (namecmp(str, "yes") == 0)
29782 - return val;
29784 - if (namecmp(str, "0") == 0)
29785 - return 0;
29786 - if (namecmp(str, "off") == 0)
29787 - return 0;
29788 - if (namecmp(str, "false") == 0)
29789 - return 0;
29790 - if (namecmp(str, "no") == 0)
29791 - return 0;
29793 - v = atoi(str);
29794 - if (v)
29795 - return v;
29797 - return val;
29798 -}
29800 static Bool fb_supports_depth(int fd, int depth)
29802 struct drm_i915_gem_create create;
29803 @@ -470,16 +433,24 @@ static void setup_dri(struct sna *sna)
29804 unsigned level;
29806 sna->dri2.available = false;
29807 + sna->dri2.enable = false;
29808 sna->dri3.available = false;
29809 + sna->dri3.enable = false;
29810 + sna->dri3.override = false;
29812 - level = sna_option_cast_to_unsigned(sna, OPTION_DRI, ~0);
29813 + level = intel_option_cast_to_unsigned(sna->Options, OPTION_DRI, DEFAULT_DRI_LEVEL);
29814 #if HAVE_DRI3
29815 - if (level >= 3)
29816 - sna->dri3.available = !!xf86LoadSubModule(sna->scrn, "dri3");
29817 + sna->dri3.available = !!xf86LoadSubModule(sna->scrn, "dri3");
29818 + sna->dri3.override =
29819 + !sna->dri3.available ||
29820 + xf86IsOptionSet(sna->Options, OPTION_DRI);
29821 + if (level >= 3 && sna->kgem.gen >= 040)
29822 + sna->dri3.enable = sna->dri3.available;
29823 #endif
29824 #if HAVE_DRI2
29825 + sna->dri2.available = !!xf86LoadSubModule(sna->scrn, "dri2");
29826 if (level >= 2)
29827 - sna->dri2.available = !!xf86LoadSubModule(sna->scrn, "dri2");
29828 + sna->dri2.enable = sna->dri2.available;
29829 #endif
29832 @@ -498,13 +469,13 @@ static bool enable_tear_free(struct sna *sna)
29833 return ENABLE_TEAR_FREE;
29836 -static void setup_tear_free(struct sna *sna)
29837 +static bool setup_tear_free(struct sna *sna)
29839 MessageType from;
29840 Bool enable;
29842 if (sna->flags & SNA_LINEAR_FB)
29843 - return;
29844 + return false;
29846 if ((sna->flags & SNA_HAS_FLIP) == 0) {
29847 from = X_PROBED;
29848 @@ -518,11 +489,12 @@ static void setup_tear_free(struct sna *sna)
29849 from = X_CONFIG;
29851 if (enable)
29852 - sna->flags |= SNA_TEAR_FREE;
29853 + sna->flags |= SNA_WANT_TEAR_FREE | SNA_TEAR_FREE;
29855 done:
29856 xf86DrvMsg(sna->scrn->scrnIndex, from, "TearFree %sabled\n",
29857 sna->flags & SNA_TEAR_FREE ? "en" : "dis");
29858 + return sna->flags & SNA_TEAR_FREE;
29861 /**
29862 @@ -612,8 +584,10 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int probe)
29865 intel_detect_chipset(scrn, sna->dev);
29866 - xf86DrvMsg(scrn->scrnIndex, X_PROBED, "CPU: %s\n",
29867 - sna_cpu_features_to_string(sna->cpu_features, buf));
29868 + xf86DrvMsg(scrn->scrnIndex, X_PROBED,
29869 + "CPU: %s; using a maximum of %d threads\n",
29870 + sna_cpu_features_to_string(sna->cpu_features, buf),
29871 + sna_use_threads(64*1024, 64*1024, 1));
29873 if (!xf86SetDepthBpp(scrn, 24, 0, 0,
29874 Support32bppFb |
29875 @@ -651,18 +625,11 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int probe)
29876 kgem_init(&sna->kgem, fd,
29877 xf86GetPciInfoForEntity(pEnt->index),
29878 sna->info->gen);
29879 - if (xf86ReturnOptValBool(sna->Options, OPTION_ACCEL_DISABLE, FALSE) ||
29880 - !sna_option_cast_to_bool(sna, OPTION_ACCEL_METHOD, TRUE)) {
29881 - xf86DrvMsg(sna->scrn->scrnIndex, X_CONFIG,
29882 - "Disabling hardware acceleration.\n");
29883 - sna->kgem.wedged = true;
29884 - }
29886 if (xf86ReturnOptValBool(sna->Options, OPTION_TILING_FB, FALSE))
29887 sna->flags |= SNA_LINEAR_FB;
29889 - if (xf86ReturnOptValBool(sna->Options, OPTION_DELETE_DP12, FALSE))
29890 - sna->flags |= SNA_REMOVE_OUTPUTS;
29891 + if (!sna->kgem.can_fence)
29892 + sna->flags |= SNA_LINEAR_FB;
29894 if (!xf86ReturnOptValBool(sna->Options, OPTION_SWAPBUFFERS_WAIT, TRUE))
29895 sna->flags |= SNA_NO_WAIT;
29896 @@ -695,7 +662,8 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int probe)
29898 scrn->currentMode = scrn->modes;
29900 - setup_tear_free(sna);
29901 + if (!setup_tear_free(sna) && sna_mode_wants_tear_free(sna))
29902 + sna->kgem.needs_dirtyfb = sna->kgem.has_dirtyfb;
29904 xf86SetGamma(scrn, zeros);
29905 xf86SetDpi(scrn, 0, 0);
29906 @@ -721,11 +689,13 @@ cleanup:
29907 return FALSE;
29910 +#if !HAVE_NOTIFY_FD
29911 static bool has_shadow(struct sna *sna)
29913 - if (!sna->mode.shadow_damage)
29914 + if (!sna->mode.shadow_enabled)
29915 return false;
29917 + assert(sna->mode.shadow_damage);
29918 if (RegionNil(DamageRegion(sna->mode.shadow_damage)))
29919 return false;
29921 @@ -748,7 +718,7 @@ sna_block_handler(BLOCKHANDLER_ARGS_DECL)
29922 sna->BlockHandler(BLOCKHANDLER_ARGS);
29924 if (*tv == NULL || ((*tv)->tv_usec | (*tv)->tv_sec) || has_shadow(sna))
29925 - sna_accel_block_handler(sna, tv);
29926 + sna_accel_block(sna, tv);
29929 static void
29930 @@ -770,52 +740,102 @@ sna_wakeup_handler(WAKEUPHANDLER_ARGS_DECL)
29932 sna->WakeupHandler(WAKEUPHANDLER_ARGS);
29934 - sna_accel_wakeup_handler(sna);
29936 if (FD_ISSET(sna->kgem.fd, (fd_set*)read_mask)) {
29937 sna_mode_wakeup(sna);
29938 /* Clear the flag so that subsequent ZaphodHeads don't block */
29939 FD_CLR(sna->kgem.fd, (fd_set*)read_mask);
29942 +#else
29943 +static void
29944 +sna_block_handler(void *data, void *_timeout)
29945 +{
29946 + struct sna *sna = data;
29947 + int *timeout = _timeout;
29948 + struct timeval tv, *tvp;
29950 + DBG(("%s (timeout=%d)\n", __FUNCTION__, *timeout));
29951 + if (*timeout == 0)
29952 + return;
29954 + if (*timeout < 0) {
29955 + tvp = NULL;
29956 + } else {
29957 + tv.tv_sec = *timeout / 1000;
29958 + tv.tv_usec = (*timeout % 1000) * 1000;
29959 + tvp = &tv;
29960 + }
29962 + sna_accel_block(sna, &tvp);
29963 + if (tvp)
29964 + *timeout = tvp->tv_sec * 1000 + tvp->tv_usec / 1000;
29965 +}
29966 +#endif
29968 #if HAVE_UDEV
29969 +#include <sys/stat.h>
29971 static void
29972 sna_handle_uevents(int fd, void *closure)
29974 struct sna *sna = closure;
29975 - struct udev_device *dev;
29976 - const char *str;
29977 struct stat s;
29978 - dev_t udev_devnum;
29979 + struct pollfd pfd;
29980 + bool hotplug = false;
29982 DBG(("%s\n", __FUNCTION__));
29984 - dev = udev_monitor_receive_device(sna->uevent_monitor);
29985 - if (!dev)
29986 - return;
29987 + pfd.fd = udev_monitor_get_fd(sna->uevent_monitor);
29988 + pfd.events = POLLIN;
29990 + if (fstat(sna->kgem.fd, &s))
29991 + memset(&s, 0, sizeof(s));
29993 + while (poll(&pfd, 1, 0) > 0) {
29994 + struct udev_device *dev;
29995 + dev_t devnum;
29997 + dev = udev_monitor_receive_device(sna->uevent_monitor);
29998 + if (dev == NULL)
29999 + break;
30001 + devnum = udev_device_get_devnum(dev);
30002 + if (memcmp(&s.st_rdev, &devnum, sizeof(dev_t)) == 0) {
30003 + const char *str;
30005 + str = udev_device_get_property_value(dev, "HOTPLUG");
30006 + if (str && atoi(str) == 1) {
30007 + str = udev_device_get_property_value(dev, "CONNECTOR");
30008 + if (str) {
30009 + hotplug |= sna_mode_find_hotplug_connector(sna, atoi(str));
30010 + } else {
30011 + sna->flags |= SNA_REPROBE;
30012 + hotplug = true;
30013 + }
30014 + }
30015 + }
30017 - udev_devnum = udev_device_get_devnum(dev);
30018 - if (fstat(sna->kgem.fd, &s) || memcmp(&s.st_rdev, &udev_devnum, sizeof (dev_t))) {
30019 udev_device_unref(dev);
30020 - return;
30023 - str = udev_device_get_property_value(dev, "HOTPLUG");
30024 - if (str && atoi(str) == 1) {
30025 - ScrnInfoPtr scrn = sna->scrn;
30027 - DBG(("%s: hotplug event (vtSema?=%d)\n", __FUNCTION__, scrn->vtSema));
30028 + if (hotplug) {
30029 + DBG(("%s: hotplug event (vtSema?=%d)\n",
30030 + __FUNCTION__, sna->scrn->vtSema));
30032 - if (scrn->vtSema) {
30033 - sna_mode_discover(sna);
30034 - sna_mode_check(sna);
30035 - RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
30036 - } else
30037 + if (sna->scrn->vtSema)
30038 + sna_mode_discover(sna, true);
30039 + else
30040 sna->flags |= SNA_REPROBE;
30042 +}
30044 - udev_device_unref(dev);
30045 +static bool has_randr(void)
30046 +{
30047 +#if HAS_DIXREGISTERPRIVATEKEY
30048 + return dixPrivateKeyRegistered(rrPrivKey);
30049 +#else
30050 + return *rrPrivKey;
30051 +#endif
30054 static void
30055 @@ -833,7 +853,7 @@ sna_uevent_init(struct sna *sna)
30056 /* RandR will be disabled if Xinerama is active, and so generating
30057 * RR hotplug events is then verboten.
30058 */
30059 - if (!dixPrivateKeyRegistered(rrPrivKey))
30060 + if (!has_randr())
30061 goto out;
30063 u = NULL;
30064 @@ -861,7 +881,8 @@ sna_uevent_init(struct sna *sna)
30066 sna->uevent_monitor = mon;
30067 out:
30068 - xf86DrvMsg(sna->scrn->scrnIndex, from, "display hotplug detection %s\n",
30069 + xf86DrvMsg(sna->scrn->scrnIndex, from,
30070 + "Display hotplug detection %s\n",
30071 sna->uevent_monitor ? "enabled" : "disabled");
30072 return;
30074 @@ -874,17 +895,10 @@ err_dev:
30076 static bool sna_uevent_poll(struct sna *sna)
30078 - struct pollfd pfd;
30080 if (sna->uevent_monitor == NULL)
30081 return false;
30083 - pfd.fd = udev_monitor_get_fd(sna->uevent_monitor);
30084 - pfd.events = POLLIN;
30086 - while (poll(&pfd, 1, 0) > 0)
30087 - sna_handle_uevents(pfd.fd, sna);
30089 + sna_handle_uevents(udev_monitor_get_fd(sna->uevent_monitor), sna);
30090 return true;
30093 @@ -918,8 +932,10 @@ sna_randr_getinfo(ScreenPtr screen, Rotation *rotations)
30095 struct sna *sna = to_sna_from_screen(screen);
30097 + DBG(("%s()\n", __FUNCTION__));
30099 if (!sna_uevent_poll(sna))
30100 - sna_mode_discover(sna);
30101 + sna_mode_discover(sna, false);
30103 return sna->mode.rrGetInfo(screen, rotations);
30105 @@ -931,8 +947,8 @@ static void sna_leave_vt(VT_FUNC_ARGS_DECL)
30107 DBG(("%s\n", __FUNCTION__));
30109 - sna_accel_leave(sna);
30110 sna_mode_reset(sna);
30111 + sna_accel_leave(sna);
30113 if (intel_put_master(sna->dev))
30114 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
30115 @@ -948,6 +964,12 @@ static Bool sna_early_close_screen(CLOSE_SCREEN_ARGS_DECL)
30117 /* XXX Note that we will leak kernel resources if !vtSema */
30119 +#if HAVE_NOTIFY_FD
30120 + RemoveBlockAndWakeupHandlers(sna_block_handler,
30121 + (ServerWakeupHandlerProcPtr)NoopDDA,
30122 + sna);
30123 +#endif
30125 sna_uevent_fini(sna);
30126 sna_mode_close(sna);
30128 @@ -1047,12 +1069,13 @@ static void sna_dri_init(struct sna *sna, ScreenPtr screen)
30130 char str[128] = "";
30132 - if (sna->dri2.available)
30133 + if (sna->dri2.enable)
30134 sna->dri2.open = sna_dri2_open(sna, screen);
30135 if (sna->dri2.open)
30136 strcat(str, "DRI2 ");
30138 - if (sna->dri3.available)
30139 + /* Load DRI3 in case DRI2 doesn't work, e.g. vgaarb */
30140 + if (sna->dri3.enable || (!sna->dri2.open && !sna->dri3.override))
30141 sna->dri3.open = sna_dri3_open(sna, screen);
30142 if (sna->dri3.open)
30143 strcat(str, "DRI3 ");
30144 @@ -1098,7 +1121,8 @@ sna_screen_init(SCREEN_INIT_ARGS_DECL)
30145 DBG(("%s\n", __FUNCTION__));
30147 assert(sna->scrn == scrn);
30148 - assert(scrn->pScreen == NULL); /* set afterwards */
30149 + assert(to_screen_from_sna(sna) == NULL || /* set afterwards */
30150 + to_screen_from_sna(sna) == screen);
30152 assert(sna->freed_pixmap == NULL);
30154 @@ -1166,11 +1190,17 @@ sna_screen_init(SCREEN_INIT_ARGS_DECL)
30155 * later memory should be bound when allocating, e.g rotate_mem */
30156 scrn->vtSema = TRUE;
30158 +#if !HAVE_NOTIFY_FD
30159 sna->BlockHandler = screen->BlockHandler;
30160 screen->BlockHandler = sna_block_handler;
30162 sna->WakeupHandler = screen->WakeupHandler;
30163 screen->WakeupHandler = sna_wakeup_handler;
30164 +#else
30165 + RegisterBlockAndWakeupHandlers(sna_block_handler,
30166 + (ServerWakeupHandlerProcPtr)NoopDDA,
30167 + sna);
30168 +#endif
30170 screen->SaveScreen = sna_save_screen;
30171 screen->CreateScreenResources = sna_create_screen_resources;
30172 @@ -1190,6 +1220,8 @@ sna_screen_init(SCREEN_INIT_ARGS_DECL)
30173 CMAP_PALETTED_TRUECOLOR))
30174 return FALSE;
30176 + if (!xf86CheckBoolOption(scrn->options, "dpms", TRUE))
30177 + sna->flags |= SNA_NO_DPMS;
30178 xf86DPMSInit(screen, sna_dpms_set, 0);
30180 sna_uevent_init(sna);
30181 @@ -1244,20 +1276,15 @@ static Bool sna_enter_vt(VT_FUNC_ARGS_DECL)
30182 if (intel_get_master(sna->dev))
30183 return FALSE;
30185 + sna_accel_enter(sna);
30187 if (sna->flags & SNA_REPROBE) {
30188 - DBG(("%s: reporting deferred hotplug event\n",
30189 - __FUNCTION__));
30190 - sna_mode_discover(sna);
30191 - RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
30192 - sna->flags &= ~SNA_REPROBE;
30193 + DBG(("%s: reporting deferred hotplug event\n", __FUNCTION__));
30194 + sna_mode_discover(sna, true);
30197 - if (!sna_set_desired_mode(sna)) {
30198 - intel_put_master(sna->dev);
30199 - return FALSE;
30200 - }
30201 + sna_set_desired_mode(sna);
30203 - sna_accel_enter(sna);
30204 return TRUE;
30207 @@ -1379,6 +1406,9 @@ static void describe_sna(ScrnInfoPtr scrn)
30208 xf86DrvMsg(scrn->scrnIndex, X_INFO,
30209 "SNA compiled: %s\n", BUILDER_DESCRIPTION);
30210 #endif
30211 +#if HAS_DEBUG_FULL
30212 + ErrorF("SNA compiled with full debug logging; expect to run slowly\n");
30213 +#endif
30214 #if !NDEBUG
30215 xf86DrvMsg(scrn->scrnIndex, X_INFO,
30216 "SNA compiled with assertions enabled\n");
30217 @@ -1400,6 +1430,7 @@ static void describe_sna(ScrnInfoPtr scrn)
30218 "SNA compiled for use with valgrind\n");
30219 VALGRIND_PRINTF("SNA compiled for use with valgrind\n");
30220 #endif
30221 + DBG(("xf86-video-intel version: %s\n", git_version));
30222 DBG(("pixman version: %s\n", pixman_version_string()));
30225 diff --git a/src/sna/sna_glyphs.c b/src/sna/sna_glyphs.c
30226 index a5dfb06b..6ee40336 100644
30227 --- a/src/sna/sna_glyphs.c
30228 +++ b/src/sna/sna_glyphs.c
30229 @@ -74,7 +74,7 @@
30230 #define NO_GLYPHS_VIA_MASK 0
30231 #define FORCE_SMALL_MASK 0 /* -1 = never, 1 = always */
30232 #define NO_GLYPHS_SLOW 0
30233 -#define NO_DISCARD_MASK 0
30234 +#define DISCARD_MASK 0 /* -1 = never, 1 = always */
30236 #define CACHE_PICTURE_SIZE 1024
30237 #define GLYPH_MIN_SIZE 8
30238 @@ -185,7 +185,7 @@ void sna_glyphs_close(struct sna *sna)
30239 */
30240 bool sna_glyphs_create(struct sna *sna)
30242 - ScreenPtr screen = sna->scrn->pScreen;
30243 + ScreenPtr screen = to_screen_from_sna(sna);
30244 pixman_color_t white = { 0xffff, 0xffff, 0xffff, 0xffff };
30245 unsigned int formats[] = {
30246 PIXMAN_a8,
30247 @@ -1094,6 +1094,9 @@ sna_glyph_get_image(GlyphPtr g, ScreenPtr s)
30249 static inline bool use_small_mask(struct sna *sna, int16_t width, int16_t height, int depth)
30251 + if (depth < 8)
30252 + return true;
30254 if (FORCE_SMALL_MASK)
30255 return FORCE_SMALL_MASK > 0;
30257 @@ -1156,12 +1159,6 @@ glyphs_via_mask(struct sna *sna,
30258 src_x += box.x1 - list->xOff;
30259 src_y += box.y1 - list->yOff;
30261 - if (format->depth < 8) {
30262 - format = PictureMatchFormat(screen, 8, PICT_a8);
30263 - if (!format)
30264 - return false;
30265 - }
30267 component_alpha = NeedsComponent(format->format);
30268 if (use_small_mask(sna, width, height, format->depth)) {
30269 pixman_image_t *mask_image;
30270 @@ -1179,7 +1176,7 @@ use_small_mask:
30271 return false;
30273 mask_image =
30274 - pixman_image_create_bits(format->depth << 24 | format->format,
30275 + pixman_image_create_bits(pixmap->drawable.bitsPerPixel << 24 | format->format,
30276 width, height,
30277 pixmap->devPrivate.ptr,
30278 pixmap->devKind);
30279 @@ -1386,10 +1383,11 @@ next_image:
30280 DBG(("%s: atlas format=%08x, mask format=%08x\n",
30281 __FUNCTION__,
30282 (int)p->atlas->format,
30283 - (int)(format->depth << 24 | format->format)));
30284 + (int)mask->format));
30286 memset(&tmp, 0, sizeof(tmp));
30287 - if (p->atlas->format == (format->depth << 24 | format->format)) {
30288 + if (p->atlas->format == mask->format ||
30289 + alphaless(p->atlas->format) == mask->format) {
30290 ok = sna->render.composite(sna, PictOpAdd,
30291 p->atlas, NULL, mask,
30292 0, 0, 0, 0, 0, 0,
30293 @@ -1561,6 +1559,9 @@ skip_glyph:
30297 + assert(format);
30298 + DBG(("%s: format=%08d, depth=%d\n",
30299 + __FUNCTION__, format->format, format->depth));
30300 out:
30301 if (list_extents != stack_extents)
30302 free(list_extents);
30303 @@ -1573,24 +1574,34 @@ static bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask,
30304 PictFormatPtr g;
30305 uint32_t color;
30307 - if (NO_DISCARD_MASK)
30308 - return false;
30309 + if (DISCARD_MASK)
30310 + return DISCARD_MASK > 0;
30312 DBG(("%s: nlist=%d, mask=%08x, depth %d, op=%d (bounded? %d)\n",
30313 __FUNCTION__, nlist,
30314 mask ? (unsigned)mask->format : 0, mask ? mask->depth : 0,
30315 op, op_is_bounded(op)));
30317 - if (nlist == 1 && list->len == 1)
30318 - return true;
30319 + if (nlist == 1 && list->len == 1) {
30320 + if (mask == list->format)
30321 + return true;
30323 + g = list->format;
30324 + goto skip;
30325 + }
30327 - if (!op_is_bounded(op))
30328 + if (!op_is_bounded(op)) {
30329 + DBG(("%s: unbounded op, not discarding\n", __FUNCTION__));
30330 return false;
30331 + }
30333 /* No glyphs overlap and we are not performing a mask conversion. */
30334 g = glyphs_format(nlist, list, glyphs);
30335 - if (mask == g)
30336 + if (mask == g) {
30337 + DBG(("%s: mask matches glyphs format, no conversion, so discard mask\n",
30338 + __FUNCTION__));
30339 return true;
30340 + }
30342 DBG(("%s: preferred mask format %08x, depth %d\n",
30343 __FUNCTION__, g ? (unsigned)g->format : 0, g ? g->depth : 0));
30344 @@ -1605,18 +1616,41 @@ static bool can_discard_mask(uint8_t op, PicturePtr src, PictFormatPtr mask,
30346 list++;
30349 + if (!sna_picture_is_solid(src, &color))
30350 + return false;
30352 + return color >> 24 == 0xff;
30353 } else {
30354 - if (PICT_FORMAT_A(mask->format) >= PICT_FORMAT_A(g->format))
30355 +skip:
30356 + if (mask->format == g->format)
30357 return true;
30359 - if (g->depth != 1)
30360 - return false;
30361 - }
30362 + if (mask->format == alphaless(g->format))
30363 + return true;
30365 + if (PICT_FORMAT_TYPE(g->format) == PICT_TYPE_A &&
30366 + PICT_FORMAT_TYPE(mask->format) != PICT_TYPE_A)
30367 + return true;
30369 - if (!sna_picture_is_solid(src, &color))
30370 return false;
30371 + }
30372 +}
30374 - return color >> 24 == 0xff;
30375 +static uint32_t pixman_format(PictFormatPtr short_format)
30376 +{
30377 + uint32_t bpp;
30379 + bpp = short_format->depth;
30380 + if (bpp <= 1)
30381 + bpp = 1;
30382 + else if (bpp <= 8)
30383 + bpp = 8;
30384 + else if (bpp <= 16)
30385 + bpp = 16;
30386 + else
30387 + bpp = 32;
30388 + return bpp << 24 | short_format->format;
30391 static void
30392 @@ -1756,7 +1790,7 @@ next:
30393 if (sigtrap_get() == 0) {
30394 if (mask_format) {
30395 pixman_composite_glyphs(op, src_image, dst_image,
30396 - mask_format->format | (mask_format->depth << 24),
30397 + pixman_format(mask_format),
30398 src_x + src_dx + region.extents.x1 - dst_x,
30399 src_y + src_dy + region.extents.y1 - dst_y,
30400 region.extents.x1, region.extents.y1,
30401 @@ -1815,10 +1849,10 @@ out:
30402 x, y,
30403 mask_format->depth,
30404 (long)mask_format->format,
30405 - (long)(mask_format->depth << 24 | mask_format->format),
30406 + (long)pixman_format(mask_format),
30407 NeedsComponent(mask_format->format)));
30408 mask_image =
30409 - pixman_image_create_bits(mask_format->depth << 24 | mask_format->format,
30410 + pixman_image_create_bits(pixman_format(mask_format),
30411 region.extents.x2 - region.extents.x1,
30412 region.extents.y2 - region.extents.y1,
30413 NULL, 0);
30414 @@ -2086,12 +2120,6 @@ glyphs_via_image(struct sna *sna,
30415 src_x += box.x1 - list->xOff;
30416 src_y += box.y1 - list->yOff;
30418 - if (format->depth < 8) {
30419 - format = PictureMatchFormat(screen, 8, PICT_a8);
30420 - if (!format)
30421 - return false;
30422 - }
30424 DBG(("%s: small mask [format=%lx, depth=%d, size=%d], rendering glyphs to upload buffer\n",
30425 __FUNCTION__, (unsigned long)format->format,
30426 format->depth, (uint32_t)width*height*format->depth));
30427 @@ -2104,7 +2132,7 @@ glyphs_via_image(struct sna *sna,
30428 return false;
30430 mask_image =
30431 - pixman_image_create_bits(format->depth << 24 | format->format,
30432 + pixman_image_create_bits(pixmap->drawable.bitsPerPixel << 24 | format->format,
30433 width, height,
30434 pixmap->devPrivate.ptr,
30435 pixmap->devKind);
30436 diff --git a/src/sna/sna_io.c b/src/sna/sna_io.c
30437 index d6aa1294..d32bd583 100644
30438 --- a/src/sna/sna_io.c
30439 +++ b/src/sna/sna_io.c
30440 @@ -105,8 +105,10 @@ read_boxes_inplace__cpu(struct kgem *kgem,
30441 if (!download_inplace__cpu(kgem, dst, bo, box, n))
30442 return false;
30444 + if (bo->tiling == I915_TILING_Y)
30445 + return false;
30447 assert(kgem_bo_can_map__cpu(kgem, bo, false));
30448 - assert(bo->tiling != I915_TILING_Y);
30450 src = kgem_bo_map__cpu(kgem, bo);
30451 if (src == NULL)
30452 @@ -281,6 +283,9 @@ fallback:
30453 if (box[n].y2 > extents.y2)
30454 extents.y2 = box[n].y2;
30456 + if (!can_blt && sna->render.max_3d_size == 0)
30457 + goto fallback;
30459 if (kgem_bo_can_map(kgem, src_bo)) {
30460 /* Is it worth detiling? */
30461 if ((extents.y2 - extents.y1 - 1) * src_bo->pitch < 4096)
30462 @@ -477,6 +482,7 @@ fallback:
30463 goto fallback;
30464 _kgem_set_mode(kgem, KGEM_BLT);
30466 + kgem_bcs_set_tiling(&sna->kgem, src_bo, NULL);
30468 tmp_nbox = nbox;
30469 tmp_box = box;
30470 @@ -539,6 +545,7 @@ fallback:
30471 break;
30473 _kgem_set_mode(kgem, KGEM_BLT);
30474 + kgem_bcs_set_tiling(&sna->kgem, src_bo, NULL);
30475 tmp_box += nbox_this_time;
30476 } while (1);
30477 } else {
30478 @@ -597,6 +604,7 @@ fallback:
30479 break;
30481 _kgem_set_mode(kgem, KGEM_BLT);
30482 + kgem_bcs_set_tiling(&sna->kgem, src_bo, NULL);
30483 tmp_box += nbox_this_time;
30484 } while (1);
30486 @@ -666,8 +674,10 @@ write_boxes_inplace__tiled(struct kgem *kgem,
30488 uint8_t *dst;
30490 + if (bo->tiling == I915_TILING_Y)
30491 + return false;
30493 assert(kgem->has_wc_mmap || kgem_bo_can_map__cpu(kgem, bo, true));
30494 - assert(bo->tiling != I915_TILING_Y);
30496 if (kgem_bo_can_map__cpu(kgem, bo, true)) {
30497 dst = kgem_bo_map__cpu(kgem, bo);
30498 @@ -778,6 +788,15 @@ static bool __upload_inplace(struct kgem *kgem,
30499 if (FORCE_INPLACE)
30500 return FORCE_INPLACE > 0;
30502 + if (bo->exec)
30503 + return false;
30505 + if (bo->flush)
30506 + return true;
30508 + if (kgem_bo_can_map__cpu(kgem, bo, true))
30509 + return true;
30511 /* If we are writing through the GTT, check first if we might be
30512 * able to almagamate a series of small writes into a single
30513 * operation.
30514 @@ -849,6 +868,8 @@ bool sna_write_boxes(struct sna *sna, PixmapPtr dst,
30515 if (box[n].y2 > extents.y2)
30516 extents.y2 = box[n].y2;
30518 + if (!can_blt && sna->render.max_3d_size == 0)
30519 + goto fallback;
30521 /* Try to avoid switching rings... */
30522 if (!can_blt || kgem->ring == KGEM_RENDER ||
30523 @@ -1038,6 +1059,7 @@ tile:
30524 goto fallback;
30525 _kgem_set_mode(kgem, KGEM_BLT);
30527 + kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
30529 if (kgem->gen >= 0100) {
30530 cmd |= 8;
30531 @@ -1129,6 +1151,7 @@ tile:
30532 if (nbox) {
30533 _kgem_submit(kgem);
30534 _kgem_set_mode(kgem, KGEM_BLT);
30535 + kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
30538 kgem_bo_destroy(kgem, src_bo);
30539 @@ -1224,6 +1247,7 @@ tile:
30540 if (nbox) {
30541 _kgem_submit(kgem);
30542 _kgem_set_mode(kgem, KGEM_BLT);
30543 + kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
30546 kgem_bo_destroy(kgem, src_bo);
30547 @@ -1541,6 +1565,7 @@ tile:
30548 goto fallback;
30549 _kgem_set_mode(kgem, KGEM_BLT);
30551 + kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
30553 if (sna->kgem.gen >= 0100) {
30554 cmd |= 8;
30555 @@ -1636,6 +1661,7 @@ tile:
30556 if (nbox) {
30557 _kgem_submit(kgem);
30558 _kgem_set_mode(kgem, KGEM_BLT);
30559 + kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
30562 kgem_bo_destroy(kgem, src_bo);
30563 @@ -1732,6 +1758,7 @@ tile:
30564 if (nbox) {
30565 _kgem_submit(kgem);
30566 _kgem_set_mode(kgem, KGEM_BLT);
30567 + kgem_bcs_set_tiling(&sna->kgem, NULL, dst_bo);
30570 kgem_bo_destroy(kgem, src_bo);
30571 diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c
30572 index 6dd6fe88..2796d972 100644
30573 --- a/src/sna/sna_present.c
30574 +++ b/src/sna/sna_present.c
30575 @@ -27,6 +27,7 @@
30576 #include <sys/types.h>
30577 #include <fcntl.h>
30578 #include <unistd.h>
30579 +#include <sys/poll.h>
30580 #include <errno.h>
30581 #include <xf86drm.h>
30583 @@ -38,21 +39,73 @@
30584 static present_screen_info_rec present_info;
30586 struct sna_present_event {
30587 - uint64_t event_id;
30588 xf86CrtcPtr crtc;
30589 + struct sna *sna;
30590 + struct list link;
30591 + uint64_t *event_id;
30592 + uint64_t target_msc;
30593 + int n_event_id;
30594 + bool queued;
30595 };
30597 +static void sna_present_unflip(ScreenPtr screen, uint64_t event_id);
30598 +static bool sna_present_queue(struct sna_present_event *info,
30599 + uint64_t last_msc);
30601 static inline struct sna_present_event *
30602 to_present_event(uintptr_t data)
30604 return (struct sna_present_event *)(data & ~3);
30607 +static struct sna_present_event *info_alloc(struct sna *sna)
30608 +{
30609 + struct sna_present_event *info;
30611 + info = sna->present.freed_info;
30612 + if (info) {
30613 + sna->present.freed_info = NULL;
30614 + return info;
30615 + }
30617 + return malloc(sizeof(struct sna_present_event) + sizeof(uint64_t));
30618 +}
30620 +static void info_free(struct sna_present_event *info)
30621 +{
30622 + struct sna *sna = info->sna;
30624 + if (sna->present.freed_info)
30625 + free(sna->present.freed_info);
30627 + sna->present.freed_info = info;
30628 +}
30630 +static inline bool msc_before(uint64_t msc, uint64_t target)
30631 +{
30632 + return (int64_t)(msc - target) < 0;
30633 +}
30635 #define MARK_PRESENT(x) ((void *)((uintptr_t)(x) | 2))
30637 -static int pipe_from_crtc(RRCrtcPtr crtc)
30638 +static inline xf86CrtcPtr unmask_crtc(xf86CrtcPtr crtc)
30639 +{
30640 + return (xf86CrtcPtr)((uintptr_t)crtc & ~1);
30641 +}
30643 +static inline xf86CrtcPtr mark_crtc(xf86CrtcPtr crtc)
30644 +{
30645 + return (xf86CrtcPtr)((uintptr_t)crtc | 1);
30646 +}
30648 +static inline bool has_vblank(xf86CrtcPtr crtc)
30649 +{
30650 + return (uintptr_t)crtc & 1;
30651 +}
30653 +static inline int pipe_from_crtc(RRCrtcPtr crtc)
30655 - return crtc ? sna_crtc_to_pipe(crtc->devPrivate) : -1;
30656 + return crtc ? sna_crtc_pipe(crtc->devPrivate) : -1;
30659 static uint32_t pipe_select(int pipe)
30660 @@ -74,6 +127,215 @@ static inline int sna_wait_vblank(struct sna *sna, union drm_wait_vblank *vbl, i
30661 return drmIoctl(sna->kgem.fd, DRM_IOCTL_WAIT_VBLANK, vbl);
30664 +static uint64_t gettime_ust64(void)
30665 +{
30666 + struct timespec tv;
30668 + if (clock_gettime(CLOCK_MONOTONIC, &tv))
30669 + return GetTimeInMicros();
30671 + return ust64(tv.tv_sec, tv.tv_nsec / 1000);
30672 +}
30674 +static void vblank_complete(struct sna_present_event *info,
30675 + uint64_t ust, uint64_t msc)
30676 +{
30677 + int n;
30679 + if (msc_before(msc, info->target_msc)) {
30680 + DBG(("%s: event=%d too early, now %lld, expected %lld\n",
30681 + __FUNCTION__,
30682 + info->event_id[0],
30683 + (long long)msc, (long long)info->target_msc));
30684 + if (sna_present_queue(info, msc))
30685 + return;
30686 + }
30688 + DBG(("%s: %d events complete\n", __FUNCTION__, info->n_event_id));
30689 + for (n = 0; n < info->n_event_id; n++) {
30690 + DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event=%lld complete%s\n", __FUNCTION__,
30691 + sna_crtc_pipe(info->crtc),
30692 + (int)(ust / 1000000), (int)(ust % 1000000),
30693 + (long long)msc, (long long)info->target_msc,
30694 + (long long)info->event_id[n],
30695 + info->target_msc && msc == (uint32_t)info->target_msc ? "" : ": MISS"));
30696 + present_event_notify(info->event_id[n], ust, msc);
30697 + }
30698 + if (info->n_event_id > 1)
30699 + free(info->event_id);
30700 + list_del(&info->link);
30701 + info_free(info);
30702 +}
30704 +static uint32_t msc_to_delay(xf86CrtcPtr crtc, uint64_t target)
30705 +{
30706 + const DisplayModeRec *mode = &crtc->desiredMode;
30707 + const struct ust_msc *swap = sna_crtc_last_swap(crtc);
30708 + int64_t delay, subframe;
30710 + assert(mode->Clock);
30712 + delay = target - swap->msc;
30713 + assert(delay >= 0);
30714 + if (delay > 1) { /* try to use the hw vblank for the last frame */
30715 + delay--;
30716 + subframe = 0;
30717 + } else {
30718 + subframe = gettime_ust64() - swap_ust(swap);
30719 + subframe += 500;
30720 + subframe /= 1000;
30721 + }
30722 + delay *= mode->VTotal * mode->HTotal / mode->Clock;
30723 + if (subframe < delay)
30724 + delay -= subframe;
30725 + else
30726 + delay = 0;
30728 + DBG(("%s: sleep %d frames, %llu ms\n", __FUNCTION__,
30729 + (int)(target - swap->msc), (long long)delay));
30730 + assert(delay >= 0);
30731 + return MIN(delay, INT32_MAX);
30732 +}
30734 +static CARD32 sna_fake_vblank_handler(OsTimerPtr timer, CARD32 now, void *data)
30735 +{
30736 + struct sna_present_event *info = data;
30737 + union drm_wait_vblank vbl;
30738 + uint64_t msc, ust;
30740 + DBG(("%s(event=%lldx%d, now=%d)\n", __FUNCTION__, (long long)info->event_id[0], info->n_event_id, now));
30742 + VG_CLEAR(vbl);
30743 + vbl.request.type = DRM_VBLANK_RELATIVE;
30744 + vbl.request.sequence = 0;
30745 + if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)) == 0) {
30746 + ust = ust64(vbl.reply.tval_sec, vbl.reply.tval_usec);
30747 + msc = sna_crtc_record_vblank(info->crtc, &vbl);
30748 + DBG(("%s: event=%lld, target msc=%lld, now %lld\n",
30749 + __FUNCTION__, (long long)info->event_id[0], (long long)info->target_msc, (long long)msc));
30750 + if (msc_before(msc, info->target_msc)) {
30751 + int delta = info->target_msc - msc;
30752 + uint32_t delay;
30754 + DBG(("%s: too early, requeuing delta=%d\n", __FUNCTION__, delta));
30755 + assert(info->target_msc - msc < 1ull<<31);
30756 + if (delta <= 2) {
30757 + vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
30758 + vbl.request.sequence = info->target_msc;
30759 + vbl.request.signal = (uintptr_t)MARK_PRESENT(info);
30760 + if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)) == 0) {
30761 + DBG(("%s: scheduled new vblank event for %lld\n", __FUNCTION__, (long long)info->target_msc));
30762 + info->queued = true;
30763 + if (delta == 1) {
30764 + sna_crtc_set_vblank(info->crtc);
30765 + info->crtc = mark_crtc(info->crtc);
30766 + }
30767 + free(timer);
30768 + return 0;
30769 + }
30770 + }
30772 + delay = msc_to_delay(info->crtc, info->target_msc);
30773 + if (delay) {
30774 + DBG(("%s: requeueing timer for %dms delay\n", __FUNCTION__, delay));
30775 + return delay;
30776 + }
30778 + /* As a last resort use a blocking wait.
30779 + * Less than a millisecond for (hopefully) a rare case.
30780 + */
30781 + DBG(("%s: blocking wait!\n", __FUNCTION__));
30782 + vbl.request.type = DRM_VBLANK_ABSOLUTE;
30783 + vbl.request.sequence = info->target_msc;
30784 + if (sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc)) == 0) {
30785 + ust = ust64(vbl.reply.tval_sec, vbl.reply.tval_usec);
30786 + msc = sna_crtc_record_vblank(info->crtc, &vbl);
30787 + } else {
30788 + DBG(("%s: blocking wait failed, fudging\n",
30789 + __FUNCTION__));
30790 + goto fixup;
30791 + }
30792 + }
30793 + } else {
30794 +fixup:
30795 + ust = gettime_ust64();
30796 + msc = info->target_msc;
30797 + DBG(("%s: event=%lld, CRTC OFF, target msc=%lld, was %lld (off)\n",
30798 + __FUNCTION__, (long long)info->event_id[0], (long long)info->target_msc, (long long)sna_crtc_last_swap(info->crtc)->msc));
30799 + }
30801 + vblank_complete(info, ust, msc);
30802 + free(timer);
30803 + return 0;
30804 +}
30806 +static bool sna_fake_vblank(struct sna_present_event *info)
30807 +{
30808 + const struct ust_msc *swap = sna_crtc_last_swap(info->crtc);
30809 + uint32_t delay;
30811 + if (msc_before(swap->msc, info->target_msc))
30812 + delay = msc_to_delay(info->crtc, info->target_msc);
30813 + else
30814 + delay = 0;
30816 + DBG(("%s(event=%lldx%d, target_msc=%lld, msc=%lld, delay=%ums)\n",
30817 + __FUNCTION__, (long long)info->event_id[0], info->n_event_id,
30818 + (long long)info->target_msc, (long long)swap->msc, delay));
30819 + if (delay == 0) {
30820 + uint64_t ust, msc;
30822 + if (msc_before(swap->msc, info->target_msc)) {
30823 + /* Fixup and pretend it completed immediately */
30824 + msc = info->target_msc;
30825 + ust = gettime_ust64();
30826 + } else {
30827 + msc = swap->msc;
30828 + ust = swap_ust(swap);
30829 + }
30831 + vblank_complete(info, ust, msc);
30832 + return true;
30833 + }
30835 + return TimerSet(NULL, 0, delay, sna_fake_vblank_handler, info);
30836 +}
30838 +static bool sna_present_queue(struct sna_present_event *info,
30839 + uint64_t last_msc)
30840 +{
30841 + union drm_wait_vblank vbl;
30842 + int delta = info->target_msc - last_msc;
30844 + DBG(("%s: target msc=%llu, seq=%u (last_msc=%llu), delta=%d\n",
30845 + __FUNCTION__,
30846 + (long long)info->target_msc,
30847 + (unsigned)info->target_msc,
30848 + (long long)last_msc,
30849 + delta));
30850 + assert(info->target_msc - last_msc < 1ull<<31);
30851 + assert(delta >= 0);
30853 + VG_CLEAR(vbl);
30854 + vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
30855 + vbl.request.sequence = info->target_msc;
30856 + vbl.request.signal = (uintptr_t)MARK_PRESENT(info);
30857 + if (delta > 2 ||
30858 + sna_wait_vblank(info->sna, &vbl, sna_crtc_pipe(info->crtc))) {
30859 + DBG(("%s: vblank enqueue failed, faking delta=%d\n", __FUNCTION__, delta));
30860 + if (!sna_fake_vblank(info))
30861 + return false;
30862 + } else {
30863 + info->queued = true;
30864 + if (delta == 1) {
30865 + sna_crtc_set_vblank(info->crtc);
30866 + info->crtc = mark_crtc(info->crtc);
30867 + }
30868 + }
30870 + return true;
30871 +}
30873 static RRCrtcPtr
30874 sna_present_get_crtc(WindowPtr window)
30876 @@ -81,7 +343,10 @@ sna_present_get_crtc(WindowPtr window)
30877 BoxRec box;
30878 xf86CrtcPtr crtc;
30880 - DBG(("%s\n", __FUNCTION__));
30881 + DBG(("%s: window=%ld (pixmap=%ld), box=(%d, %d)x(%d, %d)\n",
30882 + __FUNCTION__, window->drawable.id, get_window_pixmap(window)->drawable.serialNumber,
30883 + window->drawable.x, window->drawable.y,
30884 + window->drawable.width, window->drawable.height));
30886 box.x1 = window->drawable.x;
30887 box.y1 = window->drawable.y;
30888 @@ -99,26 +364,59 @@ static int
30889 sna_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc)
30891 struct sna *sna = to_sna_from_screen(crtc->pScreen);
30892 - int pipe = pipe_from_crtc(crtc);
30893 union drm_wait_vblank vbl;
30895 - DBG(("%s(pipe=%d)\n", __FUNCTION__, pipe));
30896 + DBG(("%s(pipe=%d)\n", __FUNCTION__, sna_crtc_pipe(crtc->devPrivate)));
30897 + if (sna_crtc_has_vblank(crtc->devPrivate)) {
30898 + DBG(("%s: vblank active, reusing last swap msc/ust\n",
30899 + __FUNCTION__));
30900 + goto last;
30901 + }
30903 VG_CLEAR(vbl);
30904 vbl.request.type = DRM_VBLANK_RELATIVE;
30905 vbl.request.sequence = 0;
30906 - if (sna_wait_vblank(sna, &vbl, pipe) == 0) {
30907 + if (sna_wait_vblank(sna, &vbl, sna_crtc_pipe(crtc->devPrivate)) == 0) {
30908 + struct sna_present_event *info;
30910 *ust = ust64(vbl.reply.tval_sec, vbl.reply.tval_usec);
30911 *msc = sna_crtc_record_vblank(crtc->devPrivate, &vbl);
30913 + info = info_alloc(sna);
30914 + if (info) {
30915 + info->crtc = crtc->devPrivate;
30916 + info->sna = sna;
30917 + info->target_msc = *msc + 1;
30918 + info->event_id = (uint64_t *)(info + 1);
30919 + info->n_event_id = 0;
30921 + vbl.request.type =
30922 + DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
30923 + vbl.request.sequence = info->target_msc;
30924 + vbl.request.signal = (uintptr_t)MARK_PRESENT(info);
30926 + if (sna_wait_vblank(info->sna, &vbl,
30927 + sna_crtc_pipe(info->crtc)) == 0) {
30928 + list_add(&info->link,
30929 + &sna->present.vblank_queue);
30930 + info->queued = true;
30931 + sna_crtc_set_vblank(info->crtc);
30932 + info->crtc = mark_crtc(info->crtc);
30933 + } else
30934 + info_free(info);
30935 + }
30936 } else {
30937 - const struct ust_msc *swap = sna_crtc_last_swap(crtc->devPrivate);
30938 - *ust = ust64(swap->tv_sec, swap->tv_usec);
30939 + const struct ust_msc *swap;
30940 +last:
30941 + swap = sna_crtc_last_swap(crtc->devPrivate);
30942 + *ust = swap_ust(swap);
30943 *msc = swap->msc;
30946 - DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld\n", __FUNCTION__, pipe,
30947 + DBG(("%s: pipe=%d, tv=%d.%06d seq=%d msc=%lld\n", __FUNCTION__,
30948 + sna_crtc_pipe(crtc->devPrivate),
30949 (int)(*ust / 1000000), (int)(*ust % 1000000),
30950 - (long long)*msc));
30951 + vbl.reply.sequence, (long long)*msc));
30953 return Success;
30955 @@ -127,43 +425,106 @@ void
30956 sna_present_vblank_handler(struct drm_event_vblank *event)
30958 struct sna_present_event *info = to_present_event(event->user_data);
30959 + uint64_t msc;
30961 - DBG(("%s: pipe=%d tv=%d.%06d msc=%d, event %lld complete\n", __FUNCTION__,
30962 - sna_crtc_to_pipe(info->crtc),
30963 - event->tv_sec, event->tv_usec, event->sequence,
30964 - (long long)info->event_id));
30965 - present_event_notify(info->event_id,
30966 - ust64(event->tv_sec, event->tv_usec),
30967 - sna_crtc_record_event(info->crtc, event));
30968 - free(info);
30969 + if (!info->queued) {
30970 + DBG(("%s: arrived unexpectedly early (not queued)\n", __FUNCTION__));
30971 + assert(!has_vblank(info->crtc));
30972 + return;
30973 + }
30975 + if (has_vblank(info->crtc)) {
30976 + DBG(("%s: clearing immediate flag\n", __FUNCTION__));
30977 + info->crtc = unmask_crtc(info->crtc);
30978 + sna_crtc_clear_vblank(info->crtc);
30979 + }
30981 + msc = sna_crtc_record_event(info->crtc, event);
30983 + if (info->sna->mode.shadow_wait) {
30984 + DBG(("%s: recursed from TearFree\n", __FUNCTION__));
30985 + if (TimerSet(NULL, 0, 1, sna_fake_vblank_handler, info))
30986 + return;
30987 + }
30989 + vblank_complete(info, ust64(event->tv_sec, event->tv_usec), msc);
30992 static int
30993 sna_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
30995 struct sna *sna = to_sna_from_screen(crtc->pScreen);
30996 - struct sna_present_event *event;
30997 - union drm_wait_vblank vbl;
30999 - DBG(("%s(pipe=%d, event=%lld, msc=%lld)\n",
31000 - __FUNCTION__, pipe_from_crtc(crtc),
31001 - (long long)event_id, (long long)msc));
31002 + struct sna_present_event *info, *tmp;
31003 + const struct ust_msc *swap;
31005 - event = malloc(sizeof(struct sna_present_event));
31006 - if (event == NULL)
31007 + if (!sna_crtc_is_on(crtc->devPrivate))
31008 return BadAlloc;
31010 - event->event_id = event_id;
31011 - event->crtc = crtc->devPrivate;
31012 + swap = sna_crtc_last_swap(crtc->devPrivate);
31013 + DBG(("%s(pipe=%d, event=%lld, msc=%lld, last swap=%lld)\n",
31014 + __FUNCTION__, sna_crtc_pipe(crtc->devPrivate),
31015 + (long long)event_id, (long long)msc, (long long)swap->msc));
31017 - VG_CLEAR(vbl);
31018 - vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
31019 - vbl.request.sequence = msc;
31020 - vbl.request.signal = (uintptr_t)MARK_PRESENT(event);
31021 - if (sna_wait_vblank(sna, &vbl, sna_crtc_to_pipe(event->crtc))) {
31022 - DBG(("%s: vblank enqueue failed\n", __FUNCTION__));
31023 - free(event);
31024 - return BadMatch;
31025 + if (warn_unless((int64_t)(msc - swap->msc) >= 0)) {
31026 + DBG(("%s: pipe=%d tv=%d.%06d msc=%lld (target=%lld), event=%lld complete\n", __FUNCTION__,
31027 + sna_crtc_pipe(crtc->devPrivate),
31028 + swap->tv_sec, swap->tv_usec,
31029 + (long long)swap->msc, (long long)msc,
31030 + (long long)event_id));
31031 + present_event_notify(event_id, swap_ust(swap), swap->msc);
31032 + return Success;
31033 + }
31034 + if (warn_unless(msc - swap->msc < 1ull<<31))
31035 + return BadValue;
31037 + list_for_each_entry(tmp, &sna->present.vblank_queue, link) {
31038 + if (tmp->target_msc == msc &&
31039 + unmask_crtc(tmp->crtc) == crtc->devPrivate) {
31040 + uint64_t *events = tmp->event_id;
31042 + if (tmp->n_event_id &&
31043 + is_power_of_two(tmp->n_event_id)) {
31044 + events = malloc(2*sizeof(uint64_t)*tmp->n_event_id);
31045 + if (events == NULL)
31046 + return BadAlloc;
31048 + memcpy(events,
31049 + tmp->event_id,
31050 + tmp->n_event_id*sizeof(uint64_t));
31051 + if (tmp->n_event_id != 1)
31052 + free(tmp->event_id);
31053 + tmp->event_id = events;
31054 + }
31056 + DBG(("%s: appending event=%lld to vblank %lld x %d\n",
31057 + __FUNCTION__, (long long)event_id, (long long)msc, tmp->n_event_id+1));
31058 + events[tmp->n_event_id++] = event_id;
31059 + return Success;
31060 + }
31061 + if ((int64_t)(tmp->target_msc - msc) > 0) {
31062 + DBG(("%s: previous target_msc=%lld invalid for coalescing\n",
31063 + __FUNCTION__, (long long)tmp->target_msc));
31064 + break;
31065 + }
31066 + }
31068 + info = info_alloc(sna);
31069 + if (info == NULL)
31070 + return BadAlloc;
31072 + info->crtc = crtc->devPrivate;
31073 + info->sna = sna;
31074 + info->target_msc = msc;
31075 + info->event_id = (uint64_t *)(info + 1);
31076 + info->event_id[0] = event_id;
31077 + info->n_event_id = 1;
31078 + list_add_tail(&info->link, &tmp->link);
31079 + info->queued = false;
31081 + if (!sna_present_queue(info, swap->msc)) {
31082 + list_del(&info->link);
31083 + info_free(info);
31084 + return BadAlloc;
31087 return Success;
31088 @@ -180,14 +541,6 @@ sna_present_abort_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
31089 static void
31090 sna_present_flush(WindowPtr window)
31092 - PixmapPtr pixmap = get_window_pixmap(window);
31093 - struct sna_pixmap *priv;
31095 - DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
31097 - priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_FORCE);
31098 - if (priv && priv->gpu_bo)
31099 - kgem_scanout_flush(&to_sna_from_pixmap(pixmap)->kgem, priv->gpu_bo);
31102 static bool
31103 @@ -201,8 +554,13 @@ check_flip__crtc(struct sna *sna,
31105 assert(sna->scrn->vtSema);
31107 - if (sna->mode.shadow_active) {
31108 - DBG(("%s: shadow buffer active\n", __FUNCTION__));
31109 + if (!sna->mode.front_active) {
31110 + DBG(("%s: DPMS off, no flips\n", __FUNCTION__));
31111 + return FALSE;
31112 + }
31114 + if (sna->mode.rr_active) {
31115 + DBG(("%s: RandR transformation active\n", __FUNCTION__));
31116 return false;
31119 @@ -224,6 +582,11 @@ sna_present_check_flip(RRCrtcPtr crtc,
31120 pixmap->drawable.serialNumber,
31121 sync_flip));
31123 + if (!sna->scrn->vtSema) {
31124 + DBG(("%s: VT switched away, no flips\n", __FUNCTION__));
31125 + return FALSE;
31126 + }
31128 if (sna->flags & SNA_NO_FLIP) {
31129 DBG(("%s: flips not suported\n", __FUNCTION__));
31130 return FALSE;
31131 @@ -231,7 +594,7 @@ sna_present_check_flip(RRCrtcPtr crtc,
31133 if (sync_flip) {
31134 if ((sna->flags & SNA_HAS_FLIP) == 0) {
31135 - DBG(("%s: async flips not suported\n", __FUNCTION__));
31136 + DBG(("%s: sync flips not suported\n", __FUNCTION__));
31137 return FALSE;
31139 } else {
31140 @@ -257,24 +620,39 @@ sna_present_check_flip(RRCrtcPtr crtc,
31141 return FALSE;
31144 - return TRUE;
31145 -}
31147 -static uint64_t gettime_ust64(void)
31148 -{
31149 - struct timespec tv;
31150 + if (flip->pinned) {
31151 + assert(flip->gpu_bo);
31152 + if (sna->flags & SNA_LINEAR_FB) {
31153 + if (flip->gpu_bo->tiling != I915_TILING_NONE) {
31154 + DBG(("%s: pined bo, tilng=%d needs NONE\n",
31155 + __FUNCTION__, flip->gpu_bo->tiling));
31156 + return FALSE;
31157 + }
31158 + } else {
31159 + if (!sna->kgem.can_scanout_y &&
31160 + flip->gpu_bo->tiling == I915_TILING_Y) {
31161 + DBG(("%s: pined bo, tilng=%d and can't scanout Y\n",
31162 + __FUNCTION__, flip->gpu_bo->tiling));
31163 + return FALSE;
31164 + }
31165 + }
31167 - if (clock_gettime(CLOCK_MONOTONIC, &tv))
31168 - return 0;
31169 + if (flip->gpu_bo->pitch & 63) {
31170 + DBG(("%s: pined bo, bad pitch=%d\n",
31171 + __FUNCTION__, flip->gpu_bo->pitch));
31172 + return FALSE;
31173 + }
31174 + }
31176 - return ust64(tv.tv_sec, tv.tv_nsec / 1000);
31177 + return TRUE;
31180 static Bool
31181 -page_flip__async(RRCrtcPtr crtc,
31182 - uint64_t event_id,
31183 - uint64_t target_msc,
31184 - struct kgem_bo *bo)
31185 +flip__async(struct sna *sna,
31186 + RRCrtcPtr crtc,
31187 + uint64_t event_id,
31188 + uint64_t target_msc,
31189 + struct kgem_bo *bo)
31191 DBG(("%s(pipe=%d, event=%lld, handle=%d)\n",
31192 __FUNCTION__,
31193 @@ -282,17 +660,17 @@ page_flip__async(RRCrtcPtr crtc,
31194 (long long)event_id,
31195 bo->handle));
31197 - if (!sna_page_flip(to_sna_from_screen(crtc->pScreen), bo, NULL, NULL)) {
31198 + if (!sna_page_flip(sna, bo, NULL, NULL)) {
31199 DBG(("%s: async pageflip failed\n", __FUNCTION__));
31200 present_info.capabilities &= ~PresentCapabilityAsync;
31201 return FALSE;
31204 - DBG(("%s: pipe=%d tv=%d.%06d msc=%d, event %lld complete\n", __FUNCTION__,
31205 + DBG(("%s: pipe=%d tv=%ld.%06d msc=%lld (target=%lld), event=%lld complete\n", __FUNCTION__,
31206 pipe_from_crtc(crtc),
31207 - gettime_ust64() / 1000000, gettime_ust64() % 1000000,
31208 - sna_crtc_last_swap(crtc->devPrivate)->msc,
31209 - (long long)event_id));
31210 + (long)(gettime_ust64() / 1000000), (int)(gettime_ust64() % 1000000),
31211 + crtc ? (long long)sna_crtc_last_swap(crtc->devPrivate)->msc : 0LL,
31212 + (long long)target_msc, (long long)event_id));
31213 present_event_notify(event_id, gettime_ust64(), target_msc);
31214 return TRUE;
31216 @@ -303,7 +681,12 @@ present_flip_handler(struct drm_event_vblank *event, void *data)
31217 struct sna_present_event *info = data;
31218 struct ust_msc swap;
31220 - DBG(("%s(sequence=%d)\n", __FUNCTION__, event->sequence));
31221 + DBG(("%s(sequence=%d): event=%lld\n", __FUNCTION__, event->sequence, (long long)info->event_id[0]));
31222 + assert(info->n_event_id == 1);
31223 + if (!info->queued) {
31224 + DBG(("%s: arrived unexpectedly early (not queued)\n", __FUNCTION__));
31225 + return;
31226 + }
31228 if (info->crtc == NULL) {
31229 swap.tv_sec = event->tv_sec;
31230 @@ -312,22 +695,33 @@ present_flip_handler(struct drm_event_vblank *event, void *data)
31231 } else
31232 swap = *sna_crtc_last_swap(info->crtc);
31234 - DBG(("%s: pipe=%d, tv=%d.%06d msc %lld, event %lld complete\n", __FUNCTION__,
31235 - info->crtc ? sna_crtc_to_pipe(info->crtc) : -1,
31236 + DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld (target %lld), event=%lld complete%s\n", __FUNCTION__,
31237 + info->crtc ? sna_crtc_pipe(info->crtc) : -1,
31238 swap.tv_sec, swap.tv_usec, (long long)swap.msc,
31239 - (long long)info->event_id));
31240 - present_event_notify(info->event_id, ust64(swap.tv_sec, swap.tv_usec), swap.msc);
31241 - free(info);
31242 + (long long)info->target_msc,
31243 + (long long)info->event_id[0],
31244 + info->target_msc && info->target_msc == swap.msc ? "" : ": MISS"));
31245 + present_event_notify(info->event_id[0], swap_ust(&swap), swap.msc);
31246 + if (info->crtc)
31247 + sna_crtc_clear_vblank(info->crtc);
31249 + if (info->sna->present.unflip) {
31250 + DBG(("%s: executing queued unflip (event=%lld)\n", __FUNCTION__, (long long)info->sna->present.unflip));
31251 + sna_present_unflip(xf86ScrnToScreen(info->sna->scrn),
31252 + info->sna->present.unflip);
31253 + info->sna->present.unflip = 0;
31254 + }
31255 + info_free(info);
31258 static Bool
31259 -page_flip(ScreenPtr screen,
31260 - RRCrtcPtr crtc,
31261 - uint64_t event_id,
31262 - struct kgem_bo *bo)
31263 +flip(struct sna *sna,
31264 + RRCrtcPtr crtc,
31265 + uint64_t event_id,
31266 + uint64_t target_msc,
31267 + struct kgem_bo *bo)
31269 - struct sna *sna = to_sna_from_screen(screen);
31270 - struct sna_present_event *event;
31271 + struct sna_present_event *info;
31273 DBG(("%s(pipe=%d, event=%lld, handle=%d)\n",
31274 __FUNCTION__,
31275 @@ -335,18 +729,27 @@ page_flip(ScreenPtr screen,
31276 (long long)event_id,
31277 bo->handle));
31279 - event = malloc(sizeof(struct sna_present_event));
31280 - if (event == NULL)
31281 + info = info_alloc(sna);
31282 + if (info == NULL)
31283 return FALSE;
31285 - event->event_id = event_id;
31286 - event->crtc = crtc ? crtc->devPrivate : NULL;
31287 - if (!sna_page_flip(sna, bo, present_flip_handler, event)) {
31288 + info->crtc = crtc ? crtc->devPrivate : NULL;
31289 + info->sna = sna;
31290 + info->event_id = (uint64_t *)(info + 1);
31291 + info->event_id[0] = event_id;
31292 + info->n_event_id = 1;
31293 + info->target_msc = target_msc;
31294 + info->queued = false;
31296 + if (!sna_page_flip(sna, bo, present_flip_handler, info)) {
31297 DBG(("%s: pageflip failed\n", __FUNCTION__));
31298 - free(event);
31299 + info_free(info);
31300 return FALSE;
31303 + info->queued = true;
31304 + if (info->crtc)
31305 + sna_crtc_set_vblank(info->crtc);
31306 return TRUE;
31309 @@ -358,12 +761,48 @@ get_flip_bo(PixmapPtr pixmap)
31311 DBG(("%s(pixmap=%ld)\n", __FUNCTION__, pixmap->drawable.serialNumber));
31313 - priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | __MOVE_FORCE);
31314 + priv = sna_pixmap_move_to_gpu(pixmap, MOVE_READ | __MOVE_SCANOUT | __MOVE_FORCE);
31315 if (priv == NULL) {
31316 DBG(("%s: cannot force pixmap to the GPU\n", __FUNCTION__));
31317 return NULL;
31320 + if (priv->gpu_bo->scanout)
31321 + return priv->gpu_bo;
31323 + if (sna->kgem.has_llc && !wedged(sna) && !priv->pinned) {
31324 + struct kgem_bo *bo;
31325 + uint32_t tiling;
31327 + tiling = I915_TILING_NONE;
31328 + if ((sna->flags & SNA_LINEAR_FB) == 0)
31329 + tiling = I915_TILING_X;
31331 + bo = kgem_create_2d(&sna->kgem,
31332 + pixmap->drawable.width,
31333 + pixmap->drawable.height,
31334 + pixmap->drawable.bitsPerPixel,
31335 + tiling, CREATE_SCANOUT | CREATE_CACHED);
31336 + if (bo) {
31337 + BoxRec box;
31339 + box.x1 = box.y1 = 0;
31340 + box.x2 = pixmap->drawable.width;
31341 + box.y2 = pixmap->drawable.height;
31343 + if (sna->render.copy_boxes(sna, GXcopy,
31344 + &pixmap->drawable, priv->gpu_bo, 0, 0,
31345 + &pixmap->drawable, bo, 0, 0,
31346 + &box, 1, 0)) {
31347 + sna_pixmap_unmap(pixmap, priv);
31348 + kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
31350 + priv->gpu_bo = bo;
31351 + } else
31352 + kgem_bo_destroy(&sna->kgem, bo);
31353 + }
31354 + }
31356 if (sna->flags & SNA_LINEAR_FB &&
31357 priv->gpu_bo->tiling &&
31358 !sna_pixmap_change_tiling(pixmap, I915_TILING_NONE)) {
31359 @@ -372,12 +811,17 @@ get_flip_bo(PixmapPtr pixmap)
31362 if (priv->gpu_bo->tiling == I915_TILING_Y &&
31363 + !sna->kgem.can_scanout_y &&
31364 !sna_pixmap_change_tiling(pixmap, I915_TILING_X)) {
31365 DBG(("%s: invalid Y-tiling, cannot convert\n", __FUNCTION__));
31366 return NULL;
31369 - priv->pinned |= PIN_SCANOUT;
31370 + if (priv->gpu_bo->pitch & 63) {
31371 + DBG(("%s: invalid pitch, no conversion\n", __FUNCTION__));
31372 + return NULL;
31373 + }
31375 return priv->gpu_bo;
31378 @@ -388,6 +832,7 @@ sna_present_flip(RRCrtcPtr crtc,
31379 PixmapPtr pixmap,
31380 Bool sync_flip)
31382 + struct sna *sna = to_sna_from_pixmap(pixmap);
31383 struct kgem_bo *bo;
31385 DBG(("%s(pipe=%d, event=%lld, msc=%lld, pixmap=%ld, sync?=%d)\n",
31386 @@ -397,11 +842,32 @@ sna_present_flip(RRCrtcPtr crtc,
31387 (long long)target_msc,
31388 pixmap->drawable.serialNumber, sync_flip));
31390 - if (!check_flip__crtc(to_sna_from_pixmap(pixmap), crtc)) {
31391 + if (!check_flip__crtc(sna, crtc)) {
31392 DBG(("%s: flip invalid for CRTC\n", __FUNCTION__));
31393 return FALSE;
31396 + assert(sna->present.unflip == 0);
31398 + if (sna->flags & SNA_TEAR_FREE) {
31399 + DBG(("%s: disabling TearFree (was %s) in favour of Present flips\n",
31400 + __FUNCTION__, sna->mode.shadow_enabled ? "enabled" : "disabled"));
31401 + sna->mode.shadow_enabled = false;
31402 + }
31403 + assert(!sna->mode.shadow_enabled);
31405 + if (sna->mode.flip_active) {
31406 + struct pollfd pfd;
31408 + DBG(("%s: flips still pending, stalling\n", __FUNCTION__));
31409 + pfd.fd = sna->kgem.fd;
31410 + pfd.events = POLLIN;
31411 + while (poll(&pfd, 1, 0) == 1)
31412 + sna_mode_wakeup(sna);
31413 + if (sna->mode.flip_active)
31414 + return FALSE;
31415 + }
31417 bo = get_flip_bo(pixmap);
31418 if (bo == NULL) {
31419 DBG(("%s: flip invalid bo\n", __FUNCTION__));
31420 @@ -409,9 +875,9 @@ sna_present_flip(RRCrtcPtr crtc,
31423 if (sync_flip)
31424 - return page_flip(crtc->pScreen, crtc, event_id, bo);
31425 + return flip(sna, crtc, event_id, target_msc, bo);
31426 else
31427 - return page_flip__async(crtc, event_id, target_msc, bo);
31428 + return flip__async(sna, crtc, event_id, target_msc, bo);
31431 static void
31432 @@ -421,29 +887,70 @@ sna_present_unflip(ScreenPtr screen, uint64_t event_id)
31433 struct kgem_bo *bo;
31435 DBG(("%s(event=%lld)\n", __FUNCTION__, (long long)event_id));
31436 - if (sna->mode.front_active == 0 || sna->mode.shadow_active) {
31437 + if (sna->mode.front_active == 0 || sna->mode.rr_active) {
31438 const struct ust_msc *swap;
31440 DBG(("%s: no CRTC active, perform no-op flip\n", __FUNCTION__));
31442 notify:
31443 - swap = sna_crtc_last_swap(sna_mode_first_crtc(sna));
31444 - DBG(("%s: pipe=%d, tv=%d.%06d msc %lld, event %lld complete\n", __FUNCTION__,
31445 + swap = sna_crtc_last_swap(sna_primary_crtc(sna));
31446 + DBG(("%s: pipe=%d, tv=%d.%06d msc=%lld, event=%lld complete\n", __FUNCTION__,
31447 -1,
31448 swap->tv_sec, swap->tv_usec, (long long)swap->msc,
31449 (long long)event_id));
31450 - present_event_notify(event_id,
31451 - ust64(swap->tv_sec, swap->tv_usec),
31452 - swap->msc);
31453 + present_event_notify(event_id, swap_ust(swap), swap->msc);
31454 + return;
31455 + }
31457 + assert(!sna->mode.shadow_enabled);
31458 + if (sna->mode.flip_active) {
31459 + DBG(("%s: %d outstanding flips, queueing unflip\n", __FUNCTION__, sna->mode.flip_active));
31460 + assert(sna->present.unflip == 0);
31461 + sna->present.unflip = event_id;
31462 return;
31465 + if (sna->flags & SNA_TEAR_FREE) {
31466 + DBG(("%s: %s TearFree after Present flips\n",
31467 + __FUNCTION__, sna->mode.shadow_damage != NULL ? "enabling" : "disabling"));
31468 + sna->mode.shadow_enabled = sna->mode.shadow_damage != NULL;
31469 + }
31471 bo = get_flip_bo(screen->GetScreenPixmap(screen));
31472 - if (bo == NULL || !page_flip(screen, NULL, event_id, bo)) {
31473 + if (bo == NULL) {
31474 +reset_mode:
31475 DBG(("%s: failed, trying to restore original mode\n", __FUNCTION__));
31476 xf86SetDesiredModes(sna->scrn);
31477 goto notify;
31480 + /* Are we unflipping after a failure that left our ScreenP in place? */
31481 + if (!sna_needs_page_flip(sna, bo))
31482 + goto notify;
31484 + assert(sna_pixmap(screen->GetScreenPixmap(screen))->pinned & PIN_SCANOUT);
31486 + if (sna->flags & SNA_HAS_ASYNC_FLIP) {
31487 + DBG(("%s: trying async flip restore\n", __FUNCTION__));
31488 + if (flip__async(sna, NULL, event_id, 0, bo))
31489 + return;
31490 + }
31492 + if (!flip(sna, NULL, event_id, 0, bo))
31493 + goto reset_mode;
31494 +}
31496 +void sna_present_cancel_flip(struct sna *sna)
31497 +{
31498 + if (sna->present.unflip) {
31499 + const struct ust_msc *swap;
31501 + swap = sna_crtc_last_swap(sna_primary_crtc(sna));
31502 + present_event_notify(sna->present.unflip,
31503 + swap_ust(swap), swap->msc);
31505 + sna->present.unflip = 0;
31506 + }
31509 static present_screen_info_rec present_info = {
31510 @@ -463,10 +970,13 @@ static present_screen_info_rec present_info = {
31512 bool sna_present_open(struct sna *sna, ScreenPtr screen)
31514 + DBG(("%s(num_crtc=%d)\n", __FUNCTION__, sna->mode.num_real_crtc));
31516 if (sna->mode.num_real_crtc == 0)
31517 return false;
31519 sna_present_update(sna);
31520 + list_init(&sna->present.vblank_queue);
31522 return present_screen_init(screen, &present_info);
31524 diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
31525 index 3fbb9ecb..3e935d57 100644
31526 --- a/src/sna/sna_render.c
31527 +++ b/src/sna/sna_render.c
31528 @@ -54,7 +54,7 @@ sna_format_for_depth(int depth)
31530 switch (depth) {
31531 case 1: return PICT_a1;
31532 - case 4: return PICT_a4;
31533 + case 4: return PICT_x4a4;
31534 case 8: return PICT_a8;
31535 case 15: return PICT_x1r5g5b5;
31536 case 16: return PICT_r5g6b5;
31537 @@ -272,18 +272,6 @@ no_render_context_switch(struct kgem *kgem,
31540 static void
31541 -no_render_retire(struct kgem *kgem)
31542 -{
31543 - (void)kgem;
31544 -}
31546 -static void
31547 -no_render_expire(struct kgem *kgem)
31548 -{
31549 - (void)kgem;
31550 -}
31552 -static void
31553 no_render_fini(struct sna *sna)
31555 (void)sna;
31556 @@ -316,8 +304,6 @@ const char *no_render_init(struct sna *sna)
31557 render->fini = no_render_fini;
31559 sna->kgem.context_switch = no_render_context_switch;
31560 - sna->kgem.retire = no_render_retire;
31561 - sna->kgem.expire = no_render_expire;
31562 if (sna->kgem.has_blt)
31563 sna->kgem.ring = KGEM_BLT;
31565 @@ -407,10 +393,7 @@ use_cpu_bo(struct sna *sna, PixmapPtr pixmap, const BoxRec *box, bool blt)
31569 - if (priv->shm) {
31570 - assert(!priv->flush);
31571 - sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
31572 - }
31573 + add_shm_flush(sna, priv);
31575 DBG(("%s for box=(%d, %d), (%d, %d)\n",
31576 __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
31577 @@ -567,6 +550,7 @@ static struct kgem_bo *upload(struct sna *sna,
31578 assert(priv->gpu_damage == NULL);
31579 assert(priv->gpu_bo == NULL);
31580 assert(bo->proxy != NULL);
31581 + sna_damage_all(&priv->cpu_damage, pixmap);
31582 kgem_proxy_bo_attach(bo, &priv->gpu_bo);
31585 @@ -627,10 +611,7 @@ sna_render_pixmap_bo(struct sna *sna,
31586 !priv->cpu_bo->snoop && priv->cpu_bo->pitch < 4096) {
31587 DBG(("%s: CPU all damaged\n", __FUNCTION__));
31588 channel->bo = priv->cpu_bo;
31589 - if (priv->shm) {
31590 - assert(!priv->flush);
31591 - sna_add_flush_pixmap(sna, priv, priv->cpu_bo);
31592 - }
31593 + add_shm_flush(sna, priv);
31594 goto done;
31597 @@ -1275,6 +1256,7 @@ sna_render_picture_extract(struct sna *sna,
31598 assert(priv->gpu_damage == NULL);
31599 assert(priv->gpu_bo == NULL);
31600 assert(bo->proxy != NULL);
31601 + sna_damage_all(&priv->cpu_damage, pixmap);
31602 kgem_proxy_bo_attach(bo, &priv->gpu_bo);
31605 @@ -1338,6 +1320,8 @@ sna_render_picture_convolve(struct sna *sna,
31606 */
31607 DBG(("%s: origin=(%d,%d) kernel=%dx%d, size=%dx%d\n",
31608 __FUNCTION__, x_off, y_off, cw, ch, w, h));
31609 + if (cw*ch > 32) /* too much loss of precision from quantization! */
31610 + return -1;
31612 assert(picture->pDrawable);
31613 assert(picture->filter == PictFilterConvolution);
31614 @@ -1388,9 +1372,9 @@ sna_render_picture_convolve(struct sna *sna,
31615 alpha = CreateSolidPicture(0, &color, &error);
31616 if (alpha) {
31617 sna_composite(PictOpAdd, picture, alpha, tmp,
31618 - x, y,
31619 + x-(x_off+i), y-(y_off+j),
31620 + 0, 0,
31621 0, 0,
31622 - x_off+i, y_off+j,
31623 w, h);
31624 FreePicture(alpha, 0);
31626 @@ -2183,11 +2167,11 @@ copy_overlap(struct sna *sna, uint8_t alu,
31627 ret = (sna->render.copy_boxes(sna, GXcopy,
31628 draw, bo, src_dx, src_dy,
31629 &tmp->drawable, tmp_bo, -extents->x1, -extents->y1,
31630 - box, n , 0) &&
31631 + box, n, 0) &&
31632 sna->render.copy_boxes(sna, alu,
31633 &tmp->drawable, tmp_bo, -extents->x1, -extents->y1,
31634 draw, bo, dst_dx, dst_dy,
31635 - box, n , 0));
31636 + box, n, 0));
31638 screen->DestroyPixmap(tmp);
31639 return ret;
31640 @@ -2308,16 +2292,22 @@ static bool can_copy_cpu(struct sna *sna,
31641 struct kgem_bo *src,
31642 struct kgem_bo *dst)
31644 - if (src->tiling != dst->tiling)
31645 - return false;
31646 + DBG(("%s: tiling=%d:%d, pitch=%d:%d, can_map=%d:%d[%d]\n",
31647 + __FUNCTION__,
31648 + src->tiling, dst->tiling,
31649 + src->pitch, dst->pitch,
31650 + kgem_bo_can_map__cpu(&sna->kgem, src, false),
31651 + kgem_bo_can_map__cpu(&sna->kgem, dst, true),
31652 + sna->kgem.has_wc_mmap));
31654 - if (src->pitch != dst->pitch)
31655 + if (src->tiling != dst->tiling)
31656 return false;
31658 if (!kgem_bo_can_map__cpu(&sna->kgem, src, false))
31659 return false;
31661 - if (!kgem_bo_can_map__cpu(&sna->kgem, dst, true))
31662 + if (!kgem_bo_can_map__cpu(&sna->kgem, dst, true) &&
31663 + !sna->kgem.has_wc_mmap)
31664 return false;
31666 DBG(("%s -- yes, src handle=%d, dst handle=%d\n", __FUNCTION__, src->handle, dst->handle));
31667 @@ -2330,31 +2320,62 @@ memcpy_copy_boxes(struct sna *sna, uint8_t op,
31668 const DrawableRec *dst_draw, struct kgem_bo *dst_bo, int16_t dx, int16_t dy,
31669 const BoxRec *box, int n, unsigned flags)
31671 + memcpy_box_func detile = NULL;
31672 void *dst, *src;
31673 - bool clipped;
31675 if (op != GXcopy)
31676 return false;
31678 - clipped = (n > 1 ||
31679 - box->x1 + dx > 0 ||
31680 - box->y1 + dy > 0 ||
31681 - box->x2 + dx < dst_draw->width ||
31682 - box->y2 + dy < dst_draw->height);
31683 + if (src_draw->depth != dst_draw->depth)
31684 + return false;
31686 dst = src = NULL;
31687 - if (!clipped && can_copy_cpu(sna, src_bo, dst_bo)) {
31688 - dst = kgem_bo_map__cpu(&sna->kgem, dst_bo);
31689 + if (can_copy_cpu(sna, src_bo, dst_bo)) {
31690 + if (src_bo->pitch != dst_bo->pitch ||
31691 + dx != sx || dy != sy || n > 1 ||
31692 + box->x1 + dx > 0 ||
31693 + box->y1 + dy > 0 ||
31694 + box->x2 + dx < dst_draw->width ||
31695 + box->y2 + dy < dst_draw->height) {
31696 + if (dx != sx) /* not implemented in memcpy yet */
31697 + goto use_gtt;
31699 + switch (dst_bo->tiling) {
31700 + default:
31701 + case I915_TILING_Y:
31702 + goto use_gtt;
31704 + case I915_TILING_X:
31705 + detile = sna->kgem.memcpy_between_tiled_x;
31706 + if (detile == NULL)
31707 + goto use_gtt;
31708 + break;
31710 + case I915_TILING_NONE:
31711 + break;
31712 + }
31713 + }
31715 + if (kgem_bo_can_map__cpu(&sna->kgem, dst_bo, true))
31716 + dst = kgem_bo_map__cpu(&sna->kgem, dst_bo);
31717 + else
31718 + dst = kgem_bo_map__wc(&sna->kgem, dst_bo);
31719 src = kgem_bo_map__cpu(&sna->kgem, src_bo);
31722 if (dst == NULL || src == NULL) {
31723 +use_gtt:
31724 dst = kgem_bo_map__gtt(&sna->kgem, dst_bo);
31725 src = kgem_bo_map__gtt(&sna->kgem, src_bo);
31726 if (dst == NULL || src == NULL)
31727 return false;
31729 + detile = NULL;
31730 } else {
31731 - kgem_bo_sync__cpu_full(&sna->kgem, dst_bo, true);
31732 + if (dst == dst_bo->map__wc)
31733 + kgem_bo_sync__gtt(&sna->kgem, dst_bo);
31734 + else
31735 + kgem_bo_sync__cpu_full(&sna->kgem, dst_bo, true);
31736 kgem_bo_sync__cpu_full(&sna->kgem, src_bo, false);
31739 @@ -2362,7 +2383,16 @@ memcpy_copy_boxes(struct sna *sna, uint8_t op,
31740 __FUNCTION__, sx, sy, dx, dy, n));
31742 if (sigtrap_get() == 0) {
31743 - do {
31744 + if (detile) {
31745 + do {
31746 + detile(src, dst, dst_draw->bitsPerPixel,
31747 + src_bo->pitch, dst_bo->pitch,
31748 + box->x1 + sx, box->y1 + sy,
31749 + box->x1 + dx, box->y1 + dy,
31750 + box->x2 - box->x1, box->y2 - box->y1);
31751 + box++;
31752 + } while (--n);
31753 + } else do {
31754 memcpy_blt(src, dst, dst_draw->bitsPerPixel,
31755 src_bo->pitch, dst_bo->pitch,
31756 box->x1 + sx, box->y1 + sy,
31757 @@ -2380,4 +2410,5 @@ void
31758 sna_render_mark_wedged(struct sna *sna)
31760 sna->render.copy_boxes = memcpy_copy_boxes;
31761 + sna->render.prefer_gpu = 0;
31763 diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h
31764 index 6e1fa480..4ba345a7 100644
31765 --- a/src/sna/sna_render.h
31766 +++ b/src/sna/sna_render.h
31767 @@ -148,6 +148,10 @@ struct sna_composite_op {
31768 struct {
31769 uint32_t flags;
31770 } gen8;
31772 + struct {
31773 + uint32_t flags;
31774 + } gen9;
31775 } u;
31777 void *priv;
31778 @@ -238,8 +242,9 @@ struct sna_render {
31779 int16_t w, int16_t h,
31780 unsigned flags,
31781 struct sna_composite_op *tmp);
31782 -#define COMPOSITE_PARTIAL 0x1
31783 -#define COMPOSITE_FALLBACK 0x80000000
31784 +#define COMPOSITE_PARTIAL 0x1
31785 +#define COMPOSITE_UPLOAD 0x40000000
31786 +#define COMPOSITE_FALLBACK 0x80000000
31788 bool (*check_composite_spans)(struct sna *sna, uint8_t op,
31789 PicturePtr dst, PicturePtr src,
31790 @@ -286,6 +291,8 @@ struct sna_render {
31791 #define COPY_LAST 0x1
31792 #define COPY_SYNC 0x2
31793 #define COPY_NO_OVERLAP 0x4
31794 +#define COPY_SMALL 0x8
31795 +#define COPY_DRI 0x10
31797 bool (*copy)(struct sna *sna, uint8_t alu,
31798 PixmapPtr src, struct kgem_bo *src_bo,
31799 @@ -481,6 +488,7 @@ enum {
31801 GEN7_WM_KERNEL_VIDEO_PLANAR,
31802 GEN7_WM_KERNEL_VIDEO_PACKED,
31803 + GEN7_WM_KERNEL_VIDEO_RGB,
31804 GEN7_WM_KERNEL_COUNT
31805 };
31807 @@ -533,12 +541,13 @@ enum {
31809 GEN8_WM_KERNEL_VIDEO_PLANAR,
31810 GEN8_WM_KERNEL_VIDEO_PACKED,
31811 + GEN8_WM_KERNEL_VIDEO_RGB,
31812 GEN8_WM_KERNEL_COUNT
31813 };
31815 struct gen8_render_state {
31816 unsigned gt;
31818 + const struct gt_info *info;
31819 struct kgem_bo *general_bo;
31821 uint32_t vs_state;
31822 @@ -565,6 +574,58 @@ struct gen8_render_state {
31823 bool emit_flush;
31824 };
31826 +enum {
31827 + GEN9_WM_KERNEL_NOMASK = 0,
31828 + GEN9_WM_KERNEL_NOMASK_P,
31830 + GEN9_WM_KERNEL_MASK,
31831 + GEN9_WM_KERNEL_MASK_P,
31833 + GEN9_WM_KERNEL_MASKCA,
31834 + GEN9_WM_KERNEL_MASKCA_P,
31836 + GEN9_WM_KERNEL_MASKSA,
31837 + GEN9_WM_KERNEL_MASKSA_P,
31839 + GEN9_WM_KERNEL_OPACITY,
31840 + GEN9_WM_KERNEL_OPACITY_P,
31842 + GEN9_WM_KERNEL_VIDEO_PLANAR,
31843 + GEN9_WM_KERNEL_VIDEO_PACKED,
31844 + GEN9_WM_KERNEL_VIDEO_RGB,
31845 + GEN9_WM_KERNEL_COUNT
31846 +};
31848 +struct gen9_render_state {
31849 + unsigned gt;
31850 + const struct gt_info *info;
31851 + struct kgem_bo *general_bo;
31853 + uint32_t vs_state;
31854 + uint32_t sf_state;
31855 + uint32_t sf_mask_state;
31856 + uint32_t wm_state;
31857 + uint32_t wm_kernel[GEN9_WM_KERNEL_COUNT][3];
31859 + uint32_t cc_blend;
31861 + uint32_t drawrect_offset;
31862 + uint32_t drawrect_limit;
31863 + uint32_t blend;
31864 + uint32_t samplers;
31865 + uint32_t kernel;
31867 + uint16_t num_sf_outputs;
31868 + uint16_t ve_id;
31869 + uint16_t last_primitive;
31870 + int16_t floats_per_vertex;
31871 + uint16_t surface_table;
31873 + bool needs_invariant;
31874 + bool emit_flush;
31875 + bool ve_dirty;
31876 +};
31878 struct sna_static_stream {
31879 uint32_t size, used;
31880 uint8_t *data;
31881 @@ -620,6 +681,7 @@ const char *gen5_render_init(struct sna *sna, const char *backend);
31882 const char *gen6_render_init(struct sna *sna, const char *backend);
31883 const char *gen7_render_init(struct sna *sna, const char *backend);
31884 const char *gen8_render_init(struct sna *sna, const char *backend);
31885 +const char *gen9_render_init(struct sna *sna, const char *backend);
31887 void sna_render_mark_wedged(struct sna *sna);
31889 diff --git a/src/sna/sna_render_inline.h b/src/sna/sna_render_inline.h
31890 index 10fbbfe2..e162e37f 100644
31891 --- a/src/sna/sna_render_inline.h
31892 +++ b/src/sna/sna_render_inline.h
31893 @@ -304,6 +304,12 @@ color_convert(uint32_t pixel,
31894 return pixel;
31897 +inline static uint32_t
31898 +solid_color(uint32_t format, uint32_t pixel)
31899 +{
31900 + return color_convert(pixel, format, PICT_a8r8g8b8);
31901 +}
31903 inline static bool dst_use_gpu(PixmapPtr pixmap)
31905 struct sna_pixmap *priv = sna_pixmap(pixmap);
31906 diff --git a/src/sna/sna_tiling.c b/src/sna/sna_tiling.c
31907 index 308efc0a..8e2627f7 100644
31908 --- a/src/sna/sna_tiling.c
31909 +++ b/src/sna/sna_tiling.c
31910 @@ -369,8 +369,7 @@ sna_tiling_composite_spans_boxes(struct sna *sna,
31911 const BoxRec *box, int nbox, float opacity)
31913 while (nbox--)
31914 - sna_tiling_composite_spans_box(sna, op->base.priv, box++, opacity);
31915 - (void)sna;
31916 + sna_tiling_composite_spans_box(sna, op, box++, opacity);
31919 fastcall static void
31920 @@ -581,6 +580,7 @@ sna_tiling_composite_spans(uint32_t op,
31921 tile->rects = tile->rects_embedded;
31922 tile->rect_count = 0;
31923 tile->rect_size = ARRAY_SIZE(tile->rects_embedded);
31924 + COMPILE_TIME_ASSERT(sizeof(tile->rects_embedded[0]) >= sizeof(struct sna_tile_span));
31926 tmp->box = sna_tiling_composite_spans_box;
31927 tmp->boxes = sna_tiling_composite_spans_boxes;
31928 diff --git a/src/sna/sna_trapezoids_boxes.c b/src/sna/sna_trapezoids_boxes.c
31929 index 9900e3f0..bbf83759 100644
31930 --- a/src/sna/sna_trapezoids_boxes.c
31931 +++ b/src/sna/sna_trapezoids_boxes.c
31932 @@ -198,7 +198,7 @@ composite_aligned_boxes(struct sna *sna,
31933 if (op == PictOpClear && sna->clear)
31934 src = sna->clear;
31936 - DBG(("%s: clipped extents (%d, %d), (%d, %d); now offset by (%d, %d), orgin (%d, %d)\n",
31937 + DBG(("%s: clipped extents (%d, %d), (%d, %d); now offset by (%d, %d), origin (%d, %d)\n",
31938 __FUNCTION__,
31939 clip.extents.x1, clip.extents.y1,
31940 clip.extents.x2, clip.extents.y2,
31941 @@ -592,6 +592,8 @@ lerp32_opacity(PixmapPtr scratch,
31942 uint32_t *ptr;
31943 int stride, i;
31945 + sigtrap_assert_active();
31947 ptr = (uint32_t*)((uint8_t *)scratch->devPrivate.ptr + scratch->devKind * y);
31948 ptr += x;
31949 stride = scratch->devKind / 4;
31950 diff --git a/src/sna/sna_trapezoids_imprecise.c b/src/sna/sna_trapezoids_imprecise.c
31951 index 37def2f9..8bc7c8a8 100644
31952 --- a/src/sna/sna_trapezoids_imprecise.c
31953 +++ b/src/sna/sna_trapezoids_imprecise.c
31954 @@ -962,6 +962,16 @@ tor_add_trapezoid(struct tor *tor,
31955 const xTrapezoid *t,
31956 int dx, int dy)
31958 + if (!xTrapezoidValid(t)) {
31959 + __DBG(("%s: skipping invalid trapezoid: top=%d, bottom=%d, left=(%d, %d), (%d, %d), right=(%d, %d), (%d, %d)\n",
31960 + __FUNCTION__,
31961 + t->top, t->bottom,
31962 + t->left.p1.x, t->left.p1.y,
31963 + t->left.p2.x, t->left.p2.y,
31964 + t->right.p1.x, t->right.p1.y,
31965 + t->right.p2.x, t->right.p2.y));
31966 + return;
31967 + }
31968 polygon_add_edge(tor->polygon, t, &t->left, 1, dx, dy);
31969 polygon_add_edge(tor->polygon, t, &t->right, -1, dx, dy);
31971 @@ -1687,31 +1697,27 @@ struct span_thread {
31972 #define SPAN_THREAD_MAX_BOXES (8192/sizeof(struct sna_opacity_box))
31973 struct span_thread_boxes {
31974 const struct sna_composite_spans_op *op;
31975 + const BoxRec *clip_start, *clip_end;
31976 int num_boxes;
31977 struct sna_opacity_box boxes[SPAN_THREAD_MAX_BOXES];
31978 };
31980 -static void span_thread_add_boxes(struct sna *sna, void *data,
31981 - const BoxRec *box, int count, float alpha)
31982 +static void span_thread_add_box(struct sna *sna, void *data,
31983 + const BoxRec *box, float alpha)
31985 struct span_thread_boxes *b = data;
31987 - __DBG(("%s: adding %d boxes with alpha=%f\n",
31988 - __FUNCTION__, count, alpha));
31989 + __DBG(("%s: adding box with alpha=%f\n", __FUNCTION__, alpha));
31991 - assert(count > 0 && count <= SPAN_THREAD_MAX_BOXES);
31992 - if (unlikely(b->num_boxes + count > SPAN_THREAD_MAX_BOXES)) {
31993 - DBG(("%s: flushing %d boxes, adding %d\n", __FUNCTION__, b->num_boxes, count));
31994 - assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES);
31995 + if (unlikely(b->num_boxes == SPAN_THREAD_MAX_BOXES)) {
31996 + DBG(("%s: flushing %d boxes\n", __FUNCTION__, b->num_boxes));
31997 b->op->thread_boxes(sna, b->op, b->boxes, b->num_boxes);
31998 b->num_boxes = 0;
32001 - do {
32002 - b->boxes[b->num_boxes].box = *box++;
32003 - b->boxes[b->num_boxes].alpha = alpha;
32004 - b->num_boxes++;
32005 - } while (--count);
32006 + b->boxes[b->num_boxes].box = *box++;
32007 + b->boxes[b->num_boxes].alpha = alpha;
32008 + b->num_boxes++;
32009 assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES);
32012 @@ -1722,8 +1728,22 @@ span_thread_box(struct sna *sna,
32013 const BoxRec *box,
32014 int coverage)
32016 + struct span_thread_boxes *b = (struct span_thread_boxes *)op;
32018 __DBG(("%s: %d -> %d @ %d\n", __FUNCTION__, box->x1, box->x2, coverage));
32019 - span_thread_add_boxes(sna, op, box, 1, AREA_TO_ALPHA(coverage));
32020 + if (b->num_boxes) {
32021 + struct sna_opacity_box *bb = &b->boxes[b->num_boxes-1];
32022 + if (bb->box.x1 == box->x1 &&
32023 + bb->box.x2 == box->x2 &&
32024 + bb->box.y2 == box->y1 &&
32025 + bb->alpha == AREA_TO_ALPHA(coverage)) {
32026 + bb->box.y2 = box->y2;
32027 + __DBG(("%s: contracted double row: %d -> %d\n", __func__, bb->box.y1, bb->box.y2));
32028 + return;
32029 + }
32030 + }
32032 + span_thread_add_box(sna, op, box, AREA_TO_ALPHA(coverage));
32035 static void
32036 @@ -1733,20 +1753,28 @@ span_thread_clipped_box(struct sna *sna,
32037 const BoxRec *box,
32038 int coverage)
32040 - pixman_region16_t region;
32041 + struct span_thread_boxes *b = (struct span_thread_boxes *)op;
32042 + const BoxRec *c;
32044 __DBG(("%s: %d -> %d @ %f\n", __FUNCTION__, box->x1, box->x2,
32045 AREA_TO_ALPHA(coverage)));
32047 - pixman_region_init_rects(&region, box, 1);
32048 - RegionIntersect(&region, &region, clip);
32049 - if (region_num_rects(&region)) {
32050 - span_thread_add_boxes(sna, op,
32051 - region_rects(&region),
32052 - region_num_rects(&region),
32053 - AREA_TO_ALPHA(coverage));
32054 + b->clip_start =
32055 + find_clip_box_for_y(b->clip_start, b->clip_end, box->y1);
32057 + c = b->clip_start;
32058 + while (c != b->clip_end) {
32059 + BoxRec clipped;
32061 + if (box->y2 <= c->y1)
32062 + break;
32064 + clipped = *box;
32065 + if (!box_intersect(&clipped, c++))
32066 + continue;
32068 + span_thread_add_box(sna, op, &clipped, AREA_TO_ALPHA(coverage));
32070 - pixman_region_fini(&region);
32073 static span_func_t
32074 @@ -1777,6 +1805,16 @@ thread_choose_span(struct sna_composite_spans_op *tmp,
32075 return span;
32078 +inline static void
32079 +span_thread_boxes_init(struct span_thread_boxes *boxes,
32080 + const struct sna_composite_spans_op *op,
32081 + const RegionRec *clip)
32082 +{
32083 + boxes->op = op;
32084 + region_get_boxes(clip, &boxes->clip_start, &boxes->clip_end);
32085 + boxes->num_boxes = 0;
32086 +}
32088 static void
32089 span_thread(void *arg)
32091 @@ -1789,8 +1827,7 @@ span_thread(void *arg)
32092 if (!tor_init(&tor, &thread->extents, 2*thread->ntrap))
32093 return;
32095 - boxes.op = thread->op;
32096 - boxes.num_boxes = 0;
32097 + span_thread_boxes_init(&boxes, thread->op, thread->clip);
32099 y1 = thread->extents.y1 - thread->draw_y;
32100 y2 = thread->extents.y2 - thread->draw_y;
32101 @@ -2190,6 +2227,52 @@ static void _tor_blt_src(struct inplace *in, const BoxRec *box, uint8_t v)
32102 } while (--h);
32105 +struct clipped_span {
32106 + span_func_t span;
32107 + const BoxRec *clip_start, *clip_end;
32108 +};
32110 +static void
32111 +tor_blt_clipped(struct sna *sna,
32112 + struct sna_composite_spans_op *op,
32113 + pixman_region16_t *clip,
32114 + const BoxRec *box,
32115 + int coverage)
32116 +{
32117 + struct clipped_span *cs = (struct clipped_span *)clip;
32118 + const BoxRec *c;
32120 + cs->clip_start =
32121 + find_clip_box_for_y(cs->clip_start, cs->clip_end, box->y1);
32123 + c = cs->clip_start;
32124 + while (c != cs->clip_end) {
32125 + BoxRec clipped;
32127 + if (box->y2 <= c->y1)
32128 + break;
32130 + clipped = *box;
32131 + if (!box_intersect(&clipped, c++))
32132 + continue;
32134 + cs->span(sna, op, NULL, &clipped, coverage);
32135 + }
32136 +}
32138 +inline static span_func_t
32139 +clipped_span(struct clipped_span *cs,
32140 + span_func_t span,
32141 + const RegionRec *clip)
32142 +{
32143 + if (clip->data) {
32144 + cs->span = span;
32145 + region_get_boxes(clip, &cs->clip_start, &cs->clip_end);
32146 + span = tor_blt_clipped;
32147 + }
32148 + return span;
32149 +}
32151 static void
32152 tor_blt_src(struct sna *sna,
32153 struct sna_composite_spans_op *op,
32154 @@ -2203,25 +2286,6 @@ tor_blt_src(struct sna *sna,
32157 static void
32158 -tor_blt_src_clipped(struct sna *sna,
32159 - struct sna_composite_spans_op *op,
32160 - pixman_region16_t *clip,
32161 - const BoxRec *box,
32162 - int coverage)
32163 -{
32164 - pixman_region16_t region;
32165 - int n;
32167 - pixman_region_init_rects(&region, box, 1);
32168 - RegionIntersect(&region, &region, clip);
32169 - n = region_num_rects(&region);
32170 - box = region_rects(&region);
32171 - while (n--)
32172 - tor_blt_src(sna, op, NULL, box++, coverage);
32173 - pixman_region_fini(&region);
32174 -}
32176 -static void
32177 tor_blt_in(struct sna *sna,
32178 struct sna_composite_spans_op *op,
32179 pixman_region16_t *clip,
32180 @@ -2253,25 +2317,6 @@ tor_blt_in(struct sna *sna,
32183 static void
32184 -tor_blt_in_clipped(struct sna *sna,
32185 - struct sna_composite_spans_op *op,
32186 - pixman_region16_t *clip,
32187 - const BoxRec *box,
32188 - int coverage)
32189 -{
32190 - pixman_region16_t region;
32191 - int n;
32193 - pixman_region_init_rects(&region, box, 1);
32194 - RegionIntersect(&region, &region, clip);
32195 - n = region_num_rects(&region);
32196 - box = region_rects(&region);
32197 - while (n--)
32198 - tor_blt_in(sna, op, NULL, box++, coverage);
32199 - pixman_region_fini(&region);
32200 -}
32202 -static void
32203 tor_blt_add(struct sna *sna,
32204 struct sna_composite_spans_op *op,
32205 pixman_region16_t *clip,
32206 @@ -2310,25 +2355,6 @@ tor_blt_add(struct sna *sna,
32209 static void
32210 -tor_blt_add_clipped(struct sna *sna,
32211 - struct sna_composite_spans_op *op,
32212 - pixman_region16_t *clip,
32213 - const BoxRec *box,
32214 - int coverage)
32215 -{
32216 - pixman_region16_t region;
32217 - int n;
32219 - pixman_region_init_rects(&region, box, 1);
32220 - RegionIntersect(&region, &region, clip);
32221 - n = region_num_rects(&region);
32222 - box = region_rects(&region);
32223 - while (n--)
32224 - tor_blt_add(sna, op, NULL, box++, coverage);
32225 - pixman_region_fini(&region);
32226 -}
32228 -static void
32229 tor_blt_lerp32(struct sna *sna,
32230 struct sna_composite_spans_op *op,
32231 pixman_region16_t *clip,
32232 @@ -2343,6 +2369,7 @@ tor_blt_lerp32(struct sna *sna,
32233 if (coverage == 0)
32234 return;
32236 + sigtrap_assert_active();
32237 ptr += box->y1 * stride + box->x1;
32239 h = box->y2 - box->y1;
32240 @@ -2383,25 +2410,6 @@ tor_blt_lerp32(struct sna *sna,
32244 -static void
32245 -tor_blt_lerp32_clipped(struct sna *sna,
32246 - struct sna_composite_spans_op *op,
32247 - pixman_region16_t *clip,
32248 - const BoxRec *box,
32249 - int coverage)
32250 -{
32251 - pixman_region16_t region;
32252 - int n;
32254 - pixman_region_init_rects(&region, box, 1);
32255 - RegionIntersect(&region, &region, clip);
32256 - n = region_num_rects(&region);
32257 - box = region_rects(&region);
32258 - while (n--)
32259 - tor_blt_lerp32(sna, op, NULL, box++, coverage);
32260 - pixman_region_fini(&region);
32261 -}
32263 struct pixman_inplace {
32264 pixman_image_t *image, *source, *mask;
32265 uint32_t color;
32266 @@ -2431,24 +2439,6 @@ pixmask_span_solid(struct sna *sna,
32267 pi->dx + box->x1, pi->dy + box->y1,
32268 box->x2 - box->x1, box->y2 - box->y1);
32270 -static void
32271 -pixmask_span_solid__clipped(struct sna *sna,
32272 - struct sna_composite_spans_op *op,
32273 - pixman_region16_t *clip,
32274 - const BoxRec *box,
32275 - int coverage)
32276 -{
32277 - pixman_region16_t region;
32278 - int n;
32280 - pixman_region_init_rects(&region, box, 1);
32281 - RegionIntersect(&region, &region, clip);
32282 - n = region_num_rects(&region);
32283 - box = region_rects(&region);
32284 - while (n--)
32285 - pixmask_span_solid(sna, op, NULL, box++, coverage);
32286 - pixman_region_fini(&region);
32287 -}
32289 static void
32290 pixmask_span(struct sna *sna,
32291 @@ -2471,24 +2461,6 @@ pixmask_span(struct sna *sna,
32292 pi->dx + box->x1, pi->dy + box->y1,
32293 box->x2 - box->x1, box->y2 - box->y1);
32295 -static void
32296 -pixmask_span__clipped(struct sna *sna,
32297 - struct sna_composite_spans_op *op,
32298 - pixman_region16_t *clip,
32299 - const BoxRec *box,
32300 - int coverage)
32301 -{
32302 - pixman_region16_t region;
32303 - int n;
32305 - pixman_region_init_rects(&region, box, 1);
32306 - RegionIntersect(&region, &region, clip);
32307 - n = region_num_rects(&region);
32308 - box = region_rects(&region);
32309 - while (n--)
32310 - pixmask_span(sna, op, NULL, box++, coverage);
32311 - pixman_region_fini(&region);
32312 -}
32314 struct inplace_x8r8g8b8_thread {
32315 xTrapezoid *traps;
32316 @@ -2507,6 +2479,7 @@ static void inplace_x8r8g8b8_thread(void *arg)
32317 struct inplace_x8r8g8b8_thread *thread = arg;
32318 struct tor tor;
32319 span_func_t span;
32320 + struct clipped_span clipped;
32321 RegionPtr clip;
32322 int y1, y2, n;
32324 @@ -2537,12 +2510,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
32325 inplace.stride = pixmap->devKind;
32326 inplace.color = thread->color;
32328 - if (clip->data)
32329 - span = tor_blt_lerp32_clipped;
32330 - else
32331 - span = tor_blt_lerp32;
32332 + span = clipped_span(&clipped, tor_blt_lerp32, clip);
32334 - tor_render(NULL, &tor, (void*)&inplace, clip, span, false);
32335 + tor_render(NULL, &tor,
32336 + (void*)&inplace, (void*)&clipped,
32337 + span, false);
32338 } else if (thread->is_solid) {
32339 struct pixman_inplace pi;
32341 @@ -2555,12 +2527,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
32342 1, 1, pi.bits, 0);
32343 pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
32345 - if (clip->data)
32346 - span = pixmask_span_solid__clipped;
32347 - else
32348 - span = pixmask_span_solid;
32349 + span = clipped_span(&clipped, pixmask_span_solid, clip);
32351 - tor_render(NULL, &tor, (void*)&pi, clip, span, false);
32352 + tor_render(NULL, &tor,
32353 + (void*)&pi, (void *)&clipped,
32354 + span, false);
32356 pixman_image_unref(pi.source);
32357 pixman_image_unref(pi.image);
32358 @@ -2579,12 +2550,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
32359 pi.bits = pixman_image_get_data(pi.mask);
32360 pi.op = thread->op;
32362 - if (clip->data)
32363 - span = pixmask_span__clipped;
32364 - else
32365 - span = pixmask_span;
32366 + span = clipped_span(&clipped, pixmask_span, clip);
32368 - tor_render(NULL, &tor, (void*)&pi, clip, span, false);
32369 + tor_render(NULL, &tor,
32370 + (void*)&pi, (void *)&clipped,
32371 + span, false);
32373 pixman_image_unref(pi.mask);
32374 pixman_image_unref(pi.source);
32375 @@ -2698,6 +2668,7 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
32376 if (num_threads == 1) {
32377 struct tor tor;
32378 span_func_t span;
32379 + struct clipped_span clipped;
32381 if (!tor_init(&tor, &region.extents, 2*ntrap))
32382 return true;
32383 @@ -2723,17 +2694,15 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
32384 inplace.stride = pixmap->devKind;
32385 inplace.color = color;
32387 - if (dst->pCompositeClip->data)
32388 - span = tor_blt_lerp32_clipped;
32389 - else
32390 - span = tor_blt_lerp32;
32391 + span = clipped_span(&clipped, tor_blt_lerp32, dst->pCompositeClip);
32393 DBG(("%s: render inplace op=%d, color=%08x\n",
32394 __FUNCTION__, op, color));
32396 if (sigtrap_get() == 0) {
32397 - tor_render(NULL, &tor, (void*)&inplace,
32398 - dst->pCompositeClip, span, false);
32399 + tor_render(NULL, &tor,
32400 + (void*)&inplace, (void*)&clipped,
32401 + span, false);
32402 sigtrap_put();
32404 } else if (is_solid) {
32405 @@ -2748,15 +2717,12 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
32406 1, 1, pi.bits, 0);
32407 pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
32409 - if (dst->pCompositeClip->data)
32410 - span = pixmask_span_solid__clipped;
32411 - else
32412 - span = pixmask_span_solid;
32413 + span = clipped_span(&clipped, pixmask_span_solid, dst->pCompositeClip);
32415 if (sigtrap_get() == 0) {
32416 - tor_render(NULL, &tor, (void*)&pi,
32417 - dst->pCompositeClip, span,
32418 - false);
32419 + tor_render(NULL, &tor,
32420 + (void*)&pi, (void*)&clipped,
32421 + span, false);
32422 sigtrap_put();
32425 @@ -2777,15 +2743,12 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
32426 pi.bits = pixman_image_get_data(pi.mask);
32427 pi.op = op;
32429 - if (dst->pCompositeClip->data)
32430 - span = pixmask_span__clipped;
32431 - else
32432 - span = pixmask_span;
32433 + span = clipped_span(&clipped, pixmask_span, dst->pCompositeClip);
32435 if (sigtrap_get() == 0) {
32436 - tor_render(NULL, &tor, (void*)&pi,
32437 - dst->pCompositeClip, span,
32438 - false);
32439 + tor_render(NULL, &tor,
32440 + (void*)&pi, (void*)&clipped,
32441 + span, false);
32442 sigtrap_put();
32445 @@ -2847,9 +2810,9 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
32447 struct inplace_thread {
32448 xTrapezoid *traps;
32449 - RegionPtr clip;
32450 span_func_t span;
32451 struct inplace inplace;
32452 + struct clipped_span clipped;
32453 BoxRec extents;
32454 int dx, dy;
32455 int draw_x, draw_y;
32456 @@ -2874,8 +2837,9 @@ static void inplace_thread(void *arg)
32457 tor_add_trapezoid(&tor, &thread->traps[n], thread->dx, thread->dy);
32460 - tor_render(NULL, &tor, (void*)&thread->inplace,
32461 - thread->clip, thread->span, thread->unbounded);
32462 + tor_render(NULL, &tor,
32463 + (void*)&thread->inplace, (void*)&thread->clipped,
32464 + thread->span, thread->unbounded);
32466 tor_fini(&tor);
32468 @@ -2889,6 +2853,7 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
32469 bool fallback)
32471 struct inplace inplace;
32472 + struct clipped_span clipped;
32473 span_func_t span;
32474 PixmapPtr pixmap;
32475 struct sna_pixmap *priv;
32476 @@ -3005,21 +2970,12 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
32477 region.extents.x2, region.extents.y2));
32479 if (op == PictOpSrc) {
32480 - if (dst->pCompositeClip->data)
32481 - span = tor_blt_src_clipped;
32482 - else
32483 - span = tor_blt_src;
32484 + span = tor_blt_src;
32485 } else if (op == PictOpIn) {
32486 - if (dst->pCompositeClip->data)
32487 - span = tor_blt_in_clipped;
32488 - else
32489 - span = tor_blt_in;
32490 + span = tor_blt_in;
32491 } else {
32492 assert(op == PictOpAdd);
32493 - if (dst->pCompositeClip->data)
32494 - span = tor_blt_add_clipped;
32495 - else
32496 - span = tor_blt_add;
32497 + span = tor_blt_add;
32500 DBG(("%s: move-to-cpu\n", __FUNCTION__));
32501 @@ -3037,6 +2993,8 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
32502 inplace.stride = pixmap->devKind;
32503 inplace.opacity = color >> 24;
32505 + span = clipped_span(&clipped, span, dst->pCompositeClip);
32507 num_threads = 1;
32508 if ((flags & COMPOSITE_SPANS_RECTILINEAR) == 0)
32509 num_threads = sna_use_threads(region.extents.x2 - region.extents.x1,
32510 @@ -3057,8 +3015,9 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
32513 if (sigtrap_get() == 0) {
32514 - tor_render(NULL, &tor, (void*)&inplace,
32515 - dst->pCompositeClip, span, unbounded);
32516 + tor_render(NULL, &tor,
32517 + (void*)&inplace, (void *)&clipped,
32518 + span, unbounded);
32519 sigtrap_put();
32522 @@ -3075,8 +3034,8 @@ imprecise_trapezoid_span_inplace(struct sna *sna,
32523 threads[0].traps = traps;
32524 threads[0].ntrap = ntrap;
32525 threads[0].inplace = inplace;
32526 + threads[0].clipped = clipped;
32527 threads[0].extents = region.extents;
32528 - threads[0].clip = dst->pCompositeClip;
32529 threads[0].span = span;
32530 threads[0].unbounded = unbounded;
32531 threads[0].dx = dx;
32532 @@ -3707,8 +3666,7 @@ tristrip_thread(void *arg)
32533 if (!tor_init(&tor, &thread->extents, 2*thread->count))
32534 return;
32536 - boxes.op = thread->op;
32537 - boxes.num_boxes = 0;
32538 + span_thread_boxes_init(&boxes, thread->op, thread->clip);
32540 cw = 0; ccw = 1;
32541 polygon_add_line(tor.polygon,
32542 @@ -3874,7 +3832,7 @@ imprecise_tristrip_span_converter(struct sna *sna,
32543 break;
32544 } while (1);
32545 polygon_add_line(tor.polygon,
32546 - &points[cw], &points[2+ccw],
32547 + &points[cw], &points[ccw],
32548 dx, dy);
32549 assert(tor.polygon->num_edges <= 2*count);
32551 diff --git a/src/sna/sna_trapezoids_mono.c b/src/sna/sna_trapezoids_mono.c
32552 index 808703a9..07a7867d 100644
32553 --- a/src/sna/sna_trapezoids_mono.c
32554 +++ b/src/sna/sna_trapezoids_mono.c
32555 @@ -72,13 +72,14 @@ struct mono {
32556 struct sna *sna;
32557 struct sna_composite_op op;
32558 pixman_region16_t clip;
32559 + const BoxRec *clip_start, *clip_end;
32561 fastcall void (*span)(struct mono *, int, int, BoxPtr);
32563 struct mono_polygon polygon;
32564 };
32566 -#define I(x) pixman_fixed_to_int ((x) + pixman_fixed_1_minus_e/2)
32567 +#define I(x) pixman_fixed_to_int((x) + pixman_fixed_1_minus_e/2)
32569 static struct quorem
32570 floored_muldivrem(int32_t x, int32_t a, int32_t b)
32571 @@ -249,22 +250,22 @@ mono_add_line(struct mono *mono,
32573 e->dxdy = floored_muldivrem(dx, pixman_fixed_1, dy);
32575 - e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1_minus_e/2 - p1->y,
32576 + e->x = floored_muldivrem((ytop - dst_y) * pixman_fixed_1 + pixman_fixed_1/2 - p1->y,
32577 dx, dy);
32578 e->x.quo += p1->x;
32579 e->x.rem -= dy;
32581 e->dy = dy;
32583 - __DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n",
32584 - __FUNCTION__,
32585 - I(e->x.quo), e->x.quo, e->x.rem, e->dy,
32586 - e->dxdy.quo, e->dxdy.rem, e->dy));
32588 e->x.quo += dst_x*pixman_fixed_1;
32589 + __DBG(("%s: initial x=%d [%d.%d/%d] + dxdy=%d.%d/%d\n",
32590 + __FUNCTION__,
32591 + I(e->x.quo), e->x.quo, e->x.rem, e->dy,
32592 + e->dxdy.quo, e->dxdy.rem, e->dy));
32595 struct mono_edge **ptail = &polygon->y_buckets[ytop - mono->clip.extents.y1];
32596 + assert(ytop - mono->clip.extents.y1 < mono->clip.extents.y2 - mono->clip.extents.y1);
32597 if (*ptail)
32598 (*ptail)->prev = e;
32599 e->next = *ptail;
32600 @@ -368,6 +369,10 @@ static struct mono_edge *mono_filter(struct mono_edge *edges)
32601 e->x.rem == n->x.rem &&
32602 e->dxdy.quo == n->dxdy.quo &&
32603 e->dxdy.rem == n->dxdy.rem) {
32604 + assert(e->dy == n->dy);
32605 + __DBG(("%s: discarding cancellation pair (%d.%d) + (%d.%d)\n",
32606 + __FUNCTION__, e->x.quo, e->x.rem, e->dxdy.quo, e->dxdy.rem));
32608 if (e->prev)
32609 e->prev->next = n->next;
32610 else
32611 @@ -378,8 +383,11 @@ static struct mono_edge *mono_filter(struct mono_edge *edges)
32612 break;
32614 e = n->next;
32615 - } else
32616 + } else {
32617 + __DBG(("%s: adding edge (%d.%d) + (%d.%d)/%d, height=%d\n",
32618 + __FUNCTION__, n->x.quo, n->x.rem, n->dxdy.quo, n->dxdy.rem, n->dy, n->height_left));
32619 e = n;
32620 + }
32623 return edges;
32624 @@ -474,6 +482,34 @@ mono_span__fast(struct mono *c, int x1, int x2, BoxPtr box)
32625 c->op.box(c->sna, &c->op, box);
32628 +fastcall static void
32629 +mono_span__clipped(struct mono *c, int x1, int x2, BoxPtr box)
32630 +{
32631 + const BoxRec *b;
32633 + __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2));
32635 + c->clip_start =
32636 + find_clip_box_for_y(c->clip_start, c->clip_end, box->y1);
32638 + b = c->clip_start;
32639 + while (b != c->clip_end) {
32640 + BoxRec clipped;
32642 + if (box->y2 <= b->y1)
32643 + break;
32645 + clipped.x1 = x1;
32646 + clipped.x2 = x2;
32647 + clipped.y1 = box->y1;
32648 + clipped.y2 = box->y2;
32649 + if (!box_intersect(&clipped, b++))
32650 + continue;
32652 + c->op.box(c->sna, &c->op, &clipped);
32653 + }
32654 +}
32656 struct mono_span_thread_boxes {
32657 const struct sna_composite_op *op;
32658 #define MONO_SPAN_MAX_BOXES (8192/sizeof(BoxRec))
32659 @@ -482,40 +518,45 @@ struct mono_span_thread_boxes {
32660 };
32662 inline static void
32663 -thread_mono_span_add_boxes(struct mono *c, const BoxRec *box, int count)
32664 +thread_mono_span_add_box(struct mono *c, const BoxRec *box)
32666 struct mono_span_thread_boxes *b = c->op.priv;
32668 - assert(count > 0 && count <= MONO_SPAN_MAX_BOXES);
32669 - if (unlikely(b->num_boxes + count > MONO_SPAN_MAX_BOXES)) {
32670 + if (unlikely(b->num_boxes == MONO_SPAN_MAX_BOXES)) {
32671 b->op->thread_boxes(c->sna, b->op, b->boxes, b->num_boxes);
32672 b->num_boxes = 0;
32675 - memcpy(b->boxes + b->num_boxes, box, count*sizeof(BoxRec));
32676 - b->num_boxes += count;
32677 + b->boxes[b->num_boxes++] = *box;
32678 assert(b->num_boxes <= MONO_SPAN_MAX_BOXES);
32681 fastcall static void
32682 thread_mono_span_clipped(struct mono *c, int x1, int x2, BoxPtr box)
32684 - pixman_region16_t region;
32685 + const BoxRec *b;
32687 __DBG(("%s [%d, %d]\n", __FUNCTION__, x1, x2));
32689 - box->x1 = x1;
32690 - box->x2 = x2;
32691 + c->clip_start =
32692 + find_clip_box_for_y(c->clip_start, c->clip_end, box->y1);
32694 - assert(c->clip.data);
32695 + b = c->clip_start;
32696 + while (b != c->clip_end) {
32697 + BoxRec clipped;
32699 + if (box->y2 <= b->y1)
32700 + break;
32702 + clipped.x1 = x1;
32703 + clipped.x2 = x2;
32704 + clipped.y1 = box->y1;
32705 + clipped.y2 = box->y2;
32706 + if (!box_intersect(&clipped, b++))
32707 + continue;
32709 - pixman_region_init_rects(&region, box, 1);
32710 - RegionIntersect(&region, &region, &c->clip);
32711 - if (region_num_rects(&region))
32712 - thread_mono_span_add_boxes(c,
32713 - region_rects(&region),
32714 - region_num_rects(&region));
32715 - pixman_region_fini(&region);
32716 + thread_mono_span_add_box(c, &clipped);
32717 + }
32720 fastcall static void
32721 @@ -525,7 +566,7 @@ thread_mono_span(struct mono *c, int x1, int x2, BoxPtr box)
32723 box->x1 = x1;
32724 box->x2 = x2;
32725 - thread_mono_span_add_boxes(c, box, 1);
32726 + thread_mono_span_add_box(c, box);
32729 inline static void
32730 @@ -537,6 +578,8 @@ mono_row(struct mono *c, int16_t y, int16_t h)
32731 int winding = 0;
32732 BoxRec box;
32734 + __DBG(("%s: y=%d, h=%d\n", __FUNCTION__, y, h));
32736 DBG_MONO_EDGES(edge);
32737 VALIDATE_MONO_EDGES(&c->head);
32739 @@ -547,6 +590,8 @@ mono_row(struct mono *c, int16_t y, int16_t h)
32740 struct mono_edge *next = edge->next;
32741 int16_t xend = I(edge->x.quo);
32743 + __DBG(("%s: adding edge dir=%d [winding=%d], x=%d [%d]\n",
32744 + __FUNCTION__, edge->dir, winding + edge->dir, xend, edge->x.quo));
32745 if (--edge->height_left) {
32746 if (edge->dy) {
32747 edge->x.quo += edge->dxdy.quo;
32748 @@ -555,6 +600,8 @@ mono_row(struct mono *c, int16_t y, int16_t h)
32749 ++edge->x.quo;
32750 edge->x.rem -= edge->dy;
32752 + __DBG(("%s: stepped edge (%d.%d) + (%d.%d)/%d, height=%d, prev_x=%d\n",
32753 + __FUNCTION__, edge->x.quo, edge->x.rem, edge->dxdy.quo, edge->dxdy.rem, edge->dy, edge->height_left, edge->x.quo));
32756 if (edge->x.quo < prev_x) {
32757 @@ -578,17 +625,22 @@ mono_row(struct mono *c, int16_t y, int16_t h)
32758 winding += edge->dir;
32759 if (winding == 0) {
32760 assert(I(next->x.quo) >= xend);
32761 - if (I(next->x.quo) > xend + 1) {
32762 + if (I(next->x.quo) > xend) {
32763 + __DBG(("%s: end span: %d\n", __FUNCTION__, xend));
32764 if (xstart < c->clip.extents.x1)
32765 xstart = c->clip.extents.x1;
32766 if (xend > c->clip.extents.x2)
32767 xend = c->clip.extents.x2;
32768 - if (xend > xstart)
32769 + if (xend > xstart) {
32770 + __DBG(("%s: emit span [%d, %d]\n", __FUNCTION__, xstart, xend));
32771 c->span(c, xstart, xend, &box);
32772 + }
32773 xstart = INT16_MIN;
32775 - } else if (xstart == INT16_MIN)
32776 + } else if (xstart == INT16_MIN) {
32777 + __DBG(("%s: starting new span: %d\n", __FUNCTION__, xend));
32778 xstart = xend;
32779 + }
32781 edge = next;
32783 @@ -650,9 +702,14 @@ mono_render(struct mono *mono)
32784 for (i = 0; i < h; i = j) {
32785 j = i + 1;
32787 + __DBG(("%s: row=%d, new edges? %d\n", __FUNCTION__,
32788 + i, polygon->y_buckets[i] != NULL));
32790 if (polygon->y_buckets[i])
32791 mono_merge_edges(mono, polygon->y_buckets[i]);
32793 + __DBG(("%s: row=%d, vertical? %d\n", __FUNCTION__,
32794 + i, mono->is_vertical));
32795 if (mono->is_vertical) {
32796 struct mono_edge *e = mono->head.next;
32797 int min_height = h - i;
32798 @@ -667,6 +724,7 @@ mono_render(struct mono *mono)
32799 j++;
32800 if (j != i + 1)
32801 mono_step_edges(mono, j - (i + 1));
32802 + __DBG(("%s: %d vertical rows\n", __FUNCTION__, j-i));
32805 mono_row(mono, i, j-i);
32806 @@ -717,6 +775,7 @@ mono_span_thread(void *arg)
32807 if (RegionNil(&mono.clip))
32808 return;
32810 + region_get_boxes(&mono.clip, &mono.clip_start, &mono.clip_end);
32812 boxes.op = thread->op;
32813 boxes.num_boxes = 0;
32814 @@ -891,9 +950,12 @@ mono_trapezoids_span_converter(struct sna *sna,
32816 if (mono.clip.data == NULL && mono.op.damage == NULL)
32817 mono.span = mono_span__fast;
32818 + else if (mono.clip.data != NULL && mono.op.damage == NULL)
32819 + mono.span = mono_span__clipped;
32820 else
32821 mono.span = mono_span;
32823 + region_get_boxes(&mono.clip, &mono.clip_start, &mono.clip_end);
32824 mono_render(&mono);
32825 mono.op.done(mono.sna, &mono.op);
32826 mono_fini(&mono);
32827 @@ -939,6 +1001,7 @@ mono_trapezoids_span_converter(struct sna *sna,
32828 mono.clip.extents.x2 - mono.clip.extents.x1,
32829 mono.clip.extents.y2 - mono.clip.extents.y1,
32830 COMPOSITE_PARTIAL, memset(&mono.op, 0, sizeof(mono.op)))) {
32831 + region_get_boxes(&mono.clip, &mono.clip_start, &mono.clip_end);
32832 mono_render(&mono);
32833 mono.op.done(mono.sna, &mono.op);
32835 @@ -974,6 +1037,7 @@ mono_inplace_fill_box(struct sna *sna,
32836 box->x2 - box->x1,
32837 box->y2 - box->y1,
32838 fill->color));
32839 + sigtrap_assert_active();
32840 pixman_fill(fill->data, fill->stride, fill->bpp,
32841 box->x1, box->y1,
32842 box->x2 - box->x1,
32843 @@ -995,6 +1059,7 @@ mono_inplace_fill_boxes(struct sna *sna,
32844 box->x2 - box->x1,
32845 box->y2 - box->y1,
32846 fill->color));
32847 + sigtrap_assert_active();
32848 pixman_fill(fill->data, fill->stride, fill->bpp,
32849 box->x1, box->y1,
32850 box->x2 - box->x1,
32851 @@ -1382,10 +1447,13 @@ mono_triangles_span_converter(struct sna *sna,
32852 mono_render(&mono);
32853 mono.op.done(mono.sna, &mono.op);
32855 + mono_fini(&mono);
32857 if (!was_clear && !operator_is_bounded(op)) {
32858 xPointFixed p1, p2;
32860 + DBG(("%s: performing unbounded clear\n", __FUNCTION__));
32862 if (!mono_init(&mono, 2+3*count))
32863 return false;
32865 @@ -1431,7 +1499,6 @@ mono_triangles_span_converter(struct sna *sna,
32866 mono_fini(&mono);
32869 - mono_fini(&mono);
32870 REGION_UNINIT(NULL, &mono.clip);
32871 return true;
32873 diff --git a/src/sna/sna_trapezoids_precise.c b/src/sna/sna_trapezoids_precise.c
32874 index 9187ab48..242b4acb 100644
32875 --- a/src/sna/sna_trapezoids_precise.c
32876 +++ b/src/sna/sna_trapezoids_precise.c
32877 @@ -1023,6 +1023,16 @@ tor_init(struct tor *converter, const BoxRec *box, int num_edges)
32878 static void
32879 tor_add_trapezoid(struct tor *tor, const xTrapezoid *t, int dx, int dy)
32881 + if (!xTrapezoidValid(t)) {
32882 + __DBG(("%s: skipping invalid trapezoid: top=%d, bottom=%d, left=(%d, %d), (%d, %d), right=(%d, %d), (%d, %d)\n",
32883 + __FUNCTION__,
32884 + t->top, t->bottom,
32885 + t->left.p1.x, t->left.p1.y,
32886 + t->left.p2.x, t->left.p2.y,
32887 + t->right.p1.x, t->right.p1.y,
32888 + t->right.p2.x, t->right.p2.y));
32889 + return;
32890 + }
32891 polygon_add_edge(tor->polygon, t, &t->left, 1, dx, dy);
32892 polygon_add_edge(tor->polygon, t, &t->right, -1, dx, dy);
32894 @@ -1635,31 +1645,27 @@ struct span_thread {
32895 #define SPAN_THREAD_MAX_BOXES (8192/sizeof(struct sna_opacity_box))
32896 struct span_thread_boxes {
32897 const struct sna_composite_spans_op *op;
32898 + const BoxRec *clip_start, *clip_end;
32899 int num_boxes;
32900 struct sna_opacity_box boxes[SPAN_THREAD_MAX_BOXES];
32901 };
32903 -static void span_thread_add_boxes(struct sna *sna, void *data,
32904 - const BoxRec *box, int count, float alpha)
32905 +static void span_thread_add_box(struct sna *sna, void *data,
32906 + const BoxRec *box, float alpha)
32908 struct span_thread_boxes *b = data;
32910 - __DBG(("%s: adding %d boxes with alpha=%f\n",
32911 - __FUNCTION__, count, alpha));
32912 + __DBG(("%s: adding box with alpha=%f\n", __FUNCTION__, alpha));
32914 - assert(count > 0 && count <= SPAN_THREAD_MAX_BOXES);
32915 - if (unlikely(b->num_boxes + count > SPAN_THREAD_MAX_BOXES)) {
32916 - DBG(("%s: flushing %d boxes, adding %d\n", __FUNCTION__, b->num_boxes, count));
32917 - assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES);
32918 + if (unlikely(b->num_boxes == SPAN_THREAD_MAX_BOXES)) {
32919 + DBG(("%s: flushing %d boxes\n", __FUNCTION__, b->num_boxes));
32920 b->op->thread_boxes(sna, b->op, b->boxes, b->num_boxes);
32921 b->num_boxes = 0;
32924 - do {
32925 - b->boxes[b->num_boxes].box = *box++;
32926 - b->boxes[b->num_boxes].alpha = alpha;
32927 - b->num_boxes++;
32928 - } while (--count);
32929 + b->boxes[b->num_boxes].box = *box++;
32930 + b->boxes[b->num_boxes].alpha = alpha;
32931 + b->num_boxes++;
32932 assert(b->num_boxes <= SPAN_THREAD_MAX_BOXES);
32935 @@ -1670,8 +1676,22 @@ span_thread_box(struct sna *sna,
32936 const BoxRec *box,
32937 int coverage)
32939 + struct span_thread_boxes *b = (struct span_thread_boxes *)op;
32941 __DBG(("%s: %d -> %d @ %d\n", __FUNCTION__, box->x1, box->x2, coverage));
32942 - span_thread_add_boxes(sna, op, box, 1, AREA_TO_FLOAT(coverage));
32943 + if (b->num_boxes) {
32944 + struct sna_opacity_box *bb = &b->boxes[b->num_boxes-1];
32945 + if (bb->box.x1 == box->x1 &&
32946 + bb->box.x2 == box->x2 &&
32947 + bb->box.y2 == box->y1 &&
32948 + bb->alpha == AREA_TO_FLOAT(coverage)) {
32949 + bb->box.y2 = box->y2;
32950 + __DBG(("%s: contracted double row: %d -> %d\n", __func__, bb->box.y1, bb->box.y2));
32951 + return;
32952 + }
32953 + }
32955 + span_thread_add_box(sna, op, box, AREA_TO_FLOAT(coverage));
32958 static void
32959 @@ -1681,20 +1701,28 @@ span_thread_clipped_box(struct sna *sna,
32960 const BoxRec *box,
32961 int coverage)
32963 - pixman_region16_t region;
32964 + struct span_thread_boxes *b = (struct span_thread_boxes *)op;
32965 + const BoxRec *c;
32967 __DBG(("%s: %d -> %d @ %f\n", __FUNCTION__, box->x1, box->x2,
32968 AREA_TO_FLOAT(coverage)));
32970 - pixman_region_init_rects(&region, box, 1);
32971 - RegionIntersect(&region, &region, clip);
32972 - if (region_num_rects(&region)) {
32973 - span_thread_add_boxes(sna, op,
32974 - region_rects(&region),
32975 - region_num_rects(&region),
32976 - AREA_TO_FLOAT(coverage));
32977 + b->clip_start =
32978 + find_clip_box_for_y(b->clip_start, b->clip_end, box->y1);
32980 + c = b->clip_start;
32981 + while (c != b->clip_end) {
32982 + BoxRec clipped;
32984 + if (box->y2 <= c->y1)
32985 + break;
32987 + clipped = *box;
32988 + if (!box_intersect(&clipped, c++))
32989 + continue;
32991 + span_thread_add_box(sna, op, &clipped, AREA_TO_FLOAT(coverage));
32993 - pixman_region_fini(&region);
32996 static span_func_t
32997 @@ -1712,7 +1740,7 @@ thread_choose_span(struct sna_composite_spans_op *tmp,
32999 assert(!is_mono(dst, maskFormat));
33000 assert(tmp->thread_boxes);
33001 - DBG(("%s: clipped? %d\n", __FUNCTION__, clip->data != NULL));
33002 + DBG(("%s: clipped? %d x %d\n", __FUNCTION__, clip->data != NULL, region_num_rects(clip)));
33003 if (clip->data)
33004 span = span_thread_clipped_box;
33005 else
33006 @@ -1721,6 +1749,17 @@ thread_choose_span(struct sna_composite_spans_op *tmp,
33007 return span;
33010 +inline static void
33011 +span_thread_boxes_init(struct span_thread_boxes *boxes,
33012 + const struct sna_composite_spans_op *op,
33013 + const RegionRec *clip)
33014 +{
33015 + boxes->op = op;
33016 + boxes->clip_start = region_rects(clip);
33017 + boxes->clip_end = boxes->clip_start + region_num_rects(clip);
33018 + boxes->num_boxes = 0;
33019 +}
33021 static void
33022 span_thread(void *arg)
33024 @@ -1733,8 +1772,7 @@ span_thread(void *arg)
33025 if (!tor_init(&tor, &thread->extents, 2*thread->ntrap))
33026 return;
33028 - boxes.op = thread->op;
33029 - boxes.num_boxes = 0;
33030 + span_thread_boxes_init(&boxes, thread->op, thread->clip);
33032 y1 = thread->extents.y1 - thread->draw_y;
33033 y2 = thread->extents.y2 - thread->draw_y;
33034 @@ -2183,6 +2221,52 @@ static force_inline uint8_t coverage_opacity(int coverage, uint8_t opacity)
33035 return opacity == 255 ? coverage : mul_8_8(coverage, opacity);
33038 +struct clipped_span {
33039 + span_func_t span;
33040 + const BoxRec *clip_start, *clip_end;
33041 +};
33043 +static void
33044 +tor_blt_clipped(struct sna *sna,
33045 + struct sna_composite_spans_op *op,
33046 + pixman_region16_t *clip,
33047 + const BoxRec *box,
33048 + int coverage)
33049 +{
33050 + struct clipped_span *cs = (struct clipped_span *)clip;
33051 + const BoxRec *c;
33053 + cs->clip_start =
33054 + find_clip_box_for_y(cs->clip_start, cs->clip_end, box->y1);
33056 + c = cs->clip_start;
33057 + while (c != cs->clip_end) {
33058 + BoxRec clipped;
33060 + if (box->y2 <= c->y1)
33061 + break;
33063 + clipped = *box;
33064 + if (!box_intersect(&clipped, c++))
33065 + continue;
33067 + cs->span(sna, op, NULL, &clipped, coverage);
33068 + }
33069 +}
33071 +inline static span_func_t
33072 +clipped_span(struct clipped_span *cs,
33073 + span_func_t span,
33074 + const RegionRec *clip)
33075 +{
33076 + if (clip->data) {
33077 + cs->span = span;
33078 + region_get_boxes(clip, &cs->clip_start, &cs->clip_end);
33079 + span = tor_blt_clipped;
33080 + }
33081 + return span;
33082 +}
33084 static void _tor_blt_src(struct inplace *in, const BoxRec *box, uint8_t v)
33086 uint8_t *ptr = in->ptr;
33087 @@ -2218,25 +2302,6 @@ tor_blt_src(struct sna *sna,
33090 static void
33091 -tor_blt_src_clipped(struct sna *sna,
33092 - struct sna_composite_spans_op *op,
33093 - pixman_region16_t *clip,
33094 - const BoxRec *box,
33095 - int coverage)
33096 -{
33097 - pixman_region16_t region;
33098 - int n;
33100 - pixman_region_init_rects(&region, box, 1);
33101 - RegionIntersect(&region, &region, clip);
33102 - n = region_num_rects(&region);
33103 - box = region_rects(&region);
33104 - while (n--)
33105 - tor_blt_src(sna, op, NULL, box++, coverage);
33106 - pixman_region_fini(&region);
33107 -}
33109 -static void
33110 tor_blt_in(struct sna *sna,
33111 struct sna_composite_spans_op *op,
33112 pixman_region16_t *clip,
33113 @@ -2268,25 +2333,6 @@ tor_blt_in(struct sna *sna,
33116 static void
33117 -tor_blt_in_clipped(struct sna *sna,
33118 - struct sna_composite_spans_op *op,
33119 - pixman_region16_t *clip,
33120 - const BoxRec *box,
33121 - int coverage)
33122 -{
33123 - pixman_region16_t region;
33124 - int n;
33126 - pixman_region_init_rects(&region, box, 1);
33127 - RegionIntersect(&region, &region, clip);
33128 - n = region_num_rects(&region);
33129 - box = region_rects(&region);
33130 - while (n--)
33131 - tor_blt_in(sna, op, NULL, box++, coverage);
33132 - pixman_region_fini(&region);
33133 -}
33135 -static void
33136 tor_blt_add(struct sna *sna,
33137 struct sna_composite_spans_op *op,
33138 pixman_region16_t *clip,
33139 @@ -2325,25 +2371,6 @@ tor_blt_add(struct sna *sna,
33142 static void
33143 -tor_blt_add_clipped(struct sna *sna,
33144 - struct sna_composite_spans_op *op,
33145 - pixman_region16_t *clip,
33146 - const BoxRec *box,
33147 - int coverage)
33148 -{
33149 - pixman_region16_t region;
33150 - int n;
33152 - pixman_region_init_rects(&region, box, 1);
33153 - RegionIntersect(&region, &region, clip);
33154 - n = region_num_rects(&region);
33155 - box = region_rects(&region);
33156 - while (n--)
33157 - tor_blt_add(sna, op, NULL, box++, coverage);
33158 - pixman_region_fini(&region);
33159 -}
33161 -static void
33162 tor_blt_lerp32(struct sna *sna,
33163 struct sna_composite_spans_op *op,
33164 pixman_region16_t *clip,
33165 @@ -2358,6 +2385,7 @@ tor_blt_lerp32(struct sna *sna,
33166 if (coverage == 0)
33167 return;
33169 + sigtrap_assert_active();
33170 ptr += box->y1 * stride + box->x1;
33172 h = box->y2 - box->y1;
33173 @@ -2396,25 +2424,6 @@ tor_blt_lerp32(struct sna *sna,
33177 -static void
33178 -tor_blt_lerp32_clipped(struct sna *sna,
33179 - struct sna_composite_spans_op *op,
33180 - pixman_region16_t *clip,
33181 - const BoxRec *box,
33182 - int coverage)
33183 -{
33184 - pixman_region16_t region;
33185 - int n;
33187 - pixman_region_init_rects(&region, box, 1);
33188 - RegionIntersect(&region, &region, clip);
33189 - n = region_num_rects(&region);
33190 - box = region_rects(&region);
33191 - while (n--)
33192 - tor_blt_lerp32(sna, op, NULL, box++, coverage);
33193 - pixman_region_fini(&region);
33194 -}
33196 struct pixman_inplace {
33197 pixman_image_t *image, *source, *mask;
33198 uint32_t color;
33199 @@ -2442,24 +2451,6 @@ pixmask_span_solid(struct sna *sna,
33200 pi->dx + box->x1, pi->dy + box->y1,
33201 box->x2 - box->x1, box->y2 - box->y1);
33203 -static void
33204 -pixmask_span_solid__clipped(struct sna *sna,
33205 - struct sna_composite_spans_op *op,
33206 - pixman_region16_t *clip,
33207 - const BoxRec *box,
33208 - int coverage)
33209 -{
33210 - pixman_region16_t region;
33211 - int n;
33213 - pixman_region_init_rects(&region, box, 1);
33214 - RegionIntersect(&region, &region, clip);
33215 - n = region_num_rects(&region);
33216 - box = region_rects(&region);
33217 - while (n--)
33218 - pixmask_span_solid(sna, op, NULL, box++, coverage);
33219 - pixman_region_fini(&region);
33220 -}
33222 static void
33223 pixmask_span(struct sna *sna,
33224 @@ -2480,24 +2471,6 @@ pixmask_span(struct sna *sna,
33225 pi->dx + box->x1, pi->dy + box->y1,
33226 box->x2 - box->x1, box->y2 - box->y1);
33228 -static void
33229 -pixmask_span__clipped(struct sna *sna,
33230 - struct sna_composite_spans_op *op,
33231 - pixman_region16_t *clip,
33232 - const BoxRec *box,
33233 - int coverage)
33234 -{
33235 - pixman_region16_t region;
33236 - int n;
33238 - pixman_region_init_rects(&region, box, 1);
33239 - RegionIntersect(&region, &region, clip);
33240 - n = region_num_rects(&region);
33241 - box = region_rects(&region);
33242 - while (n--)
33243 - pixmask_span(sna, op, NULL, box++, coverage);
33244 - pixman_region_fini(&region);
33245 -}
33247 struct inplace_x8r8g8b8_thread {
33248 xTrapezoid *traps;
33249 @@ -2516,6 +2489,7 @@ static void inplace_x8r8g8b8_thread(void *arg)
33250 struct inplace_x8r8g8b8_thread *thread = arg;
33251 struct tor tor;
33252 span_func_t span;
33253 + struct clipped_span clipped;
33254 RegionPtr clip;
33255 int y1, y2, n;
33257 @@ -2546,12 +2520,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
33258 inplace.stride = pixmap->devKind;
33259 inplace.color = thread->color;
33261 - if (clip->data)
33262 - span = tor_blt_lerp32_clipped;
33263 - else
33264 - span = tor_blt_lerp32;
33265 + span = clipped_span(&clipped, tor_blt_lerp32, clip);
33267 - tor_render(NULL, &tor, (void*)&inplace, clip, span, false);
33268 + tor_render(NULL, &tor,
33269 + (void*)&inplace, (void *)&clipped,
33270 + span, false);
33271 } else if (thread->is_solid) {
33272 struct pixman_inplace pi;
33274 @@ -2564,10 +2537,7 @@ static void inplace_x8r8g8b8_thread(void *arg)
33275 1, 1, pi.bits, 0);
33276 pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
33278 - if (clip->data)
33279 - span = pixmask_span_solid__clipped;
33280 - else
33281 - span = pixmask_span_solid;
33282 + span = clipped_span(&clipped, pixmask_span_solid, clip);
33284 tor_render(NULL, &tor, (void*)&pi, clip, span, false);
33286 @@ -2588,12 +2558,11 @@ static void inplace_x8r8g8b8_thread(void *arg)
33287 pi.bits = pixman_image_get_data(pi.mask);
33288 pi.op = thread->op;
33290 - if (clip->data)
33291 - span = pixmask_span__clipped;
33292 - else
33293 - span = pixmask_span;
33294 + span = clipped_span(&clipped, pixmask_span, clip);
33296 - tor_render(NULL, &tor, (void*)&pi, clip, span, false);
33297 + tor_render(NULL, &tor,
33298 + (void*)&pi, (void *)&clipped,
33299 + span, false);
33301 pixman_image_unref(pi.mask);
33302 pixman_image_unref(pi.source);
33303 @@ -2712,6 +2681,7 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
33304 if (num_threads == 1) {
33305 struct tor tor;
33306 span_func_t span;
33307 + struct clipped_span clipped;
33309 if (!tor_init(&tor, &region.extents, 2*ntrap))
33310 return true;
33311 @@ -2737,17 +2707,14 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
33312 inplace.stride = pixmap->devKind;
33313 inplace.color = color;
33315 - if (dst->pCompositeClip->data)
33316 - span = tor_blt_lerp32_clipped;
33317 - else
33318 - span = tor_blt_lerp32;
33320 + span = clipped_span(&clipped, tor_blt_lerp32, dst->pCompositeClip);
33321 DBG(("%s: render inplace op=%d, color=%08x\n",
33322 __FUNCTION__, op, color));
33324 if (sigtrap_get() == 0) {
33325 - tor_render(NULL, &tor, (void*)&inplace,
33326 - dst->pCompositeClip, span, false);
33327 + tor_render(NULL, &tor,
33328 + (void*)&inplace, (void*)&clipped,
33329 + span, false);
33330 sigtrap_put();
33332 } else if (is_solid) {
33333 @@ -2762,15 +2729,11 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
33334 1, 1, pi.bits, 0);
33335 pixman_image_set_repeat(pi.source, PIXMAN_REPEAT_NORMAL);
33337 - if (dst->pCompositeClip->data)
33338 - span = pixmask_span_solid__clipped;
33339 - else
33340 - span = pixmask_span_solid;
33342 + span = clipped_span(&clipped, pixmask_span_solid, dst->pCompositeClip);
33343 if (sigtrap_get() == 0) {
33344 - tor_render(NULL, &tor, (void*)&pi,
33345 - dst->pCompositeClip, span,
33346 - false);
33347 + tor_render(NULL, &tor,
33348 + (void*)&pi, (void*)&clipped,
33349 + span, false);
33350 sigtrap_put();
33353 @@ -2791,15 +2754,11 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
33354 pi.bits = pixman_image_get_data(pi.mask);
33355 pi.op = op;
33357 - if (dst->pCompositeClip->data)
33358 - span = pixmask_span__clipped;
33359 - else
33360 - span = pixmask_span;
33362 + span = clipped_span(&clipped, pixmask_span, dst->pCompositeClip);
33363 if (sigtrap_get() == 0) {
33364 - tor_render(NULL, &tor, (void*)&pi,
33365 - dst->pCompositeClip, span,
33366 - false);
33367 + tor_render(NULL, &tor,
33368 + (void*)&pi, (void *)&clipped,
33369 + span, false);
33370 sigtrap_put();
33373 @@ -2861,9 +2820,9 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
33375 struct inplace_thread {
33376 xTrapezoid *traps;
33377 - RegionPtr clip;
33378 span_func_t span;
33379 struct inplace inplace;
33380 + struct clipped_span clipped;
33381 BoxRec extents;
33382 int dx, dy;
33383 int draw_x, draw_y;
33384 @@ -2888,8 +2847,9 @@ static void inplace_thread(void *arg)
33385 tor_add_trapezoid(&tor, &thread->traps[n], thread->dx, thread->dy);
33388 - tor_render(NULL, &tor, (void*)&thread->inplace,
33389 - thread->clip, thread->span, thread->unbounded);
33390 + tor_render(NULL, &tor,
33391 + (void*)&thread->inplace, (void*)&thread->clipped,
33392 + thread->span, thread->unbounded);
33394 tor_fini(&tor);
33396 @@ -2903,6 +2863,7 @@ precise_trapezoid_span_inplace(struct sna *sna,
33397 bool fallback)
33399 struct inplace inplace;
33400 + struct clipped_span clipped;
33401 span_func_t span;
33402 PixmapPtr pixmap;
33403 struct sna_pixmap *priv;
33404 @@ -3020,21 +2981,12 @@ precise_trapezoid_span_inplace(struct sna *sna,
33405 dst->pCompositeClip->data != NULL));
33407 if (op == PictOpSrc) {
33408 - if (dst->pCompositeClip->data)
33409 - span = tor_blt_src_clipped;
33410 - else
33411 - span = tor_blt_src;
33412 + span = tor_blt_src;
33413 } else if (op == PictOpIn) {
33414 - if (dst->pCompositeClip->data)
33415 - span = tor_blt_in_clipped;
33416 - else
33417 - span = tor_blt_in;
33418 + span = tor_blt_in;
33419 } else {
33420 assert(op == PictOpAdd);
33421 - if (dst->pCompositeClip->data)
33422 - span = tor_blt_add_clipped;
33423 - else
33424 - span = tor_blt_add;
33425 + span = tor_blt_add;
33428 DBG(("%s: move-to-cpu(dst)\n", __FUNCTION__));
33429 @@ -3052,6 +3004,8 @@ precise_trapezoid_span_inplace(struct sna *sna,
33430 inplace.stride = pixmap->devKind;
33431 inplace.opacity = color >> 24;
33433 + span = clipped_span(&clipped, span, dst->pCompositeClip);
33435 num_threads = 1;
33436 if (!NO_GPU_THREADS &&
33437 (flags & COMPOSITE_SPANS_RECTILINEAR) == 0)
33438 @@ -3074,8 +3028,9 @@ precise_trapezoid_span_inplace(struct sna *sna,
33441 if (sigtrap_get() == 0) {
33442 - tor_render(NULL, &tor, (void*)&inplace,
33443 - dst->pCompositeClip, span, unbounded);
33444 + tor_render(NULL, &tor,
33445 + (void*)&inplace, (void *)&clipped,
33446 + span, unbounded);
33447 sigtrap_put();
33450 @@ -3093,7 +3048,7 @@ precise_trapezoid_span_inplace(struct sna *sna,
33451 threads[0].ntrap = ntrap;
33452 threads[0].inplace = inplace;
33453 threads[0].extents = region.extents;
33454 - threads[0].clip = dst->pCompositeClip;
33455 + threads[0].clipped = clipped;
33456 threads[0].span = span;
33457 threads[0].unbounded = unbounded;
33458 threads[0].dx = dx;
33459 @@ -3316,8 +3271,7 @@ tristrip_thread(void *arg)
33460 if (!tor_init(&tor, &thread->extents, 2*thread->count))
33461 return;
33463 - boxes.op = thread->op;
33464 - boxes.num_boxes = 0;
33465 + span_thread_boxes_init(&boxes, thread->op, thread->clip);
33467 cw = 0; ccw = 1;
33468 polygon_add_line(tor.polygon,
33469 diff --git a/src/sna/sna_video.c b/src/sna/sna_video.c
33470 index ed0e7b31..e2b11c31 100644
33471 --- a/src/sna/sna_video.c
33472 +++ b/src/sna/sna_video.c
33473 @@ -591,6 +591,72 @@ use_gtt: /* copy data, must use GTT so that we keep the overlay uncached */
33474 return true;
33477 +void sna_video_fill_colorkey(struct sna_video *video,
33478 + const RegionRec *clip)
33479 +{
33480 + struct sna *sna = video->sna;
33481 + PixmapPtr front = sna->front;
33482 + struct kgem_bo *bo = __sna_pixmap_get_bo(front);
33483 + uint8_t *dst, *tmp;
33484 + int w, width;
33486 + if (video->AlwaysOnTop || RegionEqual(&video->clip, (RegionPtr)clip))
33487 + return;
33489 + assert(bo);
33490 + if (!wedged(sna) &&
33491 + sna_blt_fill_boxes(sna, GXcopy, bo,
33492 + front->drawable.bitsPerPixel,
33493 + video->color_key,
33494 + region_rects(clip),
33495 + region_num_rects(clip))) {
33496 + RegionCopy(&video->clip, (RegionPtr)clip);
33497 + return;
33498 + }
33500 + dst = kgem_bo_map__gtt(&sna->kgem, bo);
33501 + if (dst == NULL)
33502 + return;
33504 + w = front->drawable.bitsPerPixel/8;
33505 + width = (clip->extents.x2 - clip->extents.x1) * w;
33506 + tmp = malloc(width);
33507 + if (tmp == NULL)
33508 + return;
33510 + memcpy(tmp, &video->color_key, w);
33511 + while (2 * w < width) {
33512 + memcpy(tmp + w, tmp, w);
33513 + w *= 2;
33514 + }
33515 + if (w < width)
33516 + memcpy(tmp + w, tmp, width - w);
33518 + if (sigtrap_get() == 0) {
33519 + const BoxRec *box = region_rects(clip);
33520 + int n = region_num_rects(clip);
33522 + w = front->drawable.bitsPerPixel/8;
33523 + do {
33524 + int y = box->y1;
33525 + uint8_t *row = dst + y*bo->pitch + w*box->x1;
33527 + width = (box->x2 - box->x1) * w;
33528 + while (y < box->y2) {
33529 + memcpy(row, tmp, width);
33530 + row += bo->pitch;
33531 + y++;
33532 + }
33533 + box++;
33534 + } while (--n);
33535 + sigtrap_put();
33537 + RegionCopy(&video->clip, (RegionPtr)clip);
33538 + }
33540 + free(tmp);
33541 +}
33543 XvAdaptorPtr sna_xv_adaptor_alloc(struct sna *sna)
33545 XvAdaptorPtr new_adaptors;
33546 diff --git a/src/sna/sna_video.h b/src/sna/sna_video.h
33547 index f21605fc..39cb725f 100644
33548 --- a/src/sna/sna_video.h
33549 +++ b/src/sna/sna_video.h
33550 @@ -72,6 +72,8 @@ THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33551 struct sna_video {
33552 struct sna *sna;
33554 + int idx; /* XXX expose struct plane instead? */
33556 int brightness;
33557 int contrast;
33558 int saturation;
33559 @@ -193,6 +195,9 @@ bool
33560 sna_video_copy_data(struct sna_video *video,
33561 struct sna_video_frame *frame,
33562 const uint8_t *buf);
33563 +void
33564 +sna_video_fill_colorkey(struct sna_video *video,
33565 + const RegionRec *clip);
33567 void sna_video_buffer_fini(struct sna_video *video);
33569 @@ -210,4 +215,26 @@ sna_window_set_port(WindowPtr window, XvPortPtr port)
33570 ((void **)__get_private(window, sna_window_key))[2] = port;
33573 +static inline int offset_and_clip(int x, int dx)
33574 +{
33575 + x += dx;
33576 + if (x <= 0)
33577 + return 0;
33578 + if (x >= MAXSHORT)
33579 + return MAXSHORT;
33580 + return x;
33581 +}
33583 +static inline void init_video_region(RegionRec *region,
33584 + DrawablePtr draw,
33585 + int drw_x, int drw_y,
33586 + int drw_w, int drw_h)
33587 +{
33588 + region->extents.x1 = offset_and_clip(draw->x, drw_x);
33589 + region->extents.y1 = offset_and_clip(draw->y, drw_y);
33590 + region->extents.x2 = offset_and_clip(draw->x, drw_x + drw_w);
33591 + region->extents.y2 = offset_and_clip(draw->y, drw_y + drw_h);
33592 + region->data = NULL;
33593 +}
33595 #endif /* SNA_VIDEO_H */
33596 diff --git a/src/sna/sna_video_overlay.c b/src/sna/sna_video_overlay.c
33597 index ac81f1a0..9bc5ce40 100644
33598 --- a/src/sna/sna_video_overlay.c
33599 +++ b/src/sna/sna_video_overlay.c
33600 @@ -130,7 +130,7 @@ static int sna_video_overlay_stop(ddStopVideo_ARGS)
33602 DBG(("%s()\n", __FUNCTION__));
33604 - REGION_EMPTY(scrn->pScreen, &video->clip);
33605 + REGION_EMPTY(to_screen_from_sna(sna), &video->clip);
33607 request.flags = 0;
33608 (void)drmIoctl(sna->kgem.fd,
33609 @@ -474,15 +474,13 @@ sna_video_overlay_put_image(ddPutImage_ARGS)
33610 if (src_h >= (drw_h * 8))
33611 drw_h = src_h / 7;
33613 - clip.extents.x1 = draw->x + drw_x;
33614 - clip.extents.y1 = draw->y + drw_y;
33615 - clip.extents.x2 = clip.extents.x1 + drw_w;
33616 - clip.extents.y2 = clip.extents.y1 + drw_h;
33617 - clip.data = NULL;
33618 + init_video_region(&clip, draw, drw_x, drw_y, drw_w, drw_h);
33620 DBG(("%s: always_on_top=%d\n", __FUNCTION__, video->AlwaysOnTop));
33621 - if (!video->AlwaysOnTop)
33622 + if (!video->AlwaysOnTop) {
33623 + ValidateGC(draw, gc);
33624 RegionIntersect(&clip, &clip, gc->pCompositeClip);
33625 + }
33626 if (box_empty(&clip.extents))
33627 goto invisible;
33629 @@ -551,15 +549,7 @@ sna_video_overlay_put_image(ddPutImage_ARGS)
33630 ret = Success;
33631 if (sna_video_overlay_show
33632 (sna, video, &frame, crtc, &dstBox, src_w, src_h, drw_w, drw_h)) {
33633 - //xf86XVFillKeyHelperDrawable(draw, video->color_key, &clip);
33634 - if (!video->AlwaysOnTop && !RegionEqual(&video->clip, &clip) &&
33635 - sna_blt_fill_boxes(sna, GXcopy,
33636 - __sna_pixmap_get_bo(sna->front),
33637 - sna->front->drawable.bitsPerPixel,
33638 - video->color_key,
33639 - region_rects(&clip),
33640 - region_num_rects(&clip)))
33641 - RegionCopy(&video->clip, &clip);
33642 + sna_video_fill_colorkey(video, &clip);
33643 sna_window_set_port((WindowPtr)draw, port);
33644 } else {
33645 DBG(("%s: failed to show video frame\n", __FUNCTION__));
33646 diff --git a/src/sna/sna_video_sprite.c b/src/sna/sna_video_sprite.c
33647 index 92230f97..69bfdfd2 100644
33648 --- a/src/sna/sna_video_sprite.c
33649 +++ b/src/sna/sna_video_sprite.c
33650 @@ -47,6 +47,8 @@
33651 #define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */
33652 #define DRM_FORMAT_UYVY fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */
33654 +#define has_hw_scaling(sna) ((sna)->kgem.gen < 071)
33656 #define LOCAL_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct local_mode_set_plane)
33657 struct local_mode_set_plane {
33658 uint32_t plane_id;
33659 @@ -81,19 +83,17 @@ static int sna_video_sprite_stop(ddStopVideo_ARGS)
33660 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(video->sna->scrn);
33661 int i;
33663 - for (i = 0; i < config->num_crtc; i++) {
33664 + for (i = 0; i < video->sna->mode.num_real_crtc; i++) {
33665 xf86CrtcPtr crtc = config->crtc[i];
33666 int pipe;
33668 - if (sna_crtc_id(crtc) == 0)
33669 - break;
33671 - pipe = sna_crtc_to_pipe(crtc);
33672 + pipe = sna_crtc_pipe(crtc);
33673 + assert(pipe < ARRAY_SIZE(video->bo));
33674 if (video->bo[pipe] == NULL)
33675 continue;
33677 memset(&s, 0, sizeof(s));
33678 - s.plane_id = sna_crtc_to_sprite(crtc);
33679 + s.plane_id = sna_crtc_to_sprite(crtc, video->idx);
33680 if (drmIoctl(video->sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s))
33681 xf86DrvMsg(video->sna->scrn->scrnIndex, X_ERROR,
33682 "failed to disable plane\n");
33683 @@ -153,7 +153,7 @@ static int sna_video_sprite_best_size(ddQueryBestSize_ARGS)
33684 struct sna_video *video = port->devPriv.ptr;
33685 struct sna *sna = video->sna;
33687 - if (sna->kgem.gen >= 075) {
33688 + if (!has_hw_scaling(sna) && !sna->render.video) {
33689 *p_w = vid_w;
33690 *p_h = vid_h;
33691 } else {
33692 @@ -221,12 +221,12 @@ sna_video_sprite_show(struct sna *sna,
33693 BoxPtr dstBox)
33695 struct local_mode_set_plane s;
33696 - int pipe = sna_crtc_to_pipe(crtc);
33697 + int pipe = sna_crtc_pipe(crtc);
33699 /* XXX handle video spanning multiple CRTC */
33701 VG_CLEAR(s);
33702 - s.plane_id = sna_crtc_to_sprite(crtc);
33703 + s.plane_id = sna_crtc_to_sprite(crtc, video->idx);
33705 #define DRM_I915_SET_SPRITE_COLORKEY 0x2b
33706 #define LOCAL_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct local_intel_sprite_colorkey)
33707 @@ -263,9 +263,6 @@ sna_video_sprite_show(struct sna *sna,
33708 video->color_key_changed &= ~(1 << pipe);
33711 - if (video->bo[pipe] == frame->bo)
33712 - return true;
33714 update_dst_box_to_crtc_coords(sna, crtc, dstBox);
33715 if (frame->rotation & (RR_Rotate_90 | RR_Rotate_270)) {
33716 int tmp = frame->width;
33717 @@ -283,15 +280,30 @@ sna_video_sprite_show(struct sna *sna,
33718 uint32_t handles[4];
33719 uint32_t pitches[4]; /* pitch for each plane */
33720 uint32_t offsets[4]; /* offset of each plane */
33721 + uint64_t modifiers[4];
33722 } f;
33723 bool purged = true;
33725 memset(&f, 0, sizeof(f));
33726 f.width = frame->width;
33727 f.height = frame->height;
33728 + f.flags = 1 << 1; /* +modifiers */
33729 f.handles[0] = frame->bo->handle;
33730 f.pitches[0] = frame->pitch[0];
33732 + switch (frame->bo->tiling) {
33733 + case I915_TILING_NONE:
33734 + break;
33735 + case I915_TILING_X:
33736 + /* I915_FORMAT_MOD_X_TILED */
33737 + f.modifiers[0] = (uint64_t)1 << 56 | 1;
33738 + break;
33739 + case I915_TILING_Y:
33740 + /* I915_FORMAT_MOD_X_TILED */
33741 + f.modifiers[0] = (uint64_t)1 << 56 | 2;
33742 + break;
33743 + }
33745 switch (frame->id) {
33746 case FOURCC_RGB565:
33747 f.pixel_format = DRM_FORMAT_RGB565;
33748 @@ -360,7 +372,7 @@ sna_video_sprite_show(struct sna *sna,
33749 return false;
33752 - frame->bo->domain = DOMAIN_NONE;
33753 + __kgem_bo_clear_dirty(frame->bo);
33755 if (video->bo[pipe])
33756 kgem_bo_destroy(&sna->kgem, video->bo[pipe]);
33757 @@ -374,17 +386,17 @@ static int sna_video_sprite_put_image(ddPutImage_ARGS)
33758 struct sna *sna = video->sna;
33759 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
33760 RegionRec clip;
33761 + BoxRec draw_extents;
33762 int ret, i;
33764 - clip.extents.x1 = draw->x + drw_x;
33765 - clip.extents.y1 = draw->y + drw_y;
33766 - clip.extents.x2 = clip.extents.x1 + drw_w;
33767 - clip.extents.y2 = clip.extents.y1 + drw_h;
33768 - clip.data = NULL;
33769 + init_video_region(&clip, draw, drw_x, drw_y, drw_w, drw_h);
33770 + draw_extents = clip.extents;
33772 DBG(("%s: always_on_top=%d\n", __FUNCTION__, video->AlwaysOnTop));
33773 - if (!video->AlwaysOnTop)
33774 + if (!video->AlwaysOnTop) {
33775 + ValidateGC(draw, gc);
33776 RegionIntersect(&clip, &clip, gc->pCompositeClip);
33777 + }
33779 DBG(("%s: src=(%d, %d),(%d, %d), dst=(%d, %d),(%d, %d), id=%d, sizep=%dx%d, sync?=%d\n",
33780 __FUNCTION__,
33781 @@ -402,19 +414,17 @@ static int sna_video_sprite_put_image(ddPutImage_ARGS)
33782 goto err;
33785 - for (i = 0; i < config->num_crtc; i++) {
33786 + for (i = 0; i < video->sna->mode.num_real_crtc; i++) {
33787 xf86CrtcPtr crtc = config->crtc[i];
33788 struct sna_video_frame frame;
33789 + BoxRec dst = draw_extents;
33790 int pipe;
33791 INT32 x1, x2, y1, y2;
33792 - BoxRec dst;
33793 RegionRec reg;
33794 Rotation rotation;
33795 + bool cache_bo;
33797 - if (sna_crtc_id(crtc) == 0)
33798 - break;
33800 - pipe = sna_crtc_to_pipe(crtc);
33801 + pipe = sna_crtc_pipe(crtc);
33803 sna_video_frame_init(video, format->id, width, height, &frame);
33805 @@ -423,10 +433,11 @@ static int sna_video_sprite_put_image(ddPutImage_ARGS)
33806 RegionIntersect(&reg, &reg, &clip);
33807 if (RegionNil(&reg)) {
33808 off:
33809 + assert(pipe < ARRAY_SIZE(video->bo));
33810 if (video->bo[pipe]) {
33811 struct local_mode_set_plane s;
33812 memset(&s, 0, sizeof(s));
33813 - s.plane_id = sna_crtc_to_sprite(crtc);
33814 + s.plane_id = sna_crtc_to_sprite(crtc, video->idx);
33815 if (drmIoctl(video->sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s))
33816 xf86DrvMsg(video->sna->scrn->scrnIndex, X_ERROR,
33817 "failed to disable plane\n");
33818 @@ -440,8 +451,6 @@ off:
33819 y1 = src_y;
33820 y2 = src_y + src_h;
33822 - dst = clip.extents;
33824 ret = xf86XVClipVideoHelper(&dst, &x1, &x2, &y1, &y2,
33825 &reg, frame.width, frame.height);
33826 RegionUninit(&reg);
33827 @@ -465,8 +474,8 @@ off:
33829 /* if sprite can't handle rotation natively, store it for the copy func */
33830 rotation = RR_Rotate_0;
33831 - if (!sna_crtc_set_sprite_rotation(crtc, crtc->rotation)) {
33832 - sna_crtc_set_sprite_rotation(crtc, RR_Rotate_0);
33833 + if (!sna_crtc_set_sprite_rotation(crtc, video->idx, crtc->rotation)) {
33834 + sna_crtc_set_sprite_rotation(crtc, video->idx, RR_Rotate_0);
33835 rotation = crtc->rotation;
33837 sna_video_frame_set_rotation(video, &frame, rotation);
33838 @@ -496,6 +505,8 @@ off:
33839 frame.image.y1 = 0;
33840 frame.image.x2 = frame.width;
33841 frame.image.y2 = frame.height;
33843 + cache_bo = false;
33844 } else {
33845 frame.bo = sna_video_buffer(video, &frame);
33846 if (frame.bo == NULL) {
33847 @@ -509,6 +520,60 @@ off:
33848 ret = BadAlloc;
33849 goto err;
33852 + cache_bo = true;
33853 + }
33855 + if (!has_hw_scaling(sna) && sna->render.video &&
33856 + !((frame.src.x2 - frame.src.x1) == (dst.x2 - dst.x1) &&
33857 + (frame.src.y2 - frame.src.y1) == (dst.y2 - dst.y1))) {
33858 + ScreenPtr screen = to_screen_from_sna(sna);
33859 + PixmapPtr scaled;
33860 + RegionRec r;
33862 + r.extents.x1 = r.extents.y1 = 0;
33863 + r.extents.x2 = dst.x2 - dst.x1;
33864 + r.extents.y2 = dst.y2 - dst.y1;
33865 + r.data = NULL;
33867 + DBG(("%s: scaling from (%d, %d) to (%d, %d)\n",
33868 + __FUNCTION__,
33869 + frame.src.x2 - frame.src.x1,
33870 + frame.src.y2 - frame.src.y1,
33871 + r.extents.x2, r.extents.y2));
33873 + scaled = screen->CreatePixmap(screen,
33874 + r.extents.x2,
33875 + r.extents.y2,
33876 + 24,
33877 + CREATE_PIXMAP_USAGE_SCRATCH);
33878 + if (scaled == NULL) {
33879 + ret = BadAlloc;
33880 + goto err;
33881 + }
33883 + if (!sna->render.video(sna, video, &frame, &r, scaled)) {
33884 + screen->DestroyPixmap(scaled);
33885 + ret = BadAlloc;
33886 + goto err;
33887 + }
33889 + if (cache_bo)
33890 + sna_video_buffer_fini(video);
33891 + else
33892 + kgem_bo_destroy(&sna->kgem, frame.bo);
33894 + frame.bo = kgem_bo_reference(__sna_pixmap_get_bo(scaled));
33895 + kgem_bo_submit(&sna->kgem, frame.bo);
33897 + frame.id = FOURCC_RGB888;
33898 + frame.src = frame.image = r.extents;
33899 + frame.width = frame.image.x2;
33900 + frame.height = frame.image.y2;
33901 + frame.pitch[0] = frame.bo->pitch;
33903 + screen->DestroyPixmap(scaled);
33904 + cache_bo = false;
33907 ret = Success;
33908 @@ -517,24 +582,16 @@ off:
33909 ret = BadAlloc;
33912 - frame.bo->domain = DOMAIN_NONE;
33913 - if (xvmc_passthrough(format->id))
33914 - kgem_bo_destroy(&sna->kgem, frame.bo);
33915 - else
33916 + if (cache_bo)
33917 sna_video_buffer_fini(video);
33918 + else
33919 + kgem_bo_destroy(&sna->kgem, frame.bo);
33921 if (ret != Success)
33922 goto err;
33925 - if (!video->AlwaysOnTop && !RegionEqual(&video->clip, &clip) &&
33926 - sna_blt_fill_boxes(sna, GXcopy,
33927 - __sna_pixmap_get_bo(sna->front),
33928 - sna->front->drawable.bitsPerPixel,
33929 - video->color_key,
33930 - region_rects(&clip),
33931 - region_num_rects(&clip)))
33932 - RegionCopy(&video->clip, &clip);
33933 + sna_video_fill_colorkey(video, &clip);
33934 sna_window_set_port((WindowPtr)draw, port);
33936 return Success;
33937 @@ -606,25 +663,28 @@ static int sna_video_sprite_color_key(struct sna *sna)
33938 return color_key & ((1 << scrn->depth) - 1);
33941 -static bool sna_video_has_sprites(struct sna *sna)
33942 +static int sna_video_has_sprites(struct sna *sna)
33944 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
33945 + unsigned min;
33946 int i;
33948 DBG(("%s: num_crtc=%d\n", __FUNCTION__, sna->mode.num_real_crtc));
33950 if (sna->mode.num_real_crtc == 0)
33951 - return false;
33952 + return 0;
33954 + min = -1;
33955 for (i = 0; i < sna->mode.num_real_crtc; i++) {
33956 - if (!sna_crtc_to_sprite(config->crtc[i])) {
33957 - DBG(("%s: no sprite found on pipe %d\n", __FUNCTION__, sna_crtc_to_pipe(config->crtc[i])));
33958 - return false;
33959 - }
33960 + unsigned count = sna_crtc_count_sprites(config->crtc[i]);
33961 + DBG(("%s: %d sprites found on pipe %d\n", __FUNCTION__,
33962 + count, sna_crtc_pipe(config->crtc[i])));
33963 + if (count < min)
33964 + min = count;
33967 - DBG(("%s: yes\n", __FUNCTION__));
33968 - return true;
33969 + DBG(("%s: min=%d\n", __FUNCTION__, min));
33970 + return min;
33973 void sna_video_sprite_setup(struct sna *sna, ScreenPtr screen)
33974 @@ -632,16 +692,18 @@ void sna_video_sprite_setup(struct sna *sna, ScreenPtr screen)
33975 XvAdaptorPtr adaptor;
33976 struct sna_video *video;
33977 XvPortPtr port;
33978 + int count, i;
33980 - if (!sna_video_has_sprites(sna))
33981 + count = sna_video_has_sprites(sna);
33982 + if (!count)
33983 return;
33985 adaptor = sna_xv_adaptor_alloc(sna);
33986 if (!adaptor)
33987 return;
33989 - video = calloc(1, sizeof(*video));
33990 - port = calloc(1, sizeof(*port));
33991 + video = calloc(count, sizeof(*video));
33992 + port = calloc(count, sizeof(*port));
33993 if (video == NULL || port == NULL) {
33994 free(video);
33995 free(port);
33996 @@ -686,36 +748,43 @@ void sna_video_sprite_setup(struct sna *sna, ScreenPtr screen)
33997 adaptor->ddPutImage = sna_video_sprite_put_image;
33998 adaptor->ddQueryImageAttributes = sna_video_sprite_query;
34000 - adaptor->nPorts = 1;
34001 + adaptor->nPorts = count;
34002 adaptor->pPorts = port;
34004 - adaptor->base_id = port->id = FakeClientID(0);
34005 - AddResource(port->id, XvGetRTPort(), port);
34006 - port->pAdaptor = adaptor;
34007 - port->pNotify = NULL;
34008 - port->pDraw = NULL;
34009 - port->client = NULL;
34010 - port->grab.client = NULL;
34011 - port->time = currentTime;
34012 - port->devPriv.ptr = video;
34014 - video->sna = sna;
34015 - video->alignment = 64;
34016 - video->color_key = sna_video_sprite_color_key(sna);
34017 - video->color_key_changed = ~0;
34018 - video->has_color_key = true;
34019 - video->brightness = -19; /* (255/219) * -16 */
34020 - video->contrast = 75; /* 255/219 * 64 */
34021 - video->saturation = 146; /* 128/112 * 128 */
34022 - video->desired_crtc = NULL;
34023 - video->gamma5 = 0xc0c0c0;
34024 - video->gamma4 = 0x808080;
34025 - video->gamma3 = 0x404040;
34026 - video->gamma2 = 0x202020;
34027 - video->gamma1 = 0x101010;
34028 - video->gamma0 = 0x080808;
34029 - RegionNull(&video->clip);
34030 - video->SyncToVblank = 1;
34031 + for (i = 0; i < count; i++) {
34032 + port->id = FakeClientID(0);
34033 + AddResource(port->id, XvGetRTPort(), port);
34034 + port->pAdaptor = adaptor;
34035 + port->pNotify = NULL;
34036 + port->pDraw = NULL;
34037 + port->client = NULL;
34038 + port->grab.client = NULL;
34039 + port->time = currentTime;
34040 + port->devPriv.ptr = video;
34042 + video->sna = sna;
34043 + video->idx = i;
34044 + video->alignment = 64;
34045 + video->color_key = sna_video_sprite_color_key(sna);
34046 + video->color_key_changed = ~0;
34047 + video->has_color_key = true;
34048 + video->brightness = -19; /* (255/219) * -16 */
34049 + video->contrast = 75; /* 255/219 * 64 */
34050 + video->saturation = 146; /* 128/112 * 128 */
34051 + video->desired_crtc = NULL;
34052 + video->gamma5 = 0xc0c0c0;
34053 + video->gamma4 = 0x808080;
34054 + video->gamma3 = 0x404040;
34055 + video->gamma2 = 0x202020;
34056 + video->gamma1 = 0x101010;
34057 + video->gamma0 = 0x080808;
34058 + RegionNull(&video->clip);
34059 + video->SyncToVblank = 1;
34061 + port++;
34062 + video++;
34063 + }
34064 + adaptor->base_id = adaptor->pPorts[0].id;
34066 xvColorKey = MAKE_ATOM("XV_COLORKEY");
34067 xvAlwaysOnTop = MAKE_ATOM("XV_ALWAYS_ON_TOP");
34068 diff --git a/src/sna/sna_video_textured.c b/src/sna/sna_video_textured.c
34069 index 95011939..3cce5cf1 100644
34070 --- a/src/sna/sna_video_textured.c
34071 +++ b/src/sna/sna_video_textured.c
34072 @@ -48,7 +48,12 @@ static const XvAttributeRec Attributes[] = {
34073 //{XvSettable | XvGettable, 0, 255, (char *)"XV_CONTRAST"},
34074 };
34076 -static const XvImageRec Images[] = {
34077 +static const XvImageRec gen2_Images[] = {
34078 + XVIMAGE_YUY2,
34079 + XVIMAGE_UYVY,
34080 +};
34082 +static const XvImageRec gen3_Images[] = {
34083 XVIMAGE_YUY2,
34084 XVIMAGE_YV12,
34085 XVIMAGE_I420,
34086 @@ -149,15 +154,16 @@ sna_video_textured_put_image(ddPutImage_ARGS)
34087 BoxRec dstBox;
34088 RegionRec clip;
34089 xf86CrtcPtr crtc;
34090 + int16_t dx, dy;
34091 bool flush = false;
34092 bool ret;
34094 - clip.extents.x1 = draw->x + drw_x;
34095 - clip.extents.y1 = draw->y + drw_y;
34096 - clip.extents.x2 = clip.extents.x1 + drw_w;
34097 - clip.extents.y2 = clip.extents.y1 + drw_h;
34098 - clip.data = NULL;
34099 + if (wedged(sna))
34100 + return BadAlloc;
34102 + init_video_region(&clip, draw, drw_x, drw_y, drw_w, drw_h);
34104 + ValidateGC(draw, gc);
34105 RegionIntersect(&clip, &clip, gc->pCompositeClip);
34106 if (!RegionNotEmpty(&clip))
34107 return Success;
34108 @@ -181,6 +187,9 @@ sna_video_textured_put_image(ddPutImage_ARGS)
34109 &clip))
34110 return Success;
34112 + if (get_drawable_deltas(draw, pixmap, &dx, &dy))
34113 + RegionTranslate(&clip, dx, dy);
34115 flags = MOVE_WRITE | __MOVE_FORCE;
34116 if (clip.data)
34117 flags |= MOVE_READ;
34118 @@ -234,7 +243,7 @@ sna_video_textured_put_image(ddPutImage_ARGS)
34119 DBG(("%s: failed to render video\n", __FUNCTION__));
34120 ret = BadAlloc;
34121 } else
34122 - DamageDamageRegion(draw, &clip);
34123 + DamageDamageRegion(&pixmap->drawable, &clip);
34125 kgem_bo_destroy(&sna->kgem, frame.bo);
34127 @@ -316,7 +325,7 @@ void sna_video_textured_setup(struct sna *sna, ScreenPtr screen)
34129 if (!sna->render.video) {
34130 xf86DrvMsg(sna->scrn->scrnIndex, X_INFO,
34131 - "Textured video not supported on this hardware\n");
34132 + "Textured video not supported on this hardware or backend\n");
34133 return;
34136 @@ -362,8 +371,13 @@ void sna_video_textured_setup(struct sna *sna, ScreenPtr screen)
34137 ARRAY_SIZE(Formats));
34138 adaptor->nAttributes = ARRAY_SIZE(Attributes);
34139 adaptor->pAttributes = (XvAttributeRec *)Attributes;
34140 - adaptor->nImages = ARRAY_SIZE(Images);
34141 - adaptor->pImages = (XvImageRec *)Images;
34142 + if (sna->kgem.gen < 030) {
34143 + adaptor->nImages = ARRAY_SIZE(gen2_Images);
34144 + adaptor->pImages = (XvImageRec *)gen2_Images;
34145 + } else {
34146 + adaptor->nImages = ARRAY_SIZE(gen3_Images);
34147 + adaptor->pImages = (XvImageRec *)gen3_Images;
34148 + }
34149 #if XORG_XV_VERSION < 2
34150 adaptor->ddAllocatePort = sna_xv_alloc_port;
34151 adaptor->ddFreePort = sna_xv_free_port;
34152 diff --git a/src/sna/xassert.h b/src/sna/xassert.h
34153 index 1bcfd080..e648e4bc 100644
34154 --- a/src/sna/xassert.h
34155 +++ b/src/sna/xassert.h
34156 @@ -43,6 +43,28 @@
34157 xorg_backtrace(); \
34158 FatalError("%s:%d assertion '%s' failed\n", __func__, __LINE__, #E); \
34159 } while (0)
34161 +#define warn_unless(E) \
34162 +({ \
34163 + bool fail = !(E); \
34164 + if (unlikely(fail)) { \
34165 + static int __warn_once__; \
34166 + if (!__warn_once__) { \
34167 + xorg_backtrace(); \
34168 + ErrorF("%s:%d assertion '%s' failed\n", __func__, __LINE__, #E); \
34169 + __warn_once__ = 1; \
34170 + } \
34171 + } \
34172 + unlikely(fail); \
34173 +})
34175 +#define dbg(EXPR) EXPR
34177 +#else
34179 +#define warn_unless(E) ({ bool fail = !(E); unlikely(fail); })
34180 +#define dbg(EXPR)
34182 #endif
34184 #endif /* __XASSERT_H__ */
34185 diff --git a/src/uxa/i830_reg.h b/src/uxa/i830_reg.h
34186 index d8306bcd..ba39d82c 100644
34187 --- a/src/uxa/i830_reg.h
34188 +++ b/src/uxa/i830_reg.h
34189 @@ -65,6 +65,12 @@
34190 #define MI_LOAD_SCAN_LINES_DISPLAY_PIPEA (0)
34191 #define MI_LOAD_SCAN_LINES_DISPLAY_PIPEB (0x1<<20)
34193 +#define MI_LOAD_REGISTER_IMM (0x22<<23 | (3-2))
34195 +#define BCS_SWCTRL 0x22200
34196 +# define BCS_SWCTRL_SRC_Y (1 << 0)
34197 +# define BCS_SWCTRL_DST_Y (1 << 1)
34199 /* BLT commands */
34200 #define COLOR_BLT_CMD ((2<<29)|(0x40<<22)|(0x3))
34201 #define COLOR_BLT_WRITE_ALPHA (1<<21)
34202 diff --git a/src/uxa/i965_video.c b/src/uxa/i965_video.c
34203 index 68e6fd38..438ab909 100644
34204 --- a/src/uxa/i965_video.c
34205 +++ b/src/uxa/i965_video.c
34206 @@ -37,7 +37,6 @@
34207 #include "fourcc.h"
34209 #include "intel.h"
34210 -#include "intel_xvmc.h"
34211 #include "intel_uxa.h"
34212 #include "i830_reg.h"
34213 #include "i965_reg.h"
34214 diff --git a/src/uxa/intel.h b/src/uxa/intel.h
34215 index 1b7e5339..a5e77af4 100644
34216 --- a/src/uxa/intel.h
34217 +++ b/src/uxa/intel.h
34218 @@ -121,7 +121,6 @@ typedef struct intel_screen_private {
34220 void *modes;
34221 drm_intel_bo *front_buffer, *back_buffer;
34222 - unsigned int back_name;
34223 long front_pitch, front_tiling;
34225 dri_bufmgr *bufmgr;
34226 @@ -169,6 +168,7 @@ typedef struct intel_screen_private {
34227 const struct intel_device_info *info;
34229 unsigned int BR[20];
34230 + unsigned int BR_tiling[2];
34232 CloseScreenProcPtr CloseScreen;
34234 @@ -196,7 +196,9 @@ typedef struct intel_screen_private {
34236 int colorKey;
34237 XF86VideoAdaptorPtr adaptor;
34238 +#if !HAVE_NOTIFY_FD
34239 ScreenBlockHandlerProcPtr BlockHandler;
34240 +#endif
34241 Bool overlayOn;
34243 struct {
34244 @@ -285,8 +287,6 @@ typedef struct intel_screen_private {
34245 Bool has_kernel_flush;
34246 Bool needs_flush;
34248 - struct _DRI2FrameEvent *pending_flip[MAX_PIPES];
34250 /* Broken-out options. */
34251 OptionInfoPtr Options;
34253 @@ -368,6 +368,7 @@ typedef void (*intel_drm_abort_proc)(ScrnInfoPtr scrn,
34255 extern uint32_t intel_drm_queue_alloc(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data, intel_drm_handler_proc handler, intel_drm_abort_proc abort);
34256 extern void intel_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), void *match_data);
34257 +extern void intel_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq);
34259 extern int intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc);
34260 extern int intel_crtc_id(xf86CrtcPtr crtc);
34261 @@ -408,7 +409,6 @@ typedef struct _DRI2FrameEvent {
34262 ClientPtr client;
34263 enum DRI2FrameEventType type;
34264 int frame;
34265 - int pipe;
34267 struct list drawable_resource, client_resource;
34269 @@ -418,7 +418,12 @@ typedef struct _DRI2FrameEvent {
34270 DRI2BufferPtr front;
34271 DRI2BufferPtr back;
34273 - struct _DRI2FrameEvent *chain;
34274 + /* current scanout for triple buffer */
34275 + int old_width;
34276 + int old_height;
34277 + int old_pitch;
34278 + int old_tiling;
34279 + dri_bo *old_buffer;
34280 } DRI2FrameEventRec, *DRI2FrameEventPtr;
34282 extern Bool intel_do_pageflip(intel_screen_private *intel,
34283 @@ -456,10 +461,6 @@ extern xf86CrtcPtr intel_covering_crtc(ScrnInfoPtr scrn, BoxPtr box,
34285 Bool I830DRI2ScreenInit(ScreenPtr pScreen);
34286 void I830DRI2CloseScreen(ScreenPtr pScreen);
34287 -void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
34288 - unsigned int tv_usec, DRI2FrameEventPtr flip_info);
34289 -void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
34290 - unsigned int tv_usec, DRI2FrameEventPtr flip_info);
34292 /* intel_dri3.c */
34293 Bool intel_dri3_screen_init(ScreenPtr screen);
34294 diff --git a/src/uxa/intel_batchbuffer.c b/src/uxa/intel_batchbuffer.c
34295 index a29e4434..114c6026 100644
34296 --- a/src/uxa/intel_batchbuffer.c
34297 +++ b/src/uxa/intel_batchbuffer.c
34298 @@ -245,6 +245,17 @@ void intel_batch_submit(ScrnInfoPtr scrn)
34299 if (intel->batch_used == 0)
34300 return;
34302 + if (intel->current_batch == I915_EXEC_BLT &&
34303 + INTEL_INFO(intel)->gen >= 060) {
34304 + OUT_BATCH(MI_FLUSH_DW);
34305 + OUT_BATCH(0);
34306 + OUT_BATCH(0);
34307 + OUT_BATCH(0);
34308 + OUT_BATCH(MI_LOAD_REGISTER_IMM);
34309 + OUT_BATCH(BCS_SWCTRL);
34310 + OUT_BATCH((BCS_SWCTRL_DST_Y | BCS_SWCTRL_SRC_Y) << 16);
34311 + }
34313 /* Mark the end of the batchbuffer. */
34314 OUT_BATCH(MI_BATCH_BUFFER_END);
34315 /* Emit a padding dword if we aren't going to be quad-word aligned. */
34316 diff --git a/src/uxa/intel_batchbuffer.h b/src/uxa/intel_batchbuffer.h
34317 index e5fb8d08..e71ffd19 100644
34318 --- a/src/uxa/intel_batchbuffer.h
34319 +++ b/src/uxa/intel_batchbuffer.h
34320 @@ -30,7 +30,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34321 #ifndef _INTEL_BATCHBUFFER_H
34322 #define _INTEL_BATCHBUFFER_H
34324 -#define BATCH_RESERVED 16
34325 +#define BATCH_RESERVED 64
34328 void intel_batch_init(ScrnInfoPtr scrn);
34329 @@ -202,6 +202,23 @@ do { \
34331 #define BEGIN_BATCH(n) __BEGIN_BATCH(n,RENDER_BATCH)
34332 #define BEGIN_BATCH_BLT(n) __BEGIN_BATCH(n,BLT_BATCH)
34333 +#define BEGIN_BATCH_BLT_TILED(n) \
34334 +do { \
34335 + if (INTEL_INFO(intel)->gen < 060) { \
34336 + __BEGIN_BATCH(n, BLT_BATCH); \
34337 + } else { \
34338 + __BEGIN_BATCH(n+7, BLT_BATCH); \
34339 + OUT_BATCH(MI_FLUSH_DW); \
34340 + OUT_BATCH(0); \
34341 + OUT_BATCH(0); \
34342 + OUT_BATCH(0); \
34343 + OUT_BATCH(MI_LOAD_REGISTER_IMM); \
34344 + OUT_BATCH(BCS_SWCTRL); \
34345 + OUT_BATCH((BCS_SWCTRL_DST_Y | BCS_SWCTRL_SRC_Y) << 16 | \
34346 + ((intel->BR_tiling[0] == I915_TILING_Y) ? BCS_SWCTRL_DST_Y : 0) | \
34347 + ((intel->BR_tiling[1] == I915_TILING_Y) ? BCS_SWCTRL_SRC_Y : 0)); \
34348 + } \
34349 +} while (0)
34351 #define ADVANCE_BATCH() do { \
34352 if (intel->batch_emitting == 0) \
34353 diff --git a/src/uxa/intel_display.c b/src/uxa/intel_display.c
34354 index 7b4d4e0c..809cda1d 100644
34355 --- a/src/uxa/intel_display.c
34356 +++ b/src/uxa/intel_display.c
34357 @@ -89,11 +89,11 @@ struct intel_mode {
34358 struct list outputs;
34359 struct list crtcs;
34361 - void *pageflip_data;
34362 - intel_pageflip_handler_proc pageflip_handler;
34363 - intel_pageflip_abort_proc pageflip_abort;
34365 - Bool delete_dp_12_displays;
34366 + struct {
34367 + intel_pageflip_handler_proc handler;
34368 + intel_pageflip_abort_proc abort;
34369 + void *data;
34370 + } pageflip;
34371 };
34373 struct intel_pageflip {
34374 @@ -114,7 +114,6 @@ struct intel_crtc {
34375 struct list link;
34376 PixmapPtr scanout_pixmap;
34377 uint32_t scanout_fb_id;
34378 - int32_t vblank_offset;
34379 uint32_t msc_prev;
34380 uint64_t msc_high;
34381 };
34382 @@ -193,7 +192,7 @@ intel_output_backlight_init(xf86OutputPtr output)
34384 str = xf86GetOptValString(intel->Options, OPTION_BACKLIGHT);
34385 if (str != NULL) {
34386 - if (backlight_exists(str) != BL_NONE) {
34387 + if (backlight_exists(str)) {
34388 intel_output->backlight_active_level =
34389 backlight_open(&intel_output->backlight,
34390 strdup(str));
34391 @@ -689,9 +688,11 @@ intel_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
34394 bo = intel_get_pixmap_bo(ppix);
34395 - if (intel->front_buffer) {
34396 - ErrorF("have front buffer\n");
34397 - }
34398 + if (!bo)
34399 + return FALSE;
34401 + if (intel->front_buffer)
34402 + return FALSE;
34404 drm_intel_bo_disable_reuse(bo);
34406 @@ -867,6 +868,48 @@ intel_output_attach_edid(xf86OutputPtr output)
34407 xf86OutputSetEDID(output, mon);
34410 +static void
34411 +intel_output_attach_tile(xf86OutputPtr output)
34412 +{
34413 +#if XF86_OUTPUT_VERSION >= 3
34414 + struct intel_output *intel_output = output->driver_private;
34415 + drmModeConnectorPtr koutput = intel_output->mode_output;
34416 + struct intel_mode *mode = intel_output->mode;
34417 + drmModePropertyBlobPtr blob = NULL;
34418 + struct xf86CrtcTileInfo tile_info, *set = NULL;
34419 + int i;
34421 + for (i = 0; koutput && i < koutput->count_props; i++) {
34422 + drmModePropertyPtr props;
34424 + props = drmModeGetProperty(mode->fd, koutput->props[i]);
34425 + if (!props)
34426 + continue;
34428 + if (!(props->flags & DRM_MODE_PROP_BLOB)) {
34429 + drmModeFreeProperty(props);
34430 + continue;
34431 + }
34433 + if (!strcmp(props->name, "TILE")) {
34434 + blob = drmModeGetPropertyBlob(mode->fd,
34435 + koutput->prop_values[i]);
34436 + }
34437 + drmModeFreeProperty(props);
34438 + }
34440 + if (blob) {
34441 + if (xf86OutputParseKMSTile(blob->data,
34442 + blob->length,
34443 + &tile_info))
34444 + set = &tile_info;
34445 + drmModeFreePropertyBlob(blob);
34446 + }
34448 + xf86OutputSetTile(output, set);
34449 +#endif
34450 +}
34452 static DisplayModePtr
34453 intel_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes)
34455 @@ -922,6 +965,7 @@ intel_output_get_modes(xf86OutputPtr output)
34456 int i;
34458 intel_output_attach_edid(output);
34459 + intel_output_attach_tile(output);
34461 if (!koutput)
34462 return Modes;
34463 @@ -1492,6 +1536,7 @@ intel_output_init(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_
34464 intel_output = output->driver_private;
34465 intel_output->output_id = mode_res->connectors[num];
34466 intel_output->mode_output = koutput;
34467 + RROutputChanged(output->randr_output, TRUE);
34468 return;
34471 @@ -1650,9 +1695,6 @@ intel_pageflip_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data);
34472 static void
34473 intel_pageflip_complete(struct intel_mode *mode);
34475 -static void
34476 -intel_drm_abort_seq (ScrnInfoPtr scrn, uint32_t seq);
34478 Bool
34479 intel_do_pageflip(intel_screen_private *intel,
34480 dri_bo *new_front,
34481 @@ -1671,23 +1713,30 @@ intel_do_pageflip(intel_screen_private *intel,
34482 uint32_t new_fb_id;
34483 uint32_t flags;
34484 uint32_t seq;
34485 + int err = 0;
34486 int i;
34488 /*
34489 + * We only have a single length queue in the kernel, so any
34490 + * attempts to schedule a second flip before processing the first
34491 + * is a bug. Punt it back to the caller.
34492 + */
34493 + if (mode->flip_count)
34494 + return FALSE;
34496 + /*
34497 * Create a new handle for the back buffer
34498 */
34499 if (drmModeAddFB(mode->fd, scrn->virtualX, scrn->virtualY,
34500 scrn->depth, scrn->bitsPerPixel, pitch,
34501 - new_front->handle, &new_fb_id))
34502 + new_front->handle, &new_fb_id)) {
34503 + err = errno;
34504 goto error_out;
34505 + }
34507 drm_intel_bo_disable_reuse(new_front);
34508 intel_flush(intel);
34510 - mode->pageflip_data = pageflip_data;
34511 - mode->pageflip_handler = pageflip_handler;
34512 - mode->pageflip_abort = pageflip_abort;
34514 /*
34515 * Queue flips on all enabled CRTCs
34516 * Note that if/when we get per-CRTC buffers, we'll have to update this.
34517 @@ -1699,6 +1748,7 @@ intel_do_pageflip(intel_screen_private *intel,
34518 */
34519 mode->fe_msc = 0;
34520 mode->fe_usec = 0;
34521 + memset(&mode->pageflip, 0, sizeof(mode->pageflip));
34523 flags = DRM_MODE_PAGE_FLIP_EVENT;
34524 if (async)
34525 @@ -1711,8 +1761,7 @@ intel_do_pageflip(intel_screen_private *intel,
34527 flip = calloc(1, sizeof(struct intel_pageflip));
34528 if (flip == NULL) {
34529 - xf86DrvMsg(scrn->scrnIndex, X_WARNING,
34530 - "flip queue: carrier alloc failed.\n");
34531 + err = errno;
34532 goto error_undo;
34535 @@ -1724,33 +1773,30 @@ intel_do_pageflip(intel_screen_private *intel,
34537 seq = intel_drm_queue_alloc(scrn, config->crtc[i], flip, intel_pageflip_handler, intel_pageflip_abort);
34538 if (!seq) {
34539 + err = errno;
34540 free(flip);
34541 goto error_undo;
34544 -again:
34545 + mode->flip_count++;
34547 if (drmModePageFlip(mode->fd,
34548 crtc_id(crtc),
34549 new_fb_id,
34550 flags, (void *)(uintptr_t)seq)) {
34551 - if (intel_mode_read_drm_events(intel)) {
34552 - xf86DrvMsg(scrn->scrnIndex, X_WARNING,
34553 - "flip queue retry\n");
34554 - goto again;
34555 - }
34556 - xf86DrvMsg(scrn->scrnIndex, X_WARNING,
34557 - "flip queue failed: %s\n", strerror(errno));
34558 - if (seq)
34559 - intel_drm_abort_seq(scrn, seq);
34560 - free(flip);
34561 + err = errno;
34562 + intel_drm_abort_seq(scrn, seq);
34563 goto error_undo;
34565 - mode->flip_count++;
34568 mode->old_fb_id = mode->fb_id;
34569 mode->fb_id = new_fb_id;
34571 + mode->pageflip.data = pageflip_data;
34572 + mode->pageflip.handler = pageflip_handler;
34573 + mode->pageflip.abort = pageflip_abort;
34575 if (!mode->flip_count)
34576 intel_pageflip_complete(mode);
34578 @@ -1765,7 +1811,7 @@ error_undo:
34580 error_out:
34581 xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
34582 - strerror(errno));
34583 + strerror(err));
34585 mode->flip_count = 0;
34586 return FALSE;
34587 @@ -1839,7 +1885,7 @@ intel_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), v
34588 /*
34589 * Abort by drm queue sequence number
34590 */
34591 -static void
34592 +void
34593 intel_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq)
34595 struct intel_drm_queue *q;
34596 @@ -1911,7 +1957,6 @@ intel_sequence_to_crtc_msc(xf86CrtcPtr crtc, uint32_t sequence)
34598 struct intel_crtc *intel_crtc = crtc->driver_private;
34600 - sequence += intel_crtc->vblank_offset;
34601 if ((int32_t) (sequence - intel_crtc->msc_prev) < -0x40000000)
34602 intel_crtc->msc_high += 0x100000000L;
34603 intel_crtc->msc_prev = sequence;
34604 @@ -1935,37 +1980,10 @@ intel_get_crtc_msc_ust(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t *msc, uint64
34605 return 0;
34608 -/*
34609 - * Convert a 64-bit adjusted MSC value into a 32-bit kernel sequence number,
34610 - * removing the high 32 bits and subtracting out the vblank_offset term.
34611 - *
34612 - * This also updates the vblank_offset when it notices that the value should
34613 - * change.
34614 - */
34616 -#define MAX_VBLANK_OFFSET 1000
34618 uint32_t
34619 intel_crtc_msc_to_sequence(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t expect)
34621 - struct intel_crtc *intel_crtc = crtc->driver_private;
34622 - uint64_t msc, ust;
34624 - if (intel_get_crtc_msc_ust(scrn, crtc, &msc, &ust) == 0) {
34625 - int64_t diff = expect - msc;
34627 - /* We're way off here, assume that the kernel has lost its mind
34628 - * and smack the vblank back to something sensible
34629 - */
34630 - if (diff < -MAX_VBLANK_OFFSET || diff > MAX_VBLANK_OFFSET) {
34631 - intel_crtc->vblank_offset += (int32_t) diff;
34632 - if (intel_crtc->vblank_offset > -MAX_VBLANK_OFFSET &&
34633 - intel_crtc->vblank_offset < MAX_VBLANK_OFFSET)
34634 - intel_crtc->vblank_offset = 0;
34635 - }
34636 - }
34638 - return (uint32_t) (expect - intel_crtc->vblank_offset);
34639 + return (uint32_t)expect;
34642 /*
34643 @@ -1998,14 +2016,13 @@ intel_drm_handler(int fd, uint32_t frame, uint32_t sec, uint32_t usec, void *use
34644 static void
34645 intel_pageflip_complete(struct intel_mode *mode)
34647 - /* Release framebuffer */
34648 - drmModeRmFB(mode->fd, mode->old_fb_id);
34650 - if (!mode->pageflip_handler)
34651 + if (!mode->pageflip.handler)
34652 return;
34654 - mode->pageflip_handler(mode->fe_msc, mode->fe_usec,
34655 - mode->pageflip_data);
34656 + /* Release framebuffer */
34657 + drmModeRmFB(mode->fd, mode->old_fb_id);
34658 + mode->pageflip.handler(mode->fe_msc, mode->fe_usec,
34659 + mode->pageflip.data);
34662 /*
34663 @@ -2045,6 +2062,7 @@ intel_pageflip_handler(ScrnInfoPtr scrn, xf86CrtcPtr crtc,
34665 if (!mode)
34666 return;
34668 intel_pageflip_complete(mode);
34671 @@ -2060,18 +2078,18 @@ intel_pageflip_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data)
34672 if (!mode)
34673 return;
34675 - /* Release framebuffer */
34676 - drmModeRmFB(mode->fd, mode->old_fb_id);
34678 - if (!mode->pageflip_abort)
34679 + if (!mode->pageflip.abort)
34680 return;
34682 - mode->pageflip_abort(mode->pageflip_data);
34683 + /* Release framebuffer */
34684 + drmModeRmFB(mode->fd, mode->old_fb_id);
34685 + mode->pageflip.abort(mode->pageflip.data);
34688 /*
34689 * Check for pending DRM events and process them.
34690 */
34691 +#if !HAVE_NOTIFY_FD
34692 static void
34693 drm_wakeup_handler(pointer data, int err, pointer p)
34695 @@ -2086,6 +2104,14 @@ drm_wakeup_handler(pointer data, int err, pointer p)
34696 if (FD_ISSET(mode->fd, read_mask))
34697 drmHandleEvent(mode->fd, &mode->event_context);
34699 +#else
34700 +static void
34701 +drm_notify_fd(int fd, int ready, void *data)
34702 +{
34703 + struct intel_mode *mode = data;
34704 + drmHandleEvent(mode->fd, &mode->event_context);
34705 +}
34706 +#endif
34708 /*
34709 * If there are any available, read drm_events
34710 @@ -2231,10 +2257,6 @@ Bool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
34711 intel->use_pageflipping = TRUE;
34714 - if (xf86ReturnOptValBool(intel->Options, OPTION_DELETE_DP12, FALSE)) {
34715 - mode->delete_dp_12_displays = TRUE;
34716 - }
34718 intel->modes = mode;
34719 drmModeFreeResources(mode_res);
34720 return TRUE;
34721 @@ -2250,9 +2272,11 @@ intel_mode_init(struct intel_screen_private *intel)
34722 * registration within ScreenInit and not PreInit.
34723 */
34724 mode->flip_count = 0;
34725 - AddGeneralSocket(mode->fd);
34726 + SetNotifyFd(mode->fd, drm_notify_fd, X_NOTIFY_READ, mode);
34727 +#if !HAVE_NOTIFY_FD
34728 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
34729 drm_wakeup_handler, mode);
34730 +#endif
34733 void
34734 @@ -2276,9 +2300,11 @@ intel_mode_close(intel_screen_private *intel)
34736 intel_drm_abort_scrn(intel->scrn);
34738 +#if !HAVE_NOTIFY_FD
34739 RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
34740 drm_wakeup_handler, mode);
34741 - RemoveGeneralSocket(mode->fd);
34742 +#endif
34743 + RemoveNotifyFd(mode->fd);
34746 void
34747 @@ -2498,12 +2524,11 @@ intel_mode_hotplug(struct intel_screen_private *intel)
34748 int i, j;
34749 Bool found;
34750 Bool changed = FALSE;
34751 - struct intel_mode *mode = intel->modes;
34753 mode_res = drmModeGetResources(intel->drmSubFD);
34754 if (!mode_res)
34755 goto out;
34757 -restart_destroy:
34758 for (i = 0; i < config->num_output; i++) {
34759 xf86OutputPtr output = config->output[i];
34760 struct intel_output *intel_output;
34761 @@ -2522,13 +2547,9 @@ restart_destroy:
34762 drmModeFreeConnector(intel_output->mode_output);
34763 intel_output->mode_output = NULL;
34764 intel_output->output_id = -1;
34765 + RROutputChanged(output->randr_output, TRUE);
34767 changed = TRUE;
34768 - if (mode->delete_dp_12_displays) {
34769 - RROutputDestroy(output->randr_output);
34770 - xf86OutputDestroy(output);
34771 - goto restart_destroy;
34772 - }
34775 /* find new output ids we don't have outputs for */
34776 @@ -2552,10 +2573,8 @@ restart_destroy:
34777 intel_output_init(scrn, intel->modes, mode_res, i, 1);
34780 - if (changed) {
34781 - RRSetChanged(xf86ScrnToScreen(scrn));
34782 + if (changed)
34783 RRTellChanged(xf86ScrnToScreen(scrn));
34784 - }
34786 drmModeFreeResources(mode_res);
34787 out:
34788 diff --git a/src/uxa/intel_dri.c b/src/uxa/intel_dri.c
34789 index f61c6210..524826d2 100644
34790 --- a/src/uxa/intel_dri.c
34791 +++ b/src/uxa/intel_dri.c
34792 @@ -81,6 +81,47 @@ static DevPrivateKeyRec i830_client_key;
34793 static int i830_client_key;
34794 #endif
34796 +static void I830DRI2FlipEventHandler(unsigned int frame,
34797 + unsigned int tv_sec,
34798 + unsigned int tv_usec,
34799 + DRI2FrameEventPtr flip_info);
34801 +static void I830DRI2FrameEventHandler(unsigned int frame,
34802 + unsigned int tv_sec,
34803 + unsigned int tv_usec,
34804 + DRI2FrameEventPtr swap_info);
34806 +static void
34807 +i830_dri2_del_frame_event(DRI2FrameEventPtr info);
34809 +static uint32_t pipe_select(int pipe)
34810 +{
34811 + if (pipe > 1)
34812 + return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
34813 + else if (pipe > 0)
34814 + return DRM_VBLANK_SECONDARY;
34815 + else
34816 + return 0;
34817 +}
34819 +static void
34820 +intel_dri2_vblank_handler(ScrnInfoPtr scrn,
34821 + xf86CrtcPtr crtc,
34822 + uint64_t msc,
34823 + uint64_t usec,
34824 + void *data)
34825 +{
34826 + I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, data);
34827 +}
34829 +static void
34830 +intel_dri2_vblank_abort(ScrnInfoPtr scrn,
34831 + xf86CrtcPtr crtc,
34832 + void *data)
34833 +{
34834 + i830_dri2_del_frame_event(data);
34835 +}
34837 static uint32_t pixmap_flink(PixmapPtr pixmap)
34839 struct intel_uxa_pixmap *priv = intel_uxa_get_pixmap_private(pixmap);
34840 @@ -135,9 +176,6 @@ I830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments,
34841 pixmap = NULL;
34842 if (attachments[i] == DRI2BufferFrontLeft) {
34843 pixmap = get_front_buffer(drawable);
34845 - if (pixmap == NULL)
34846 - drawable = &(get_drawable_pixmap(drawable)->drawable);
34847 } else if (attachments[i] == DRI2BufferStencil && pDepthPixmap) {
34848 pixmap = pDepthPixmap;
34849 pixmap->refcnt++;
34850 @@ -246,11 +284,8 @@ I830DRI2CreateBuffer(DrawablePtr drawable, unsigned int attachment,
34853 pixmap = NULL;
34854 - if (attachment == DRI2BufferFrontLeft) {
34855 + if (attachment == DRI2BufferFrontLeft)
34856 pixmap = get_front_buffer(drawable);
34857 - if (pixmap == NULL)
34858 - drawable = &(get_drawable_pixmap(drawable)->drawable);
34859 - }
34861 if (pixmap == NULL) {
34862 unsigned int hint = INTEL_CREATE_PIXMAP_DRI2;
34863 @@ -673,6 +708,20 @@ i830_dri2_del_frame_event(DRI2FrameEventPtr info)
34864 if (info->back)
34865 I830DRI2DestroyBuffer(NULL, info->back);
34867 + if (info->old_buffer) {
34868 + /* Check that the old buffer still matches the front buffer
34869 + * in case a mode change occurred before we woke up.
34870 + */
34871 + if (info->intel->back_buffer == NULL &&
34872 + info->old_width == info->intel->scrn->virtualX &&
34873 + info->old_height == info->intel->scrn->virtualY &&
34874 + info->old_pitch == info->intel->front_pitch &&
34875 + info->old_tiling == info->intel->front_tiling)
34876 + info->intel->back_buffer = info->old_buffer;
34877 + else
34878 + dri_bo_unreference(info->old_buffer);
34879 + }
34881 free(info);
34884 @@ -708,16 +757,14 @@ static void
34885 I830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front, DRI2BufferPtr back)
34887 I830DRI2BufferPrivatePtr front_priv, back_priv;
34888 - int tmp;
34889 struct intel_uxa_pixmap *new_front;
34891 front_priv = front->driverPrivate;
34892 back_priv = back->driverPrivate;
34894 /* Swap BO names so DRI works */
34895 - tmp = front->name;
34896 front->name = back->name;
34897 - back->name = tmp;
34898 + back->name = pixmap_flink(front_priv->pixmap);
34900 /* Swap pixmap bos */
34901 new_front = intel_exchange_pixmap_buffers(intel,
34902 @@ -753,87 +800,30 @@ I830DRI2FlipAbort(void *pageflip_data)
34903 i830_dri2_del_frame_event(info);
34906 -/*
34907 - * Our internal swap routine takes care of actually exchanging, blitting, or
34908 - * flipping buffers as necessary.
34909 - */
34910 static Bool
34911 -I830DRI2ScheduleFlip(struct intel_screen_private *intel,
34912 - DrawablePtr draw,
34913 - DRI2FrameEventPtr info)
34914 +allocate_back_buffer(struct intel_screen_private *intel)
34916 - I830DRI2BufferPrivatePtr priv = info->back->driverPrivate;
34917 - drm_intel_bo *new_back, *old_back;
34918 - int tmp_name;
34920 - if (!intel->use_triple_buffer) {
34921 - info->type = DRI2_SWAP;
34922 - if (!intel_do_pageflip(intel,
34923 - get_pixmap_bo(priv),
34924 - info->pipe, FALSE, info,
34925 - I830DRI2FlipComplete,
34926 - I830DRI2FlipAbort))
34927 - return FALSE;
34929 - I830DRI2ExchangeBuffers(intel, info->front, info->back);
34930 - return TRUE;
34931 - }
34932 + drm_intel_bo *bo;
34933 + int pitch;
34934 + uint32_t tiling;
34936 - if (intel->pending_flip[info->pipe]) {
34937 - assert(intel->pending_flip[info->pipe]->chain == NULL);
34938 - intel->pending_flip[info->pipe]->chain = info;
34939 + if (intel->back_buffer)
34940 return TRUE;
34941 - }
34943 - if (intel->back_buffer == NULL) {
34944 - new_back = drm_intel_bo_alloc(intel->bufmgr, "front buffer",
34945 - intel->front_buffer->size, 0);
34946 - if (new_back == NULL)
34947 - return FALSE;
34949 - if (intel->front_tiling != I915_TILING_NONE) {
34950 - uint32_t tiling = intel->front_tiling;
34951 - drm_intel_bo_set_tiling(new_back, &tiling, intel->front_pitch);
34952 - if (tiling != intel->front_tiling) {
34953 - drm_intel_bo_unreference(new_back);
34954 - return FALSE;
34955 - }
34956 - }
34958 - drm_intel_bo_disable_reuse(new_back);
34959 - dri_bo_flink(new_back, &intel->back_name);
34960 - } else {
34961 - new_back = intel->back_buffer;
34962 - intel->back_buffer = NULL;
34963 - }
34964 + bo = intel_allocate_framebuffer(intel->scrn,
34965 + intel->scrn->virtualX,
34966 + intel->scrn->virtualY,
34967 + intel->cpp,
34968 + &pitch, &tiling);
34969 + if (bo == NULL)
34970 + return FALSE;
34972 - old_back = get_pixmap_bo(priv);
34973 - if (!intel_do_pageflip(intel, old_back, info->pipe, FALSE, info, I830DRI2FlipComplete, I830DRI2FlipAbort)) {
34974 - intel->back_buffer = new_back;
34975 + if (pitch != intel->front_pitch || tiling != intel->front_tiling) {
34976 + drm_intel_bo_unreference(bo);
34977 return FALSE;
34979 - info->type = DRI2_SWAP_CHAIN;
34980 - intel->pending_flip[info->pipe] = info;
34982 - priv = info->front->driverPrivate;
34984 - /* Exchange the current front-buffer with the fresh bo */
34986 - intel->back_buffer = intel->front_buffer;
34987 - drm_intel_bo_reference(intel->back_buffer);
34988 - intel_set_pixmap_bo(priv->pixmap, new_back);
34989 - drm_intel_bo_unreference(new_back);
34991 - tmp_name = info->front->name;
34992 - info->front->name = intel->back_name;
34993 - intel->back_name = tmp_name;
34995 - /* Then flip DRI2 pointers and update the screen pixmap */
34996 - I830DRI2ExchangeBuffers(intel, info->front, info->back);
34997 - DRI2SwapComplete(info->client, draw, 0, 0, 0,
34998 - DRI2_EXCHANGE_COMPLETE,
34999 - info->event_complete,
35000 - info->event_data);
35001 + intel->back_buffer = bo;
35002 return TRUE;
35005 @@ -889,8 +879,88 @@ can_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back)
35006 return TRUE;
35009 -void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
35010 - unsigned int tv_usec, DRI2FrameEventPtr swap_info)
35011 +static Bool
35012 +queue_flip(struct intel_screen_private *intel,
35013 + DrawablePtr draw,
35014 + DRI2FrameEventPtr info)
35015 +{
35016 + xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
35017 + I830DRI2BufferPrivatePtr priv = info->back->driverPrivate;
35018 + drm_intel_bo *old_back = get_pixmap_bo(priv);
35020 + if (crtc == NULL)
35021 + return FALSE;
35023 + if (!can_exchange(draw, info->front, info->back))
35024 + return FALSE;
35026 + if (!intel_do_pageflip(intel, old_back,
35027 + intel_crtc_to_pipe(crtc),
35028 + FALSE, info,
35029 + I830DRI2FlipComplete, I830DRI2FlipAbort))
35030 + return FALSE;
35032 +#if DRI2INFOREC_VERSION >= 6
35033 + if (intel->use_triple_buffer && allocate_back_buffer(intel)) {
35034 + info->old_width = intel->scrn->virtualX;
35035 + info->old_height = intel->scrn->virtualY;
35036 + info->old_pitch = intel->front_pitch;
35037 + info->old_tiling = intel->front_tiling;
35038 + info->old_buffer = intel->front_buffer;
35039 + dri_bo_reference(info->old_buffer);
35041 + priv = info->front->driverPrivate;
35042 + intel_set_pixmap_bo(priv->pixmap, intel->back_buffer);
35044 + dri_bo_unreference(intel->back_buffer);
35045 + intel->back_buffer = NULL;
35047 + DRI2SwapLimit(draw, 2);
35048 + } else
35049 + DRI2SwapLimit(draw, 1);
35050 +#endif
35052 + /* Then flip DRI2 pointers and update the screen pixmap */
35053 + I830DRI2ExchangeBuffers(intel, info->front, info->back);
35054 + return TRUE;
35055 +}
35057 +static Bool
35058 +queue_swap(struct intel_screen_private *intel,
35059 + DrawablePtr draw,
35060 + DRI2FrameEventPtr info)
35061 +{
35062 + xf86CrtcPtr crtc = I830DRI2DrawableCrtc(draw);
35063 + drmVBlank vbl;
35065 + if (crtc == NULL)
35066 + return FALSE;
35068 + vbl.request.type =
35069 + DRM_VBLANK_RELATIVE |
35070 + DRM_VBLANK_EVENT |
35071 + pipe_select(intel_crtc_to_pipe(crtc));
35072 + vbl.request.sequence = 1;
35073 + vbl.request.signal =
35074 + intel_drm_queue_alloc(intel->scrn, crtc, info,
35075 + intel_dri2_vblank_handler,
35076 + intel_dri2_vblank_abort);
35077 + if (vbl.request.signal == 0)
35078 + return FALSE;
35080 + info->type = DRI2_SWAP;
35081 + if (drmWaitVBlank(intel->drmSubFD, &vbl)) {
35082 + intel_drm_abort_seq(intel->scrn, vbl.request.signal);
35083 + return FALSE;
35084 + }
35086 + return TRUE;
35087 +}
35089 +static void I830DRI2FrameEventHandler(unsigned int frame,
35090 + unsigned int tv_sec,
35091 + unsigned int tv_usec,
35092 + DRI2FrameEventPtr swap_info)
35094 intel_screen_private *intel = swap_info->intel;
35095 DrawablePtr drawable;
35096 @@ -906,24 +976,22 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
35097 return;
35101 switch (swap_info->type) {
35102 case DRI2_FLIP:
35103 /* If we can still flip... */
35104 - if (can_exchange(drawable, swap_info->front, swap_info->back) &&
35105 - I830DRI2ScheduleFlip(intel, drawable, swap_info))
35106 - return;
35108 - /* else fall through to exchange/blit */
35109 - case DRI2_SWAP: {
35110 - I830DRI2FallbackBlitSwap(drawable,
35111 - swap_info->front, swap_info->back);
35112 - DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec,
35113 - DRI2_BLIT_COMPLETE,
35114 - swap_info->client ? swap_info->event_complete : NULL,
35115 - swap_info->event_data);
35116 - break;
35117 - }
35118 + if (!queue_flip(intel, drawable, swap_info) &&
35119 + !queue_swap(intel, drawable, swap_info)) {
35120 + case DRI2_SWAP:
35121 + I830DRI2FallbackBlitSwap(drawable,
35122 + swap_info->front, swap_info->back);
35123 + DRI2SwapComplete(swap_info->client, drawable, frame, tv_sec, tv_usec,
35124 + DRI2_BLIT_COMPLETE,
35125 + swap_info->client ? swap_info->event_complete : NULL,
35126 + swap_info->event_data);
35127 + break;
35128 + }
35129 + return;
35131 case DRI2_WAITMSC:
35132 if (swap_info->client)
35133 DRI2WaitMSCComplete(swap_info->client, drawable,
35134 @@ -939,12 +1007,13 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
35135 i830_dri2_del_frame_event(swap_info);
35138 -void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
35139 - unsigned int tv_usec, DRI2FrameEventPtr flip_info)
35140 +static void I830DRI2FlipEventHandler(unsigned int frame,
35141 + unsigned int tv_sec,
35142 + unsigned int tv_usec,
35143 + DRI2FrameEventPtr flip_info)
35145 struct intel_screen_private *intel = flip_info->intel;
35146 DrawablePtr drawable;
35147 - DRI2FrameEventPtr chain;
35149 drawable = NULL;
35150 if (flip_info->drawable_id)
35151 @@ -954,6 +1023,7 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
35153 /* We assume our flips arrive in order, so we don't check the frame */
35154 switch (flip_info->type) {
35155 + case DRI2_FLIP:
35156 case DRI2_SWAP:
35157 if (!drawable)
35158 break;
35159 @@ -984,35 +1054,6 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
35160 flip_info->event_data);
35161 break;
35163 - case DRI2_SWAP_CHAIN:
35164 - assert(intel->pending_flip[flip_info->pipe] == flip_info);
35165 - intel->pending_flip[flip_info->pipe] = NULL;
35167 - chain = flip_info->chain;
35168 - if (chain) {
35169 - DrawablePtr chain_drawable = NULL;
35170 - if (chain->drawable_id)
35171 - dixLookupDrawable(&chain_drawable,
35172 - chain->drawable_id,
35173 - serverClient,
35174 - M_ANY, DixWriteAccess);
35175 - if (chain_drawable == NULL) {
35176 - i830_dri2_del_frame_event(chain);
35177 - } else if (!can_exchange(chain_drawable, chain->front, chain->back) ||
35178 - !I830DRI2ScheduleFlip(intel, chain_drawable, chain)) {
35179 - I830DRI2FallbackBlitSwap(chain_drawable,
35180 - chain->front,
35181 - chain->back);
35183 - DRI2SwapComplete(chain->client, chain_drawable, frame, tv_sec, tv_usec,
35184 - DRI2_BLIT_COMPLETE,
35185 - chain->client ? chain->event_complete : NULL,
35186 - chain->event_data);
35187 - i830_dri2_del_frame_event(chain);
35188 - }
35189 - }
35190 - break;
35192 default:
35193 xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
35194 "%s: unknown vblank event received\n", __func__);
35195 @@ -1023,38 +1064,6 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
35196 i830_dri2_del_frame_event(flip_info);
35199 -static uint32_t pipe_select(int pipe)
35200 -{
35201 - if (pipe > 1)
35202 - return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT;
35203 - else if (pipe > 0)
35204 - return DRM_VBLANK_SECONDARY;
35205 - else
35206 - return 0;
35207 -}
35209 -static void
35210 -intel_dri2_vblank_handler(ScrnInfoPtr scrn,
35211 - xf86CrtcPtr crtc,
35212 - uint64_t msc,
35213 - uint64_t usec,
35214 - void *data)
35215 -{
35216 - DRI2FrameEventPtr swap_info = data;
35218 - I830DRI2FrameEventHandler((uint32_t) msc, usec / 1000000, usec % 1000000, swap_info);
35219 -}
35221 -static void
35222 -intel_dri2_vblank_abort(ScrnInfoPtr scrn,
35223 - xf86CrtcPtr crtc,
35224 - void *data)
35225 -{
35226 - DRI2FrameEventPtr swap_info = data;
35228 - i830_dri2_del_frame_event(swap_info);
35229 -}
35231 /*
35232 * ScheduleSwap is responsible for requesting a DRM vblank event for the
35233 * appropriate frame.
35234 @@ -1089,7 +1098,6 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
35235 int pipe = crtc ? intel_crtc_to_pipe(crtc) : -1;
35236 int flip = 0;
35237 DRI2FrameEventPtr swap_info = NULL;
35238 - enum DRI2FrameEventType swap_type = DRI2_SWAP;
35239 uint64_t current_msc, current_ust;
35240 uint64_t request_msc;
35241 uint32_t seq;
35242 @@ -1109,7 +1117,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
35243 swap_info->event_data = data;
35244 swap_info->front = front;
35245 swap_info->back = back;
35246 - swap_info->pipe = pipe;
35247 + swap_info->type = DRI2_SWAP;
35249 if (!i830_dri2_add_frame_event(swap_info)) {
35250 free(swap_info);
35251 @@ -1124,20 +1132,27 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
35252 if (ret)
35253 goto blit_fallback;
35255 - /* Flips need to be submitted one frame before */
35256 + /*
35257 + * If we can, schedule the flip directly from here rather
35258 + * than waiting for an event from the kernel for the current
35259 + * (or a past) MSC.
35260 + */
35261 + if (divisor == 0 &&
35262 + current_msc >= *target_msc &&
35263 + queue_flip(intel, draw, swap_info))
35264 + return TRUE;
35266 if (can_exchange(draw, front, back)) {
35267 - swap_type = DRI2_FLIP;
35268 - flip = 1;
35269 + swap_info->type = DRI2_FLIP;
35270 + /* Flips need to be submitted one frame before */
35271 + if (*target_msc > 0)
35272 + --*target_msc;
35273 + flip = 1;
35276 - swap_info->type = swap_type;
35278 - /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
35279 - * Do it early, so handling of different timing constraints
35280 - * for divisor, remainder and msc vs. target_msc works.
35281 - */
35282 - if (*target_msc > 0)
35283 - *target_msc -= flip;
35284 +#if DRI2INFOREC_VERSION >= 6
35285 + DRI2SwapLimit(draw, 1);
35286 +#endif
35288 /*
35289 * If divisor is zero, or current_msc is smaller than target_msc
35290 @@ -1145,15 +1160,6 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
35291 * the swap.
35292 */
35293 if (divisor == 0 || current_msc < *target_msc) {
35294 - /*
35295 - * If we can, schedule the flip directly from here rather
35296 - * than waiting for an event from the kernel for the current
35297 - * (or a past) MSC.
35298 - */
35299 - if (flip && divisor == 0 && current_msc >= *target_msc &&
35300 - I830DRI2ScheduleFlip(intel, draw, swap_info))
35301 - return TRUE;
35303 vbl.request.type =
35304 DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
35306 @@ -1168,7 +1174,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
35307 * current_msc to ensure we return a reasonable value back
35308 * to the caller. This makes swap_interval logic more robust.
35309 */
35310 - if (current_msc >= *target_msc)
35311 + if (current_msc > *target_msc)
35312 *target_msc = current_msc;
35314 seq = intel_drm_queue_alloc(scrn, crtc, swap_info, intel_dri2_vblank_handler, intel_dri2_vblank_abort);
35315 @@ -1183,6 +1189,8 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
35316 xf86DrvMsg(scrn->scrnIndex, X_WARNING,
35317 "divisor 0 get vblank counter failed: %s\n",
35318 strerror(errno));
35319 + intel_drm_abort_seq(intel->scrn, seq);
35320 + swap_info = NULL;
35321 goto blit_fallback;
35324 @@ -1332,7 +1340,6 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
35326 if (!i830_dri2_add_frame_event(wait_info)) {
35327 free(wait_info);
35328 - wait_info = NULL;
35329 goto out_complete;
35332 @@ -1374,7 +1381,8 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
35333 strerror(errno));
35334 limit--;
35336 - goto out_free;
35337 + intel_drm_abort_seq(intel->scrn, seq);
35338 + goto out_complete;
35341 wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
35342 @@ -1417,7 +1425,8 @@ I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
35343 strerror(errno));
35344 limit--;
35346 - goto out_free;
35347 + intel_drm_abort_seq(intel->scrn, seq);
35348 + goto out_complete;
35351 wait_info->frame = intel_sequence_to_crtc_msc(crtc, vbl.reply.sequence);
35352 @@ -1440,13 +1449,92 @@ static int has_i830_dri(void)
35353 return access(DRI_DRIVER_PATH "/i830_dri.so", R_OK) == 0;
35356 -static const char *dri_driver_name(intel_screen_private *intel)
35357 +static int
35358 +namecmp(const char *s1, const char *s2)
35359 +{
35360 + char c1, c2;
35362 + if (!s1 || *s1 == 0) {
35363 + if (!s2 || *s2 == 0)
35364 + return 0;
35365 + else
35366 + return 1;
35367 + }
35369 + while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
35370 + s1++;
35372 + while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
35373 + s2++;
35375 + c1 = isupper(*s1) ? tolower(*s1) : *s1;
35376 + c2 = isupper(*s2) ? tolower(*s2) : *s2;
35377 + while (c1 == c2) {
35378 + if (c1 == '\0')
35379 + return 0;
35381 + s1++;
35382 + while (*s1 == '_' || *s1 == ' ' || *s1 == '\t')
35383 + s1++;
35385 + s2++;
35386 + while (*s2 == '_' || *s2 == ' ' || *s2 == '\t')
35387 + s2++;
35389 + c1 = isupper(*s1) ? tolower(*s1) : *s1;
35390 + c2 = isupper(*s2) ? tolower(*s2) : *s2;
35391 + }
35393 + return c1 - c2;
35394 +}
35396 +static Bool is_level(const char **str)
35397 +{
35398 + const char *s = *str;
35399 + char *end;
35400 + unsigned val;
35402 + if (s == NULL || *s == '\0')
35403 + return TRUE;
35405 + if (namecmp(s, "on") == 0)
35406 + return TRUE;
35407 + if (namecmp(s, "true") == 0)
35408 + return TRUE;
35409 + if (namecmp(s, "yes") == 0)
35410 + return TRUE;
35412 + if (namecmp(s, "0") == 0)
35413 + return TRUE;
35414 + if (namecmp(s, "off") == 0)
35415 + return TRUE;
35416 + if (namecmp(s, "false") == 0)
35417 + return TRUE;
35418 + if (namecmp(s, "no") == 0)
35419 + return TRUE;
35421 + val = strtoul(s, &end, 0);
35422 + if (val && *end == '\0')
35423 + return TRUE;
35424 + if (val && *end == ':')
35425 + *str = end + 1;
35426 + return FALSE;
35427 +}
35429 +static const char *options_get_dri(intel_screen_private *intel)
35431 #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
35432 - const char *s = xf86GetOptValString(intel->Options, OPTION_DRI);
35433 - Bool dummy;
35434 + return xf86GetOptValString(intel->Options, OPTION_DRI);
35435 +#else
35436 + return NULL;
35437 +#endif
35438 +}
35440 - if (s == NULL || xf86getBoolValue(&dummy, s)) {
35441 +static const char *dri_driver_name(intel_screen_private *intel)
35442 +{
35443 + const char *s = options_get_dri(intel);
35445 + if (is_level(&s)) {
35446 if (INTEL_INFO(intel)->gen < 030)
35447 return has_i830_dri() ? "i830" : "i915";
35448 else if (INTEL_INFO(intel)->gen < 040)
35449 @@ -1456,14 +1544,6 @@ static const char *dri_driver_name(intel_screen_private *intel)
35452 return s;
35453 -#else
35454 - if (INTEL_INFO(intel)->gen < 030)
35455 - return has_i830_dri() ? "i830" : "i915";
35456 - else if (INTEL_INFO(intel)->gen < 040)
35457 - return "i915";
35458 - else
35459 - return "i965";
35460 -#endif
35463 Bool I830DRI2ScreenInit(ScreenPtr screen)
35464 @@ -1544,7 +1624,7 @@ Bool I830DRI2ScreenInit(ScreenPtr screen)
35465 info.numDrivers = 2;
35466 info.driverNames = driverNames;
35467 driverNames[0] = info.driverName;
35468 - driverNames[1] = info.driverName;
35469 + driverNames[1] = "va_gl";
35470 #endif
35472 return DRI2ScreenInit(screen, &info);
35473 diff --git a/src/uxa/intel_driver.c b/src/uxa/intel_driver.c
35474 index 2793da5d..3703c412 100644
35475 --- a/src/uxa/intel_driver.c
35476 +++ b/src/uxa/intel_driver.c
35477 @@ -237,24 +237,17 @@ static Bool I830GetEarlyOptions(ScrnInfoPtr scrn)
35478 return TRUE;
35481 -static Bool intel_option_cast_string_to_bool(intel_screen_private *intel,
35482 - int id, Bool val)
35483 -{
35484 -#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,99,901,0)
35485 - xf86getBoolValue(&val, xf86GetOptValString(intel->Options, id));
35486 - return val;
35487 -#else
35488 - return val;
35489 -#endif
35490 -}
35492 static void intel_check_dri_option(ScrnInfoPtr scrn)
35494 intel_screen_private *intel = intel_get_screen_private(scrn);
35495 + unsigned level;
35497 intel->dri2 = intel->dri3 = DRI_NONE;
35498 - if (!intel_option_cast_string_to_bool(intel, OPTION_DRI, TRUE))
35499 - intel->dri2 = intel->dri3 = DRI_DISABLED;
35500 + level = intel_option_cast_to_unsigned(intel->Options, OPTION_DRI, DEFAULT_DRI_LEVEL);
35501 + if (level < 3 || INTEL_INFO(intel)->gen < 040)
35502 + intel->dri3 = DRI_DISABLED;
35503 + if (level < 2)
35504 + intel->dri2 = DRI_DISABLED;
35506 if (scrn->depth != 16 && scrn->depth != 24 && scrn->depth != 30) {
35507 xf86DrvMsg(scrn->scrnIndex, X_CONFIG,
35508 @@ -371,8 +364,8 @@ static Bool can_accelerate_blt(struct intel_screen_private *intel)
35509 if (INTEL_INFO(intel)->gen == -1)
35510 return FALSE;
35512 - if (xf86ReturnOptValBool(intel->Options, OPTION_ACCEL_DISABLE, FALSE) ||
35513 - !intel_option_cast_string_to_bool(intel, OPTION_ACCEL_METHOD, TRUE)) {
35514 + if (!xf86ReturnOptValBool(intel->Options, OPTION_ACCEL_ENABLE, TRUE) ||
35515 + !intel_option_cast_to_bool(intel->Options, OPTION_ACCEL_METHOD, TRUE)) {
35516 xf86DrvMsg(intel->scrn->scrnIndex, X_CONFIG,
35517 "Disabling hardware acceleration.\n");
35518 return FALSE;
35519 @@ -659,8 +652,9 @@ redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty)
35522 static void
35523 -intel_dirty_update(ScreenPtr screen)
35524 +intel_dirty_update(intel_screen_private *intel)
35526 + ScreenPtr screen = xf86ScrnToScreen(intel->scrn);
35527 RegionPtr region;
35528 PixmapDirtyUpdatePtr ent;
35530 @@ -677,6 +671,7 @@ intel_dirty_update(ScreenPtr screen)
35532 #endif
35534 +#if !HAVE_NOTIFY_FD
35535 static void
35536 I830BlockHandler(BLOCKHANDLER_ARGS_DECL)
35538 @@ -694,9 +689,22 @@ I830BlockHandler(BLOCKHANDLER_ARGS_DECL)
35539 intel_uxa_block_handler(intel);
35540 intel_video_block_handler(intel);
35541 #ifdef INTEL_PIXMAP_SHARING
35542 - intel_dirty_update(screen);
35543 + intel_dirty_update(intel);
35544 #endif
35546 +#else
35547 +static void
35548 +I830BlockHandler(void *data, void *timeout)
35549 +{
35550 + intel_screen_private *intel = data;
35552 + intel_uxa_block_handler(intel);
35553 + intel_video_block_handler(intel);
35554 +#ifdef INTEL_PIXMAP_SHARING
35555 + intel_dirty_update(intel);
35556 +#endif
35557 +}
35558 +#endif
35560 static Bool
35561 intel_init_initial_framebuffer(ScrnInfoPtr scrn)
35562 @@ -735,6 +743,8 @@ intel_flush_callback(CallbackListPtr *list,
35565 #if HAVE_UDEV
35566 +#include <sys/stat.h>
35568 static void
35569 I830HandleUEvents(int fd, void *closure)
35571 @@ -771,6 +781,15 @@ I830HandleUEvents(int fd, void *closure)
35572 udev_device_unref(dev);
35575 +static int has_randr(void)
35576 +{
35577 +#if HAS_DIXREGISTERPRIVATEKEY
35578 + return dixPrivateKeyRegistered(rrPrivKey);
35579 +#else
35580 + return *rrPrivKey;
35581 +#endif
35582 +}
35584 static void
35585 I830UeventInit(ScrnInfoPtr scrn)
35587 @@ -780,6 +799,10 @@ I830UeventInit(ScrnInfoPtr scrn)
35588 Bool hotplug;
35589 MessageType from = X_CONFIG;
35591 + /* Without RR, nothing we can do here */
35592 + if (!has_randr())
35593 + return;
35595 if (!xf86GetOptValBool(intel->Options, OPTION_HOTPLUG, &hotplug)) {
35596 from = X_DEFAULT;
35597 hotplug = TRUE;
35598 @@ -939,8 +962,14 @@ I830ScreenInit(SCREEN_INIT_ARGS_DECL)
35599 "Hardware cursor initialization failed\n");
35602 +#if !HAVE_NOTIFY_FD
35603 intel->BlockHandler = screen->BlockHandler;
35604 screen->BlockHandler = I830BlockHandler;
35605 +#else
35606 + RegisterBlockAndWakeupHandlers(I830BlockHandler,
35607 + (ServerWakeupHandlerProcPtr)NoopDDA,
35608 + intel);
35609 +#endif
35611 #ifdef INTEL_PIXMAP_SHARING
35612 screen->StartPixmapTracking = PixmapStartDirtyTracking;
35613 @@ -1164,8 +1193,6 @@ static Bool I830CloseScreen(CLOSE_SCREEN_ARGS_DECL)
35615 intel_sync_close(screen);
35617 - xf86GARTCloseScreen(scrn->scrnIndex);
35619 scrn->vtSema = FALSE;
35620 return TRUE;
35622 diff --git a/src/uxa/intel_hwmc.c b/src/uxa/intel_hwmc.c
35623 index 829cb8e0..78540600 100644
35624 --- a/src/uxa/intel_hwmc.c
35625 +++ b/src/uxa/intel_hwmc.c
35626 @@ -193,7 +193,7 @@ Bool intel_xvmc_adaptor_init(ScreenPtr pScreen)
35627 intel_screen_private *intel = intel_get_screen_private(scrn);
35628 struct pci_device *pci;
35629 static XF86MCAdaptorRec *pAdapt;
35630 - char *name;
35631 + const char *name;
35632 char buf[64];
35634 if (!intel->XvMCEnabled)
35635 diff --git a/src/uxa/intel_memory.c b/src/uxa/intel_memory.c
35636 index 0c6cf30c..b2d7a367 100644
35637 --- a/src/uxa/intel_memory.c
35638 +++ b/src/uxa/intel_memory.c
35639 @@ -42,7 +42,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35640 * This is the video memory allocator. Our memory allocation is different from
35641 * other graphics chips, where you have a fixed amount of graphics memory
35642 * available that you want to put to the best use. Instead, we have almost no
35643 - * memory pre-allocated, and we have to choose an appropriate amount of sytem
35644 + * memory pre-allocated, and we have to choose an appropriate amount of system
35645 * memory to use.
35647 * The allocations we might do:
35648 diff --git a/src/uxa/intel_present.c b/src/uxa/intel_present.c
35649 index d20043f3..ac028edd 100644
35650 --- a/src/uxa/intel_present.c
35651 +++ b/src/uxa/intel_present.c
35652 @@ -244,6 +244,7 @@ intel_present_check_flip(RRCrtcPtr crtc,
35653 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
35654 intel_screen_private *intel = intel_get_screen_private(scrn);
35655 dri_bo *bo;
35656 + uint32_t tiling, swizzle;
35658 if (!scrn->vtSema)
35659 return FALSE;
35660 @@ -266,6 +267,12 @@ intel_present_check_flip(RRCrtcPtr crtc,
35661 if (!bo)
35662 return FALSE;
35664 + if (drm_intel_bo_get_tiling(bo, &tiling, &swizzle))
35665 + return FALSE;
35667 + if (tiling == I915_TILING_Y)
35668 + return FALSE;
35670 return TRUE;
35673 @@ -343,29 +350,33 @@ intel_present_unflip(ScreenPtr screen, uint64_t event_id)
35675 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
35676 intel_screen_private *intel = intel_get_screen_private(scrn);
35677 - struct intel_present_vblank_event *event;
35678 PixmapPtr pixmap = screen->GetScreenPixmap(screen);
35679 + struct intel_present_vblank_event *event = NULL;
35680 dri_bo *bo;
35681 - Bool ret;
35683 if (!intel_present_check_flip(NULL, screen->root, pixmap, true))
35684 - return;
35685 + goto fail;
35687 bo = intel_get_pixmap_bo(pixmap);
35688 if (!bo)
35689 - return;
35690 + goto fail;
35692 event = calloc(1, sizeof(struct intel_present_vblank_event));
35693 if (!event)
35694 - return;
35695 + goto fail;
35697 event->event_id = event_id;
35699 - ret = intel_do_pageflip(intel, bo, -1, FALSE, event, intel_present_flip_event, intel_present_flip_abort);
35700 - if (!ret) {
35701 - xf86DrvMsg(scrn->scrnIndex, X_ERROR,
35702 - "present unflip failed\n");
35703 - }
35704 + if (!intel_do_pageflip(intel, bo, -1, FALSE, event,
35705 + intel_present_flip_event,
35706 + intel_present_flip_abort))
35707 + goto fail;
35709 + return;
35710 +fail:
35711 + xf86SetDesiredModes(scrn);
35712 + present_event_notify(event_id, 0, 0);
35713 + free(event);
35716 static present_screen_info_rec intel_present_screen_info = {
35717 diff --git a/src/uxa/intel_uxa.c b/src/uxa/intel_uxa.c
35718 index 590ff5d1..ec32a723 100644
35719 --- a/src/uxa/intel_uxa.c
35720 +++ b/src/uxa/intel_uxa.c
35721 @@ -176,6 +176,24 @@ intel_uxa_check_solid(DrawablePtr drawable, int alu, Pixel planemask)
35722 return TRUE;
35725 +static Bool
35726 +intel_uxa_check_bo_tiling(intel_screen_private *intel,
35727 + PixmapPtr pixmap,
35728 + unsigned *tiling_out)
35729 +{
35730 + struct intel_uxa_pixmap *priv;
35732 + priv = intel_uxa_get_pixmap_private(pixmap);
35733 + if (!priv)
35734 + return FALSE;
35736 + if (priv->tiling == I915_TILING_Y && INTEL_INFO(intel)->gen < 060)
35737 + return FALSE;
35739 + *tiling_out = priv->tiling;
35740 + return TRUE;
35741 +}
35743 /**
35744 * Sets up hardware state for a series of solid fills.
35745 */
35746 @@ -189,6 +207,9 @@ intel_uxa_prepare_solid(PixmapPtr pixmap, int alu, Pixel planemask, Pixel fg)
35747 intel_uxa_get_pixmap_bo(pixmap),
35748 };
35750 + if (!intel_uxa_check_bo_tiling(intel, pixmap, &intel->BR_tiling[0]))
35751 + return FALSE;
35753 if (!intel_uxa_check_pitch_2d(pixmap))
35754 return FALSE;
35756 @@ -236,7 +257,7 @@ static void intel_uxa_solid(PixmapPtr pixmap, int x1, int y1, int x2, int y2)
35759 int len = INTEL_INFO(intel)->gen >= 0100 ? 7 : 6;
35760 - BEGIN_BATCH_BLT(len);
35761 + BEGIN_BATCH_BLT_TILED(len);
35763 cmd = XY_COLOR_BLT_CMD | (len - 2);
35765 @@ -310,6 +331,10 @@ intel_uxa_prepare_copy(PixmapPtr source, PixmapPtr dest, int xdir,
35766 intel_uxa_get_pixmap_bo(dest),
35767 };
35769 + if (!intel_uxa_check_bo_tiling(intel, dest, &intel->BR_tiling[0]) ||
35770 + !intel_uxa_check_bo_tiling(intel, source, &intel->BR_tiling[1]))
35771 + return FALSE;
35773 if (!intel_uxa_get_aperture_space(scrn, bo_table, ARRAY_SIZE(bo_table)))
35774 return FALSE;
35776 @@ -375,7 +400,7 @@ intel_uxa_copy(PixmapPtr dest, int src_x1, int src_y1, int dst_x1,
35779 int len = INTEL_INFO(intel)->gen >= 0100 ? 10 : 8;
35780 - BEGIN_BATCH_BLT(len);
35781 + BEGIN_BATCH_BLT_TILED(len);
35783 cmd = XY_SRC_COPY_BLT_CMD | (len - 2);
35785 @@ -1068,7 +1093,7 @@ Bool intel_uxa_create_screen_resources(ScreenPtr screen)
35786 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
35787 PixmapPtr pixmap;
35788 intel_screen_private *intel = intel_get_screen_private(scrn);
35789 - dri_bo *bo = intel->front_buffer;
35790 + dri_bo *bo = intel->front_buffer, *old_bo;
35791 int old_width, old_height, old_pitch;
35793 if (!uxa_resources_init(screen))
35794 @@ -1081,6 +1106,7 @@ Bool intel_uxa_create_screen_resources(ScreenPtr screen)
35795 old_width = pixmap->drawable.width;
35796 old_height = pixmap->drawable.height;
35797 old_pitch = pixmap->devKind;
35798 + old_bo = intel_uxa_get_pixmap_bo(pixmap);
35800 if (!screen->ModifyPixmapHeader(pixmap,
35801 scrn->virtualX,
35802 @@ -1102,6 +1128,9 @@ Bool intel_uxa_create_screen_resources(ScreenPtr screen)
35803 err:
35804 screen->ModifyPixmapHeader(pixmap,
35805 old_width, old_height, -1, -1, old_pitch, NULL);
35806 + if (old_bo)
35807 + intel_uxa_set_pixmap_bo(pixmap, old_bo);
35809 return FALSE;
35812 diff --git a/test/Makefile.am b/test/Makefile.am
35813 index 66ed8ebb..12b5d5d8 100644
35814 --- a/test/Makefile.am
35815 +++ b/test/Makefile.am
35816 @@ -5,6 +5,7 @@ stress_TESTS = \
35817 basic-rectangle \
35818 basic-string \
35819 basic-copyarea \
35820 + basic-copyplane \
35821 basic-copyarea-size \
35822 basic-putimage \
35823 basic-lines \
35824 @@ -12,8 +13,10 @@ stress_TESTS = \
35825 DrawSegments \
35826 cursor-test \
35827 render-fill \
35828 + render-glyphs \
35829 render-trapezoid \
35830 render-trapezoid-image \
35831 + render-triangle \
35832 render-fill-copy \
35833 render-composite-solid \
35834 render-composite-solid-mask \
35835 @@ -25,9 +28,16 @@ stress_TESTS = \
35836 shm-test \
35837 $(NULL)
35839 +if X11_VM
35840 +stress_TESTS += \
35841 + xvidmode \
35842 + $(NULL)
35843 +endif
35845 if DRI2
35846 stress_TESTS += \
35847 dri2-race \
35848 + dri2-speed \
35849 dri2-swap \
35850 dri2-test \
35851 $(NULL)
35852 @@ -36,8 +46,11 @@ endif
35853 if X11_DRI3
35854 stress_TESTS += \
35855 dri3-test \
35856 + present-race \
35857 + present-speed \
35858 present-test \
35859 $(NULL)
35860 +present_speed_CFLAGS = ${AM_CFLAGS} -pthread
35861 endif
35862 check_PROGRAMS = $(stress_TESTS)
35864 diff --git a/test/basic-copyplane.c b/test/basic-copyplane.c
35865 new file mode 100644
35866 index 00000000..f049b82b
35867 --- /dev/null
35868 +++ b/test/basic-copyplane.c
35869 @@ -0,0 +1,99 @@
35870 +#include <stdint.h>
35871 +#include <stdio.h>
35872 +#include <stdlib.h>
35874 +#include <X11/Xutil.h> /* for XDestroyImage */
35875 +#include <pixman.h> /* for pixman blt functions */
35877 +#include "test.h"
35879 +static uint8_t clock_bits[] = {0x3C, 0x5E, 0xEF, 0xF7, 0x87, 0xFF, 0x7E, 0x3C};
35881 +/* https://bugs.freedesktop.org/show_bug.cgi?id=91499 */
35882 +static void draw_clock(struct test_display *t, Drawable d,
35883 + uint8_t alu, int x, int y, uint32_t fg, uint32_t bg)
35884 +{
35885 + Pixmap pixmap;
35886 + XGCValues val;
35887 + GC gc;
35889 + val.graphics_exposures = 0;
35890 + val.function = alu;
35891 + val.foreground = fg;
35892 + val.background = fg;
35894 + gc = XCreateGC(t->dpy, d,
35895 + GCGraphicsExposures | GCForeground | GCBackground | GCFunction,
35896 + &val);
35897 + pixmap = XCreateBitmapFromData(t->dpy, d, (char *)clock_bits, 8, 8);
35899 + XCopyPlane(t->dpy, pixmap, d, gc, 0, 0, 8, 8, x, y, 1);
35901 + XFreePixmap(t->dpy, pixmap);
35902 + XFreeGC(t->dpy, gc);
35903 +}
35905 +static void clear(struct test_display *dpy, struct test_target *tt)
35906 +{
35907 + XRenderColor render_color = {0};
35908 + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color,
35909 + 0, 0, tt->width, tt->height);
35910 +}
35912 +static void clock_tests(struct test *t, int reps, int sets, enum target target)
35913 +{
35914 + struct test_target out, ref;
35915 + int r, s;
35917 + printf("Testing clock (%s): ", test_target_name(target));
35918 + fflush(stdout);
35920 + test_target_create_render(&t->out, target, &out);
35921 + clear(&t->out, &out);
35923 + test_target_create_render(&t->ref, target, &ref);
35924 + clear(&t->ref, &ref);
35926 + for (s = 0; s < sets; s++) {
35927 + for (r = 0; r < reps; r++) {
35928 + int x = rand() % (out.width - 8);
35929 + int y = rand() % (out.height - 8);
35930 + uint8_t alu = rand() % (GXset + 1);
35931 + uint32_t bg = rand();
35932 + uint32_t fg = rand();
35934 + draw_clock(&t->out, out.draw, alu, x, y, fg, bg);
35935 + draw_clock(&t->ref, ref.draw, alu, x, y, fg, bg);
35936 + }
35938 + test_compare(t,
35939 + out.draw, out.format,
35940 + ref.draw, ref.format,
35941 + 0, 0, out.width, out.height,
35942 + "");
35943 + }
35945 + printf("passed [%d iterations x %d]\n", reps, sets);
35947 + test_target_destroy_render(&t->out, &out);
35948 + test_target_destroy_render(&t->ref, &ref);
35949 +}
35951 +int main(int argc, char **argv)
35952 +{
35953 + struct test test;
35954 + int i;
35956 + test_init(&test, argc, argv);
35958 + for (i = 0; i <= DEFAULT_ITERATIONS; i++) {
35959 + int reps = REPS(i), sets = SETS(i);
35960 + enum target t;
35962 + for (t = TARGET_FIRST; t <= TARGET_LAST; t++) {
35963 + clock_tests(&test, reps, sets, t);
35964 + }
35965 + }
35967 + return 0;
35968 +}
35969 diff --git a/test/dri2-race.c b/test/dri2-race.c
35970 index 8862c84c..ece624f6 100644
35971 --- a/test/dri2-race.c
35972 +++ b/test/dri2-race.c
35973 @@ -5,6 +5,11 @@
35974 #include <X11/Xlib.h>
35975 #include <X11/Xutil.h>
35976 #include <X11/extensions/Xfixes.h>
35977 +#include <X11/extensions/Xcomposite.h>
35978 +#include <X11/Xlib-xcb.h>
35979 +#include <xcb/xcb.h>
35980 +#include <xcb/xcbext.h>
35981 +#include <xcb/dri2.h>
35982 #include <unistd.h>
35983 #include <fcntl.h>
35984 #include <string.h>
35985 @@ -12,11 +17,49 @@
35987 #include <xf86drm.h>
35988 #include <drm.h>
35989 +#include <setjmp.h>
35991 #include "dri2.h"
35993 #define COUNT 60
35995 +#define N_DIVISORS 3
35996 +static const int divisors[N_DIVISORS] = { 0, 1, 16 };
35998 +static jmp_buf error_handler[4];
35999 +static int have_error_handler;
36001 +#define error_get() \
36002 + setjmp(error_handler[have_error_handler++])
36004 +#define error_put() \
36005 + have_error_handler--
36007 +static int (*saved_io_error)(Display *dpy);
36009 +static int io_error(Display *dpy)
36010 +{
36011 + if (have_error_handler)
36012 + longjmp(error_handler[--have_error_handler], 0);
36014 + return saved_io_error(dpy);
36015 +}
36017 +static int x_error(Display *dpy, XErrorEvent *e)
36018 +{
36019 + return Success;
36020 +}
36022 +static uint32_t upper_32_bits(uint64_t val)
36023 +{
36024 + return val >> 32;
36025 +}
36027 +static uint32_t lower_32_bits(uint64_t val)
36028 +{
36029 + return val & 0xffffffff;
36030 +}
36032 static int dri2_open(Display *dpy)
36034 drm_auth_t auth;
36035 @@ -41,45 +84,701 @@ static int dri2_open(Display *dpy)
36036 return fd;
36039 -static void run(Display *dpy, int width, int height,
36040 - unsigned int *attachments, int nattachments,
36041 - const char *name)
36042 +static void swap_buffers(Display *dpy, Window win, int divisor,
36043 + unsigned int *attachments, int nattachments)
36044 +{
36045 + xcb_connection_t *c = XGetXCBConnection(dpy);
36046 + unsigned int seq[2];
36048 + seq[0] = xcb_dri2_swap_buffers_unchecked(c, win,
36049 + 0, 0, 0, divisor, 0, 0).sequence;
36052 + seq[1] = xcb_dri2_get_buffers_unchecked(c, win,
36053 + nattachments, nattachments,
36054 + attachments).sequence;
36056 + xcb_flush(c);
36057 + xcb_discard_reply(c, seq[0]);
36058 + xcb_discard_reply(c, seq[1]);
36059 +}
36061 +#define COMPOSITE 1
36063 +static int has_composite(Display *dpy)
36064 +{
36065 + Display *dummy = NULL;
36066 + int event, error;
36067 + int major = -1, minor = -1;
36069 + if (dpy == NULL)
36070 + dummy = dpy = XOpenDisplay(NULL);
36072 + if (XCompositeQueryExtension(dpy, &event, &error))
36073 + XCompositeQueryVersion(dpy, &major, &minor);
36075 + if (dummy)
36076 + XCloseDisplay(dummy);
36078 + return major > 0 || minor >= 4;
36079 +}
36081 +static void race_window(Display *dpy, int width, int height,
36082 + unsigned int *attachments, int nattachments,
36083 + unsigned flags, const char *name)
36085 Window win;
36086 XSetWindowAttributes attr;
36087 - int count, loop;
36088 + int count, loop, n;
36089 DRI2Buffer *buffers;
36091 + if (flags & COMPOSITE && !has_composite(dpy))
36092 + return;
36094 + printf("%s(%s)\n", __func__, name);
36096 /* Be nasty and install a fullscreen window on top so that we
36097 * can guarantee we do not get clipped by children.
36098 */
36099 attr.override_redirect = 1;
36100 - loop = 100;
36101 - do {
36102 + for (n = 0; n < N_DIVISORS; n++) {
36103 + loop = 256 >> ffs(divisors[n]);
36104 + printf("DRI2SwapBuffers(divisor=%d), loop=%d", divisors[n], loop);
36105 + fflush(stdout);
36106 + do {
36107 + win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36108 + 0, 0, width, height, 0,
36109 + DefaultDepth(dpy, DefaultScreen(dpy)),
36110 + InputOutput,
36111 + DefaultVisual(dpy, DefaultScreen(dpy)),
36112 + CWOverrideRedirect, &attr);
36113 + if (flags & COMPOSITE)
36114 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36115 + XMapWindow(dpy, win);
36117 + DRI2CreateDrawable(dpy, win);
36119 + buffers = DRI2GetBuffers(dpy, win, &width, &height,
36120 + attachments, nattachments, &count);
36121 + if (count != nattachments)
36122 + return;
36124 + free(buffers);
36125 + for (count = 0; count < loop; count++)
36126 + DRI2SwapBuffers(dpy, win, 0, divisors[n], count & (divisors[n]-1));
36127 + XDestroyWindow(dpy, win);
36128 + printf("."); fflush(stdout);
36129 + } while (--loop);
36130 + printf("*\n");
36131 + }
36133 + for (n = 0; n < N_DIVISORS; n++) {
36134 + loop = 256 >> ffs(divisors[n]);
36135 + printf("xcb_dri2_swap_buffers(divisor=%d), loops=%d", divisors[n], loop);
36136 + fflush(stdout);
36137 + do {
36138 + win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36139 + 0, 0, width, height, 0,
36140 + DefaultDepth(dpy, DefaultScreen(dpy)),
36141 + InputOutput,
36142 + DefaultVisual(dpy, DefaultScreen(dpy)),
36143 + CWOverrideRedirect, &attr);
36144 + if (flags & COMPOSITE)
36145 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36146 + XMapWindow(dpy, win);
36148 + DRI2CreateDrawable(dpy, win);
36150 + buffers = DRI2GetBuffers(dpy, win, &width, &height,
36151 + attachments, nattachments, &count);
36152 + if (count != nattachments)
36153 + return;
36155 + free(buffers);
36156 + for (count = 0; count < loop; count++)
36157 + swap_buffers(dpy, win, divisors[n], attachments, nattachments);
36158 + XDestroyWindow(dpy, win);
36159 + printf("."); fflush(stdout);
36160 + } while (--loop);
36161 + printf("*\n");
36162 + }
36164 + for (n = 0; n < N_DIVISORS; n++) {
36165 + loop = 256 >> ffs(divisors[n]);
36166 + printf("DRI2WaitMsc(divisor=%d), loop=%d", divisors[n], loop);
36167 + fflush(stdout);
36168 + do {
36169 + uint64_t ignore, msc;
36170 + xcb_connection_t *c = XGetXCBConnection(dpy);
36172 + win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36173 + 0, 0, width, height, 0,
36174 + DefaultDepth(dpy, DefaultScreen(dpy)),
36175 + InputOutput,
36176 + DefaultVisual(dpy, DefaultScreen(dpy)),
36177 + CWOverrideRedirect, &attr);
36178 + if (flags & COMPOSITE)
36179 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36180 + XMapWindow(dpy, win);
36182 + DRI2CreateDrawable(dpy, win);
36183 + DRI2GetMSC(dpy, win, &ignore, &msc, &ignore);
36184 + msc++;
36185 + for (count = 0; count < loop; count++) {
36186 + xcb_discard_reply(c,
36187 + xcb_dri2_wait_msc(c, win,
36188 + upper_32_bits(msc),
36189 + lower_32_bits(msc),
36190 + 0, 0, 0, 0).sequence);
36191 + msc += divisors[n];
36192 + }
36193 + XFlush(dpy);
36194 + XDestroyWindow(dpy, win);
36195 + printf("."); fflush(stdout);
36196 + } while (--loop);
36197 + printf("*\n");
36198 + }
36200 + XSync(dpy, 1);
36201 + sleep(2);
36202 + XSync(dpy, 1);
36203 +}
36205 +static int rand_size(int max)
36206 +{
36207 + return 1 + (rand() % (max - 1));
36208 +}
36210 +static void race_resize(Display *dpy, int width, int height,
36211 + unsigned int *attachments, int nattachments,
36212 + unsigned flags, const char *name)
36213 +{
36214 + Window win;
36215 + XSetWindowAttributes attr;
36216 + int count, loop, n;
36217 + DRI2Buffer *buffers;
36219 + if (flags & COMPOSITE && !has_composite(dpy))
36220 + return;
36222 + printf("%s(%s)\n", __func__, name);
36224 + attr.override_redirect = 1;
36225 + for (n = 0; n < N_DIVISORS; n++) {
36226 + win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36227 + 0, 0, width, height, 0,
36228 + DefaultDepth(dpy, DefaultScreen(dpy)),
36229 + InputOutput,
36230 + DefaultVisual(dpy, DefaultScreen(dpy)),
36231 + CWOverrideRedirect, &attr);
36232 + if (flags & COMPOSITE)
36233 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36234 + XMapWindow(dpy, win);
36236 + DRI2CreateDrawable(dpy, win);
36238 + loop = 256 >> ffs(divisors[n]);
36239 + printf("DRI2SwapBuffers(divisor=%d), loop=%d", divisors[n], loop);
36240 + fflush(stdout);
36241 + do {
36242 + int w, h;
36244 + buffers = DRI2GetBuffers(dpy, win, &w, &h,
36245 + attachments, nattachments, &count);
36246 + if (count != nattachments)
36247 + return;
36249 + free(buffers);
36250 + for (count = 0; count < loop; count++)
36251 + DRI2SwapBuffers(dpy, win, 0, divisors[n], count & (divisors[n]-1));
36252 + XResizeWindow(dpy, win, rand_size(width), rand_size(height));
36253 + printf("."); fflush(stdout);
36254 + } while (--loop);
36255 + XDestroyWindow(dpy, win);
36256 + XSync(dpy, True);
36257 + printf("*\n");
36258 + }
36260 + for (n = 0; n < N_DIVISORS; n++) {
36261 win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36262 0, 0, width, height, 0,
36263 DefaultDepth(dpy, DefaultScreen(dpy)),
36264 InputOutput,
36265 DefaultVisual(dpy, DefaultScreen(dpy)),
36266 CWOverrideRedirect, &attr);
36267 + if (flags & COMPOSITE)
36268 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36269 XMapWindow(dpy, win);
36271 DRI2CreateDrawable(dpy, win);
36273 - buffers = DRI2GetBuffers(dpy, win, &width, &height,
36274 - attachments, nattachments, &count);
36275 - if (count != nattachments)
36276 - return;
36277 + loop = 256 >> ffs(divisors[n]);
36278 + printf("xcb_dri2_swap_buffers(divisor=%d), loops=%d", divisors[n], loop);
36279 + fflush(stdout);
36280 + do {
36281 + int w, h;
36283 + buffers = DRI2GetBuffers(dpy, win, &w, &h,
36284 + attachments, nattachments, &count);
36285 + if (count != nattachments)
36286 + return;
36288 - free(buffers);
36289 - for (count = 0; count < loop; count++)
36290 - DRI2SwapBuffers(dpy, win, 0, 0, 0);
36291 + free(buffers);
36292 + for (count = 0; count < loop; count++)
36293 + swap_buffers(dpy, win, divisors[n], attachments, nattachments);
36294 + XResizeWindow(dpy, win, rand_size(width), rand_size(height));
36295 + printf("."); fflush(stdout);
36296 + } while (--loop);
36297 XDestroyWindow(dpy, win);
36298 - } while (--loop);
36299 + XSync(dpy, True);
36300 + printf("*\n");
36301 + }
36303 + for (n = 0; n < N_DIVISORS; n++) {
36304 + win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36305 + 0, 0, width, height, 0,
36306 + DefaultDepth(dpy, DefaultScreen(dpy)),
36307 + InputOutput,
36308 + DefaultVisual(dpy, DefaultScreen(dpy)),
36309 + CWOverrideRedirect, &attr);
36310 + if (flags & COMPOSITE)
36311 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36312 + XMapWindow(dpy, win);
36314 + DRI2CreateDrawable(dpy, win);
36316 + loop = 256 >> ffs(divisors[n]);
36317 + printf("DRI2WaitMsc(divisor=%d), loop=%d", divisors[n], loop);
36318 + fflush(stdout);
36319 + do {
36320 + uint64_t ignore, msc;
36321 + xcb_connection_t *c = XGetXCBConnection(dpy);
36323 + DRI2GetMSC(dpy, win, &ignore, &msc, &ignore);
36324 + msc++;
36325 + for (count = 0; count < loop; count++) {
36326 + xcb_discard_reply(c,
36327 + xcb_dri2_wait_msc(c, win,
36328 + upper_32_bits(msc),
36329 + lower_32_bits(msc),
36330 + 0, 0, 0, 0).sequence);
36331 + msc += divisors[n];
36332 + }
36333 + XFlush(dpy);
36334 + XResizeWindow(dpy, win, rand_size(width), rand_size(height));
36335 + printf("."); fflush(stdout);
36336 + } while (--loop);
36337 + XDestroyWindow(dpy, win);
36338 + XSync(dpy, True);
36339 + printf("*\n");
36340 + }
36342 + XSync(dpy, 1);
36343 + sleep(2);
36344 + XSync(dpy, 1);
36345 +}
36347 +static void race_manager(Display *dpy, int width, int height,
36348 + unsigned int *attachments, int nattachments,
36349 + unsigned flags, const char *name)
36350 +{
36351 + Display *mgr = XOpenDisplay(NULL);
36352 + Window win;
36353 + XSetWindowAttributes attr;
36354 + int count, loop, n;
36355 + DRI2Buffer *buffers;
36357 + if (flags & COMPOSITE && !has_composite(dpy))
36358 + return;
36360 + printf("%s(%s)\n", __func__, name);
36362 + /* Be nasty and install a fullscreen window on top so that we
36363 + * can guarantee we do not get clipped by children.
36364 + */
36365 + attr.override_redirect = 1;
36366 + for (n = 0; n < N_DIVISORS; n++) {
36367 + printf("DRI2SwapBuffers(divisor=%d)", divisors[n]);
36368 + fflush(stdout);
36369 + loop = 256 >> ffs(divisors[n]);
36370 + do {
36371 + win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36372 + 0, 0, width, height, 0,
36373 + DefaultDepth(dpy, DefaultScreen(dpy)),
36374 + InputOutput,
36375 + DefaultVisual(dpy, DefaultScreen(dpy)),
36376 + CWOverrideRedirect, &attr);
36377 + if (flags & COMPOSITE)
36378 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36379 + XMapWindow(dpy, win);
36381 + DRI2CreateDrawable(dpy, win);
36383 + buffers = DRI2GetBuffers(dpy, win, &width, &height,
36384 + attachments, nattachments, &count);
36385 + if (count != nattachments)
36386 + return;
36388 + free(buffers);
36389 + for (count = 0; count < loop; count++)
36390 + DRI2SwapBuffers(dpy, win, 0, divisors[n], count & (divisors[n]-1));
36391 + XFlush(dpy);
36392 + XDestroyWindow(mgr, win);
36393 + XFlush(mgr);
36394 + printf("."); fflush(stdout);
36395 + } while (--loop);
36396 + printf("*\n");
36397 + }
36399 + for (n = 0; n < N_DIVISORS; n++) {
36400 + printf("xcb_dri2_swap_buffers(divisor=%d)", divisors[n]);
36401 + fflush(stdout);
36402 + loop = 256 >> ffs(divisors[n]);
36403 + do {
36404 + win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36405 + 0, 0, width, height, 0,
36406 + DefaultDepth(dpy, DefaultScreen(dpy)),
36407 + InputOutput,
36408 + DefaultVisual(dpy, DefaultScreen(dpy)),
36409 + CWOverrideRedirect, &attr);
36410 + if (flags & COMPOSITE)
36411 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36412 + XMapWindow(dpy, win);
36414 + DRI2CreateDrawable(dpy, win);
36416 + buffers = DRI2GetBuffers(dpy, win, &width, &height,
36417 + attachments, nattachments, &count);
36418 + if (count != nattachments)
36419 + return;
36421 + free(buffers);
36422 + for (count = 0; count < loop; count++)
36423 + swap_buffers(dpy, win, divisors[n], attachments, nattachments);
36424 + XFlush(dpy);
36425 + XDestroyWindow(mgr, win);
36426 + XFlush(mgr);
36427 + printf("."); fflush(stdout);
36428 + } while (--loop);
36429 + printf("*\n");
36430 + }
36432 + for (n = 0; n < N_DIVISORS; n++) {
36433 + printf("DRI2WaitMsc(divisor=%d)", divisors[n]);
36434 + fflush(stdout);
36435 + loop = 256 >> ffs(divisors[n]);
36436 + do {
36437 + uint64_t ignore, msc;
36438 + xcb_connection_t *c = XGetXCBConnection(dpy);
36440 + win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36441 + 0, 0, width, height, 0,
36442 + DefaultDepth(dpy, DefaultScreen(dpy)),
36443 + InputOutput,
36444 + DefaultVisual(dpy, DefaultScreen(dpy)),
36445 + CWOverrideRedirect, &attr);
36446 + if (flags & COMPOSITE)
36447 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36448 + XMapWindow(dpy, win);
36450 + DRI2CreateDrawable(dpy, win);
36451 + DRI2GetMSC(dpy, win, &ignore, &msc, &ignore);
36452 + msc++;
36453 + for (count = 0; count < loop; count++) {
36454 + xcb_discard_reply(c,
36455 + xcb_dri2_wait_msc(c, win,
36456 + upper_32_bits(msc),
36457 + lower_32_bits(msc),
36458 + 0, 0, 0, 0).sequence);
36459 + msc += divisors[n];
36460 + }
36461 + XFlush(dpy);
36462 + XDestroyWindow(mgr, win);
36463 + XFlush(mgr);
36464 + printf("."); fflush(stdout);
36465 + } while (--loop);
36466 + printf("*\n");
36467 + }
36469 XSync(dpy, 1);
36470 + XSync(mgr, 1);
36471 sleep(2);
36472 XSync(dpy, 1);
36473 + XSync(mgr, 1);
36475 + XCloseDisplay(mgr);
36476 +}
36478 +static void race_close(int width, int height,
36479 + unsigned int *attachments, int nattachments,
36480 + unsigned flags, const char *name)
36481 +{
36482 + XSetWindowAttributes attr;
36483 + int count, loop, n;
36485 + if (flags & COMPOSITE && !has_composite(NULL))
36486 + return;
36488 + printf("%s(%s)\n", __func__, name);
36490 + /* Be nasty and install a fullscreen window on top so that we
36491 + * can guarantee we do not get clipped by children.
36492 + */
36493 + attr.override_redirect = 1;
36494 + for (n = 0; n < N_DIVISORS; n++) {
36495 + printf("DRI2SwapBuffers(divisor=%d)", divisors[n]);
36496 + fflush(stdout);
36497 + loop = 256 >> ffs(divisors[n]);
36498 + do {
36499 + Display *dpy = XOpenDisplay(NULL);
36500 + Window win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36501 + 0, 0, width, height, 0,
36502 + DefaultDepth(dpy, DefaultScreen(dpy)),
36503 + InputOutput,
36504 + DefaultVisual(dpy, DefaultScreen(dpy)),
36505 + CWOverrideRedirect, &attr);
36506 + if (flags & COMPOSITE)
36507 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36508 + XMapWindow(dpy, win);
36510 + DRI2CreateDrawable(dpy, win);
36511 + free(DRI2GetBuffers(dpy, win, &width, &height,
36512 + attachments, nattachments, &count));
36513 + if (count != nattachments)
36514 + return;
36516 + for (count = 0; count < loop; count++)
36517 + DRI2SwapBuffers(dpy, win, 0, divisors[n], count & (divisors[n]-1));
36518 + XCloseDisplay(dpy);
36519 + printf("."); fflush(stdout);
36520 + } while (--loop);
36521 + printf("*\n");
36522 + }
36524 + for (n = 0; n < N_DIVISORS; n++) {
36525 + printf("xcb_dri2_swap_buffers(divisor=%d)", divisors[n]);
36526 + fflush(stdout);
36527 + loop = 256 >> ffs(divisors[n]);
36528 + do {
36529 + Display *dpy = XOpenDisplay(NULL);
36530 + Window win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36531 + 0, 0, width, height, 0,
36532 + DefaultDepth(dpy, DefaultScreen(dpy)),
36533 + InputOutput,
36534 + DefaultVisual(dpy, DefaultScreen(dpy)),
36535 + CWOverrideRedirect, &attr);
36536 + if (flags & COMPOSITE)
36537 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36538 + XMapWindow(dpy, win);
36540 + DRI2CreateDrawable(dpy, win);
36541 + free(DRI2GetBuffers(dpy, win, &width, &height,
36542 + attachments, nattachments, &count));
36543 + if (count != nattachments)
36544 + return;
36546 + for (count = 0; count < loop; count++)
36547 + swap_buffers(dpy, win, divisors[n], attachments, nattachments);
36548 + XCloseDisplay(dpy);
36549 + printf("."); fflush(stdout);
36550 + } while (--loop);
36551 + printf("*\n");
36552 + }
36554 + for (n = 0; n < N_DIVISORS; n++) {
36555 + printf("DRI2WaitMsc(divisor=%d)", divisors[n]);
36556 + fflush(stdout);
36557 + loop = 256 >> ffs(divisors[n]);
36558 + do {
36559 + uint64_t ignore, msc;
36560 + Display *dpy = XOpenDisplay(NULL);
36561 + xcb_connection_t *c = XGetXCBConnection(dpy);
36562 + Window win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36563 + 0, 0, width, height, 0,
36564 + DefaultDepth(dpy, DefaultScreen(dpy)),
36565 + InputOutput,
36566 + DefaultVisual(dpy, DefaultScreen(dpy)),
36567 + CWOverrideRedirect, &attr);
36568 + if (flags & COMPOSITE)
36569 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36570 + XMapWindow(dpy, win);
36572 + DRI2CreateDrawable(dpy, win);
36573 + DRI2GetMSC(dpy, win, &ignore, &msc, &ignore);
36574 + msc++;
36575 + for (count = 0; count < loop; count++) {
36576 + xcb_discard_reply(c,
36577 + xcb_dri2_wait_msc(c, win,
36578 + upper_32_bits(msc),
36579 + lower_32_bits(msc),
36580 + 0, 0, 0, 0).sequence);
36581 + msc += divisors[n];
36582 + }
36583 + XFlush(dpy);
36584 + XCloseDisplay(dpy);
36585 + printf("."); fflush(stdout);
36586 + } while (--loop);
36587 + printf("*\n");
36588 + }
36589 +}
36591 +static void race_client(int width, int height,
36592 + unsigned int *attachments, int nattachments,
36593 + unsigned flags, const char *name)
36594 +{
36595 + Display *mgr = XOpenDisplay(NULL);
36596 + XSetWindowAttributes attr;
36597 + int count, loop, n;
36599 + if (flags & COMPOSITE && !has_composite(NULL))
36600 + return;
36602 + printf("%s(%s)\n", __func__, name);
36604 + /* Be nasty and install a fullscreen window on top so that we
36605 + * can guarantee we do not get clipped by children.
36606 + */
36607 + attr.override_redirect = 1;
36608 + for (n = 0; n < N_DIVISORS; n++) {
36609 + printf("DRI2SwapBuffers(divisor=%d)", divisors[n]);
36610 + fflush(stdout);
36611 + loop = 256 >> ffs(divisors[n]);
36612 + do {
36613 + Display *dpy = XOpenDisplay(NULL);
36614 + Window win;
36616 + if (error_get()) {
36617 + XCloseDisplay(dpy);
36618 + printf("+"); fflush(stdout);
36619 + continue;
36620 + }
36622 + win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36623 + 0, 0, width, height, 0,
36624 + DefaultDepth(dpy, DefaultScreen(dpy)),
36625 + InputOutput,
36626 + DefaultVisual(dpy, DefaultScreen(dpy)),
36627 + CWOverrideRedirect, &attr);
36628 + if (flags & COMPOSITE)
36629 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36630 + XMapWindow(dpy, win);
36632 + DRI2CreateDrawable(dpy, win);
36633 + free(DRI2GetBuffers(dpy, win, &width, &height,
36634 + attachments, nattachments, &count));
36635 + if (count == nattachments) {
36636 + for (count = 0; count < loop; count++)
36637 + DRI2SwapBuffers(dpy, win, 0, divisors[n], count & (divisors[n]-1));
36638 + }
36640 + XFlush(dpy);
36641 + XKillClient(mgr, win);
36642 + XFlush(mgr);
36644 + XCloseDisplay(dpy);
36645 + printf("."); fflush(stdout);
36647 + error_put();
36648 + } while (--loop);
36649 + printf("*\n");
36650 + }
36652 + for (n = 0; n < N_DIVISORS; n++) {
36653 + printf("xcb_dri2_swap_buffers(divisor=%d)", divisors[n]);
36654 + fflush(stdout);
36655 + loop = 256 >> ffs(divisors[n]);
36656 + do {
36657 + Display *dpy = XOpenDisplay(NULL);
36658 + Window win;
36660 + if (error_get()) {
36661 + XCloseDisplay(dpy);
36662 + printf("+"); fflush(stdout);
36663 + continue;
36664 + }
36666 + win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36667 + 0, 0, width, height, 0,
36668 + DefaultDepth(dpy, DefaultScreen(dpy)),
36669 + InputOutput,
36670 + DefaultVisual(dpy, DefaultScreen(dpy)),
36671 + CWOverrideRedirect, &attr);
36672 + if (flags & COMPOSITE)
36673 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36674 + XMapWindow(dpy, win);
36676 + DRI2CreateDrawable(dpy, win);
36677 + free(DRI2GetBuffers(dpy, win, &width, &height,
36678 + attachments, nattachments, &count));
36679 + if (count == nattachments) {
36680 + for (count = 0; count < loop; count++)
36681 + swap_buffers(dpy, win, divisors[n], attachments, nattachments);
36682 + }
36684 + XFlush(dpy);
36685 + XKillClient(mgr, win);
36686 + XFlush(mgr);
36688 + XCloseDisplay(dpy);
36689 + printf("."); fflush(stdout);
36691 + error_put();
36692 + } while (--loop);
36693 + printf("*\n");
36694 + }
36696 + for (n = 0; n < N_DIVISORS; n++) {
36697 + printf("DRI2WaitMsc(divisor=%d)", divisors[n]);
36698 + fflush(stdout);
36699 + loop = 256 >> ffs(divisors[n]);
36700 + do {
36701 + Display *dpy = XOpenDisplay(NULL);
36702 + uint64_t ignore, msc;
36703 + xcb_connection_t *c;
36704 + Window win;
36706 + if (error_get()) {
36707 + XCloseDisplay(dpy);
36708 + printf("+"); fflush(stdout);
36709 + continue;
36710 + }
36712 + win = XCreateWindow(dpy, DefaultRootWindow(dpy),
36713 + 0, 0, width, height, 0,
36714 + DefaultDepth(dpy, DefaultScreen(dpy)),
36715 + InputOutput,
36716 + DefaultVisual(dpy, DefaultScreen(dpy)),
36717 + CWOverrideRedirect, &attr);
36718 + if (flags & COMPOSITE)
36719 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
36720 + XMapWindow(dpy, win);
36722 + DRI2CreateDrawable(dpy, win);
36723 + DRI2GetMSC(dpy, win, &ignore, &msc, &ignore);
36724 + c = XGetXCBConnection(dpy);
36725 + msc++;
36726 + for (count = 0; count < loop; count++) {
36727 + xcb_discard_reply(c,
36728 + xcb_dri2_wait_msc(c, win,
36729 + upper_32_bits(msc),
36730 + lower_32_bits(msc),
36731 + 0, 0, 0, 0).sequence);
36732 + msc += divisors[n];
36733 + }
36735 + XFlush(dpy);
36736 + XKillClient(mgr, win);
36737 + XFlush(mgr);
36739 + XCloseDisplay(dpy);
36740 + printf("."); fflush(stdout);
36742 + error_put();
36743 + } while (--loop);
36744 + printf("*\n");
36745 + }
36747 + XCloseDisplay(mgr);
36750 int main(void)
36751 @@ -91,7 +790,10 @@ int main(void)
36752 DRI2BufferFrontLeft,
36753 };
36755 - dpy = XOpenDisplay (NULL);
36756 + saved_io_error = XSetIOErrorHandler(io_error);
36757 + XSetErrorHandler(x_error);
36759 + dpy = XOpenDisplay(NULL);
36760 if (dpy == NULL)
36761 return 77;
36763 @@ -101,13 +803,52 @@ int main(void)
36765 width = WidthOfScreen(DefaultScreenOfDisplay(dpy));
36766 height = HeightOfScreen(DefaultScreenOfDisplay(dpy));
36767 - run(dpy, width, height, attachments, 1, "fullscreen");
36768 - run(dpy, width, height, attachments, 2, "fullscreen (with front)");
36769 + race_window(dpy, width, height, attachments, 1, 0, "fullscreen");
36770 + race_window(dpy, width, height, attachments, 1, COMPOSITE, "composite fullscreen");
36771 + race_window(dpy, width, height, attachments, 2, 0, "fullscreen (with front)");
36772 + race_window(dpy, width, height, attachments, 2, COMPOSITE, "composite fullscreen (with front)");
36774 + race_resize(dpy, width, height, attachments, 1, 0, "");
36775 + race_resize(dpy, width, height, attachments, 1, COMPOSITE, "composite");
36776 + race_resize(dpy, width, height, attachments, 2, 0, "with front");
36777 + race_resize(dpy, width, height, attachments, 2, COMPOSITE, "composite with front");
36779 + race_manager(dpy, width, height, attachments, 1, 0, "fullscreen");
36780 + race_manager(dpy, width, height, attachments, 1, COMPOSITE, "composite fullscreen");
36781 + race_manager(dpy, width, height, attachments, 2, 0, "fullscreen (with front)");
36782 + race_manager(dpy, width, height, attachments, 2, COMPOSITE, "composite fullscreen (with front)");
36784 + race_close(width, height, attachments, 1, 0, "fullscreen");
36785 + race_close(width, height, attachments, 1, COMPOSITE, "composite fullscreen");
36786 + race_close(width, height, attachments, 2, 0, "fullscreen (with front)");
36787 + race_close(width, height, attachments, 2, COMPOSITE, "composite fullscreen (with front)");
36789 + race_client(width, height, attachments, 1, 0, "fullscreen");
36790 + race_client(width, height, attachments, 1, COMPOSITE, "composite fullscreen");
36791 + race_client(width, height, attachments, 2, 0, "fullscreen (with front)");
36792 + race_client(width, height, attachments, 2, COMPOSITE, "composite fullscreen (with front)");
36794 width /= 2;
36795 height /= 2;
36796 - run(dpy, width, height, attachments, 1, "windowed");
36797 - run(dpy, width, height, attachments, 2, "windowed (with front)");
36798 + race_window(dpy, width, height, attachments, 1, 0, "windowed");
36799 + race_window(dpy, width, height, attachments, 1, COMPOSITE, "composite windowed");
36800 + race_window(dpy, width, height, attachments, 2, 0, "windowed (with front)");
36801 + race_window(dpy, width, height, attachments, 2, COMPOSITE, "composite windowed (with front)");
36803 + race_manager(dpy, width, height, attachments, 1, 0, "windowed");
36804 + race_manager(dpy, width, height, attachments, 1, COMPOSITE, "composite windowed");
36805 + race_manager(dpy, width, height, attachments, 2, 0, "windowed (with front)");
36806 + race_manager(dpy, width, height, attachments, 2, COMPOSITE, "composite windowed (with front)");
36808 + race_close(width, height, attachments, 1, 0, "windowed");
36809 + race_close(width, height, attachments, 1, COMPOSITE, "composite windowed");
36810 + race_close(width, height, attachments, 2, 0, "windowed (with front)");
36811 + race_close(width, height, attachments, 2, COMPOSITE, "composite windowed (with front)");
36813 + race_client(width, height, attachments, 1, 0, "windowed");
36814 + race_client(width, height, attachments, 1, COMPOSITE, "composite windowed");
36815 + race_client(width, height, attachments, 2, 0, "windowed (with front)");
36816 + race_client(width, height, attachments, 2, COMPOSITE, "composite windowed (with front)");
36818 return 0;
36820 diff --git a/test/dri2-speed.c b/test/dri2-speed.c
36821 new file mode 100644
36822 index 00000000..87b9d0b6
36823 --- /dev/null
36824 +++ b/test/dri2-speed.c
36825 @@ -0,0 +1,342 @@
36826 +/*
36827 + * Copyright (c) 2015 Intel Corporation
36828 + *
36829 + * Permission is hereby granted, free of charge, to any person obtaining a
36830 + * copy of this software and associated documentation files (the "Software"),
36831 + * to deal in the Software without restriction, including without limitation
36832 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
36833 + * and/or sell copies of the Software, and to permit persons to whom the
36834 + * Software is furnished to do so, subject to the following conditions:
36835 + *
36836 + * The above copyright notice and this permission notice (including the next
36837 + * paragraph) shall be included in all copies or substantial portions of the
36838 + * Software.
36839 + *
36840 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36841 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36842 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
36843 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36844 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36845 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36846 + * SOFTWARE.
36847 + *
36848 + */
36850 +#ifdef HAVE_CONFIG_H
36851 +#include "config.h"
36852 +#endif
36854 +#include <X11/Xlib.h>
36855 +#include <X11/Xatom.h>
36856 +#include <X11/Xlib-xcb.h>
36857 +#include <X11/Xutil.h>
36858 +#include <X11/Xlibint.h>
36859 +#include <X11/extensions/dpms.h>
36860 +#include <X11/extensions/randr.h>
36861 +#include <X11/extensions/Xcomposite.h>
36862 +#include <X11/extensions/Xdamage.h>
36863 +#include <X11/extensions/Xrandr.h>
36864 +#include <xcb/xcb.h>
36865 +#include <xcb/dri2.h>
36866 +#include <xf86drm.h>
36868 +#include <stdio.h>
36869 +#include <string.h>
36870 +#include <fcntl.h>
36871 +#include <unistd.h>
36872 +#include <assert.h>
36873 +#include <errno.h>
36874 +#include <setjmp.h>
36875 +#include <signal.h>
36877 +#include "dri2.h"
36879 +static int _x_error_occurred;
36881 +static int
36882 +_check_error_handler(Display *display,
36883 + XErrorEvent *event)
36884 +{
36885 + printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
36886 + DisplayString(display),
36887 + event->serial,
36888 + event->error_code,
36889 + event->request_code,
36890 + event->minor_code);
36891 + _x_error_occurred++;
36892 + return False; /* ignored */
36893 +}
36895 +static double elapsed(const struct timespec *start,
36896 + const struct timespec *end)
36897 +{
36898 + return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000;
36899 +}
36901 +static void run(Display *dpy, Window win, const char *name)
36902 +{
36903 + xcb_connection_t *c = XGetXCBConnection(dpy);
36904 + struct timespec start, end;
36905 + int n, completed = 0;
36907 + _x_error_occurred = 0;
36909 + clock_gettime(CLOCK_MONOTONIC, &start);
36910 + do {
36911 + for (n = 0; n < 1000; n++) {
36912 + unsigned int attachments[] = { DRI2BufferBackLeft };
36913 + unsigned int seq[2];
36915 + seq[0] = xcb_dri2_swap_buffers_unchecked(c, win,
36916 + 0, 0, 0, 0, 0, 0).sequence;
36919 + seq[1] = xcb_dri2_get_buffers_unchecked(c, win,
36920 + 1, 1, attachments).sequence;
36922 + xcb_flush(c);
36923 + xcb_discard_reply(c, seq[0]);
36924 + xcb_discard_reply(c, seq[1]);
36925 + completed++;
36926 + }
36927 + clock_gettime(CLOCK_MONOTONIC, &end);
36928 + } while (end.tv_sec < start.tv_sec + 10);
36930 + XSync(dpy, True);
36931 + if (_x_error_occurred)
36932 + abort();
36934 + printf("%s: Completed %d swaps in %.1fs, %.3fus each (%.1f FPS)\n",
36935 + name, completed, elapsed(&start, &end) / 1000000,
36936 + elapsed(&start, &end) / completed,
36937 + completed / (elapsed(&start, &end) / 1000000));
36938 +}
36940 +static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
36941 +{
36942 + XRRScreenResources *res;
36944 + res = XRRGetScreenResourcesCurrent(dpy, window);
36945 + if (res == NULL)
36946 + res = XRRGetScreenResources(dpy, window);
36948 + return res;
36949 +}
36951 +static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
36952 +{
36953 + int i;
36955 + for (i = 0; i < res->nmode; i++) {
36956 + if (res->modes[i].id == id)
36957 + return &res->modes[i];
36958 + }
36960 + return NULL;
36961 +}
36963 +static int dri2_open(Display *dpy)
36964 +{
36965 + drm_auth_t auth;
36966 + char *driver, *device;
36967 + int fd;
36969 + if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device))
36970 + return -1;
36972 + printf ("Connecting to %s driver on %s\n", driver, device);
36974 + fd = open(device, O_RDWR);
36975 + if (fd < 0)
36976 + return -1;
36978 + if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
36979 + return -1;
36981 + if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic))
36982 + return -1;
36984 + return fd;
36985 +}
36987 +static void fullscreen(Display *dpy, Window win)
36988 +{
36989 + Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
36990 + XChangeProperty(dpy, win,
36991 + XInternAtom(dpy, "_NET_WM_STATE", False),
36992 + XA_ATOM, 32, PropModeReplace,
36993 + (unsigned char *)&atom, 1);
36994 +}
36996 +static int has_composite(Display *dpy)
36997 +{
36998 + int event, error;
36999 + int major, minor;
37001 + if (!XDamageQueryExtension (dpy, &event, &error))
37002 + return 0;
37004 + if (!XCompositeQueryExtension(dpy, &event, &error))
37005 + return 0;
37007 + XCompositeQueryVersion(dpy, &major, &minor);
37009 + return major > 0 || minor >= 4;
37010 +}
37012 +int main(void)
37013 +{
37014 + Display *dpy;
37015 + Window root, win;
37016 + XRRScreenResources *res;
37017 + XRRCrtcInfo **original_crtc;
37018 + XSetWindowAttributes attr;
37019 + int i, j, fd;
37021 + attr.override_redirect = 1;
37023 + dpy = XOpenDisplay(NULL);
37024 + if (dpy == NULL)
37025 + return 77;
37027 + fd = dri2_open(dpy);
37028 + if (fd < 0)
37029 + return 77;
37031 + if (DPMSQueryExtension(dpy, &i, &i))
37032 + DPMSDisable(dpy);
37034 + root = DefaultRootWindow(dpy);
37036 + signal(SIGALRM, SIG_IGN);
37037 + XSetErrorHandler(_check_error_handler);
37039 + res = NULL;
37040 + if (XRRQueryVersion(dpy, &i, &i))
37041 + res = _XRRGetScreenResourcesCurrent(dpy, root);
37042 + if (res == NULL)
37043 + return 77;
37045 + original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc);
37046 + for (i = 0; i < res->ncrtc; i++)
37047 + original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
37049 + printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc);
37050 + for (i = 0; i < res->ncrtc; i++)
37051 + XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
37052 + 0, 0, None, RR_Rotate_0, NULL, 0);
37054 + DRI2CreateDrawable(dpy, root);
37055 + DRI2SwapInterval(dpy, root, 0);
37056 + run(dpy, root, "off");
37057 + XSync(dpy, True);
37059 + for (i = 0; i < res->noutput; i++) {
37060 + XRROutputInfo *output;
37061 + XRRModeInfo *mode;
37063 + output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
37064 + if (output == NULL)
37065 + continue;
37067 + mode = NULL;
37068 + if (res->nmode)
37069 + mode = lookup_mode(res, output->modes[0]);
37071 + for (j = 0; mode && j < 2*output->ncrtc; j++) {
37072 + int c = j;
37073 + if (c >= output->ncrtc)
37074 + c = 2*output->ncrtc - j - 1;
37076 + printf("[%d, %d] -- OUTPUT:%ld, CRTC:%ld: %dx%d\n",
37077 + i, c, (long)res->outputs[i], (long)output->crtcs[c],
37078 + mode->width, mode->height);
37079 + XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
37080 + 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1);
37082 + run(dpy, root, "root");
37083 + XSync(dpy, True);
37085 + win = XCreateWindow(dpy, root,
37086 + 0, 0, mode->width, mode->height, 0,
37087 + DefaultDepth(dpy, DefaultScreen(dpy)),
37088 + InputOutput,
37089 + DefaultVisual(dpy, DefaultScreen(dpy)),
37090 + CWOverrideRedirect, &attr);
37091 + DRI2CreateDrawable(dpy, win);
37092 + DRI2SwapInterval(dpy, win, 0);
37093 + fullscreen(dpy, win);
37094 + XMapWindow(dpy, win);
37095 + run(dpy, win, "fullscreen");
37096 + XDestroyWindow(dpy, win);
37097 + XSync(dpy, True);
37099 + win = XCreateWindow(dpy, root,
37100 + 0, 0, mode->width, mode->height, 0,
37101 + DefaultDepth(dpy, DefaultScreen(dpy)),
37102 + InputOutput,
37103 + DefaultVisual(dpy, DefaultScreen(dpy)),
37104 + CWOverrideRedirect, &attr);
37105 + DRI2CreateDrawable(dpy, win);
37106 + DRI2SwapInterval(dpy, win, 0);
37107 + XMapWindow(dpy, win);
37108 + run(dpy, win, "windowed");
37109 + XDestroyWindow(dpy, win);
37110 + XSync(dpy, True);
37112 + if (has_composite(dpy)) {
37113 + Damage damage;
37115 + _x_error_occurred = 0;
37116 + win = XCreateWindow(dpy, root,
37117 + 0, 0, mode->width, mode->height, 0,
37118 + DefaultDepth(dpy, DefaultScreen(dpy)),
37119 + InputOutput,
37120 + DefaultVisual(dpy, DefaultScreen(dpy)),
37121 + CWOverrideRedirect, &attr);
37122 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
37123 + damage = XDamageCreate(dpy, win, XDamageReportRawRectangles);
37124 + DRI2CreateDrawable(dpy, win);
37125 + DRI2SwapInterval(dpy, win, 0);
37126 + XMapWindow(dpy, win);
37127 + XSync(dpy, True);
37128 + if (!_x_error_occurred)
37129 + run(dpy, win, "composited");
37130 + XDamageDestroy(dpy, damage);
37131 + XDestroyWindow(dpy, win);
37132 + XSync(dpy, True);
37133 + }
37135 + win = XCreateWindow(dpy, root,
37136 + 0, 0, mode->width/2, mode->height/2, 0,
37137 + DefaultDepth(dpy, DefaultScreen(dpy)),
37138 + InputOutput,
37139 + DefaultVisual(dpy, DefaultScreen(dpy)),
37140 + CWOverrideRedirect, &attr);
37141 + DRI2CreateDrawable(dpy, win);
37142 + DRI2SwapInterval(dpy, win, 0);
37143 + XMapWindow(dpy, win);
37144 + run(dpy, win, "half");
37145 + XDestroyWindow(dpy, win);
37146 + XSync(dpy, True);
37148 + XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
37149 + 0, 0, None, RR_Rotate_0, NULL, 0);
37150 + }
37152 + XRRFreeOutputInfo(output);
37153 + }
37155 + for (i = 0; i < res->ncrtc; i++)
37156 + XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
37157 + original_crtc[i]->x,
37158 + original_crtc[i]->y,
37159 + original_crtc[i]->mode,
37160 + original_crtc[i]->rotation,
37161 + original_crtc[i]->outputs,
37162 + original_crtc[i]->noutput);
37164 + if (DPMSQueryExtension(dpy, &i, &i))
37165 + DPMSEnable(dpy);
37166 + return 0;
37167 +}
37168 diff --git a/test/dri2-test.c b/test/dri2-test.c
37169 index dd4179f3..bdf01f38 100644
37170 --- a/test/dri2-test.c
37171 +++ b/test/dri2-test.c
37172 @@ -6,6 +6,10 @@
37173 #include <X11/Xutil.h>
37174 #include <X11/extensions/Xfixes.h>
37175 #include <X11/extensions/Xrandr.h>
37176 +#include <X11/Xlib-xcb.h>
37177 +#include <xcb/xcb.h>
37178 +#include <xcb/xcbext.h>
37179 +#include <xcb/dri2.h>
37180 #include <unistd.h>
37181 #include <fcntl.h>
37182 #include <string.h>
37183 @@ -18,6 +22,8 @@
37185 #define COUNT 60
37187 +static int prime[] = { 0, 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47, 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131 };
37189 static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
37191 XRRScreenResources *res;
37192 @@ -101,16 +107,41 @@ static uint64_t check_msc(Display *dpy, Window win, uint64_t last_msc)
37193 return current_msc;
37196 +static void wait_next_vblank(Display *dpy, Window win)
37197 +{
37198 + uint64_t msc, ust, sbc;
37199 + DRI2WaitMSC(dpy, win, 0, 1, 0, &ust, &msc, &sbc);
37200 +}
37202 +static void swap_buffers(xcb_connection_t *c, Window win,
37203 + unsigned int *attachments, int nattachments)
37204 +{
37205 + unsigned int seq[2];
37207 + seq[0] = xcb_dri2_swap_buffers_unchecked(c, win,
37208 + 0, 0, 0, 0, 0, 0).sequence;
37211 + seq[1] = xcb_dri2_get_buffers_unchecked(c, win,
37212 + nattachments, nattachments,
37213 + attachments).sequence;
37215 + xcb_flush(c);
37216 + xcb_discard_reply(c, seq[0]);
37217 + xcb_discard_reply(c, seq[1]);
37218 +}
37220 static void run(Display *dpy, int width, int height,
37221 unsigned int *attachments, int nattachments,
37222 const char *name)
37224 + xcb_connection_t *c = XGetXCBConnection(dpy);
37225 Window win;
37226 XSetWindowAttributes attr;
37227 - int count;
37228 DRI2Buffer *buffers;
37229 struct timespec start, end;
37230 - uint64_t msc;
37231 + uint64_t start_msc, end_msc;
37232 + int modulus, remainder, count;
37234 /* Be nasty and install a fullscreen window on top so that we
37235 * can guarantee we do not get clipped by children.
37236 @@ -125,42 +156,99 @@ static void run(Display *dpy, int width, int height,
37237 XMapWindow(dpy, win);
37239 DRI2CreateDrawable(dpy, win);
37240 - msc = check_msc(dpy, win, 0);
37241 + DRI2SwapInterval(dpy, win, 1);
37242 + start_msc = check_msc(dpy, win, 0);
37244 buffers = DRI2GetBuffers(dpy, win, &width, &height,
37245 attachments, nattachments, &count);
37246 if (count != nattachments)
37247 return;
37249 - msc = check_msc(dpy, win, msc);
37250 + swap_buffers(c, win, attachments, nattachments);
37251 + start_msc = check_msc(dpy, win, start_msc);
37252 clock_gettime(CLOCK_MONOTONIC, &start);
37253 for (count = 0; count < COUNT; count++)
37254 - DRI2SwapBuffers(dpy, win, 0, 0, 0);
37255 - msc = check_msc(dpy, win, msc);
37256 + swap_buffers(c, win, attachments, nattachments);
37257 + end_msc = check_msc(dpy, win, start_msc);
37258 clock_gettime(CLOCK_MONOTONIC, &end);
37259 - printf("%d %s (%dx%d) swaps in %fs.\n",
37260 - count, name, width, height, elapsed(&start, &end));
37261 + printf("%d [%ld] %s (%dx%d) swaps in %fs.\n",
37262 + count, (long)(end_msc - start_msc),
37263 + name, width, height, elapsed(&start, &end));
37265 - msc = check_msc(dpy, win, msc);
37266 + swap_buffers(c, win, attachments, nattachments);
37267 + start_msc = check_msc(dpy, win, end_msc);
37268 clock_gettime(CLOCK_MONOTONIC, &start);
37269 for (count = 0; count < COUNT; count++)
37270 dri2_copy_swap(dpy, win, width, height, nattachments == 2);
37271 - msc = check_msc(dpy, win, msc);
37272 + end_msc = check_msc(dpy, win, start_msc);
37273 clock_gettime(CLOCK_MONOTONIC, &end);
37275 - printf("%d %s (%dx%d) blits in %fs.\n",
37276 - count, name, width, height, elapsed(&start, &end));
37277 + printf("%d [%ld] %s (%dx%d) blits in %fs.\n",
37278 + count, (long)(end_msc - start_msc),
37279 + name, width, height, elapsed(&start, &end));
37281 DRI2SwapInterval(dpy, win, 0);
37282 + wait_next_vblank(dpy, win);
37284 + swap_buffers(c, win, attachments, nattachments);
37285 + start_msc = check_msc(dpy, win, end_msc);
37286 + clock_gettime(CLOCK_MONOTONIC, &start);
37287 + for (count = 0; count < COUNT; count++)
37288 + swap_buffers(c, win, attachments, nattachments);
37289 + end_msc = check_msc(dpy, win, start_msc);
37290 + clock_gettime(CLOCK_MONOTONIC, &end);
37291 + printf("%d [%ld] %s (%dx%d) vblank=0 swaps in %fs.\n",
37292 + count, (long)(end_msc - start_msc),
37293 + name, width, height, elapsed(&start, &end));
37295 - msc = check_msc(dpy, win, msc);
37296 + start_msc = check_msc(dpy, win, end_msc);
37297 clock_gettime(CLOCK_MONOTONIC, &start);
37298 for (count = 0; count < COUNT; count++)
37299 - DRI2SwapBuffers(dpy, win, 0, 0, 0);
37300 - msc = check_msc(dpy, win, msc);
37301 + wait_next_vblank(dpy, win);
37302 + end_msc = check_msc(dpy, win, start_msc);
37303 clock_gettime(CLOCK_MONOTONIC, &end);
37304 - printf("%d %s (%dx%d) vblank=0 swaps in %fs.\n",
37305 - count, name, width, height, elapsed(&start, &end));
37306 + printf("%d [%ld] %s waits in %fs.\n",
37307 + count, (long)(end_msc - start_msc),
37308 + name, elapsed(&start, &end));
37310 + printf("Testing past & future waits\n");
37311 + for (modulus = 1; modulus <= 128; modulus <<= 1) {
37312 + for (count = 0; prime[count] < modulus; count++) {
37313 + uint64_t msc, ust, sbc;
37314 + uint64_t target;
37316 + remainder = prime[count];
37318 + DRI2WaitMSC(dpy, win, 0, 1, 0, &ust, &msc, &sbc);
37320 + target = msc + modulus + 1;
37321 + target &= -modulus;
37322 + target += remainder;
37324 + DRI2WaitMSC(dpy, win, target, modulus, remainder,
37325 + &ust, &msc, &sbc);
37326 + if (msc != target) {
37327 + printf("Missed future MSC (%d, %d): expected=%lld, found=%lld\n",
37328 + modulus, remainder,
37329 + (long long)target, (long long)msc);
37330 + }
37332 + target = msc;
37333 + target &= -modulus;
37334 + target += remainder;
37335 + if (target <= msc)
37336 + target += modulus;
37338 + DRI2WaitMSC(dpy, win, msc, modulus, remainder,
37339 + &ust, &msc, &sbc);
37341 + if (msc != target) {
37342 + printf("Missed past MSC (%d, %d): expected=%lld, found=%lld\n",
37343 + modulus, remainder,
37344 + (long long)target, (long long)msc);
37345 + }
37346 + }
37347 + }
37349 XDestroyWindow(dpy, win);
37350 free(buffers);
37351 diff --git a/test/dri3-test.c b/test/dri3-test.c
37352 index c66da313..78e105a8 100644
37353 --- a/test/dri3-test.c
37354 +++ b/test/dri3-test.c
37355 @@ -93,14 +93,9 @@ static const struct pci_id_match ids[] = {
37356 INTEL_IVB_D_IDS(070),
37357 INTEL_IVB_M_IDS(070),
37359 - INTEL_HSW_D_IDS(075),
37360 - INTEL_HSW_M_IDS(075),
37362 - INTEL_VLV_D_IDS(071),
37363 - INTEL_VLV_M_IDS(071),
37365 - INTEL_BDW_D_IDS(0100),
37366 - INTEL_BDW_M_IDS(0100),
37367 + INTEL_HSW_IDS(075),
37368 + INTEL_VLV_IDS(071),
37369 + INTEL_BDW_IDS(0100),
37370 };
37372 static int i915_gen(int device)
37373 @@ -1020,6 +1015,67 @@ fail:
37374 return 1;
37377 +static int gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
37378 +{
37379 + struct drm_i915_gem_set_tiling set_tiling;
37381 + set_tiling.handle = handle;
37382 + set_tiling.tiling_mode = tiling;
37383 + set_tiling.stride = stride;
37385 + return drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0;
37386 +}
37388 +static int test_tiling(Display *dpy, int device)
37389 +{
37390 + Window root = RootWindow(dpy, DefaultScreen(dpy));
37391 + const int tiling[] = { I915_TILING_NONE, I915_TILING_X, I915_TILING_Y };
37392 + int line = -1;
37393 + int t;
37395 + _x_error_occurred = 0;
37397 + for (t = 0; t < sizeof(tiling)/sizeof(tiling[0]); t++) {
37398 + uint32_t src;
37399 + int src_fd;
37400 + Pixmap src_pix;
37402 + src = gem_create(device, 4*4096);
37403 + if (!src) {
37404 + line = __LINE__;
37405 + goto fail;
37406 + }
37408 + gem_set_tiling(device, src, tiling[t], 512);
37410 + src_fd = gem_export(device, src);
37411 + if (src_fd < 0) {
37412 + line = __LINE__;
37413 + goto fail;
37414 + }
37416 + src_pix = dri3_create_pixmap(dpy, root,
37417 + 128, 32, 32,
37418 + src_fd, 32, 512, 4*4096);
37419 + XSync(dpy, True);
37420 + if (_x_error_occurred) {
37421 + line = __LINE__;
37422 + goto fail;
37423 + }
37424 + XFreePixmap(dpy, src_pix);
37425 + _x_error_occurred = 0;
37427 + close(src_fd);
37428 + gem_close(device, src);
37429 + }
37431 + return 0;
37433 +fail:
37434 + printf("%s failed with tiling %d, line %d\n", __func__, tiling[t], line);
37435 + return 1;
37436 +}
37438 static int
37439 _check_error_handler(Display *display,
37440 XErrorEvent *event)
37441 @@ -1060,6 +1116,7 @@ int main(void)
37443 error += test_bad_size(dpy, device);
37444 error += test_bad_pitch(dpy, device);
37445 + error += test_tiling(dpy, device);
37447 error += test_shm(dpy, device, 400, 300);
37448 error += test_shm(dpy, device, 300, 400);
37449 diff --git a/test/dri3.c b/test/dri3.c
37450 index 45f3285c..e5644629 100644
37451 --- a/test/dri3.c
37452 +++ b/test/dri3.c
37453 @@ -29,6 +29,7 @@
37454 #include <xcb/dri3.h>
37455 #include <xcb/sync.h>
37456 #include <unistd.h>
37457 +#include <stdlib.h>
37459 #include "dri3.h"
37461 @@ -109,12 +110,45 @@ void dri3_fence_free(Display *dpy, struct dri3_fence *fence)
37462 xcb_sync_destroy_fence(c, fence->xid);
37465 +static void dri3_query_version(xcb_connection_t *c, int *major, int *minor)
37466 +{
37467 + xcb_dri3_query_version_reply_t *reply;
37469 + reply = xcb_dri3_query_version_reply(c,
37470 + xcb_dri3_query_version(c,
37471 + XCB_DRI3_MAJOR_VERSION,
37472 + XCB_DRI3_MINOR_VERSION),
37473 + NULL);
37474 + if (reply != NULL) {
37475 + *major = reply->major_version;
37476 + *minor = reply->minor_version;
37477 + free(reply);
37478 + }
37479 +}
37481 +static int dri3_exists(xcb_connection_t *c)
37482 +{
37483 + const xcb_query_extension_reply_t *ext;
37484 + int major, minor;
37486 + major = minor = -1;
37488 + ext = xcb_get_extension_data(c, &xcb_dri3_id);
37489 + if (ext != NULL && ext->present)
37490 + dri3_query_version(c, &major, &minor);
37492 + return major >= 0;
37493 +}
37495 int dri3_open__full(Display *dpy, Window root, unsigned provider)
37497 xcb_connection_t *c = XGetXCBConnection(dpy);
37498 xcb_dri3_open_cookie_t cookie;
37499 xcb_dri3_open_reply_t *reply;
37501 + if (!dri3_exists(c))
37502 + return -1;
37504 cookie = xcb_dri3_open(c, root, provider);
37505 reply = xcb_dri3_open_reply(c, cookie, NULL);
37507 diff --git a/test/present-race.c b/test/present-race.c
37508 new file mode 100644
37509 index 00000000..b2b6aa2b
37510 --- /dev/null
37511 +++ b/test/present-race.c
37512 @@ -0,0 +1,484 @@
37513 +/*
37514 + * Copyright (c) 2014 Intel Corporation
37515 + *
37516 + * Permission is hereby granted, free of charge, to any person obtaining a
37517 + * copy of this software and associated documentation files (the "Software"),
37518 + * to deal in the Software without restriction, including without limitation
37519 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
37520 + * and/or sell copies of the Software, and to permit persons to whom the
37521 + * Software is furnished to do so, subject to the following conditions:
37522 + *
37523 + * The above copyright notice and this permission notice (including the next
37524 + * paragraph) shall be included in all copies or substantial portions of the
37525 + * Software.
37526 + *
37527 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37528 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37529 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
37530 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37531 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37532 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37533 + * SOFTWARE.
37534 + *
37535 + */
37537 +#ifdef HAVE_CONFIG_H
37538 +#include "config.h"
37539 +#endif
37541 +#include <X11/Xlib.h>
37542 +#include <X11/Xlib-xcb.h>
37543 +#include <X11/xshmfence.h>
37544 +#include <X11/Xutil.h>
37545 +#include <X11/Xlibint.h>
37546 +#include <X11/extensions/dpms.h>
37547 +#include <X11/extensions/randr.h>
37548 +#include <X11/extensions/Xcomposite.h>
37549 +#include <X11/extensions/Xrandr.h>
37550 +#include <X11/extensions/Xrender.h>
37551 +#include <X11/extensions/XShm.h>
37552 +#if HAVE_X11_EXTENSIONS_SHMPROTO_H
37553 +#include <X11/extensions/shmproto.h>
37554 +#elif HAVE_X11_EXTENSIONS_SHMSTR_H
37555 +#include <X11/extensions/shmstr.h>
37556 +#else
37557 +#error Failed to find the right header for X11 MIT-SHM protocol definitions
37558 +#endif
37559 +#include <xcb/xcb.h>
37560 +#include <xcb/present.h>
37561 +#include <xcb/xfixes.h>
37562 +#include <xcb/dri3.h>
37563 +#include <xf86drm.h>
37564 +#include <i915_drm.h>
37566 +#include <stdio.h>
37567 +#include <string.h>
37568 +#include <fcntl.h>
37569 +#include <unistd.h>
37570 +#include <assert.h>
37571 +#include <errno.h>
37572 +#include <setjmp.h>
37573 +#include <signal.h>
37575 +#include <sys/mman.h>
37576 +#include <sys/ipc.h>
37577 +#include <sys/shm.h>
37578 +#include <pciaccess.h>
37580 +#include "dri3.h"
37582 +static int _x_error_occurred;
37583 +static uint32_t stamp;
37585 +static int
37586 +_check_error_handler(Display *display,
37587 + XErrorEvent *event)
37588 +{
37589 + printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
37590 + DisplayString(display),
37591 + event->serial,
37592 + event->error_code,
37593 + event->request_code,
37594 + event->minor_code);
37595 + _x_error_occurred++;
37596 + return False; /* ignored */
37597 +}
37599 +static int has_composite(Display *dpy)
37600 +{
37601 + int event, error;
37602 + int major, minor;
37604 + if (!XCompositeQueryExtension(dpy, &event, &error))
37605 + return 0;
37607 + XCompositeQueryVersion(dpy, &major, &minor);
37609 + return major > 0 || minor >= 4;
37610 +}
37612 +static void *setup_msc(Display *dpy, Window win)
37613 +{
37614 + xcb_connection_t *c = XGetXCBConnection(dpy);
37615 + xcb_void_cookie_t cookie;
37616 + uint32_t id = xcb_generate_id(c);
37617 + xcb_generic_error_t *error;
37618 + void *q;
37620 + cookie = xcb_present_select_input_checked(c, id, win, XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
37621 + q = xcb_register_for_special_xge(c, &xcb_present_id, id, &stamp);
37623 + error = xcb_request_check(c, cookie);
37624 + assert(error == NULL);
37626 + return q;
37627 +}
37629 +static void teardown_msc(Display *dpy, void *q)
37630 +{
37631 + xcb_unregister_for_special_event(XGetXCBConnection(dpy), q);
37632 +}
37634 +static uint64_t wait_vblank(Display *dpy, Window win)
37635 +{
37636 + xcb_connection_t *c = XGetXCBConnection(dpy);
37637 + static uint32_t serial = 1;
37638 + uint64_t msc = 0;
37639 + int complete = 0;
37640 + void *q;
37642 + if (win == 0)
37643 + win = DefaultRootWindow(dpy);
37645 + q = setup_msc(dpy, win);
37647 + xcb_present_notify_msc(c, win, serial ^ 0xdeadbeef, 0, 1, 0);
37648 + xcb_flush(c);
37650 + do {
37651 + xcb_present_complete_notify_event_t *ce;
37652 + xcb_generic_event_t *ev;
37654 + ev = xcb_wait_for_special_event(c, q);
37655 + if (ev == NULL)
37656 + break;
37658 + ce = (xcb_present_complete_notify_event_t *)ev;
37659 + if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
37660 + ce->serial == (serial ^ 0xdeadbeef)) {
37661 + msc = ce->msc;
37662 + complete = 1;
37663 + }
37664 + free(ev);
37665 + } while (!complete);
37667 + if (++serial == 0)
37668 + serial = 1;
37670 + teardown_msc(dpy, q);
37672 + return msc;
37673 +}
37675 +static int test_basic(Display *dpy, int dummy)
37676 +{
37677 + xcb_connection_t *c = XGetXCBConnection(dpy);
37678 + XSetWindowAttributes attr;
37679 + Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
37680 + Pixmap pixmap;
37681 + struct dri3_fence fence;
37682 + Window root, win;
37683 + unsigned int width, height;
37684 + unsigned border, depth;
37685 + int x, y, ret = 1;
37686 + const char *phase;
37687 + uint64_t msc;
37689 + root = DefaultRootWindow(dpy);
37690 + XGetGeometry(dpy, root,
37691 + &win, &x, &y,
37692 + &width, &height, &border, &depth);
37694 + _x_error_occurred = 0;
37695 + attr.override_redirect = 1;
37696 + switch (dummy) {
37697 + case 0:
37698 + win = root;
37699 + phase = "root";
37700 + break;
37701 + case 1:
37702 + win = XCreateWindow(dpy, root,
37703 + 0, 0, width, height, 0, depth,
37704 + InputOutput, visual,
37705 + CWOverrideRedirect, &attr);
37706 + phase = "fullscreen";
37707 + break;
37708 + case 2:
37709 + width /= 2;
37710 + height /= 2;
37711 + win = XCreateWindow(dpy, root,
37712 + 0, 0, width, height, 0, depth,
37713 + InputOutput, visual,
37714 + CWOverrideRedirect, &attr);
37715 + phase = "window";
37716 + break;
37717 + case 3:
37718 + if (!has_composite(dpy))
37719 + return 0;
37721 + win = XCreateWindow(dpy, root,
37722 + 0, 0, width, height, 0,
37723 + DefaultDepth(dpy, DefaultScreen(dpy)),
37724 + InputOutput,
37725 + DefaultVisual(dpy, DefaultScreen(dpy)),
37726 + CWOverrideRedirect, &attr);
37727 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
37728 + phase = "composite";
37729 + break;
37731 + default:
37732 + phase = "broken";
37733 + win = root;
37734 + abort();
37735 + break;
37736 + }
37738 + XMapWindow(dpy, win);
37739 + XSync(dpy, True);
37740 + if (_x_error_occurred)
37741 + return 1;
37743 + if (dri3_create_fence(dpy, win, &fence))
37744 + return 0;
37746 + printf("%s: Testing basic flip: %dx%d\n", phase, width, height);
37747 + fflush(stdout);
37748 + _x_error_occurred = 0;
37750 + xshmfence_reset(fence.addr);
37751 + msc = wait_vblank(dpy, win);
37753 + pixmap = XCreatePixmap(dpy, win, width, height, depth);
37754 + xcb_present_pixmap(c, win, pixmap, 0,
37755 + 0, /* valid */
37756 + 0, /* update */
37757 + 0, /* x_off */
37758 + 0, /* y_off */
37759 + None,
37760 + None, /* wait fence */
37761 + fence.xid,
37762 + XCB_PRESENT_OPTION_NONE,
37763 + (msc + 64) & -64, /* target msc */
37764 + 64, /* divisor */
37765 + 32, /* remainder */
37766 + 0, NULL);
37767 + XFreePixmap(dpy, pixmap);
37769 + pixmap = XCreatePixmap(dpy, win, width, height, depth);
37770 + xcb_present_pixmap(c, win, pixmap, 0,
37771 + 0, /* valid */
37772 + 0, /* update */
37773 + 0, /* x_off */
37774 + 0, /* y_off */
37775 + None,
37776 + None, /* wait fence */
37777 + None, /* sync fence */
37778 + XCB_PRESENT_OPTION_NONE,
37779 + (msc + 64) & -64, /* target msc */
37780 + 64, /* divisor */
37781 + 48, /* remainder */
37782 + 0, NULL);
37783 + XFreePixmap(dpy, pixmap);
37784 + XDestroyWindow(dpy, win);
37785 + XFlush(dpy);
37787 + ret = !!xshmfence_await(fence.addr);
37788 + dri3_fence_free(dpy, &fence);
37790 + XSync(dpy, True);
37791 + ret += !!_x_error_occurred;
37793 + return ret;
37794 +}
37796 +static int test_race(Display *dpy, int dummy)
37797 +{
37798 + Display *mgr = XOpenDisplay(NULL);
37799 + xcb_connection_t *c = XGetXCBConnection(dpy);
37800 + XSetWindowAttributes attr;
37801 + Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
37802 + Pixmap pixmap;
37803 + struct dri3_fence fence;
37804 + Window root, win;
37805 + unsigned int width, height;
37806 + unsigned border, depth;
37807 + int x, y, ret = 1;
37808 + const char *phase;
37809 + uint64_t msc;
37811 + root = DefaultRootWindow(dpy);
37812 + XGetGeometry(dpy, root,
37813 + &win, &x, &y,
37814 + &width, &height, &border, &depth);
37816 + _x_error_occurred = 0;
37817 + attr.override_redirect = 1;
37818 + switch (dummy) {
37819 + case 0:
37820 + win = root;
37821 + phase = "root";
37822 + break;
37823 + case 1:
37824 + win = XCreateWindow(dpy, root,
37825 + 0, 0, width, height, 0, depth,
37826 + InputOutput, visual,
37827 + CWOverrideRedirect, &attr);
37828 + phase = "fullscreen";
37829 + break;
37830 + case 2:
37831 + width /= 2;
37832 + height /= 2;
37833 + win = XCreateWindow(dpy, root,
37834 + 0, 0, width, height, 0, depth,
37835 + InputOutput, visual,
37836 + CWOverrideRedirect, &attr);
37837 + phase = "window";
37838 + break;
37839 + case 3:
37840 + if (!has_composite(dpy))
37841 + return 0;
37843 + win = XCreateWindow(dpy, root,
37844 + 0, 0, width, height, 0,
37845 + DefaultDepth(dpy, DefaultScreen(dpy)),
37846 + InputOutput,
37847 + DefaultVisual(dpy, DefaultScreen(dpy)),
37848 + CWOverrideRedirect, &attr);
37849 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
37850 + phase = "composite";
37851 + break;
37853 + default:
37854 + phase = "broken";
37855 + win = root;
37856 + abort();
37857 + break;
37858 + }
37860 + XMapWindow(dpy, win);
37861 + XSync(dpy, True);
37862 + if (_x_error_occurred)
37863 + return 1;
37865 + if (dri3_create_fence(dpy, win, &fence))
37866 + return 0;
37868 + printf("%s: Testing race with manager: %dx%d\n", phase, width, height);
37869 + fflush(stdout);
37870 + _x_error_occurred = 0;
37872 + xshmfence_reset(fence.addr);
37873 + msc = wait_vblank(dpy, win);
37875 + pixmap = XCreatePixmap(dpy, win, width, height, depth);
37876 + xcb_present_pixmap(c, win, pixmap, 0,
37877 + 0, /* valid */
37878 + 0, /* update */
37879 + 0, /* x_off */
37880 + 0, /* y_off */
37881 + None,
37882 + None, /* wait fence */
37883 + fence.xid,
37884 + XCB_PRESENT_OPTION_NONE,
37885 + (msc + 64) & -64, /* target msc */
37886 + 64, /* divisor */
37887 + 32, /* remainder */
37888 + 0, NULL);
37889 + XFreePixmap(dpy, pixmap);
37891 + XFlush(dpy);
37892 + XDestroyWindow(mgr, win);
37893 + XFlush(mgr);
37895 + pixmap = XCreatePixmap(dpy, win, width, height, depth);
37896 + xcb_present_pixmap(c, win, pixmap, 0,
37897 + 0, /* valid */
37898 + 0, /* update */
37899 + 0, /* x_off */
37900 + 0, /* y_off */
37901 + None,
37902 + None, /* wait fence */
37903 + None, /* sync fence */
37904 + XCB_PRESENT_OPTION_NONE,
37905 + (msc + 64) & -64, /* target msc */
37906 + 64, /* divisor */
37907 + 48, /* remainder */
37908 + 0, NULL);
37909 + XFreePixmap(dpy, pixmap);
37910 + XFlush(dpy);
37912 + ret = !!xshmfence_await(fence.addr);
37913 + dri3_fence_free(dpy, &fence);
37915 + XSync(dpy, True);
37916 + ret += !!_x_error_occurred;
37918 + XCloseDisplay(mgr);
37920 + return ret;
37921 +}
37923 +static int has_present(Display *dpy)
37924 +{
37925 + xcb_connection_t *c = XGetXCBConnection(dpy);
37926 + xcb_generic_error_t *error = NULL;
37927 + void *reply;
37929 + reply = xcb_xfixes_query_version_reply(c,
37930 + xcb_xfixes_query_version(c,
37931 + XCB_XFIXES_MAJOR_VERSION,
37932 + XCB_XFIXES_MINOR_VERSION),
37933 + &error);
37934 + free(reply);
37935 + free(error);
37936 + if (reply == NULL) {
37937 + fprintf(stderr, "XFixes not supported on %s\n", DisplayString(dpy));
37938 + return 0;
37939 + }
37941 + reply = xcb_dri3_query_version_reply(c,
37942 + xcb_dri3_query_version(c,
37943 + XCB_DRI3_MAJOR_VERSION,
37944 + XCB_DRI3_MINOR_VERSION),
37945 + &error);
37946 + free(reply);
37947 + free(error);
37948 + if (reply == NULL) {
37949 + fprintf(stderr, "DRI3 not supported on %s\n", DisplayString(dpy));
37950 + return 0;
37951 + }
37953 + reply = xcb_present_query_version_reply(c,
37954 + xcb_present_query_version(c,
37955 + XCB_PRESENT_MAJOR_VERSION,
37956 + XCB_PRESENT_MINOR_VERSION),
37957 + &error);
37959 + free(reply);
37960 + free(error);
37961 + if (reply == NULL) {
37962 + fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy));
37963 + return 0;
37964 + }
37966 + return 1;
37967 +}
37969 +int main(void)
37970 +{
37971 + Display *dpy;
37972 + int dummy;
37973 + int error = 0;
37975 + dpy = XOpenDisplay(NULL);
37976 + if (dpy == NULL)
37977 + return 77;
37979 + if (!has_present(dpy))
37980 + return 77;
37982 + if (DPMSQueryExtension(dpy, &dummy, &dummy))
37983 + DPMSDisable(dpy);
37985 + signal(SIGALRM, SIG_IGN);
37986 + XSetErrorHandler(_check_error_handler);
37988 + for (dummy = 0; dummy <= 3; dummy++) {
37989 + error += test_basic(dpy, dummy);
37990 + error += test_race(dpy, dummy);
37991 + }
37993 + if (DPMSQueryExtension(dpy, &dummy, &dummy))
37994 + DPMSEnable(dpy);
37995 + return !!error;
37996 +}
37997 diff --git a/test/present-speed.c b/test/present-speed.c
37998 new file mode 100644
37999 index 00000000..eccde931
38000 --- /dev/null
38001 +++ b/test/present-speed.c
38002 @@ -0,0 +1,1015 @@
38003 +/*
38004 + * Copyright (c) 2015 Intel Corporation
38005 + *
38006 + * Permission is hereby granted, free of charge, to any person obtaining a
38007 + * copy of this software and associated documentation files (the "Software"),
38008 + * to deal in the Software without restriction, including without limitation
38009 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
38010 + * and/or sell copies of the Software, and to permit persons to whom the
38011 + * Software is furnished to do so, subject to the following conditions:
38012 + *
38013 + * The above copyright notice and this permission notice (including the next
38014 + * paragraph) shall be included in all copies or substantial portions of the
38015 + * Software.
38016 + *
38017 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38018 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38019 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
38020 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38021 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38022 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38023 + * SOFTWARE.
38024 + *
38025 + */
38027 +#ifdef HAVE_CONFIG_H
38028 +#include "config.h"
38029 +#endif
38031 +#include <X11/Xlib.h>
38032 +#include <X11/Xatom.h>
38033 +#include <X11/Xlib-xcb.h>
38034 +#include <X11/xshmfence.h>
38035 +#include <X11/Xutil.h>
38036 +#include <X11/Xlibint.h>
38037 +#include <X11/extensions/Xcomposite.h>
38038 +#include <X11/extensions/Xdamage.h>
38039 +#include <X11/extensions/dpms.h>
38040 +#include <X11/extensions/randr.h>
38041 +#include <X11/extensions/Xrandr.h>
38042 +#include <xcb/xcb.h>
38043 +#include <xcb/present.h>
38044 +#include <xcb/dri3.h>
38045 +#include <xcb/xfixes.h>
38046 +#include <xf86drm.h>
38047 +#include <i915_drm.h>
38049 +#include <stdio.h>
38050 +#include <string.h>
38051 +#include <fcntl.h>
38052 +#include <unistd.h>
38053 +#include <assert.h>
38054 +#include <errno.h>
38055 +#include <setjmp.h>
38056 +#include <signal.h>
38057 +#include <sys/wait.h>
38059 +#include "dri3.h"
38061 +static int _x_error_occurred;
38062 +static uint32_t stamp;
38064 +struct list {
38065 + struct list *next, *prev;
38066 +};
38068 +static void
38069 +list_init(struct list *list)
38070 +{
38071 + list->next = list->prev = list;
38072 +}
38074 +static inline void
38075 +__list_add(struct list *entry,
38076 + struct list *prev,
38077 + struct list *next)
38078 +{
38079 + next->prev = entry;
38080 + entry->next = next;
38081 + entry->prev = prev;
38082 + prev->next = entry;
38083 +}
38085 +static inline void
38086 +list_add(struct list *entry, struct list *head)
38087 +{
38088 + __list_add(entry, head, head->next);
38089 +}
38091 +static inline void
38092 +__list_del(struct list *prev, struct list *next)
38093 +{
38094 + next->prev = prev;
38095 + prev->next = next;
38096 +}
38098 +static inline void
38099 +_list_del(struct list *entry)
38100 +{
38101 + __list_del(entry->prev, entry->next);
38102 +}
38104 +static inline void
38105 +list_move(struct list *list, struct list *head)
38106 +{
38107 + if (list->prev != head) {
38108 + _list_del(list);
38109 + list_add(list, head);
38110 + }
38111 +}
38113 +#define __container_of(ptr, sample, member) \
38114 + (void *)((char *)(ptr) - ((char *)&(sample)->member - (char *)(sample)))
38116 +#define list_for_each_entry(pos, head, member) \
38117 + for (pos = __container_of((head)->next, pos, member); \
38118 + &pos->member != (head); \
38119 + pos = __container_of(pos->member.next, pos, member))
38121 +static int
38122 +_check_error_handler(Display *display,
38123 + XErrorEvent *event)
38124 +{
38125 + if (_x_error_occurred < 0)
38126 + return True;
38128 + printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n",
38129 + DisplayString(display),
38130 + event->serial,
38131 + event->error_code,
38132 + event->request_code,
38133 + event->minor_code);
38134 + _x_error_occurred++;
38135 + return False; /* ignored */
38136 +}
38138 +static double elapsed(const struct timespec *start,
38139 + const struct timespec *end)
38140 +{
38141 + return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000;
38142 +}
38144 +struct buffer {
38145 + struct list link;
38146 + Pixmap pixmap;
38147 + struct dri3_fence fence;
38148 + int fd;
38149 + int busy;
38150 + int id;
38151 +};
38153 +#define DRI3 1
38154 +#define NOCOPY 2
38155 +#define ASYNC 4
38156 +static void run(Display *dpy, Window win, const char *name, unsigned options)
38157 +{
38158 + xcb_connection_t *c = XGetXCBConnection(dpy);
38159 + struct timespec start, end;
38160 +#define N_BACK 8
38161 + char test_name[128];
38162 + struct buffer buffer[N_BACK];
38163 + struct list mru;
38164 + Window root;
38165 + unsigned int width, height;
38166 + unsigned border, depth;
38167 + unsigned present_flags = 0;
38168 + xcb_xfixes_region_t update = 0;
38169 + int completed = 0;
38170 + int queued = 0;
38171 + uint32_t eid = 0;
38172 + void *Q = NULL;
38173 + int i, n;
38175 + list_init(&mru);
38177 + XGetGeometry(dpy, win,
38178 + &root, &i, &n, &width, &height, &border, &depth);
38180 + _x_error_occurred = 0;
38182 + for (n = 0; n < N_BACK; n++) {
38183 + buffer[n].pixmap = xcb_generate_id(c);
38184 + xcb_create_pixmap(c, depth, buffer[n].pixmap, win,
38185 + width, height);
38186 + buffer[n].fence.xid = 0;
38187 + buffer[n].fd = -1;
38188 + buffer[n].id = n;
38189 + if (options & DRI3) {
38190 + xcb_dri3_buffer_from_pixmap_reply_t *reply;
38191 + int *fds;
38193 + if (dri3_create_fence(dpy, win, &buffer[n].fence))
38194 + return;
38196 + reply = xcb_dri3_buffer_from_pixmap_reply (c,
38197 + xcb_dri3_buffer_from_pixmap(c, buffer[n].pixmap),
38198 + NULL);
38199 + if (reply == NULL)
38200 + return;
38202 + fds = xcb_dri3_buffer_from_pixmap_reply_fds (c, reply);
38203 + buffer[n].fd = fds[0];
38204 + free(reply);
38206 + /* start idle */
38207 + xshmfence_trigger(buffer[n].fence.addr);
38208 + }
38209 + buffer[n].busy = 0;
38210 + list_add(&buffer[n].link, &mru);
38211 + }
38212 + if (options & ASYNC)
38213 + present_flags |= XCB_PRESENT_OPTION_ASYNC;
38214 + if (options & NOCOPY) {
38215 + update = xcb_generate_id(c);
38216 + xcb_xfixes_create_region(c, update, 0, NULL);
38217 + present_flags |= XCB_PRESENT_OPTION_COPY;
38218 + }
38220 + if (!(options & DRI3)) {
38221 + eid = xcb_generate_id(c);
38222 + xcb_present_select_input(c, eid, win,
38223 + (options & NOCOPY ? 0 : XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY) |
38224 + XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
38225 + Q = xcb_register_for_special_xge(c, &xcb_present_id, eid, &stamp);
38226 + }
38228 + clock_gettime(CLOCK_MONOTONIC, &start);
38229 + do {
38230 + for (n = 0; n < 1000; n++) {
38231 + struct buffer *tmp, *b = NULL;
38232 +retry:
38233 + list_for_each_entry(tmp, &mru, link) {
38234 + if (tmp->fence.xid)
38235 + tmp->busy = !xshmfence_query(tmp->fence.addr);
38236 + if (!tmp->busy) {
38237 + b = tmp;
38238 + break;
38239 + }
38240 + }
38241 + if (options & DRI3) {
38242 + if (b == NULL)
38243 + goto retry;
38245 + xshmfence_reset(b->fence.addr);
38246 + queued--;
38247 + completed++;
38248 + } else while (b == NULL) {
38249 + xcb_present_generic_event_t *ev;
38251 + ev = (xcb_present_generic_event_t *)
38252 + xcb_wait_for_special_event(c, Q);
38253 + if (ev == NULL)
38254 + abort();
38256 + do {
38257 + switch (ev->evtype) {
38258 + case XCB_PRESENT_COMPLETE_NOTIFY:
38259 + completed++;
38260 + queued--;
38261 + break;
38263 + case XCB_PRESENT_EVENT_IDLE_NOTIFY:
38264 + {
38265 + xcb_present_idle_notify_event_t *ie = (xcb_present_idle_notify_event_t *)ev;
38266 + assert(ie->serial < N_BACK);
38267 + buffer[ie->serial].busy = 0;
38268 + if (b == NULL)
38269 + b = &buffer[ie->serial];
38270 + break;
38271 + }
38272 + }
38273 + free(ev);
38274 + } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
38275 + }
38277 + b->busy = (options & NOCOPY) == 0;
38278 + xcb_present_pixmap(c, win, b->pixmap, b->id,
38279 + 0, /* valid */
38280 + update, /* update */
38281 + 0, /* x_off */
38282 + 0, /* y_off */
38283 + None,
38284 + None, /* wait fence */
38285 + b->fence.xid,
38286 + present_flags,
38287 + 0, /* target msc */
38288 + 0, /* divisor */
38289 + 0, /* remainder */
38290 + 0, NULL);
38291 + list_move(&b->link, &mru);
38292 + queued++;
38293 + xcb_flush(c);
38294 + }
38295 + clock_gettime(CLOCK_MONOTONIC, &end);
38296 + } while (end.tv_sec < start.tv_sec + 10);
38298 + if (options & DRI3) {
38299 + struct buffer *b;
38300 + XID pixmap;
38302 + pixmap = xcb_generate_id(c);
38303 + xcb_create_pixmap(c, depth, pixmap, win, width, height);
38304 + xcb_present_pixmap(c, win, pixmap, 0xdeadbeef,
38305 + 0, /* valid */
38306 + None, /* update */
38307 + 0, /* x_off */
38308 + 0, /* y_off */
38309 + None,
38310 + None, /* wait fence */
38311 + None,
38312 + 0,
38313 + 0, /* target msc */
38314 + 0, /* divisor */
38315 + 0, /* remainder */
38316 + 0, NULL);
38317 + xcb_flush(c);
38319 + list_for_each_entry(b, &mru, link)
38320 + xshmfence_await(b->fence.addr);
38322 + xcb_free_pixmap(c, pixmap);
38323 + completed += queued;
38324 + } else while (queued) {
38325 + xcb_present_generic_event_t *ev;
38327 + ev = (xcb_present_generic_event_t *)
38328 + xcb_wait_for_special_event(c, Q);
38329 + if (ev == NULL)
38330 + abort();
38332 + do {
38333 + switch (ev->evtype) {
38334 + case XCB_PRESENT_COMPLETE_NOTIFY:
38335 + completed++;
38336 + queued--;
38337 + break;
38339 + case XCB_PRESENT_EVENT_IDLE_NOTIFY:
38340 + break;
38341 + }
38342 + free(ev);
38343 + } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, Q)));
38344 + }
38345 + clock_gettime(CLOCK_MONOTONIC, &end);
38347 + if (update)
38348 + xcb_xfixes_destroy_region(c, update);
38349 + for (n = 0; n < N_BACK; n++) {
38350 + if (buffer[n].fence.xid)
38351 + dri3_fence_free(dpy, &buffer[n].fence);
38352 + if (buffer[n].fd != -1)
38353 + close(buffer[n].fd);
38354 + xcb_free_pixmap(c, buffer[n].pixmap);
38355 + }
38357 + if (Q) {
38358 + xcb_discard_reply(c, xcb_present_select_input_checked(c, eid, win, 0).sequence);
38359 + XSync(dpy, True);
38360 + xcb_unregister_for_special_event(c, Q);
38361 + }
38363 + test_name[0] = '\0';
38364 + if (options) {
38365 + snprintf(test_name, sizeof(test_name), "(%s%s%s )",
38366 + options & NOCOPY ? " no-copy" : "",
38367 + options & DRI3 ? " dri3" : "",
38368 + options & ASYNC ? " async" : "");
38369 + }
38370 + printf("%s%s: Completed %d presents in %.1fs, %.3fus each (%.1f FPS)\n",
38371 + name, test_name,
38372 + completed, elapsed(&start, &end) / 1000000,
38373 + elapsed(&start, &end) / completed,
38374 + completed / (elapsed(&start, &end) / 1000000));
38375 +}
38377 +struct perpixel {
38378 + Window win;
38379 + struct buffer buffer[N_BACK];
38380 + struct list mru;
38381 + uint32_t eid;
38382 + void *Q;
38383 + int queued;
38384 +};
38386 +static void perpixel(Display *dpy,
38387 + int max_width, int max_height, unsigned options)
38388 +{
38389 + //const int sz = max_width * max_height;
38390 + const int sz = 1048;
38391 + struct perpixel *pp;
38392 + xcb_connection_t *c = XGetXCBConnection(dpy);
38393 + struct timespec start, end;
38394 + char test_name[128];
38395 + unsigned present_flags = 0;
38396 + xcb_xfixes_region_t update = 0;
38397 + int completed = 0;
38398 + int i, n;
38400 + pp = calloc(sz, sizeof(*pp));
38401 + if (!pp)
38402 + return;
38404 + for (i = 0; i < sz; i++) {
38405 + XSetWindowAttributes attr = { .override_redirect = 1 };
38406 + int depth = DefaultDepth(dpy, DefaultScreen(dpy));
38407 + pp[i].win = XCreateWindow(dpy, DefaultRootWindow(dpy),
38408 + i % max_width, i / max_width, 1, 1, 0, depth,
38409 + InputOutput,
38410 + DefaultVisual(dpy, DefaultScreen(dpy)),
38411 + CWOverrideRedirect, &attr);
38412 + XMapWindow(dpy, pp[i].win);
38413 + list_init(&pp[i].mru);
38414 + for (n = 0; n < N_BACK; n++) {
38415 + pp[i].buffer[n].pixmap = xcb_generate_id(c);
38416 + xcb_create_pixmap(c, depth, pp[i].buffer[n].pixmap,
38417 + pp[i].win, 1, 1);
38418 + pp[i].buffer[n].fence.xid = 0;
38419 + pp[i].buffer[n].fd = -1;
38420 + pp[i].buffer[n].id = n;
38421 + if (options & DRI3) {
38422 + xcb_dri3_buffer_from_pixmap_reply_t *reply;
38423 + int *fds;
38425 + if (dri3_create_fence(dpy, pp[i].win, &pp[i].buffer[n].fence))
38426 + return;
38428 + reply = xcb_dri3_buffer_from_pixmap_reply(c,
38429 + xcb_dri3_buffer_from_pixmap(c, pp[i].buffer[n].pixmap),
38430 + NULL);
38431 + if (reply == NULL)
38432 + return;
38434 + fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, reply);
38435 + pp[i].buffer[n].fd = fds[0];
38436 + free(reply);
38438 + /* start idle */
38439 + xshmfence_trigger(pp[i].buffer[n].fence.addr);
38440 + }
38441 + pp[i].buffer[n].busy = 0;
38442 + list_add(&pp[i].buffer[n].link, &pp[i].mru);
38443 + }
38445 + if (!(options & DRI3)) {
38446 + pp[i].eid = xcb_generate_id(c);
38447 + xcb_present_select_input(c, pp[i].eid, pp[i].win,
38448 + (options & NOCOPY ? 0 : XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY) |
38449 + XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY);
38450 + pp[i].Q = xcb_register_for_special_xge(c, &xcb_present_id, pp[i].eid, &stamp);
38451 + }
38452 + pp[i].queued = 0;
38453 + }
38455 + XSync(dpy, True);
38456 + _x_error_occurred = 0;
38458 + if (options & ASYNC)
38459 + present_flags |= XCB_PRESENT_OPTION_ASYNC;
38460 + if (options & NOCOPY) {
38461 + update = xcb_generate_id(c);
38462 + xcb_xfixes_create_region(c, update, 0, NULL);
38463 + present_flags |= XCB_PRESENT_OPTION_COPY;
38464 + }
38466 + clock_gettime(CLOCK_MONOTONIC, &start);
38467 + do {
38468 + for (i = 0; i < sz; i++) {
38469 + struct buffer *tmp, *b = NULL;
38470 +retry:
38471 + list_for_each_entry(tmp, &pp[i].mru, link) {
38472 + if (tmp->fence.xid)
38473 + tmp->busy = !xshmfence_query(tmp->fence.addr);
38474 + if (!tmp->busy) {
38475 + b = tmp;
38476 + break;
38477 + }
38478 + }
38479 + if (options & DRI3) {
38480 + if (b == NULL)
38481 + goto retry;
38483 + xshmfence_reset(b->fence.addr);
38484 + pp[i].queued--;
38485 + completed++;
38486 + } else while (b == NULL) {
38487 + xcb_present_generic_event_t *ev;
38489 + ev = (xcb_present_generic_event_t *)
38490 + xcb_wait_for_special_event(c, pp[i].Q);
38491 + if (ev == NULL)
38492 + abort();
38494 + do {
38495 + switch (ev->evtype) {
38496 + case XCB_PRESENT_COMPLETE_NOTIFY:
38497 + completed++;
38498 + pp[i].queued--;
38499 + break;
38501 + case XCB_PRESENT_EVENT_IDLE_NOTIFY:
38502 + {
38503 + xcb_present_idle_notify_event_t *ie = (xcb_present_idle_notify_event_t *)ev;
38504 + assert(ie->serial < N_BACK);
38505 + pp[i].buffer[ie->serial].busy = 0;
38506 + if (b == NULL)
38507 + b = &pp[i].buffer[ie->serial];
38508 + break;
38509 + }
38510 + }
38511 + free(ev);
38512 + } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, pp[i].Q)));
38513 + }
38515 + b->busy = (options & NOCOPY) == 0;
38516 + xcb_present_pixmap(c, pp[i].win, b->pixmap, b->id,
38517 + 0, /* valid */
38518 + update, /* update */
38519 + 0, /* x_off */
38520 + 0, /* y_off */
38521 + None,
38522 + None, /* wait fence */
38523 + b->fence.xid,
38524 + present_flags,
38525 + 0, /* target msc */
38526 + 0, /* divisor */
38527 + 0, /* remainder */
38528 + 0, NULL);
38529 + list_move(&b->link, &pp[i].mru);
38530 + pp[i].queued++;
38531 + }
38532 + xcb_flush(c);
38533 + clock_gettime(CLOCK_MONOTONIC, &end);
38534 + } while (end.tv_sec < start.tv_sec + 10);
38536 + for (i = 0; i < sz; i++) {
38537 + if (options & DRI3) {
38538 + int depth = DefaultDepth(dpy, DefaultScreen(dpy));
38539 + struct buffer *b;
38540 + XID pixmap;
38542 + pixmap = xcb_generate_id(c);
38543 + xcb_create_pixmap(c, depth, pixmap, pp[i].win, 1, 1);
38544 + xcb_present_pixmap(c, pp[i].win, pixmap, 0xdeadbeef,
38545 + 0, /* valid */
38546 + None, /* update */
38547 + 0, /* x_off */
38548 + 0, /* y_off */
38549 + None,
38550 + None, /* wait fence */
38551 + None,
38552 + 0,
38553 + 0, /* target msc */
38554 + 0, /* divisor */
38555 + 0, /* remainder */
38556 + 0, NULL);
38557 + xcb_flush(c);
38559 + list_for_each_entry(b, &pp[i].mru, link)
38560 + xshmfence_await(b->fence.addr);
38562 + xcb_free_pixmap(c, pixmap);
38563 + completed += pp[i].queued;
38564 + } else while (pp[i].queued) {
38565 + xcb_present_generic_event_t *ev;
38567 + ev = (xcb_present_generic_event_t *)
38568 + xcb_wait_for_special_event(c, pp[i].Q);
38569 + if (ev == NULL)
38570 + abort();
38572 + do {
38573 + switch (ev->evtype) {
38574 + case XCB_PRESENT_COMPLETE_NOTIFY:
38575 + completed++;
38576 + pp[i].queued--;
38577 + break;
38579 + case XCB_PRESENT_EVENT_IDLE_NOTIFY:
38580 + break;
38581 + }
38582 + free(ev);
38583 + } while ((ev = (xcb_present_generic_event_t *)xcb_poll_for_special_event(c, pp[i].Q)));
38584 + }
38585 + }
38586 + clock_gettime(CLOCK_MONOTONIC, &end);
38588 + if (update)
38589 + xcb_xfixes_destroy_region(c, update);
38591 + for (i = 0; i < sz; i++) {
38592 + for (n = 0; n < N_BACK; n++) {
38593 + if (pp[i].buffer[n].fence.xid)
38594 + dri3_fence_free(dpy, &pp[i].buffer[n].fence);
38595 + if (pp[i].buffer[n].fd != -1)
38596 + close(pp[i].buffer[n].fd);
38597 + xcb_free_pixmap(c, pp[i].buffer[n].pixmap);
38598 + }
38600 + if (pp[i].Q) {
38601 + xcb_discard_reply(c, xcb_present_select_input_checked(c, pp[i].eid, pp[i].win, 0).sequence);
38602 + XSync(dpy, True);
38603 + xcb_unregister_for_special_event(c, pp[i].Q);
38604 + }
38606 + XDestroyWindow(dpy, pp[i].win);
38607 + }
38608 + free(pp);
38610 + test_name[0] = '\0';
38611 + if (options) {
38612 + snprintf(test_name, sizeof(test_name), "(%s%s%s )",
38613 + options & NOCOPY ? " no-copy" : "",
38614 + options & DRI3 ? " dri3" : "",
38615 + options & ASYNC ? " async" : "");
38616 + }
38617 + printf("%s%s: Completed %d presents in %.1fs, %.3fus each (%.1f FPS)\n",
38618 + __func__, test_name,
38619 + completed, elapsed(&start, &end) / 1000000,
38620 + elapsed(&start, &end) / completed,
38621 + completed / (elapsed(&start, &end) / 1000000));
38622 +}
38624 +static int isqrt(int x)
38625 +{
38626 + int i;
38628 + for (i = 2; i*i < x; i++)
38629 + ;
38630 + return i;
38631 +}
38633 +struct sibling {
38634 + pthread_t thread;
38635 + Display *dpy;
38636 + int x, y;
38637 + int width, height;
38638 + unsigned options;
38639 +};
38641 +static void *sibling(void *arg)
38642 +{
38643 + struct sibling *s = arg;
38644 + XSetWindowAttributes attr = { .override_redirect = 1 };
38645 + Window win = XCreateWindow(s->dpy, DefaultRootWindow(s->dpy),
38646 + s->x, s->y, s->width, s->height, 0,
38647 + DefaultDepth(s->dpy, DefaultScreen(s->dpy)),
38648 + InputOutput,
38649 + DefaultVisual(s->dpy, DefaultScreen(s->dpy)),
38650 + CWOverrideRedirect, &attr);
38651 + XMapWindow(s->dpy, win);
38652 + run(s->dpy, win, "sibling", s->options);
38653 + return NULL;
38654 +}
38656 +static void siblings(Display *dpy,
38657 + int max_width, int max_height, int ncpus, unsigned options)
38658 +{
38659 + int sq_ncpus = isqrt(ncpus);
38660 + int width = max_width / sq_ncpus;
38661 + int height = max_height/ sq_ncpus;
38662 + struct sibling s[ncpus];
38663 + int child;
38665 + if (ncpus <= 1)
38666 + return;
38668 + for (child = 0; child < ncpus; child++) {
38669 + s[child].dpy = dpy;
38670 + s[child].x = (child % sq_ncpus) * width;
38671 + s[child].y = (child / sq_ncpus) * height;
38672 + s[child].width = width;
38673 + s[child].height = height;
38674 + s[child].options = options;
38675 + pthread_create(&s[child].thread, NULL, sibling, &s[child]);
38676 + }
38678 + for (child = 0; child < ncpus; child++)
38679 + pthread_join(s[child].thread, NULL);
38680 +}
38682 +static void cousins(int max_width, int max_height, int ncpus, unsigned options)
38683 +{
38684 + int sq_ncpus = isqrt(ncpus);
38685 + int width = max_width / sq_ncpus;
38686 + int height = max_height/ sq_ncpus;
38687 + int child;
38689 + if (ncpus <= 1)
38690 + return;
38692 + for (child = 0; child < ncpus; child++) {
38693 + for (; fork() == 0; exit(0)) {
38694 + int x = (child % sq_ncpus) * width;
38695 + int y = (child / sq_ncpus) * height;
38696 + XSetWindowAttributes attr = { .override_redirect = 1 };
38697 + Display *dpy = XOpenDisplay(NULL);
38698 + Window win = XCreateWindow(dpy, DefaultRootWindow(dpy),
38699 + x, y, width, height, 0,
38700 + DefaultDepth(dpy, DefaultScreen(dpy)),
38701 + InputOutput,
38702 + DefaultVisual(dpy, DefaultScreen(dpy)),
38703 + CWOverrideRedirect, &attr);
38704 + XMapWindow(dpy, win);
38705 + run(dpy, win, "cousin", options);
38706 + }
38707 + }
38709 + while (child) {
38710 + int status = -1;
38711 + pid_t pid = wait(&status);
38712 + if (pid == -1)
38713 + continue;
38714 + child--;
38715 + }
38716 +}
38718 +static int has_present(Display *dpy)
38719 +{
38720 + xcb_connection_t *c = XGetXCBConnection(dpy);
38721 + xcb_generic_error_t *error = NULL;
38722 + void *reply;
38724 + reply = xcb_present_query_version_reply(c,
38725 + xcb_present_query_version(c,
38726 + XCB_PRESENT_MAJOR_VERSION,
38727 + XCB_PRESENT_MINOR_VERSION),
38728 + &error);
38730 + free(reply);
38731 + free(error);
38732 + if (reply == NULL) {
38733 + fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy));
38734 + return 0;
38735 + }
38737 + return 1;
38738 +}
38740 +static int has_composite(Display *dpy)
38741 +{
38742 + int event, error;
38743 + int major, minor;
38745 + if (!XDamageQueryExtension (dpy, &event, &error))
38746 + return 0;
38748 + if (!XCompositeQueryExtension(dpy, &event, &error))
38749 + return 0;
38751 + XCompositeQueryVersion(dpy, &major, &minor);
38753 + return major > 0 || minor >= 4;
38754 +}
38756 +static int dri3_query_version(Display *dpy, int *major, int *minor)
38757 +{
38758 + xcb_connection_t *c = XGetXCBConnection(dpy);
38759 + xcb_dri3_query_version_reply_t *reply;
38760 + xcb_generic_error_t *error;
38762 + *major = *minor = -1;
38764 + reply = xcb_dri3_query_version_reply(c,
38765 + xcb_dri3_query_version(c,
38766 + XCB_DRI3_MAJOR_VERSION,
38767 + XCB_DRI3_MINOR_VERSION),
38768 + &error);
38769 + free(error);
38770 + if (reply == NULL)
38771 + return -1;
38773 + *major = reply->major_version;
38774 + *minor = reply->minor_version;
38775 + free(reply);
38777 + return 0;
38778 +}
38780 +static int has_dri3(Display *dpy)
38781 +{
38782 + const xcb_query_extension_reply_t *ext;
38783 + int major, minor;
38785 + ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id);
38786 + if (ext == NULL || !ext->present)
38787 + return 0;
38789 + if (dri3_query_version(dpy, &major, &minor) < 0)
38790 + return 0;
38792 + return major >= 0;
38793 +}
38795 +static int has_xfixes(Display *dpy)
38796 +{
38797 + xcb_connection_t *c = XGetXCBConnection(dpy);
38798 + const xcb_query_extension_reply_t *ext;
38799 + void *reply;
38801 + ext = xcb_get_extension_data(c, &xcb_xfixes_id);
38802 + if (ext == NULL || !ext->present)
38803 + return 0;
38805 + reply = xcb_xfixes_query_version_reply(c,
38806 + xcb_xfixes_query_version(c,
38807 + XCB_XFIXES_MAJOR_VERSION,
38808 + XCB_XFIXES_MINOR_VERSION),
38809 + NULL);
38810 + free(reply);
38812 + return reply != NULL;
38813 +}
38815 +static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window)
38816 +{
38817 + XRRScreenResources *res;
38819 + res = XRRGetScreenResourcesCurrent(dpy, window);
38820 + if (res == NULL)
38821 + res = XRRGetScreenResources(dpy, window);
38823 + return res;
38824 +}
38826 +static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id)
38827 +{
38828 + int i;
38830 + for (i = 0; i < res->nmode; i++) {
38831 + if (res->modes[i].id == id)
38832 + return &res->modes[i];
38833 + }
38835 + return NULL;
38836 +}
38838 +static void fullscreen(Display *dpy, Window win)
38839 +{
38840 + Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
38841 + XChangeProperty(dpy, win,
38842 + XInternAtom(dpy, "_NET_WM_STATE", False),
38843 + XA_ATOM, 32, PropModeReplace,
38844 + (unsigned char *)&atom, 1);
38845 +}
38847 +static void loop(Display *dpy, XRRScreenResources *res, unsigned options)
38848 +{
38849 + Window root = DefaultRootWindow(dpy);
38850 + Window win;
38851 + XSetWindowAttributes attr;
38852 + int i, j;
38854 + attr.override_redirect = 1;
38856 + run(dpy, root, "off", options);
38857 + XSync(dpy, True);
38859 + for (i = 0; i < res->noutput; i++) {
38860 + XRROutputInfo *output;
38861 + XRRModeInfo *mode;
38863 + output = XRRGetOutputInfo(dpy, res, res->outputs[i]);
38864 + if (output == NULL)
38865 + continue;
38867 + mode = NULL;
38868 + if (res->nmode)
38869 + mode = lookup_mode(res, output->modes[0]);
38871 + for (j = 0; mode && j < 2*output->ncrtc; j++) {
38872 + int c = j;
38873 + if (c >= output->ncrtc)
38874 + c = 2*output->ncrtc - j - 1;
38876 + printf("[%d, %d] -- OUTPUT:%ld, CRTC:%ld: %dx%d\n",
38877 + i, c, (long)res->outputs[i], (long)output->crtcs[c],
38878 + mode->width, mode->height);
38879 + XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
38880 + 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1);
38882 + run(dpy, root, "root", options);
38883 + XSync(dpy, True);
38885 + win = XCreateWindow(dpy, root,
38886 + 0, 0, mode->width, mode->height, 0,
38887 + DefaultDepth(dpy, DefaultScreen(dpy)),
38888 + InputOutput,
38889 + DefaultVisual(dpy, DefaultScreen(dpy)),
38890 + CWOverrideRedirect, &attr);
38891 + fullscreen(dpy, win);
38892 + XMapWindow(dpy, win);
38893 + run(dpy, win, "fullscreen", options);
38894 + XDestroyWindow(dpy, win);
38895 + XSync(dpy, True);
38897 + win = XCreateWindow(dpy, root,
38898 + 0, 0, mode->width, mode->height, 0,
38899 + DefaultDepth(dpy, DefaultScreen(dpy)),
38900 + InputOutput,
38901 + DefaultVisual(dpy, DefaultScreen(dpy)),
38902 + CWOverrideRedirect, &attr);
38903 + XMapWindow(dpy, win);
38904 + run(dpy, win, "windowed", options);
38905 + XDestroyWindow(dpy, win);
38906 + XSync(dpy, True);
38908 + if (has_composite(dpy)) {
38909 + Damage damage;
38911 + _x_error_occurred = 0;
38912 + win = XCreateWindow(dpy, root,
38913 + 0, 0, mode->width, mode->height, 0,
38914 + DefaultDepth(dpy, DefaultScreen(dpy)),
38915 + InputOutput,
38916 + DefaultVisual(dpy, DefaultScreen(dpy)),
38917 + CWOverrideRedirect, &attr);
38918 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
38919 + damage = XDamageCreate(dpy, win, XDamageReportNonEmpty);
38920 + XMapWindow(dpy, win);
38921 + XSync(dpy, True);
38922 + if (!_x_error_occurred)
38923 + run(dpy, win, "composited", options);
38924 + XDamageDestroy(dpy, damage);
38925 + XDestroyWindow(dpy, win);
38926 + XSync(dpy, True);
38927 + }
38929 + win = XCreateWindow(dpy, root,
38930 + 0, 0, mode->width/2, mode->height/2, 0,
38931 + DefaultDepth(dpy, DefaultScreen(dpy)),
38932 + InputOutput,
38933 + DefaultVisual(dpy, DefaultScreen(dpy)),
38934 + CWOverrideRedirect, &attr);
38935 + XMapWindow(dpy, win);
38936 + run(dpy, win, "half", options);
38937 + XDestroyWindow(dpy, win);
38938 + XSync(dpy, True);
38940 + perpixel(dpy, mode->width, mode->height, options);
38942 + siblings(dpy, mode->width, mode->height,
38943 + sysconf(_SC_NPROCESSORS_ONLN),
38944 + options);
38946 + cousins(mode->width, mode->height,
38947 + sysconf(_SC_NPROCESSORS_ONLN),
38948 + options);
38950 + XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime,
38951 + 0, 0, None, RR_Rotate_0, NULL, 0);
38952 + }
38954 + XRRFreeOutputInfo(output);
38955 + }
38957 +}
38959 +int main(void)
38960 +{
38961 + Display *dpy;
38962 + XRRScreenResources *res;
38963 + XRRCrtcInfo **original_crtc;
38964 + int i;
38966 + XInitThreads();
38968 + dpy = XOpenDisplay(NULL);
38969 + if (dpy == NULL)
38970 + return 77;
38972 + if (!has_present(dpy))
38973 + return 77;
38975 + if (DPMSQueryExtension(dpy, &i, &i))
38976 + DPMSDisable(dpy);
38978 + signal(SIGALRM, SIG_IGN);
38979 + XSetErrorHandler(_check_error_handler);
38981 + res = NULL;
38982 + if (XRRQueryVersion(dpy, &i, &i))
38983 + res = _XRRGetScreenResourcesCurrent(dpy, DefaultRootWindow(dpy));
38984 + if (res == NULL)
38985 + return 77;
38987 + original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc);
38988 + for (i = 0; i < res->ncrtc; i++)
38989 + original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
38991 + printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc);
38992 + for (i = 0; i < res->ncrtc; i++)
38993 + XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
38994 + 0, 0, None, RR_Rotate_0, NULL, 0);
38996 + loop(dpy, res, 0);
38997 + loop(dpy, res, ASYNC);
38998 + if (has_xfixes(dpy))
38999 + loop(dpy, res, NOCOPY);
39000 + if (has_dri3(dpy)) {
39001 + loop(dpy, res, DRI3);
39002 + loop(dpy, res, DRI3 | ASYNC);
39003 + }
39005 + for (i = 0; i < res->ncrtc; i++)
39006 + XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime,
39007 + original_crtc[i]->x,
39008 + original_crtc[i]->y,
39009 + original_crtc[i]->mode,
39010 + original_crtc[i]->rotation,
39011 + original_crtc[i]->outputs,
39012 + original_crtc[i]->noutput);
39014 + if (DPMSQueryExtension(dpy, &i, &i))
39015 + DPMSEnable(dpy);
39016 + return 0;
39017 +}
39018 diff --git a/test/present-test.c b/test/present-test.c
39019 index 6b562eb0..5a12a24f 100644
39020 --- a/test/present-test.c
39021 +++ b/test/present-test.c
39022 @@ -31,7 +31,9 @@
39023 #include <X11/xshmfence.h>
39024 #include <X11/Xutil.h>
39025 #include <X11/Xlibint.h>
39026 +#include <X11/extensions/dpms.h>
39027 #include <X11/extensions/randr.h>
39028 +#include <X11/extensions/Xcomposite.h>
39029 #include <X11/extensions/Xrandr.h>
39030 #include <X11/extensions/Xrender.h>
39031 #include <X11/extensions/XShm.h>
39032 @@ -44,6 +46,8 @@
39033 #endif
39034 #include <xcb/xcb.h>
39035 #include <xcb/present.h>
39036 +#include <xcb/xfixes.h>
39037 +#include <xcb/dri3.h>
39038 #include <xf86drm.h>
39039 #include <i915_drm.h>
39041 @@ -134,12 +138,14 @@ static void *setup_msc(Display *dpy, Window win)
39042 return q;
39045 -static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc)
39046 +static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc, uint64_t *ust)
39048 xcb_connection_t *c = XGetXCBConnection(dpy);
39049 + static uint32_t serial = 1;
39050 uint64_t msc = 0;
39051 + int complete = 0;
39053 - xcb_present_notify_msc(c, win, 0, 0, 0, 0);
39054 + xcb_present_notify_msc(c, win, serial ^ 0xcc00ffee, 0, 0, 0);
39055 xcb_flush(c);
39057 do {
39058 @@ -151,82 +157,1268 @@ static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc)
39059 break;
39061 ce = (xcb_present_complete_notify_event_t *)ev;
39062 - if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
39063 + if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
39064 + ce->serial == (serial ^ 0xcc00ffee)) {
39065 + msc = ce->msc;
39066 + if (ust)
39067 + *ust = ce->ust;
39068 + complete = 1;
39069 + }
39070 + free(ev);
39071 + } while (!complete);
39073 + if ((int64_t)(msc - last_msc) < 0) {
39074 + printf("Invalid MSC: was %llu, now %llu\n",
39075 + (long long)last_msc, (long long)msc);
39076 + }
39078 + if (++serial == 0)
39079 + serial = 1;
39081 + return msc;
39082 +}
39084 +static uint64_t wait_vblank(Display *dpy, Window win, void *q)
39085 +{
39086 + xcb_connection_t *c = XGetXCBConnection(dpy);
39087 + static uint32_t serial = 1;
39088 + uint64_t msc = 0;
39089 + int complete = 0;
39091 + xcb_present_notify_msc(c, win, serial ^ 0xdeadbeef, 0, 1, 0);
39092 + xcb_flush(c);
39094 + do {
39095 + xcb_present_complete_notify_event_t *ce;
39096 + xcb_generic_event_t *ev;
39098 + ev = xcb_wait_for_special_event(c, q);
39099 + if (ev == NULL)
39100 + break;
39102 + ce = (xcb_present_complete_notify_event_t *)ev;
39103 + if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
39104 + ce->serial == (serial ^ 0xdeadbeef)) {
39105 msc = ce->msc;
39106 + complete = 1;
39107 + }
39108 + free(ev);
39109 + } while (!complete);
39111 + if (++serial == 0)
39112 + serial = 1;
39114 + return msc;
39115 +}
39117 +static uint64_t msc_interval(Display *dpy, Window win, void *q)
39118 +{
39119 + xcb_connection_t *c = XGetXCBConnection(dpy);
39120 + uint64_t msc, ust;
39121 + int complete = 0;
39123 + msc = check_msc(dpy, win, q, 0, NULL);
39125 + xcb_present_notify_msc(c, win, 0xc0ffee00, msc, 0, 0);
39126 + xcb_present_notify_msc(c, win, 0xc0ffee01, msc + 10, 0, 0);
39127 + xcb_flush(c);
39129 + ust = msc = 0;
39130 + do {
39131 + xcb_present_complete_notify_event_t *ce;
39132 + xcb_generic_event_t *ev;
39134 + ev = xcb_wait_for_special_event(c, q);
39135 + if (ev == NULL)
39136 + break;
39138 + ce = (xcb_present_complete_notify_event_t *)ev;
39139 + if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
39140 + ce->serial == 0xc0ffee00) {
39141 + msc -= ce->msc;
39142 + ust -= ce->ust;
39143 + complete++;
39144 + }
39145 + if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC &&
39146 + ce->serial == 0xc0ffee01) {
39147 + msc += ce->msc;
39148 + ust += ce->ust;
39149 + complete++;
39150 + }
39151 + free(ev);
39152 + } while (complete != 2);
39154 + printf("10 frame interval: msc=%lld, ust=%lld\n",
39155 + (long long)msc, (long long)ust);
39156 + XSync(dpy, True);
39157 + if (msc == 0)
39158 + return 0;
39160 + return (ust + msc/2) / msc;
39161 +}
39163 +static void teardown_msc(Display *dpy, void *q)
39164 +{
39165 + xcb_unregister_for_special_event(XGetXCBConnection(dpy), q);
39166 +}
39168 +static int test_whole(Display *dpy, Window win, const char *phase)
39169 +{
39170 + xcb_connection_t *c = XGetXCBConnection(dpy);
39171 + Pixmap pixmap;
39172 + struct dri3_fence fence;
39173 + Window root;
39174 + unsigned int width, height;
39175 + unsigned border, depth;
39176 + int x, y, ret = 1;
39178 + XGetGeometry(dpy, win,
39179 + &root, &x, &y, &width, &height, &border, &depth);
39181 + if (dri3_create_fence(dpy, win, &fence))
39182 + return 0;
39184 + printf("%s: Testing simple flip: %dx%d\n", phase, width, height);
39185 + _x_error_occurred = 0;
39187 + xshmfence_reset(fence.addr);
39189 + pixmap = XCreatePixmap(dpy, win, width, height, depth);
39190 + xcb_present_pixmap(c, win, pixmap, 0,
39191 + 0, /* valid */
39192 + 0, /* update */
39193 + 0, /* x_off */
39194 + 0, /* y_off */
39195 + None,
39196 + None, /* wait fence */
39197 + fence.xid,
39198 + XCB_PRESENT_OPTION_NONE,
39199 + 0, /* target msc */
39200 + 0, /* divisor */
39201 + 0, /* remainder */
39202 + 0, NULL);
39203 + XFreePixmap(dpy, pixmap);
39205 + pixmap = XCreatePixmap(dpy, win, width, height, depth);
39206 + xcb_present_pixmap(c, win, pixmap, 0,
39207 + 0, /* valid */
39208 + 0, /* update */
39209 + 0, /* x_off */
39210 + 0, /* y_off */
39211 + None,
39212 + None, /* wait fence */
39213 + None, /* sync fence */
39214 + XCB_PRESENT_OPTION_NONE,
39215 + 0, /* target msc */
39216 + 0, /* divisor */
39217 + 0, /* remainder */
39218 + 0, NULL);
39219 + XFreePixmap(dpy, pixmap);
39220 + XFlush(dpy);
39222 + ret = !!xshmfence_await(fence.addr);
39223 + dri3_fence_free(dpy, &fence);
39225 + XSync(dpy, True);
39226 + ret += !!_x_error_occurred;
39228 + return ret;
39229 +}
39231 +static uint64_t flush_flips(Display *dpy, Window win, Pixmap pixmap, void *Q, uint64_t *ust)
39232 +{
39233 + xcb_connection_t *c = XGetXCBConnection(dpy);
39234 + uint64_t msc;
39235 + int complete;
39237 + msc = check_msc(dpy, win, Q, 0, NULL);
39238 + xcb_present_pixmap(c, win, pixmap,
39239 + 0xdeadbeef, /* serial */
39240 + 0, /* valid */
39241 + 0, /* update */
39242 + 0, /* x_off */
39243 + 0, /* y_off */
39244 + None,
39245 + None, /* wait fence */
39246 + None,
39247 + XCB_PRESENT_OPTION_NONE,
39248 + msc + 60, /* target msc */
39249 + 0, /* divisor */
39250 + 0, /* remainder */
39251 + 0, NULL);
39252 + xcb_flush(c);
39253 + complete = 0;
39254 + do {
39255 + xcb_present_complete_notify_event_t *ce;
39256 + xcb_generic_event_t *ev;
39258 + ev = xcb_wait_for_special_event(c, Q);
39259 + if (ev == NULL)
39260 + break;
39262 + ce = (xcb_present_complete_notify_event_t *)ev;
39263 + complete = (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP &&
39264 + ce->serial == 0xdeadbeef);
39265 + free(ev);
39266 + } while (!complete);
39267 + XSync(dpy, True);
39269 + return check_msc(dpy, win, Q, msc, ust);
39270 +}
39272 +static int test_double(Display *dpy, Window win, const char *phase, void *Q)
39273 +{
39274 +#define COUNT (15*60)
39275 + xcb_connection_t *c = XGetXCBConnection(dpy);
39276 + Pixmap pixmap;
39277 + Window root;
39278 + unsigned int width, height;
39279 + unsigned border, depth;
39280 + int x, y, n, ret;
39281 + struct {
39282 + uint64_t msc, ust;
39283 + } frame[COUNT+1];
39284 + int offset = 0;
39286 + XGetGeometry(dpy, win,
39287 + &root, &x, &y, &width, &height, &border, &depth);
39289 + printf("%s: Testing flip double buffering: %dx%d\n", phase, width, height);
39290 + _x_error_occurred = 0;
39292 + pixmap = XCreatePixmap(dpy, win, width, height, depth);
39293 + flush_flips(dpy, win, pixmap, Q, NULL);
39294 + for (n = 0; n <= COUNT; n++) {
39295 + int complete;
39297 + xcb_present_pixmap(c, win, pixmap, n,
39298 + 0, /* valid */
39299 + 0, /* update */
39300 + 0, /* x_off */
39301 + 0, /* y_off */
39302 + None,
39303 + None, /* wait fence */
39304 + None,
39305 + XCB_PRESENT_OPTION_NONE,
39306 + 0, /* target msc */
39307 + 0, /* divisor */
39308 + 0, /* remainder */
39309 + 0, NULL);
39310 + xcb_flush(c);
39312 + complete = 0;
39313 + do {
39314 + xcb_present_complete_notify_event_t *ce;
39315 + xcb_generic_event_t *ev;
39317 + ev = xcb_wait_for_special_event(c, Q);
39318 + if (ev == NULL)
39319 + break;
39321 + ce = (xcb_present_complete_notify_event_t *)ev;
39322 + if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP &&
39323 + ce->serial == n) {
39324 + frame[n].msc = ce->msc;
39325 + frame[n].ust = ce->ust;
39326 + complete = 1;
39327 + }
39328 + free(ev);
39329 + } while (!complete);
39330 + }
39331 + XFreePixmap(dpy, pixmap);
39333 + XSync(dpy, True);
39334 + ret = !!_x_error_occurred;
39336 + if (frame[COUNT].msc - frame[0].msc != COUNT) {
39337 + printf("Expected %d frames interval, %d elapsed instead\n",
39338 + COUNT, (int)(frame[COUNT].msc - frame[0].msc));
39339 + for (n = 0; n <= COUNT; n++) {
39340 + if (frame[n].msc - frame[0].msc != n + offset) {
39341 + printf("frame[%d]: msc=%03lld, ust=%lld\n", n,
39342 + (long long)(frame[n].msc - frame[0].msc),
39343 + (long long)(frame[n].ust - frame[0].ust));
39344 + offset = frame[n].msc - frame[0].msc - n;
39345 + ret++;
39346 + }
39347 + }
39348 + }
39350 + return ret;
39351 +}
39353 +static int test_future(Display *dpy, Window win, const char *phase, void *Q)
39354 +{
39355 + xcb_connection_t *c = XGetXCBConnection(dpy);
39356 + Pixmap pixmap;
39357 + struct dri3_fence fence;
39358 + Window root;
39359 + unsigned int width, height;
39360 + unsigned border, depth;
39361 + int x, y, ret = 0, n;
39362 + uint64_t msc, ust;
39363 + int complete, count;
39364 + int early = 0, late = 0;
39365 + int earliest = 0, latest = 0;
39366 + uint64_t interval;
39368 + XGetGeometry(dpy, win,
39369 + &root, &x, &y, &width, &height, &border, &depth);
39371 + if (dri3_create_fence(dpy, win, &fence))
39372 + return 0;
39374 + printf("%s: Testing flips into the future: %dx%d\n", phase, width, height);
39375 + _x_error_occurred = 0;
39377 + interval = msc_interval(dpy, win, Q);
39378 + if (interval == 0) {
39379 + printf("Zero delay between frames\n");
39380 + return 1;
39381 + }
39383 + pixmap = XCreatePixmap(dpy, win, width, height, depth);
39384 + msc = flush_flips(dpy, win, pixmap, Q, &ust);
39385 + for (n = 1; n <= 10; n++)
39386 + xcb_present_pixmap(c, win, pixmap,
39387 + n, /* serial */
39388 + 0, /* valid */
39389 + 0, /* update */
39390 + 0, /* x_off */
39391 + 0, /* y_off */
39392 + None,
39393 + None, /* wait fence */
39394 + None,
39395 + XCB_PRESENT_OPTION_NONE,
39396 + msc + 60 + n*15*60, /* target msc */
39397 + 0, /* divisor */
39398 + 0, /* remainder */
39399 + 0, NULL);
39400 + xcb_present_pixmap(c, win, pixmap,
39401 + 0xdeadbeef, /* serial */
39402 + 0, /* valid */
39403 + 0, /* update */
39404 + 0, /* x_off */
39405 + 0, /* y_off */
39406 + None,
39407 + None, /* wait fence */
39408 + None,
39409 + XCB_PRESENT_OPTION_NONE,
39410 + msc + 60 + n*15*60, /* target msc */
39411 + 0, /* divisor */
39412 + 0, /* remainder */
39413 + 0, NULL);
39414 + xcb_flush(c);
39416 + complete = 0;
39417 + count = 0;
39418 + do {
39419 + xcb_present_complete_notify_event_t *ce;
39420 + xcb_generic_event_t *ev;
39422 + ev = xcb_wait_for_special_event(c, Q);
39423 + if (ev == NULL)
39424 + break;
39426 + ce = (xcb_present_complete_notify_event_t *)ev;
39427 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP);
39429 + if (ce->serial == 0xdeadbeef) {
39430 + int64_t time;
39432 + time = ce->ust - (ust + (60 + 15*60*n) * interval);
39433 + if (time < -(int64_t)interval) {
39434 + fprintf(stderr,
39435 + "\tflips completed too early by %lldms\n",
39436 + (long long)(-time / 1000));
39437 + } else if (time > (int64_t)interval) {
39438 + fprintf(stderr,
39439 + "\tflips completed too late by %lldms\n",
39440 + (long long)(time / 1000));
39441 + }
39442 + complete = 1;
39443 + } else {
39444 + int diff = (int64_t)(ce->msc - (15*60*ce->serial + msc + 60));
39445 + if (diff < 0) {
39446 + if (-diff > earliest) {
39447 + fprintf(stderr, "\tframe %d displayed early by %d frames\n", ce->serial, -diff);
39448 + earliest = -diff;
39449 + }
39450 + early++;
39451 + ret++;
39452 + } else if (diff > 0) {
39453 + if (diff > latest) {
39454 + fprintf(stderr, "\tframe %d displayed late by %d frames\n", ce->serial, diff);
39455 + latest = diff;
39456 + }
39457 + late++;
39458 + ret++;
39459 + }
39460 + count++;
39461 + }
39462 + free(ev);
39463 + } while (!complete);
39465 + if (early)
39466 + printf("\t%d frames shown too early (worst %d)!\n", early, earliest);
39467 + if (late)
39468 + printf("\t%d frames shown too late (worst %d)!\n", late, latest);
39470 + if (count != 10) {
39471 + fprintf(stderr, "Sentinel frame received too early! %d frames outstanding\n", 10 - count);
39472 + ret++;
39474 + do {
39475 + xcb_present_complete_notify_event_t *ce;
39476 + xcb_generic_event_t *ev;
39478 + ev = xcb_wait_for_special_event(c, Q);
39479 + if (ev == NULL)
39480 + break;
39482 + ce = (xcb_present_complete_notify_event_t *)ev;
39483 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP);
39484 + free(ev);
39485 + } while (++count != 10);
39486 + }
39488 + ret += !!_x_error_occurred;
39490 + return ret;
39491 +}
39493 +static int test_exhaustion(Display *dpy, Window win, const char *phase, void *Q)
39494 +{
39495 +#define N_VBLANKS 256 /* kernel event queue length: 128 vblanks */
39496 + xcb_connection_t *c = XGetXCBConnection(dpy);
39497 + Pixmap pixmap;
39498 + struct dri3_fence fence[2];
39499 + Window root;
39500 + xcb_xfixes_region_t region;
39501 + unsigned int width, height;
39502 + unsigned border, depth;
39503 + int x, y, ret = 0, n;
39504 + uint64_t target, final;
39506 + XGetGeometry(dpy, win,
39507 + &root, &x, &y, &width, &height, &border, &depth);
39509 + if (dri3_create_fence(dpy, win, &fence[0]) ||
39510 + dri3_create_fence(dpy, win, &fence[1]))
39511 + return 0;
39513 + printf("%s: Testing flips with long vblank queues: %dx%d\n", phase, width, height);
39514 + _x_error_occurred = 0;
39516 + region = xcb_generate_id(c);
39517 + xcb_xfixes_create_region(c, region, 0, NULL);
39519 + pixmap = XCreatePixmap(dpy, win, width, height, depth);
39520 + xshmfence_reset(fence[0].addr);
39521 + xshmfence_reset(fence[1].addr);
39522 + target = check_msc(dpy, win, Q, 0, NULL);
39523 + for (n = N_VBLANKS; n--; )
39524 + xcb_present_pixmap(c, win, pixmap, 0,
39525 + 0, /* valid */
39526 + region, /* update */
39527 + 0, /* x_off */
39528 + 0, /* y_off */
39529 + None,
39530 + None, /* wait fence */
39531 + None,
39532 + XCB_PRESENT_OPTION_NONE,
39533 + target + N_VBLANKS, /* target msc */
39534 + 1, /* divisor */
39535 + 0, /* remainder */
39536 + 0, NULL);
39537 + xcb_present_pixmap(c, win, pixmap, 0,
39538 + region, /* valid */
39539 + region, /* update */
39540 + 0, /* x_off */
39541 + 0, /* y_off */
39542 + None,
39543 + None, /* wait fence */
39544 + fence[0].xid,
39545 + XCB_PRESENT_OPTION_NONE,
39546 + target, /* target msc */
39547 + 0, /* divisor */
39548 + 0, /* remainder */
39549 + 0, NULL);
39550 + for (n = 1; n < N_VBLANKS; n++)
39551 + xcb_present_pixmap(c, win, pixmap, 0,
39552 + region, /* valid */
39553 + region, /* update */
39554 + 0, /* x_off */
39555 + 0, /* y_off */
39556 + None,
39557 + None, /* wait fence */
39558 + None,
39559 + XCB_PRESENT_OPTION_NONE,
39560 + target + n, /* target msc */
39561 + 0, /* divisor */
39562 + 0, /* remainder */
39563 + 0, NULL);
39564 + xcb_present_pixmap(c, win, pixmap, 0,
39565 + region, /* valid */
39566 + region, /* update */
39567 + 0, /* x_off */
39568 + 0, /* y_off */
39569 + None,
39570 + None, /* wait fence */
39571 + fence[1].xid,
39572 + XCB_PRESENT_OPTION_NONE,
39573 + target + N_VBLANKS, /* target msc */
39574 + 0, /* divisor */
39575 + 0, /* remainder */
39576 + 0, NULL);
39577 + xcb_flush(c);
39579 + ret += !!xshmfence_await(fence[0].addr);
39580 + final = check_msc(dpy, win, Q, 0, NULL);
39581 + if (final < target) {
39582 + printf("\tFirst flip too early, MSC was %llu, expected %llu\n",
39583 + (long long)final, (long long)target);
39584 + ret++;
39585 + } else if (final > target + 1) {
39586 + printf("\tFirst flip too late, MSC was %llu, expected %llu\n",
39587 + (long long)final, (long long)target);
39588 + ret++;
39589 + }
39591 + ret += !!xshmfence_await(fence[1].addr);
39592 + final = check_msc(dpy, win, Q, 0, NULL);
39593 + if (final < target + N_VBLANKS) {
39594 + printf("\tLast flip too early, MSC was %llu, expected %llu\n",
39595 + (long long)final, (long long)(target + N_VBLANKS));
39596 + ret++;
39597 + } else if (final > target + N_VBLANKS + 1) {
39598 + printf("\tLast flip too late, MSC was %llu, expected %llu\n",
39599 + (long long)final, (long long)(target + N_VBLANKS));
39600 + ret++;
39601 + }
39603 + flush_flips(dpy, win, pixmap, Q, NULL);
39605 + XFreePixmap(dpy, pixmap);
39606 + xcb_xfixes_destroy_region(c, region);
39607 + dri3_fence_free(dpy, &fence[1]);
39608 + dri3_fence_free(dpy, &fence[0]);
39610 + XSync(dpy, True);
39611 + ret += !!_x_error_occurred;
39613 + return ret;
39614 +#undef N_VBLANKS
39615 +}
39617 +static int test_accuracy(Display *dpy, Window win, const char *phase, void *Q)
39618 +{
39619 +#define N_VBLANKS (60 * 120) /* ~2 minutes */
39620 + xcb_connection_t *c = XGetXCBConnection(dpy);
39621 + Pixmap pixmap;
39622 + Window root;
39623 + unsigned int width, height;
39624 + unsigned border, depth;
39625 + int x, y, ret = 0, n;
39626 + uint64_t target;
39627 + int early = 0, late = 0;
39628 + int earliest = 0, latest = 0;
39629 + int complete, count;
39631 + XGetGeometry(dpy, win,
39632 + &root, &x, &y, &width, &height, &border, &depth);
39634 + printf("%s: Testing flip accuracy: %dx%d\n", phase, width, height);
39635 + _x_error_occurred = 0;
39637 + pixmap = XCreatePixmap(dpy, win, width, height, depth);
39638 + target = flush_flips(dpy, win, pixmap, Q, NULL);
39639 + for (n = 0; n <= N_VBLANKS; n++)
39640 + xcb_present_pixmap(c, win, pixmap,
39641 + n, /* serial */
39642 + 0, /* valid */
39643 + 0, /* update */
39644 + 0, /* x_off */
39645 + 0, /* y_off */
39646 + None,
39647 + None, /* wait fence */
39648 + None,
39649 + XCB_PRESENT_OPTION_NONE,
39650 + target + 60 + n, /* target msc */
39651 + 0, /* divisor */
39652 + 0, /* remainder */
39653 + 0, NULL);
39654 + xcb_present_pixmap(c, win, pixmap,
39655 + 0xdeadbeef, /* serial */
39656 + 0, /* valid */
39657 + 0, /* update */
39658 + 0, /* x_off */
39659 + 0, /* y_off */
39660 + None,
39661 + None, /* wait fence */
39662 + None,
39663 + XCB_PRESENT_OPTION_NONE,
39664 + target + 60 + n, /* target msc */
39665 + 0, /* divisor */
39666 + 0, /* remainder */
39667 + 0, NULL);
39668 + xcb_flush(c);
39670 + complete = 0;
39671 + count = 0;
39672 + do {
39673 + xcb_present_complete_notify_event_t *ce;
39674 + xcb_generic_event_t *ev;
39676 + ev = xcb_wait_for_special_event(c, Q);
39677 + if (ev == NULL)
39678 + break;
39680 + ce = (xcb_present_complete_notify_event_t *)ev;
39681 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP);
39683 + if (ce->serial != 0xdeadbeef) {
39684 + int diff = (int64_t)(ce->msc - (target + ce->serial + 60));
39685 + if (diff < 0) {
39686 + if (-diff > earliest) {
39687 + fprintf(stderr, "\tframe %d displayed early by %d frames\n", ce->serial, -diff);
39688 + earliest = -diff;
39689 + }
39690 + early++;
39691 + ret++;
39692 + } else if (diff > 0) {
39693 + if (diff > latest) {
39694 + fprintf(stderr, "\tframe %d displayed late by %d frames\n", ce->serial, diff);
39695 + latest = diff;
39696 + }
39697 + late++;
39698 + ret++;
39699 + }
39700 + count++;
39701 + } else
39702 + complete = 1;
39703 free(ev);
39704 - } while (msc == 0);
39705 + } while (!complete);
39707 + if (early)
39708 + printf("\t%d frames shown too early (worst %d)!\n", early, earliest);
39709 + if (late)
39710 + printf("\t%d frames shown too late (worst %d)!\n", late, latest);
39712 + if (count != N_VBLANKS+1) {
39713 + fprintf(stderr, "Sentinel frame received too early! %d frames outstanding\n", N_VBLANKS+1 - count);
39714 + ret++;
39715 + do {
39716 + xcb_present_complete_notify_event_t *ce;
39717 + xcb_generic_event_t *ev;
39719 + ev = xcb_wait_for_special_event(c, Q);
39720 + if (ev == NULL)
39721 + break;
39723 + ce = (xcb_present_complete_notify_event_t *)ev;
39724 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP);
39725 + free(ev);
39726 + } while (++count != N_VBLANKS+1);
39727 + }
39729 + XFreePixmap(dpy, pixmap);
39731 + XSync(dpy, True);
39732 + ret += !!_x_error_occurred;
39734 + return ret;
39735 +#undef N_VBLANKS
39736 +}
39738 +static int test_modulus(Display *dpy, Window win, const char *phase, void *Q)
39739 +{
39740 + xcb_connection_t *c = XGetXCBConnection(dpy);
39741 + Pixmap pixmap;
39742 + Window root;
39743 + unsigned int width, height;
39744 + unsigned border, depth;
39745 + xcb_xfixes_region_t region;
39746 + int x, y, ret = 0;
39747 + uint64_t target;
39748 + int early = 0, late = 0;
39749 + int earliest = 0, latest = 0;
39750 + int complete, expect, count;
39752 + XGetGeometry(dpy, win,
39753 + &root, &x, &y, &width, &height, &border, &depth);
39755 + printf("%s: Testing flip modulus: %dx%d\n", phase, width, height);
39756 + _x_error_occurred = 0;
39758 + region = xcb_generate_id(c);
39759 + xcb_xfixes_create_region(c, region, 0, NULL);
39761 + pixmap = XCreatePixmap(dpy, win, width, height, depth);
39762 + target = flush_flips(dpy, win, pixmap, Q, NULL);
39763 + expect = 0;
39764 + for (x = 1; x <= 7; x++) {
39765 + for (y = 0; y < x; y++) {
39766 + xcb_present_pixmap(c, win, pixmap,
39767 + y << 16 | x, /* serial */
39768 + region, /* valid */
39769 + region, /* update */
39770 + 0, /* x_off */
39771 + 0, /* y_off */
39772 + None,
39773 + None, /* wait fence */
39774 + None,
39775 + XCB_PRESENT_OPTION_NONE,
39776 + 0, /* target msc */
39777 + x, /* divisor */
39778 + y, /* remainder */
39779 + 0, NULL);
39780 + expect++;
39781 + }
39782 + }
39783 + xcb_present_pixmap(c, win, pixmap,
39784 + 0xdeadbeef, /* serial */
39785 + 0, /* valid */
39786 + 0, /* update */
39787 + 0, /* x_off */
39788 + 0, /* y_off */
39789 + None,
39790 + None, /* wait fence */
39791 + None,
39792 + XCB_PRESENT_OPTION_NONE,
39793 + target + 2*x, /* target msc */
39794 + 0, /* divisor */
39795 + 0, /* remainder */
39796 + 0, NULL);
39797 + xcb_flush(c);
39799 + complete = 0;
39800 + count = 0;
39801 + do {
39802 + xcb_present_complete_notify_event_t *ce;
39803 + xcb_generic_event_t *ev;
39805 + ev = xcb_wait_for_special_event(c, Q);
39806 + if (ev == NULL)
39807 + break;
39809 + ce = (xcb_present_complete_notify_event_t *)ev;
39810 + if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP)
39811 + break;
39813 + assert(ce->serial);
39814 + if (ce->serial != 0xdeadbeef) {
39815 + uint64_t msc;
39816 + int diff;
39818 + x = ce->serial & 0xffff;
39819 + y = ce->serial >> 16;
39821 + msc = target;
39822 + msc -= target % x;
39823 + msc += y;
39824 + if (msc <= target)
39825 + msc += x;
39827 + diff = (int64_t)(ce->msc - msc);
39828 + if (diff < 0) {
39829 + if (-diff > earliest) {
39830 + fprintf(stderr, "\tframe (%d, %d) displayed early by %d frames\n", y, x, -diff);
39831 + earliest = -diff;
39832 + }
39833 + early++;
39834 + ret++;
39835 + } else if (diff > 0) {
39836 + if (diff > latest) {
39837 + fprintf(stderr, "\tframe (%d, %d) displayed late by %d frames\n", y, x, diff);
39838 + latest = diff;
39839 + }
39840 + late++;
39841 + ret++;
39842 + }
39843 + count++;
39844 + } else
39845 + complete = 1;
39846 + free(ev);
39847 + } while (!complete);
39849 + if (early)
39850 + printf("\t%d frames shown too early (worst %d)!\n", early, earliest);
39851 + if (late)
39852 + printf("\t%d frames shown too late (worst %d)!\n", late, latest);
39854 + if (count != expect) {
39855 + fprintf(stderr, "Sentinel frame received too early! %d frames outstanding\n", expect - count);
39856 + ret++;
39857 + do {
39858 + xcb_present_complete_notify_event_t *ce;
39859 + xcb_generic_event_t *ev;
39861 + ev = xcb_wait_for_special_event(c, Q);
39862 + if (ev == NULL)
39863 + break;
39865 + ce = (xcb_present_complete_notify_event_t *)ev;
39866 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
39867 + free(ev);
39868 + } while (++count != expect);
39869 + }
39871 + XFreePixmap(dpy, pixmap);
39872 + xcb_xfixes_destroy_region(c, region);
39874 + XSync(dpy, True);
39875 + ret += !!_x_error_occurred;
39877 + return ret;
39878 +}
39880 +static int test_future_msc(Display *dpy, void *Q)
39881 +{
39882 + xcb_connection_t *c = XGetXCBConnection(dpy);
39883 + Window root = DefaultRootWindow(dpy);
39884 + int ret = 0, n;
39885 + uint64_t msc, ust;
39886 + int complete, count;
39887 + int early = 0, late = 0;
39888 + int earliest = 0, latest = 0;
39889 + uint64_t interval;
39891 + printf("Testing notifies into the future\n");
39892 + _x_error_occurred = 0;
39894 + interval = msc_interval(dpy, root, Q);
39895 + if (interval == 0) {
39896 + printf("Zero delay between frames\n");
39897 + return 1;
39898 + }
39899 + msc = check_msc(dpy, root, Q, 0, &ust);
39900 + printf("Initial msc=%llx, interval between frames %lldus\n",
39901 + (long long)msc, (long long)interval);
39903 + for (n = 1; n <= 10; n++)
39904 + xcb_present_notify_msc(c, root, n, msc + 60 + n*15*60, 0, 0);
39905 + xcb_present_notify_msc(c, root, 0xdeadbeef, msc + 60 + n*15*60, 0, 0);
39906 + xcb_flush(c);
39908 + complete = 0;
39909 + count = 0;
39910 + do {
39911 + xcb_present_complete_notify_event_t *ce;
39912 + xcb_generic_event_t *ev;
39914 + ev = xcb_wait_for_special_event(c, Q);
39915 + if (ev == NULL)
39916 + break;
39918 + ce = (xcb_present_complete_notify_event_t *)ev;
39919 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
39921 + if (ce->serial == 0xdeadbeef) {
39922 + int64_t time, tolerance;
39924 + tolerance = 60 + 15*60*n/10;
39925 + if (tolerance < interval)
39926 + tolerance = interval;
39928 + time = ce->ust - (ust + (60 + 15*60*n) * interval);
39929 + if (time < -(int64_t)tolerance) {
39930 + fprintf(stderr,
39931 + "\tnotifies completed too early by %lldms, tolerance %lldus\n",
39932 + (long long)(-time / 1000), (long long)tolerance);
39933 + } else if (time > (int64_t)tolerance) {
39934 + fprintf(stderr,
39935 + "\tnotifies completed too late by %lldms, tolerance %lldus\n",
39936 + (long long)(time / 1000), (long long)tolerance);
39937 + }
39938 + complete = 1;
39939 + } else {
39940 + int diff = (int64_t)(ce->msc - (15*60*ce->serial + msc + 60));
39942 + if (ce->serial != count + 1) {
39943 + fprintf(stderr, "vblank received out of order! expected %d, received %d\n",
39944 + count + 1, (int)ce->serial);
39945 + ret++;
39946 + }
39947 + count++;
39949 + if (diff < 0) {
39950 + if (-diff > earliest) {
39951 + fprintf(stderr, "\tnotify %d early by %d msc\n", ce->serial, -diff);
39952 + earliest = -diff;
39953 + }
39954 + early++;
39955 + ret++;
39956 + } else if (diff > 0) {
39957 + if (diff > latest) {
39958 + fprintf(stderr, "\tnotify %d late by %d msc\n", ce->serial, diff);
39959 + latest = diff;
39960 + }
39961 + late++;
39962 + ret++;
39963 + }
39964 + }
39965 + free(ev);
39966 + } while (!complete);
39968 + if (early)
39969 + printf("\t%d notifies too early (worst %d)!\n", early, earliest);
39970 + if (late)
39971 + printf("\t%d notifies too late (worst %d)!\n", late, latest);
39973 + if (count != 10) {
39974 + fprintf(stderr, "Sentinel vblank received too early! %d waits outstanding\n", 10 - count);
39975 + ret++;
39976 + do {
39977 + xcb_present_complete_notify_event_t *ce;
39978 + xcb_generic_event_t *ev;
39980 + ev = xcb_wait_for_special_event(c, Q);
39981 + if (ev == NULL)
39982 + break;
39984 + ce = (xcb_present_complete_notify_event_t *)ev;
39985 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
39986 + free(ev);
39987 + } while (++count != 10);
39988 + }
39990 + XSync(dpy, True);
39991 + ret += !!_x_error_occurred;
39993 + return ret;
39994 +}
39996 +static int test_wrap_msc(Display *dpy)
39997 +{
39998 + xcb_connection_t *c = XGetXCBConnection(dpy);
39999 + Window root, win;
40000 + int x, y;
40001 + unsigned int width, height;
40002 + unsigned border, depth;
40003 + XSetWindowAttributes attr;
40004 + int ret = 0, n;
40005 + uint64_t msc, ust;
40006 + int complete;
40007 + uint64_t interval;
40008 + void *Q;
40010 + XGetGeometry(dpy, DefaultRootWindow(dpy),
40011 + &root, &x, &y, &width, &height, &border, &depth);
40013 + attr.override_redirect = 1;
40014 + win = XCreateWindow(dpy, root,
40015 + 0, 0, width, height, 0, depth,
40016 + InputOutput, DefaultVisual(dpy, DefaultScreen(dpy)),
40017 + CWOverrideRedirect, &attr);
40018 + XMapWindow(dpy, win);
40019 + XSync(dpy, True);
40020 + if (_x_error_occurred)
40021 + return 1;
40023 - if (msc < last_msc) {
40024 - printf("Invalid MSC: was %llu, now %llu\n",
40025 - (long long)last_msc, (long long)msc);
40026 + printf("Testing wraparound notifies\n");
40027 + _x_error_occurred = 0;
40029 + Q = setup_msc(dpy, win);
40030 + interval = msc_interval(dpy, win, Q);
40031 + if (interval == 0) {
40032 + printf("Zero delay between frames\n");
40033 + return 1;
40035 + msc = check_msc(dpy, win, Q, 0, &ust);
40036 + printf("Initial msc=%llx, interval between frames %lldus\n",
40037 + (long long)msc, (long long)interval);
40039 + for (n = 1; n <= 10; n++)
40040 + xcb_present_notify_msc(c, win, n,
40041 + msc + ((long long)n<<32) + n,
40042 + 0, 0);
40043 + for (n = 1; n <= 10; n++)
40044 + xcb_present_notify_msc(c, win, -n,
40045 + 0, (long long)n << 32, 0);
40046 + xcb_present_notify_msc(c, win, 0xdeadbeef, msc + 60*10, 0, 0);
40047 + xcb_flush(c);
40049 - return msc;
40050 + complete = 0;
40051 + do {
40052 + xcb_present_complete_notify_event_t *ce;
40053 + xcb_generic_event_t *ev;
40055 + ev = xcb_wait_for_special_event(c, Q);
40056 + if (ev == NULL)
40057 + break;
40059 + ce = (xcb_present_complete_notify_event_t *)ev;
40060 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
40062 + if (ce->serial == 0xdeadbeef) {
40063 + complete = 1;
40064 + } else {
40065 + fprintf(stderr,
40066 + "\tnotify %d recieved at +%llu\n",
40067 + ce->serial, ce->msc - msc);
40068 + ret++;
40069 + }
40070 + free(ev);
40071 + } while (!complete);
40073 + teardown_msc(dpy, Q);
40074 + XDestroyWindow(dpy, win);
40075 + XSync(dpy, True);
40077 + return ret;
40080 -static void teardown_msc(Display *dpy, void *q)
40081 +static int test_exhaustion_msc(Display *dpy, void *Q)
40083 - xcb_unregister_for_special_event(XGetXCBConnection(dpy), q);
40084 +#define N_VBLANKS 256 /* kernel event queue length: 128 vblanks */
40085 + xcb_connection_t *c = XGetXCBConnection(dpy);
40086 + Window root = DefaultRootWindow(dpy);
40087 + int ret = 0, n, complete;
40088 + int earliest = 0, early = 0;
40089 + int latest = 0, late = 0;
40090 + uint64_t msc;
40092 + printf("Testing notifies with long queues\n");
40093 + _x_error_occurred = 0;
40095 + msc = check_msc(dpy, root, Q, 0, NULL);
40096 + for (n = N_VBLANKS; n--; )
40097 + xcb_present_notify_msc(c, root, N_VBLANKS, msc + N_VBLANKS, 0, 0);
40098 + for (n = 1; n <= N_VBLANKS ; n++)
40099 + xcb_present_notify_msc(c, root, n, msc + n, 0, 0);
40100 + xcb_flush(c);
40102 + complete = 2*N_VBLANKS;
40103 + do {
40104 + xcb_present_complete_notify_event_t *ce;
40105 + xcb_generic_event_t *ev;
40106 + int diff;
40108 + ev = xcb_wait_for_special_event(c, Q);
40109 + if (ev == NULL)
40110 + break;
40112 + ce = (xcb_present_complete_notify_event_t *)ev;
40113 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
40115 + diff = (int64_t)(ce->msc - msc - ce->serial);
40116 + if (diff < 0) {
40117 + if (-diff > earliest) {
40118 + fprintf(stderr, "\tnotify %d early by %d msc\n",(int)ce->serial, -diff);
40119 + earliest = -diff;
40120 + }
40121 + early++;
40122 + ret++;
40123 + } else if (diff > 0) {
40124 + if (diff > latest) {
40125 + fprintf(stderr, "\tnotify %d late by %d msc\n", (int)ce->serial, diff);
40126 + latest = diff;
40127 + }
40128 + late++;
40129 + ret++;
40130 + }
40131 + free(ev);
40132 + } while (--complete);
40134 + if (early)
40135 + printf("\t%d notifies too early (worst %d)!\n", early, earliest);
40136 + if (late)
40137 + printf("\t%d notifies too late (worst %d)!\n", late, latest);
40139 + XSync(dpy, True);
40140 + ret += !!_x_error_occurred;
40142 + return ret;
40143 +#undef N_VBLANKS
40145 -static int test_whole(Display *dpy)
40147 +static int test_accuracy_msc(Display *dpy, void *Q)
40149 - Pixmap pixmap;
40150 - struct dri3_fence fence;
40151 - Window root;
40152 - unsigned int width, height;
40153 - unsigned border, depth;
40154 - int x, y, ret = 1;
40155 +#define N_VBLANKS (60 * 120) /* ~2 minutes */
40156 + xcb_connection_t *c = XGetXCBConnection(dpy);
40157 + Window root = DefaultRootWindow(dpy);
40158 + int ret = 0, n;
40159 + uint64_t msc;
40160 + int early = 0, late = 0;
40161 + int earliest = 0, latest = 0;
40162 + int complete, count;
40164 - XGetGeometry(dpy, DefaultRootWindow(dpy),
40165 - &root, &x, &y, &width, &height, &border, &depth);
40166 + printf("Testing notify accuracy\n");
40167 + _x_error_occurred = 0;
40169 - if (dri3_create_fence(dpy, root, &fence))
40170 - return 0;
40171 + msc = check_msc(dpy, root, Q, 0, NULL);
40172 + for (n = 0; n <= N_VBLANKS; n++)
40173 + xcb_present_notify_msc(c, root, n, msc + 60 + n, 0, 0);
40174 + xcb_present_notify_msc(c, root, 0xdeadbeef, msc + 60 + n, 0, 0);
40175 + xcb_flush(c);
40177 + complete = 0;
40178 + count = 0;
40179 + do {
40180 + xcb_present_complete_notify_event_t *ce;
40181 + xcb_generic_event_t *ev;
40183 + ev = xcb_wait_for_special_event(c, Q);
40184 + if (ev == NULL)
40185 + break;
40187 + ce = (xcb_present_complete_notify_event_t *)ev;
40188 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
40190 + if (ce->serial != 0xdeadbeef) {
40191 + int diff = (int64_t)(ce->msc - (msc + ce->serial + 60));
40192 + if (diff < 0) {
40193 + if (-diff > earliest) {
40194 + fprintf(stderr, "\tnotify %d early by %d msc\n", ce->serial, -diff);
40195 + earliest = -diff;
40196 + }
40197 + early++;
40198 + ret++;
40199 + } else if (diff > 0) {
40200 + if (diff > latest) {
40201 + fprintf(stderr, "\tnotify %d late by %d msc\n", ce->serial, diff);
40202 + latest = diff;
40203 + }
40204 + late++;
40205 + ret++;
40206 + }
40207 + count++;
40208 + } else
40209 + complete = 1;
40210 + free(ev);
40211 + } while (!complete);
40213 + if (early)
40214 + printf("\t%d notifies too early (worst %d)!\n", early, earliest);
40215 + if (late)
40216 + printf("\t%d notifies too late (worst %d)!\n", late, latest);
40218 + if (count != N_VBLANKS+1) {
40219 + fprintf(stderr, "Sentinel vblank received too early! %d waits outstanding\n", N_VBLANKS+1 - count);
40220 + ret++;
40221 + do {
40222 + xcb_present_complete_notify_event_t *ce;
40223 + xcb_generic_event_t *ev;
40225 + ev = xcb_wait_for_special_event(c, Q);
40226 + if (ev == NULL)
40227 + break;
40229 + ce = (xcb_present_complete_notify_event_t *)ev;
40230 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
40231 + free(ev);
40232 + } while (++count != N_VBLANKS+1);
40233 + }
40235 + XSync(dpy, True);
40236 + ret += !!_x_error_occurred;
40238 + return ret;
40239 +#undef N_VBLANKS
40240 +}
40242 - printf("Testing whole screen flip: %dx%d\n", width, height);
40243 +static int test_modulus_msc(Display *dpy, void *Q)
40244 +{
40245 + xcb_connection_t *c = XGetXCBConnection(dpy);
40246 + Window root = DefaultRootWindow(dpy);
40247 + xcb_present_complete_notify_event_t *ce;
40248 + xcb_generic_event_t *ev;
40249 + int x, y, ret = 0;
40250 + uint64_t target;
40251 + int early = 0, late = 0;
40252 + int earliest = 0, latest = 0;
40253 + int complete, count, expect;
40255 + printf("Testing notify modulus\n");
40256 _x_error_occurred = 0;
40258 - xshmfence_reset(fence.addr);
40259 + target = wait_vblank(dpy, root, Q);
40261 - pixmap = XCreatePixmap(dpy, root, width, height, depth);
40262 - xcb_present_pixmap(XGetXCBConnection(dpy),
40263 - root, pixmap,
40264 - 0, /* sbc */
40265 - 0, /* valid */
40266 - 0, /* update */
40267 - 0, /* x_off */
40268 - 0, /* y_off */
40269 - None,
40270 - None, /* wait fence */
40271 - fence.xid,
40272 - XCB_PRESENT_OPTION_NONE,
40273 - 0, /* target msc */
40274 - 0, /* divisor */
40275 - 0, /* remainder */
40276 - 0, NULL);
40277 - XFreePixmap(dpy, pixmap);
40278 + expect = 0;
40279 + xcb_present_notify_msc(c, root, 0, 0, 0, 0);
40280 + for (x = 1; x <= 19; x++) {
40281 + for (y = 0; y < x; y++) {
40282 + xcb_present_notify_msc(c, root, y << 16 | x, 0, x, y);
40283 + expect++;
40284 + }
40285 + }
40286 + xcb_present_notify_msc(c, root, 0xdeadbeef, target + 2*x, 0, 0);
40287 + xcb_flush(c);
40289 - pixmap = XCreatePixmap(dpy, root, width, height, depth);
40290 - xcb_present_pixmap(XGetXCBConnection(dpy),
40291 - root, pixmap,
40292 - 0, /* sbc */
40293 - 0, /* valid */
40294 - 0, /* update */
40295 - 0, /* x_off */
40296 - 0, /* y_off */
40297 - None,
40298 - None, /* wait fence */
40299 - None, /* sync fence */
40300 - XCB_PRESENT_OPTION_NONE,
40301 - 0, /* target msc */
40302 - 0, /* divisor */
40303 - 0, /* remainder */
40304 - 0, NULL);
40305 - XFreePixmap(dpy, pixmap);
40306 - XFlush(dpy);
40307 + ev = xcb_wait_for_special_event(c, Q);
40308 + if (ev) {
40309 + ce = (xcb_present_complete_notify_event_t *)ev;
40310 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
40311 + assert(ce->serial == 0);
40312 + assert(target == ce->msc);
40313 + target = ce->msc;
40314 + }
40316 - ret = !!xshmfence_await(fence.addr);
40317 - dri3_fence_free(dpy, &fence);
40318 + complete = 0;
40319 + count = 0;
40320 + do {
40321 + ev = xcb_wait_for_special_event(c, Q);
40322 + if (ev == NULL)
40323 + break;
40325 + ce = (xcb_present_complete_notify_event_t *)ev;
40326 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
40328 + assert(ce->serial);
40329 + if (ce->serial != 0xdeadbeef) {
40330 + uint64_t msc;
40331 + int diff;
40333 + x = ce->serial & 0xffff;
40334 + y = ce->serial >> 16;
40336 + msc = target;
40337 + msc -= target % x;
40338 + msc += y;
40339 + if (msc <= target)
40340 + msc += x;
40342 + diff = (int64_t)(ce->msc - msc);
40343 + if (diff < 0) {
40344 + if (-diff > earliest) {
40345 + fprintf(stderr, "\tnotify (%d, %d) early by %d msc (target %lld, reported %lld)\n", y, x, -diff, (long long)msc, (long long)ce->msc);
40346 + earliest = -diff;
40347 + }
40348 + early++;
40349 + ret++;
40350 + } else if (diff > 0) {
40351 + if (diff > latest) {
40352 + fprintf(stderr, "\tnotify (%d, %d) late by %d msc (target %lld, reported %lld)\n", y, x, diff, (long long)msc, (long long)ce->msc);
40353 + latest = diff;
40354 + }
40355 + late++;
40356 + ret++;
40357 + }
40358 + count++;
40359 + } else
40360 + complete = 1;
40361 + free(ev);
40362 + } while (!complete);
40364 + if (early)
40365 + printf("\t%d notifies too early (worst %d)!\n", early, earliest);
40366 + if (late)
40367 + printf("\t%d notifies too late (worst %d)!\n", late, latest);
40369 + if (count != expect) {
40370 + fprintf(stderr, "Sentinel vblank received too early! %d waits outstanding\n", expect - count);
40371 + ret++;
40372 + do {
40373 + ev = xcb_wait_for_special_event(c, Q);
40374 + if (ev == NULL)
40375 + break;
40377 + ce = (xcb_present_complete_notify_event_t *)ev;
40378 + assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC);
40379 + free(ev);
40380 + } while (++count != expect);
40381 + }
40383 XSync(dpy, True);
40384 ret += !!_x_error_occurred;
40385 @@ -279,8 +1471,6 @@ static int for_each_crtc(Display *dpy,
40386 for (i = 0; i < res->ncrtc; i++)
40387 original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]);
40389 - printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc);
40391 for (i = 0; i < res->noutput; i++) {
40392 XRROutputInfo *output;
40393 XRRModeInfo *mode;
40394 @@ -322,7 +1512,7 @@ static int for_each_crtc(Display *dpy,
40395 free(original_crtc);
40396 XRRFreeScreenResources(res);
40398 - return j;
40399 + return err;
40402 struct test_crtc {
40403 @@ -335,6 +1525,7 @@ struct test_crtc {
40404 uint64_t msc;
40405 };
40406 #define SYNC 0x1
40407 +#define FUTURE 0x2
40409 static int __test_crtc(Display *dpy, RRCrtc crtc,
40410 int width, int height,
40411 @@ -344,7 +1535,7 @@ static int __test_crtc(Display *dpy, RRCrtc crtc,
40412 Pixmap pixmap;
40413 int err = 0;
40415 - test->msc = check_msc(dpy, test->win, test->queue, test->msc);
40416 + test->msc = check_msc(dpy, test->win, test->queue, test->msc, NULL);
40418 if (test->flags & SYNC)
40419 xshmfence_reset(test->fence.addr);
40420 @@ -361,16 +1552,14 @@ static int __test_crtc(Display *dpy, RRCrtc crtc,
40421 None, /* wait fence */
40422 test->flags & SYNC ? test->fence.xid : None,
40423 XCB_PRESENT_OPTION_NONE,
40424 - 0, /* target msc */
40425 + test->msc, /* target msc */
40426 1, /* divisor */
40427 0, /* remainder */
40428 0, NULL);
40429 - XFreePixmap(dpy, pixmap);
40431 if (test->flags & SYNC) {
40432 - pixmap = XCreatePixmap(dpy, test->win, width, height, test->depth);
40433 + Pixmap tmp = XCreatePixmap(dpy, test->win, width, height, test->depth);
40434 xcb_present_pixmap(XGetXCBConnection(dpy),
40435 - test->win, pixmap,
40436 + test->win, tmp,
40437 1, /* sbc */
40438 0, /* valid */
40439 0, /* update */
40440 @@ -380,16 +1569,17 @@ static int __test_crtc(Display *dpy, RRCrtc crtc,
40441 None, /* wait fence */
40442 None, /* sync fence */
40443 XCB_PRESENT_OPTION_NONE,
40444 - 1, /* target msc */
40445 + test->msc + (test->flags & FUTURE ? 5 * 16 : 1), /* target msc */
40446 1, /* divisor */
40447 0, /* remainder */
40448 0, NULL);
40449 - XFreePixmap(dpy, pixmap);
40450 + XFreePixmap(dpy, tmp);
40451 XFlush(dpy);
40452 err += !!xshmfence_await(test->fence.addr);
40454 + XFreePixmap(dpy, pixmap);
40456 - test->msc = check_msc(dpy, test->win, test->queue, test->msc);
40457 + test->msc = check_msc(dpy, test->win, test->queue, test->msc, NULL);
40458 return err;
40461 @@ -410,15 +1600,23 @@ static int test_crtc(Display *dpy, void *queue, uint64_t last_msc)
40463 printf("Testing each crtc, without waiting for each flip\n");
40464 test.flags = 0;
40465 + test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
40466 err += for_each_crtc(dpy, __test_crtc, &test);
40467 + test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
40469 printf("Testing each crtc, waiting for flips to complete\n");
40470 test.flags = SYNC;
40471 + test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
40472 err += for_each_crtc(dpy, __test_crtc, &test);
40473 + test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
40475 - test.msc = check_msc(dpy, test.win, test.queue, test.msc);
40476 - dri3_fence_free(dpy, &test.fence);
40477 + printf("Testing each crtc, with future flips\n");
40478 + test.flags = FUTURE | SYNC;
40479 + test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
40480 + err += for_each_crtc(dpy, __test_crtc, &test);
40481 + test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL);
40483 + dri3_fence_free(dpy, &test.fence);
40484 XSync(dpy, True);
40485 err += !!_x_error_occurred;
40487 @@ -536,6 +1734,31 @@ static int gem_set_caching(int fd, uint32_t handle, int caching)
40488 return drmIoctl(fd, LOCAL_IOCTL_I915_GEM_SET_CACHING, &arg) == 0;
40491 +static int gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
40492 +{
40493 + struct drm_i915_gem_set_tiling set_tiling;
40494 + int err;
40496 +restart:
40497 + set_tiling.handle = handle;
40498 + set_tiling.tiling_mode = tiling;
40499 + set_tiling.stride = stride;
40501 + if (drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0)
40502 + return 1;
40504 + err = errno;
40505 + if (err == EINTR)
40506 + goto restart;
40508 + if (err == EAGAIN) {
40509 + sched_yield();
40510 + goto restart;
40511 + }
40513 + return 0;
40514 +}
40516 static int gem_export(int fd, uint32_t handle)
40518 struct drm_prime_handle args;
40519 @@ -557,6 +1780,126 @@ static void gem_close(int fd, uint32_t handle)
40520 (void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close);
40523 +static int test_dri3_tiling(Display *dpy)
40524 +{
40525 + Window win = DefaultRootWindow(dpy);
40526 + const int tiling[] = { I915_TILING_NONE, I915_TILING_X, I915_TILING_Y };
40527 + Window root;
40528 + unsigned int width, height;
40529 + unsigned border, depth, bpp;
40530 + unsigned stride, size;
40531 + void *Q;
40532 + int x, y;
40533 + int device;
40534 + int line = -1;
40535 + int t;
40537 + device = dri3_open(dpy);
40538 + if (device < 0)
40539 + return 0;
40541 + if (!is_intel(device))
40542 + return 0;
40544 + printf("Opened Intel DRI3 device\n");
40546 + XGetGeometry(dpy, win, &root, &x, &y,
40547 + &width, &height, &border, &depth);
40549 + switch (depth) {
40550 + case 8: bpp = 8; break;
40551 + case 15: case 16: bpp = 16; break;
40552 + case 24: case 32: bpp = 32; break;
40553 + default: return 0;
40554 + }
40556 + stride = ALIGN(width * bpp/8, 512);
40557 + size = PAGE_ALIGN(stride * ALIGN(height, 32));
40558 + printf("Creating DRI3 %dx%d (source stride=%d, size=%d) for GTT\n",
40559 + width, height, stride, size);
40561 + _x_error_occurred = 0;
40562 + Q = setup_msc(dpy, root);
40564 + for (t = 0; t < sizeof(tiling)/sizeof(tiling[0]); t++) {
40565 + uint64_t msc;
40566 + uint32_t src;
40567 + int src_fd;
40568 + Pixmap src_pix;
40570 + src = gem_create(device, size);
40571 + if (!src) {
40572 + line = __LINE__;
40573 + goto fail;
40574 + }
40576 + gem_set_tiling(device, src, tiling[t], stride);
40578 + src_fd = gem_export(device, src);
40579 + if (src_fd < 0) {
40580 + line = __LINE__;
40581 + goto fail;
40582 + }
40584 + src_pix = dri3_create_pixmap(dpy, root,
40585 + width, height, depth,
40586 + src_fd, bpp, stride, size);
40588 + msc = wait_vblank(dpy, root, Q);
40590 + xcb_present_pixmap(XGetXCBConnection(dpy),
40591 + win, src_pix,
40592 + 0, /* sbc */
40593 + 0, /* valid */
40594 + 0, /* update */
40595 + 0, /* x_off */
40596 + 0, /* y_off */
40597 + None,
40598 + None, /* wait fence */
40599 + None,
40600 + XCB_PRESENT_OPTION_NONE,
40601 + msc + 2, /* target msc */
40602 + 1, /* divisor */
40603 + 0, /* remainder */
40604 + 0, NULL);
40606 + xcb_present_pixmap(XGetXCBConnection(dpy),
40607 + win, src_pix,
40608 + 0, /* sbc */
40609 + 0, /* valid */
40610 + 0, /* update */
40611 + 0, /* x_off */
40612 + 0, /* y_off */
40613 + None,
40614 + None, /* wait fence */
40615 + None,
40616 + XCB_PRESENT_OPTION_NONE,
40617 + msc + 3, /* target msc */
40618 + 1, /* divisor */
40619 + 0, /* remainder */
40620 + 0, NULL);
40622 + XSync(dpy, True);
40623 + if (_x_error_occurred) {
40624 + line = __LINE__;
40625 + goto fail;
40626 + }
40627 + XFreePixmap(dpy, src_pix);
40628 + _x_error_occurred = 0;
40630 + close(src_fd);
40631 + gem_close(device, src);
40632 + }
40634 + teardown_msc(dpy, Q);
40635 + return 0;
40637 +fail:
40638 + printf("%s failed with tiling %d, line %d\n", __func__, tiling[t], line);
40639 + teardown_msc(dpy, Q);
40640 + return 1;
40641 +}
40643 static int test_dri3(Display *dpy)
40645 Window win = DefaultRootWindow(dpy);
40646 @@ -670,8 +2013,32 @@ fail:
40647 static int has_present(Display *dpy)
40649 xcb_connection_t *c = XGetXCBConnection(dpy);
40650 - xcb_present_query_version_reply_t *reply;
40651 xcb_generic_error_t *error = NULL;
40652 + void *reply;
40654 + reply = xcb_xfixes_query_version_reply(c,
40655 + xcb_xfixes_query_version(c,
40656 + XCB_XFIXES_MAJOR_VERSION,
40657 + XCB_XFIXES_MINOR_VERSION),
40658 + &error);
40659 + free(reply);
40660 + free(error);
40661 + if (reply == NULL) {
40662 + fprintf(stderr, "XFixes not supported on %s\n", DisplayString(dpy));
40663 + return 0;
40664 + }
40666 + reply = xcb_dri3_query_version_reply(c,
40667 + xcb_dri3_query_version(c,
40668 + XCB_DRI3_MAJOR_VERSION,
40669 + XCB_DRI3_MINOR_VERSION),
40670 + &error);
40671 + free(reply);
40672 + free(error);
40673 + if (reply == NULL) {
40674 + fprintf(stderr, "DRI3 not supported on %s\n", DisplayString(dpy));
40675 + return 0;
40676 + }
40678 reply = xcb_present_query_version_reply(c,
40679 xcb_present_query_version(c,
40680 @@ -681,14 +2048,32 @@ static int has_present(Display *dpy)
40682 free(reply);
40683 free(error);
40684 + if (reply == NULL) {
40685 + fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy));
40686 + return 0;
40687 + }
40689 + return 1;
40690 +}
40692 +static int has_composite(Display *dpy)
40693 +{
40694 + int event, error;
40695 + int major, minor;
40697 + if (!XCompositeQueryExtension(dpy, &event, &error))
40698 + return 0;
40700 + XCompositeQueryVersion(dpy, &major, &minor);
40702 - return reply != NULL;
40703 + return major > 0 || minor >= 4;
40706 int main(void)
40708 Display *dpy;
40709 Window root;
40710 + int dummy;
40711 int error = 0;
40712 uint64_t last_msc;
40713 void *queue;
40714 @@ -700,27 +2085,135 @@ int main(void)
40715 if (!has_present(dpy))
40716 return 77;
40718 + if (DPMSQueryExtension(dpy, &dummy, &dummy))
40719 + DPMSDisable(dpy);
40721 root = DefaultRootWindow(dpy);
40723 signal(SIGALRM, SIG_IGN);
40724 XSetErrorHandler(_check_error_handler);
40726 queue = setup_msc(dpy, root);
40727 - last_msc = check_msc(dpy, root, queue, 0);
40728 + last_msc = check_msc(dpy, root, queue, 0, NULL);
40730 + error += test_future_msc(dpy, queue);
40731 + last_msc = check_msc(dpy, root, queue, last_msc, NULL);
40733 + error += test_wrap_msc(dpy);
40734 + last_msc = check_msc(dpy, root, queue, last_msc, NULL);
40736 + error += test_accuracy_msc(dpy, queue);
40737 + last_msc = check_msc(dpy, root, queue, last_msc, NULL);
40739 + error += test_modulus_msc(dpy, queue);
40740 + last_msc = check_msc(dpy, root, queue, last_msc, NULL);
40742 + error += test_exhaustion_msc(dpy, queue);
40743 + last_msc = check_msc(dpy, root, queue, last_msc, NULL);
40745 + for (dummy = 0; dummy <= 3; dummy++) {
40746 + Window win;
40747 + uint64_t msc = 0;
40748 + XSetWindowAttributes attr;
40749 + Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy));
40750 + unsigned int width, height;
40751 + unsigned border, depth;
40752 + const char *phase;
40753 + int x, y;
40754 + void *Q;
40756 + attr.override_redirect = 1;
40758 + XGetGeometry(dpy, root, &win, &x, &y,
40759 + &width, &height, &border, &depth);
40761 + _x_error_occurred = 0;
40762 + switch (dummy) {
40763 + case 0:
40764 + win = root;
40765 + phase = "root";
40766 + break;
40767 + case 1:
40768 + win = XCreateWindow(dpy, root,
40769 + 0, 0, width, height, 0, depth,
40770 + InputOutput, visual,
40771 + CWOverrideRedirect, &attr);
40772 + phase = "fullscreen";
40773 + break;
40774 + case 2:
40775 + win = XCreateWindow(dpy, root,
40776 + 0, 0, width/2, height/2, 0, depth,
40777 + InputOutput, visual,
40778 + CWOverrideRedirect, &attr);
40779 + phase = "window";
40780 + break;
40781 + case 3:
40782 + if (!has_composite(dpy))
40783 + continue;
40785 + win = XCreateWindow(dpy, root,
40786 + 0, 0, width, height, 0,
40787 + DefaultDepth(dpy, DefaultScreen(dpy)),
40788 + InputOutput,
40789 + DefaultVisual(dpy, DefaultScreen(dpy)),
40790 + CWOverrideRedirect, &attr);
40791 + XCompositeRedirectWindow(dpy, win, CompositeRedirectManual);
40792 + phase = "composite";
40793 + break;
40795 + default:
40796 + phase = "broken";
40797 + win = root;
40798 + abort();
40799 + break;
40800 + }
40802 + XMapWindow(dpy, win);
40803 + XSync(dpy, True);
40804 + if (_x_error_occurred)
40805 + continue;
40807 + Q = setup_msc(dpy, win);
40808 + msc = check_msc(dpy, win, Q, msc, NULL);
40810 - error += test_whole(dpy);
40811 - last_msc = check_msc(dpy, root, queue, last_msc);
40812 + error += test_whole(dpy, win, phase);
40813 + msc = check_msc(dpy, win, Q, msc, NULL);
40815 + error += test_double(dpy, win, phase, Q);
40816 + msc = check_msc(dpy, win, Q, msc, NULL);
40818 + error += test_future(dpy, win, phase, Q);
40819 + msc = check_msc(dpy, win, Q, msc, NULL);
40821 + error += test_accuracy(dpy, win, phase, Q);
40822 + msc = check_msc(dpy, win, Q, msc, NULL);
40824 + error += test_modulus(dpy, win, phase, Q);
40825 + msc = check_msc(dpy, win, Q, msc, NULL);
40827 + error += test_exhaustion(dpy, win, phase, Q);
40828 + msc = check_msc(dpy, win, Q, msc, NULL);
40830 + teardown_msc(dpy, Q);
40831 + if (win != root)
40832 + XDestroyWindow(dpy, win);
40833 + }
40835 error += test_crtc(dpy, queue, last_msc);
40836 - last_msc = check_msc(dpy, root, queue, last_msc);
40837 + last_msc = check_msc(dpy, root, queue, last_msc, NULL);
40839 error += test_shm(dpy);
40840 - last_msc = check_msc(dpy, root, queue, last_msc);
40841 + last_msc = check_msc(dpy, root, queue, last_msc, NULL);
40843 error += test_dri3(dpy);
40844 - last_msc = check_msc(dpy, root, queue, last_msc);
40845 + last_msc = check_msc(dpy, root, queue, last_msc, NULL);
40847 + error += test_dri3_tiling(dpy);
40848 + last_msc = check_msc(dpy, root, queue, last_msc, NULL);
40850 teardown_msc(dpy, queue);
40852 + if (DPMSQueryExtension(dpy, &dummy, &dummy))
40853 + DPMSEnable(dpy);
40854 return !!error;
40856 diff --git a/test/render-glyphs.c b/test/render-glyphs.c
40857 new file mode 100644
40858 index 00000000..8822e36a
40859 --- /dev/null
40860 +++ b/test/render-glyphs.c
40861 @@ -0,0 +1,441 @@
40862 +#include <stdint.h>
40863 +#include <stdio.h>
40864 +#include <stdlib.h>
40865 +#include <stdbool.h>
40866 +#include <stdarg.h>
40867 +#include <string.h>
40869 +#include <X11/Xutil.h> /* for XDestroyImage */
40870 +#include <pixman.h> /* for pixman blt functions */
40872 +#include "test.h"
40874 +static const XRenderColor colors[] = {
40875 + /* red, green, blue, alpha */
40876 + { 0 },
40877 + { 0, 0, 0, 0xffff },
40878 + { 0xffff, 0, 0, 0xffff },
40879 + { 0, 0xffff, 0, 0xffff },
40880 + { 0, 0, 0xffff, 0xffff },
40881 + { 0xffff, 0xffff, 0xffff, 0xffff },
40882 +};
40884 +static struct clip {
40885 + void *func;
40886 +} clips[] = {
40887 + { NULL },
40888 +};
40890 +static int _x_error_occurred;
40892 +static int
40893 +_check_error_handler(Display *display,
40894 + XErrorEvent *event)
40895 +{
40896 + _x_error_occurred = 1;
40897 + return False; /* ignored */
40898 +}
40900 +static void clear(struct test_display *dpy,
40901 + struct test_target *tt,
40902 + const XRenderColor *c)
40903 +{
40904 + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, c,
40905 + 0, 0, tt->width, tt->height);
40906 +}
40908 +static bool check_op(struct test_display *dpy, int op, struct test_target *tt)
40909 +{
40910 + XRenderColor render_color = {0};
40912 + XSync(dpy->dpy, True);
40913 + _x_error_occurred = 0;
40915 + XRenderFillRectangle(dpy->dpy, op,
40916 + tt->picture, &render_color,
40917 + 0, 0, 0, 0);
40919 + XSync(dpy->dpy, True);
40920 + return _x_error_occurred == 0;
40921 +}
40923 +struct glyph_iter {
40924 + enum {
40925 + GLYPHS, OP, DST, SRC, MASK, CLIP,
40926 + } stage;
40928 + int glyph_format;
40929 + int op;
40930 + int dst_color;
40931 + int src_color;
40932 + int mask_format;
40933 + int clip;
40935 + struct {
40936 + struct test_display *dpy;
40937 + struct test_target tt;
40938 + GlyphSet glyphset;
40939 + Picture src;
40940 + XRenderPictFormat *mask_format;
40941 + } ref, out;
40942 +};
40944 +static void glyph_iter_init(struct glyph_iter *gi,
40945 + struct test *t, enum target target)
40946 +{
40947 + memset(gi, 0, sizeof(*gi));
40949 + gi->out.dpy = &t->out;
40950 + test_target_create_render(&t->out, target, &gi->out.tt);
40952 + gi->ref.dpy = &t->ref;
40953 + test_target_create_render(&t->ref, target, &gi->ref.tt);
40955 + gi->stage = GLYPHS;
40956 + gi->glyph_format = -1;
40957 + gi->op = -1;
40958 + gi->dst_color = -1;
40959 + gi->src_color = -1;
40960 + gi->mask_format = -1;
40961 + gi->clip = -1;
40962 +}
40964 +static void render_clear(char *image, int image_size, int bpp)
40965 +{
40966 + memset(image, 0, image_size);
40967 +}
40969 +static void render_black(char *image, int image_size, int bpp)
40970 +{
40971 + if (bpp == 4) {
40972 + uint32_t *p = (uint32_t *)image;
40973 + image_size /= 4;
40974 + while (image_size--)
40975 + *p++ = 0x000000ff;
40976 + } else
40977 + memset(image, 0x55, image_size);
40978 +}
40980 +static void render_green(char *image, int image_size, int bpp)
40981 +{
40982 + if (bpp == 4) {
40983 + uint32_t *p = (uint32_t *)image;
40984 + image_size /= 4;
40985 + while (image_size--)
40986 + *p++ = 0xffff0000;
40987 + } else
40988 + memset(image, 0xaa, image_size);
40989 +}
40991 +static void render_white(char *image, int image_size, int bpp)
40992 +{
40993 + memset(image, 0xff, image_size);
40994 +}
40996 +static GlyphSet create_glyphs(Display *dpy, int format_id)
40997 +{
40998 +#define N_GLYPHS 4
40999 + XRenderPictFormat *format;
41000 + XGlyphInfo glyph = { 8, 8, 0, 0, 8, 0 };
41001 + char image[4*8*8];
41002 + GlyphSet glyphset;
41003 + Glyph gid;
41004 + int image_size;
41005 + int bpp;
41006 + int n;
41008 + format = XRenderFindStandardFormat(dpy, format_id);
41009 + if (format == NULL)
41010 + return 0;
41012 + switch (format_id) {
41013 + case PictStandardARGB32:
41014 + case PictStandardRGB24:
41015 + image_size = 4 * 8 * 8;
41016 + bpp = 4;
41017 + break;
41018 + case PictStandardA8:
41019 + case PictStandardA4:
41020 + image_size = 8 * 8;
41021 + bpp = 1;
41022 + break;
41023 + case PictStandardA1:
41024 + image_size = 8;
41025 + bpp = 0;
41026 + break;
41027 + default:
41028 + return 0;
41029 + }
41031 + glyphset = XRenderCreateGlyphSet(dpy, format);
41032 + for (n = 0; n < N_GLYPHS; n++) {
41033 + gid = n;
41035 + switch (n) {
41036 + case 0: render_clear(image, image_size, bpp); break;
41037 + case 1: render_black(image, image_size, bpp); break;
41038 + case 2: render_green(image, image_size, bpp); break;
41039 + case 3: render_white(image, image_size, bpp); break;
41040 + }
41042 + XRenderAddGlyphs(dpy, glyphset,
41043 + &gid, &glyph, 1, image, image_size);
41044 + }
41046 + return glyphset;
41047 +}
41049 +static const char *glyph_name(int n)
41050 +{
41051 + switch (n) {
41052 + case 0: return "clear";
41053 + case 1: return "black";
41054 + case 2: return "green";
41055 + case 3: return "white";
41056 + default: return "unknown";
41057 + }
41058 +}
41060 +static bool glyph_iter_next(struct glyph_iter *gi)
41061 +{
41062 +restart:
41063 + if (gi->stage == GLYPHS) {
41064 + if (++gi->glyph_format == PictStandardNUM)
41065 + return false;
41067 + if (gi->out.glyphset)
41068 + XRenderFreeGlyphSet(gi->out.dpy->dpy,
41069 + gi->out.glyphset);
41070 + gi->out.glyphset = create_glyphs(gi->out.dpy->dpy,
41071 + gi->glyph_format);
41073 + if (gi->ref.glyphset)
41074 + XRenderFreeGlyphSet(gi->ref.dpy->dpy,
41075 + gi->ref.glyphset);
41076 + gi->ref.glyphset = create_glyphs(gi->ref.dpy->dpy,
41077 + gi->glyph_format);
41079 + gi->stage++;
41080 + }
41082 + if (gi->stage == OP) {
41083 + do {
41084 + if (++gi->op == 255)
41085 + goto reset_op;
41086 + } while (!check_op(gi->out.dpy, gi->op, &gi->out.tt) ||
41087 + !check_op(gi->ref.dpy, gi->op, &gi->ref.tt));
41089 + gi->stage++;
41090 + }
41092 + if (gi->stage == DST) {
41093 + if (++gi->dst_color == ARRAY_SIZE(colors))
41094 + goto reset_dst;
41096 + gi->stage++;
41097 + }
41099 + if (gi->stage == SRC) {
41100 + if (++gi->src_color == ARRAY_SIZE(colors))
41101 + goto reset_src;
41103 + if (gi->ref.src)
41104 + XRenderFreePicture(gi->ref.dpy->dpy, gi->ref.src);
41105 + gi->ref.src = XRenderCreateSolidFill(gi->ref.dpy->dpy,
41106 + &colors[gi->src_color]);
41108 + if (gi->out.src)
41109 + XRenderFreePicture(gi->out.dpy->dpy, gi->out.src);
41110 + gi->out.src = XRenderCreateSolidFill(gi->out.dpy->dpy,
41111 + &colors[gi->src_color]);
41113 + gi->stage++;
41114 + }
41116 + if (gi->stage == MASK) {
41117 + if (++gi->mask_format > PictStandardNUM)
41118 + goto reset_mask;
41120 + if (gi->mask_format == PictStandardRGB24)
41121 + gi->mask_format++;
41123 + if (gi->mask_format < PictStandardNUM) {
41124 + gi->out.mask_format = XRenderFindStandardFormat(gi->out.dpy->dpy,
41125 + gi->mask_format);
41126 + gi->ref.mask_format = XRenderFindStandardFormat(gi->ref.dpy->dpy,
41127 + gi->mask_format);
41128 + } else {
41129 + gi->out.mask_format = NULL;
41130 + gi->ref.mask_format = NULL;
41131 + }
41133 + gi->stage++;
41134 + }
41136 + if (gi->stage == CLIP) {
41137 + if (++gi->clip == ARRAY_SIZE(clips))
41138 + goto reset_clip;
41140 + gi->stage++;
41141 + }
41143 + gi->stage--;
41144 + return true;
41146 +reset_op:
41147 + gi->op = -1;
41148 +reset_dst:
41149 + gi->dst_color = -1;
41150 +reset_src:
41151 + gi->src_color = -1;
41152 +reset_mask:
41153 + gi->mask_format = -1;
41154 +reset_clip:
41155 + gi->clip = -1;
41156 + gi->stage--;
41157 + goto restart;
41158 +}
41160 +static void glyph_iter_fini(struct glyph_iter *gi)
41161 +{
41162 + if (gi->out.glyphset)
41163 + XRenderFreeGlyphSet (gi->out.dpy->dpy, gi->out.glyphset);
41164 + if (gi->ref.glyphset)
41165 + XRenderFreeGlyphSet (gi->ref.dpy->dpy, gi->ref.glyphset);
41167 + test_target_destroy_render(gi->out.dpy, &gi->out.tt);
41168 + test_target_destroy_render(gi->ref.dpy, &gi->ref.tt);
41169 +}
41171 +static const char *stdformat_to_str(int id)
41172 +{
41173 + switch (id) {
41174 + case PictStandardARGB32: return "ARGB32";
41175 + case PictStandardRGB24: return "RGB24";
41176 + case PictStandardA8: return "A8";
41177 + case PictStandardA4: return "A4";
41178 + case PictStandardA1: return "A1";
41179 + default: return "none";
41180 + }
41181 +}
41183 +static char *glyph_iter_to_string(struct glyph_iter *gi,
41184 + const char *format,
41185 + ...)
41186 +{
41187 + static char buf[100];
41188 + va_list ap;
41189 + int len;
41191 + len = sprintf(buf, "glyphs=%s, op=%d, dst=%08x, src=%08x, mask=%s",
41192 + stdformat_to_str(gi->glyph_format), gi->op,
41193 + xrender_color(&colors[gi->dst_color]),
41194 + xrender_color(&colors[gi->src_color]),
41195 + stdformat_to_str(gi->mask_format));
41197 + if (format) {
41198 + buf[len++] = ' ';
41199 + va_start(ap, format);
41200 + vsprintf(buf+len, format, ap);
41201 + va_end(ap);
41202 + }
41204 + return buf;
41205 +}
41207 +static void single(struct test *t, enum target target)
41208 +{
41209 + struct glyph_iter gi;
41210 + int n;
41212 + printf("Testing single glyph (%s): ", test_target_name(target));
41213 + fflush(stdout);
41215 + glyph_iter_init(&gi, t, target);
41216 + while (glyph_iter_next(&gi)) {
41217 + XGlyphElt8 elt;
41218 + char id[N_GLYPHS];
41220 + for (n = 0; n < N_GLYPHS; n++) {
41221 + id[n] = n;
41223 + elt.chars = &id[n];
41224 + elt.nchars = 1;
41225 + elt.xOff = 0;
41226 + elt.yOff = 0;
41228 + clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]);
41229 + elt.glyphset = gi.out.glyphset;
41230 + XRenderCompositeText8 (gi.out.dpy->dpy, gi.op,
41231 + gi.out.src,
41232 + gi.out.tt.picture,
41233 + gi.out.mask_format,
41234 + 0, 0,
41235 + 0, 8,
41236 + &elt, 1);
41238 + clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]);
41239 + elt.glyphset = gi.ref.glyphset;
41240 + XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op,
41241 + gi.ref.src,
41242 + gi.ref.tt.picture,
41243 + gi.ref.mask_format,
41244 + 0, 0,
41245 + 0, 8,
41246 + &elt, 1);
41247 + test_compare(t,
41248 + gi.out.tt.draw, gi.out.tt.format,
41249 + gi.ref.tt.draw, gi.ref.tt.format,
41250 + 0, 0, gi.out.tt.width, gi.out.tt.height,
41251 + glyph_iter_to_string(&gi,
41252 + "glyph=%s",
41253 + glyph_name(n)));
41254 + }
41256 + elt.chars = &id[0];
41257 + elt.nchars = n;
41258 + clear(gi.out.dpy, &gi.out.tt, &colors[gi.dst_color]);
41259 + elt.glyphset = gi.out.glyphset;
41260 + XRenderCompositeText8 (gi.out.dpy->dpy, gi.op,
41261 + gi.out.src,
41262 + gi.out.tt.picture,
41263 + gi.out.mask_format,
41264 + 0, 0,
41265 + 0, 8,
41266 + &elt, 1);
41268 + clear(gi.ref.dpy, &gi.ref.tt, &colors[gi.dst_color]);
41269 + elt.glyphset = gi.ref.glyphset;
41270 + XRenderCompositeText8 (gi.ref.dpy->dpy, gi.op,
41271 + gi.ref.src,
41272 + gi.ref.tt.picture,
41273 + gi.ref.mask_format,
41274 + 0, 0,
41275 + 0, 8,
41276 + &elt, 1);
41277 + test_compare(t,
41278 + gi.out.tt.draw, gi.out.tt.format,
41279 + gi.ref.tt.draw, gi.ref.tt.format,
41280 + 0, 0, gi.out.tt.width, gi.out.tt.height,
41281 + glyph_iter_to_string(&gi, "all"));
41282 + }
41283 + glyph_iter_fini(&gi);
41284 +}
41286 +int main(int argc, char **argv)
41287 +{
41288 + struct test test;
41289 + int t;
41291 + test_init(&test, argc, argv);
41292 + XSetErrorHandler(_check_error_handler);
41294 + for (t = TARGET_FIRST; t <= TARGET_LAST; t++) {
41295 + single(&test, t);
41296 + //overlapping(&test, t);
41297 + //gap(&test, t);
41298 + //mixed(&test, t);
41299 + }
41301 + return 0;
41302 +}
41303 diff --git a/test/render-trapezoid.c b/test/render-trapezoid.c
41304 index cd990143..f15a78e3 100644
41305 --- a/test/render-trapezoid.c
41306 +++ b/test/render-trapezoid.c
41307 @@ -403,16 +403,141 @@ static void trap_tests(struct test *t,
41308 free(traps);
41311 +enum edge {
41312 + EDGE_SHARP = PolyEdgeSharp,
41313 + EDGE_SMOOTH,
41314 +};
41316 +static const char *edge_name(enum edge edge)
41317 +{
41318 + switch (edge) {
41319 + default:
41320 + case EDGE_SHARP: return "sharp";
41321 + case EDGE_SMOOTH: return "smooth";
41322 + }
41323 +}
41325 +static void set_edge(Display *dpy, Picture p, enum edge edge)
41326 +{
41327 + XRenderPictureAttributes a;
41329 + a.poly_edge = edge;
41330 + XRenderChangePicture(dpy, p, CPPolyEdge, &a);
41331 +}
41333 +static void edge_test(struct test *t,
41334 + enum mask mask,
41335 + enum edge edge,
41336 + enum target target)
41337 +{
41338 + struct test_target out, ref;
41339 + XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
41340 + Picture src_ref, src_out;
41341 + XTrapezoid trap;
41342 + int left_or_right, p;
41344 + test_target_create_render(&t->out, target, &out);
41345 + set_edge(t->out.dpy, out.picture, edge);
41346 + src_out = XRenderCreateSolidFill(t->out.dpy, &white);
41348 + test_target_create_render(&t->ref, target, &ref);
41349 + set_edge(t->ref.dpy, ref.picture, edge);
41350 + src_ref = XRenderCreateSolidFill(t->ref.dpy, &white);
41352 + printf("Testing edges (with mask %s and %s edges) (%s): ",
41353 + mask_name(mask),
41354 + edge_name(edge),
41355 + test_target_name(target));
41356 + fflush(stdout);
41358 + for (left_or_right = 0; left_or_right <= 1; left_or_right++) {
41359 + for (p = -64; p <= out.width + 64; p++) {
41360 + char buf[80];
41362 + if (left_or_right) {
41363 + trap.left.p1.x = 0;
41364 + trap.left.p1.y = 0;
41365 + trap.left.p2.x = 0;
41366 + trap.left.p2.y = out.height << 16;
41368 + trap.right.p1.x = p << 16;
41369 + trap.right.p1.y = 0;
41370 + trap.right.p2.x = out.width << 16;
41371 + trap.right.p2.y = out.height << 16;
41372 + } else {
41373 + trap.right.p1.x = out.width << 16;
41374 + trap.right.p1.y = 0;
41375 + trap.right.p2.x = out.width << 16;
41376 + trap.right.p2.y = out.height << 16;
41378 + trap.left.p1.x = 0;
41379 + trap.left.p1.y = 0;
41380 + trap.left.p2.x = p << 16;
41381 + trap.left.p2.y = out.height << 16;
41382 + }
41384 + trap.top = 0;
41385 + trap.bottom = out.height << 16;
41387 + sprintf(buf,
41388 + "trap=((%d, %d), (%d, %d)), ((%d, %d), (%d, %d))\n",
41389 + trap.left.p1.x >> 16, trap.left.p1.y >> 16,
41390 + trap.left.p2.x >> 16, trap.left.p2.y >> 16,
41391 + trap.right.p1.x >> 16, trap.right.p1.y >> 16,
41392 + trap.right.p2.x >> 16, trap.right.p2.y >> 16);
41394 + clear(&t->out, &out);
41395 + XRenderCompositeTrapezoids(t->out.dpy,
41396 + PictOpSrc,
41397 + src_out,
41398 + out.picture,
41399 + mask_format(t->out.dpy, mask),
41400 + 0, 0,
41401 + &trap, 1);
41403 + clear(&t->ref, &ref);
41404 + XRenderCompositeTrapezoids(t->ref.dpy,
41405 + PictOpSrc,
41406 + src_ref,
41407 + ref.picture,
41408 + mask_format(t->ref.dpy, mask),
41409 + 0, 0,
41410 + &trap, 1);
41412 + test_compare(t,
41413 + out.draw, out.format,
41414 + ref.draw, ref.format,
41415 + 0, 0, out.width, out.height,
41416 + buf);
41417 + }
41418 + }
41420 + XRenderFreePicture(t->out.dpy, src_out);
41421 + test_target_destroy_render(&t->out, &out);
41423 + XRenderFreePicture(t->ref.dpy, src_ref);
41424 + test_target_destroy_render(&t->ref, &ref);
41426 + printf("pass\n");
41427 +}
41429 int main(int argc, char **argv)
41431 struct test test;
41432 int i, dx, dy;
41433 enum target target;
41434 enum mask mask;
41435 + enum edge edge;
41436 enum trapezoid trapezoid;
41438 test_init(&test, argc, argv);
41440 + for (target = TARGET_FIRST; target <= TARGET_LAST; target++) {
41441 + for (mask = MASK_NONE; mask <= MASK_A8; mask++)
41442 + for (edge = EDGE_SHARP; edge <= EDGE_SMOOTH; edge++)
41443 + edge_test(&test, mask, edge, target);
41444 + }
41446 for (i = 0; i <= DEFAULT_ITERATIONS; i++) {
41447 int reps = REPS(i), sets = SETS(i);
41449 diff --git a/test/render-triangle.c b/test/render-triangle.c
41450 new file mode 100644
41451 index 00000000..165834ce
41452 --- /dev/null
41453 +++ b/test/render-triangle.c
41454 @@ -0,0 +1,180 @@
41455 +#include <stdint.h>
41456 +#include <stdio.h>
41457 +#include <stdlib.h>
41459 +#include "test.h"
41461 +enum edge {
41462 + EDGE_SHARP = PolyEdgeSharp,
41463 + EDGE_SMOOTH,
41464 +};
41466 +static void set_edge(Display *dpy, Picture p, enum edge edge)
41467 +{
41468 + XRenderPictureAttributes a;
41470 + a.poly_edge = edge;
41471 + XRenderChangePicture(dpy, p, CPPolyEdge, &a);
41472 +}
41474 +static XRenderPictFormat *mask_format(Display *dpy, enum mask mask)
41475 +{
41476 + switch (mask) {
41477 + default:
41478 + case MASK_NONE: return NULL;
41479 + case MASK_A1: return XRenderFindStandardFormat(dpy, PictStandardA1);
41480 + case MASK_A8: return XRenderFindStandardFormat(dpy, PictStandardA8);
41481 + }
41482 +}
41484 +static const char *mask_name(enum mask mask)
41485 +{
41486 + switch (mask) {
41487 + default:
41488 + case MASK_NONE: return "none";
41489 + case MASK_A1: return "a1";
41490 + case MASK_A8: return "a8";
41491 + }
41492 +}
41494 +static const char *edge_name(enum edge edge)
41495 +{
41496 + switch (edge) {
41497 + default:
41498 + case EDGE_SHARP: return "sharp";
41499 + case EDGE_SMOOTH: return "smooth";
41500 + }
41501 +}
41503 +static void clear(struct test_display *dpy, struct test_target *tt)
41504 +{
41505 + XRenderColor render_color = {0};
41506 + XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color,
41507 + 0, 0, tt->width, tt->height);
41508 +}
41510 +static void step_to_point(int step, int width, int height, XPointFixed *p)
41511 +{
41512 + do {
41513 + p->x = (step - 64) << 16;
41514 + p->y = -64 << 16;
41516 + step -= width - 128;
41517 + if (step <= 0)
41518 + return;
41520 + p->x = (width + 64) << 16;
41521 + p->y = (step - 64) << 16;
41522 + step -= height - 128;
41524 + if (step <= 0)
41525 + return;
41527 + p->x = (width + 64 - step) << 16;
41528 + p->y = (height + 64) << 16;
41529 + step -= width - 128;
41531 + if (step <= 0)
41532 + return;
41534 + p->x = -64 << 16;
41535 + p->y = (height + 64 - step) << 16;
41536 + step -= height - 128;
41537 + } while (step > 0);
41538 +}
41540 +static void edge_test(struct test *t,
41541 + enum mask mask,
41542 + enum edge edge,
41543 + enum target target)
41544 +{
41545 + struct test_target out, ref;
41546 + XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
41547 + Picture src_ref, src_out;
41548 + XTriangle tri;
41549 + unsigned step, max;
41551 + test_target_create_render(&t->out, target, &out);
41552 + set_edge(t->out.dpy, out.picture, edge);
41553 + src_out = XRenderCreateSolidFill(t->out.dpy, &white);
41555 + test_target_create_render(&t->ref, target, &ref);
41556 + set_edge(t->ref.dpy, ref.picture, edge);
41557 + src_ref = XRenderCreateSolidFill(t->ref.dpy, &white);
41559 + printf("Testing edges (with mask %s and %s edges) (%s): ",
41560 + mask_name(mask),
41561 + edge_name(edge),
41562 + test_target_name(target));
41563 + fflush(stdout);
41565 + max = 2*(out.width + 128 + out.height+128);
41566 + step = 0;
41567 + for (step = 0; step <= max; step++) {
41568 + char buf[80];
41570 + step_to_point(step, out.width, out.height, &tri.p1);
41571 + step_to_point(step + out.width + 128,
41572 + out.width, out.height,
41573 + &tri.p2);
41574 + step_to_point(step + out.height + 128 + 2*(out.width + 128),
41575 + out.width, out.height,
41576 + &tri.p3);
41578 + sprintf(buf,
41579 + "tri=((%d, %d), (%d, %d), (%d, %d))\n",
41580 + tri.p1.x >> 16, tri.p1.y >> 16,
41581 + tri.p2.x >> 16, tri.p2.y >> 16,
41582 + tri.p3.x >> 16, tri.p3.y >> 16);
41584 + clear(&t->out, &out);
41585 + XRenderCompositeTriangles(t->out.dpy,
41586 + PictOpSrc,
41587 + src_out,
41588 + out.picture,
41589 + mask_format(t->out.dpy, mask),
41590 + 0, 0,
41591 + &tri, 1);
41593 + clear(&t->ref, &ref);
41594 + XRenderCompositeTriangles(t->ref.dpy,
41595 + PictOpSrc,
41596 + src_ref,
41597 + ref.picture,
41598 + mask_format(t->ref.dpy, mask),
41599 + 0, 0,
41600 + &tri, 1);
41602 + test_compare(t,
41603 + out.draw, out.format,
41604 + ref.draw, ref.format,
41605 + 0, 0, out.width, out.height,
41606 + buf);
41607 + }
41609 + XRenderFreePicture(t->out.dpy, src_out);
41610 + test_target_destroy_render(&t->out, &out);
41612 + XRenderFreePicture(t->ref.dpy, src_ref);
41613 + test_target_destroy_render(&t->ref, &ref);
41615 + printf("pass\n");
41616 +}
41618 +int main(int argc, char **argv)
41619 +{
41620 + struct test test;
41621 + enum target target;
41622 + enum mask mask;
41623 + enum edge edge;
41625 + test_init(&test, argc, argv);
41627 + for (target = TARGET_FIRST; target <= TARGET_LAST; target++) {
41628 + for (mask = MASK_NONE; mask <= MASK_A8; mask++)
41629 + for (edge = EDGE_SHARP; edge <= EDGE_SMOOTH; edge++)
41630 + edge_test(&test, mask, edge, target);
41631 + }
41633 + return 0;
41634 +}
41635 diff --git a/test/test.h b/test/test.h
41636 index a3ef979d..9eec1cf9 100644
41637 --- a/test/test.h
41638 +++ b/test/test.h
41639 @@ -107,6 +107,15 @@ static inline uint32_t color(uint8_t red, uint8_t green, uint8_t blue, uint8_t a
41640 return alpha << 24 | ra >> 8 << 16 | ga >> 8 << 8 | ba >> 8;
41643 +static inline uint32_t xrender_color(const XRenderColor *c)
41644 +{
41645 + uint32_t ra = c->red * c->alpha;
41646 + uint32_t ga = c->green * c->alpha;
41647 + uint32_t ba = c->blue * c->alpha;
41649 + return c->alpha >> 8 << 24 | ra >> 24 << 16 | ga >> 24 << 8 | ba >> 24;
41650 +}
41652 void test_timer_start(struct test_display *t, struct timespec *tv);
41653 double test_timer_stop(struct test_display *t, struct timespec *tv);
41655 diff --git a/test/test_image.c b/test/test_image.c
41656 index d15a8af8..1c076990 100644
41657 --- a/test/test_image.c
41658 +++ b/test/test_image.c
41659 @@ -197,13 +197,10 @@ void test_compare(struct test *t,
41660 const char *info)
41662 XImage out_image, ref_image;
41663 - Pixmap tmp;
41664 - char *out, *ref;
41665 + uint32_t *out, *ref;
41666 char buf[600];
41667 uint32_t mask;
41668 int i, j;
41669 - XGCValues gcv;
41670 - GC gc;
41672 if (w * h * 4 > t->out.max_shm_size)
41673 return test_compare_fallback(t,
41674 @@ -214,37 +211,24 @@ void test_compare(struct test *t,
41675 test_init_image(&out_image, &t->out.shm, out_format, w, h);
41676 test_init_image(&ref_image, &t->ref.shm, ref_format, w, h);
41678 - gcv.graphics_exposures = 0;
41680 die_unless(out_image.depth == ref_image.depth);
41681 die_unless(out_image.bits_per_pixel == ref_image.bits_per_pixel);
41682 die_unless(out_image.bits_per_pixel == 32);
41684 - mask = depth_mask(out_image.depth);
41685 + XShmGetImage(t->out.dpy, out_draw, &out_image, x, y, AllPlanes);
41686 + out = (uint32_t *)out_image.data;
41688 - tmp = XCreatePixmap(t->out.dpy, out_draw, w, h, out_image.depth);
41689 - gc = XCreateGC(t->out.dpy, tmp, GCGraphicsExposures, &gcv);
41690 - XCopyArea(t->out.dpy, out_draw, tmp, gc, x, y, w, h, 0, 0);
41691 - XShmGetImage(t->out.dpy, tmp, &out_image, 0, 0, AllPlanes);
41692 - XFreeGC(t->out.dpy, gc);
41693 - XFreePixmap(t->out.dpy, tmp);
41694 - out = out_image.data;
41696 - tmp = XCreatePixmap(t->ref.dpy, ref_draw, w, h, ref_image.depth);
41697 - gc = XCreateGC(t->ref.dpy, tmp, GCGraphicsExposures, &gcv);
41698 - XCopyArea(t->ref.dpy, ref_draw, tmp, gc, x, y, w, h, 0, 0);
41699 - XShmGetImage(t->ref.dpy, tmp, &ref_image, 0, 0, AllPlanes);
41700 - XFreeGC(t->ref.dpy, gc);
41701 - XFreePixmap(t->ref.dpy, tmp);
41702 - ref = ref_image.data;
41703 + XShmGetImage(t->ref.dpy, ref_draw, &ref_image, x, y, AllPlanes);
41704 + ref = (uint32_t *)ref_image.data;
41706 /* Start with an exact comparison. However, one quicky desires
41707 * a fuzzy comparator to hide hardware inaccuracies...
41708 */
41709 + mask = depth_mask(out_image.depth);
41710 for (j = 0; j < h; j++) {
41711 for (i = 0; i < w; i++) {
41712 - uint32_t a = ((uint32_t *)out)[i] & mask;
41713 - uint32_t b = ((uint32_t *)ref)[i] & mask;
41714 + uint32_t a = out[i] & mask;
41715 + uint32_t b = ref[i] & mask;
41716 if (a != b && pixel_difference(a, b) > MAX_DELTA) {
41717 show_pixels(buf,
41718 &out_image, &ref_image,
41719 @@ -255,8 +239,8 @@ void test_compare(struct test *t,
41720 x,i, y,j, a, b, pixel_difference(a, b), buf, info);
41723 - out += out_image.bytes_per_line;
41724 - ref += ref_image.bytes_per_line;
41725 + out = (uint32_t *)((char *)out + out_image.bytes_per_line);
41726 + ref = (uint32_t *)((char *)ref + ref_image.bytes_per_line);
41730 diff --git a/test/xvidmode.c b/test/xvidmode.c
41731 new file mode 100644
41732 index 00000000..5cde8286
41733 --- /dev/null
41734 +++ b/test/xvidmode.c
41735 @@ -0,0 +1,54 @@
41736 +#include <stdlib.h>
41737 +#include <stdio.h>
41738 +#include <string.h>
41739 +#include <X11/Xlib.h>
41740 +#include <X11/extensions/xf86vmode.h>
41742 +int main(void)
41743 +{
41744 + Display *dpy;
41745 + XF86VidModeModeLine current;
41746 + XF86VidModeModeInfo **modes;
41747 + int num_modes, i;
41748 + int saved_mode = -1;
41749 + int dotclock;
41751 + dpy = XOpenDisplay(NULL);
41752 + if (dpy == NULL)
41753 + dpy = XOpenDisplay(":0");
41755 + XF86VidModeGetModeLine(dpy, DefaultScreen(dpy), &dotclock, &current);
41756 + XF86VidModeGetAllModeLines(dpy, XDefaultScreen(dpy),
41757 + &num_modes, &modes);
41758 + for (i = 0; i < num_modes; i++) {
41759 + int this;
41761 + this = (current.hdisplay == modes[i]->hdisplay &&
41762 + current.vdisplay == modes[i]->vdisplay &&
41763 + dotclock == modes[i]->dotclock);
41764 + if (this && saved_mode == -1)
41765 + saved_mode = i;
41767 + printf("[%d] %dx%d%s\n",
41768 + i,
41769 + modes[i]->hdisplay,
41770 + modes[i]->vdisplay,
41771 + this ? "*" : "");
41772 + }
41774 + for (i = 0; i < num_modes; i++) {
41775 + printf("Switching to mode %dx%d\n",
41776 + modes[i]->hdisplay,
41777 + modes[i]->vdisplay);
41778 + XF86VidModeSwitchToMode(dpy, XDefaultScreen(dpy), modes[i]);
41779 + XSync(dpy, True);
41780 + }
41782 + if (saved_mode != -1) {
41783 + XF86VidModeSwitchToMode(dpy, XDefaultScreen(dpy),
41784 + modes[saved_mode]);
41785 + XFlush(dpy);
41786 + }
41788 + return 0;
41789 +}
41790 diff --git a/tools/Makefile.am b/tools/Makefile.am
41791 index b5de2c96..92df266b 100644
41792 --- a/tools/Makefile.am
41793 +++ b/tools/Makefile.am
41794 @@ -26,13 +26,30 @@ AM_CFLAGS = \
41795 drivermandir = $(DRIVER_MAN_DIR)
41796 policydir = $(datarootdir)/polkit-1/actions
41798 +bin_PROGRAMS =
41799 +noinst_PROGRAMS =
41800 +libexec_PROGRAMS =
41802 if BUILD_TOOLS
41803 -bin_PROGRAMS = intel-virtual-output
41804 +bin_PROGRAMS += intel-virtual-output
41805 driverman_DATA = intel-virtual-output.$(DRIVER_MAN_SUFFIX)
41806 endif
41808 +if BUILD_TOOL_CURSOR
41809 +noinst_PROGRAMS += cursor
41810 +cursor_CFLAGS = $(TOOL_CURSOR_CFLAGS)
41811 +cursor_LDADD = $(TOOL_CURSOR_LIBS)
41812 +endif
41814 +if X11_DRI3
41815 +noinst_PROGRAMS += dri3info
41816 +dri3info_SOURCES = dri3info.c
41817 +dri3info_CFLAGS = $(X11_DRI3_CFLAGS) $(DRI_CFLAGS)
41818 +dri3info_LDADD = $(X11_DRI3_LIBS) $(DRI_LIBS)
41819 +endif
41821 if BUILD_BACKLIGHT_HELPER
41822 -libexec_PROGRAMS = xf86-video-intel-backlight-helper
41823 +libexec_PROGRAMS += xf86-video-intel-backlight-helper
41824 nodist_policy_DATA = org.x.xf86-video-intel.backlight-helper.policy
41826 backlight_helper = $(libexecdir)/xf86-video-intel-backlight-helper
41827 diff --git a/tools/backlight_helper.c b/tools/backlight_helper.c
41828 index 8b2667dc..aadb8fac 100644
41829 --- a/tools/backlight_helper.c
41830 +++ b/tools/backlight_helper.c
41831 @@ -1,3 +1,7 @@
41832 +#ifdef HAVE_CONFIG_H
41833 +#include "config.h"
41834 +#endif
41836 #include <stdio.h>
41837 #include <string.h>
41838 #include <stdarg.h>
41839 @@ -9,6 +13,12 @@
41840 #include <sys/types.h>
41841 #include <sys/stat.h>
41843 +#if MAJOR_IN_MKDEV
41844 +#include <sys/mkdev.h>
41845 +#elif MAJOR_IN_SYSMACROS
41846 +#include <sys/sysmacros.h>
41847 +#endif
41849 #define DBG 0
41851 #if defined(__GNUC__) && (__GNUC__ > 3)
41852 diff --git a/tools/cursor.c b/tools/cursor.c
41853 new file mode 100644
41854 index 00000000..6a2438ad
41855 --- /dev/null
41856 +++ b/tools/cursor.c
41857 @@ -0,0 +1,127 @@
41858 +/*
41859 + * Copyright © 2015 Intel Corporation
41860 + *
41861 + * Permission is hereby granted, free of charge, to any person obtaining a
41862 + * copy of this software and associated documentation files (the "Software"),
41863 + * to deal in the Software without restriction, including without limitation
41864 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
41865 + * and/or sell copies of the Software, and to permit persons to whom the
41866 + * Software is furnished to do so, subject to the following conditions:
41867 + *
41868 + * The above copyright notice and this permission notice (including the next
41869 + * paragraph) shall be included in all copies or substantial portions of the
41870 + * Software.
41871 + *
41872 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41873 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41874 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
41875 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41876 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
41877 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
41878 + * IN THE SOFTWARE.
41879 + *
41880 + */
41882 +#ifdef HAVE_CONFIG_H
41883 +#include "config.h"
41884 +#endif
41886 +#include <X11/Xlib.h>
41887 +#include <X11/extensions/Xfixes.h>
41889 +#include <stdint.h>
41890 +#include <stdio.h>
41891 +#include <stdlib.h>
41892 +#include <png.h>
41894 +int main(int argc, char **argv)
41895 +{
41896 + Display *dpy;
41897 + XFixesCursorImage *cur;
41898 + unsigned long *src; /* XXX deep sigh */
41899 + unsigned x, y;
41900 + png_struct *png;
41901 + png_info *info;
41902 + png_byte **rows;
41903 + FILE *file;
41905 + dpy = XOpenDisplay(NULL);
41906 + if (dpy == NULL)
41907 + return 1;
41909 + if (!XFixesQueryExtension(dpy, (int *)&x, (int *)&y))
41910 + return 1;
41912 + cur = XFixesGetCursorImage(dpy);
41913 + if (cur == NULL)
41914 + return 1;
41916 + printf("Cursor on display '%s': %dx%d, (hotspot %dx%d)\n",
41917 + DisplayString(dpy),
41918 + cur->width, cur->height,
41919 + cur->xhot, cur->yhot);
41921 + if (1) {
41922 + int x, y;
41924 + src = cur->pixels;
41925 + for (y = 0; y < cur->height; y++) {
41926 + for (x = 0; x < cur->width; x++) {
41927 + if (x == cur->xhot && y == cur->yhot)
41928 + printf("+");
41929 + else
41930 + printf("%c", *src ? *src >> 24 >= 127 ? 'x' : '.' : ' ');
41931 + src++;
41932 + }
41933 + printf("\n");
41934 + }
41935 + }
41937 + file = fopen("cursor.png", "wb");
41938 + if (file == NULL)
41939 + return 2;
41941 + png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
41942 + info = png_create_info_struct(png);
41943 + png_init_io(png, file);
41944 + png_set_IHDR(png, info,
41945 + cur->width, cur->height, 8,
41946 + PNG_COLOR_TYPE_RGB_ALPHA,
41947 + PNG_INTERLACE_NONE,
41948 + PNG_COMPRESSION_TYPE_DEFAULT,
41949 + PNG_FILTER_TYPE_DEFAULT);
41950 + png_write_info(png, info);
41952 + src = cur->pixels;
41953 + rows = malloc(cur->height*sizeof(png_byte*));
41954 + if (rows == NULL)
41955 + return 3;
41957 + for (y = 0; y < cur->height; y++) {
41958 + rows[y] = malloc(cur->width * 4);
41959 + for (x = 0; x < cur->width; x++) {
41960 + uint32_t p = *src++;
41961 + uint8_t r = p >> 0;
41962 + uint8_t g = p >> 8;
41963 + uint8_t b = p >> 16;
41964 + uint8_t a = p >> 24;
41966 + if (a > 0x00 && a < 0xff) {
41967 + r = (r * 0xff + a /2) / a;
41968 + g = (g * 0xff + a /2) / a;
41969 + b = (b * 0xff + a /2) / a;
41970 + }
41972 + rows[y][4*x + 0] = b;
41973 + rows[y][4*x + 1] = g;
41974 + rows[y][4*x + 2] = r;
41975 + rows[y][4*x + 3] = a;
41976 + }
41977 + }
41979 + png_write_image(png, rows);
41980 + png_write_end(png, NULL);
41981 + fclose(file);
41983 + return 0;
41984 +}
41985 diff --git a/tools/dri3info.c b/tools/dri3info.c
41986 new file mode 100644
41987 index 00000000..0c33fc5a
41988 --- /dev/null
41989 +++ b/tools/dri3info.c
41990 @@ -0,0 +1,329 @@
41991 +/*
41992 + * Copyright (c) 2015 Intel Corporation
41993 + *
41994 + * Permission is hereby granted, free of charge, to any person obtaining a
41995 + * copy of this software and associated documentation files (the "Software"),
41996 + * to deal in the Software without restriction, including without limitation
41997 + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
41998 + * and/or sell copies of the Software, and to permit persons to whom the
41999 + * Software is furnished to do so, subject to the following conditions:
42000 + *
42001 + * The above copyright notice and this permission notice (including the next
42002 + * paragraph) shall be included in all copies or substantial portions of the
42003 + * Software.
42004 + *
42005 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42006 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42007 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
42008 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42009 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42010 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
42011 + * SOFTWARE.
42012 + *
42013 + * To compile standalone: gcc -o dri3info dri3info.c `pkg-config --cflags --libs xcb-dri3 x11-xcb xrandr xxf86vm libdrm`
42014 + */
42016 +#include <X11/Xlib.h>
42017 +#include <X11/Xlib-xcb.h>
42018 +#include <xcb/xcb.h>
42019 +#include <xcb/dri3.h>
42020 +#include <unistd.h>
42021 +#include <stdio.h>
42022 +#include <stdlib.h>
42023 +#include <stdint.h>
42024 +#include <string.h>
42025 +#include <sys/stat.h>
42026 +#include <drm.h>
42027 +#include <xf86drm.h>
42029 +#include <X11/extensions/Xrandr.h>
42030 +#include <X11/extensions/xf86vmode.h>
42032 +static int dri3_query_version(Display *dpy, int *major, int *minor)
42033 +{
42034 + xcb_connection_t *c = XGetXCBConnection(dpy);
42035 + xcb_dri3_query_version_reply_t *reply;
42036 + xcb_generic_error_t *error;
42038 + *major = *minor = -1;
42040 + reply = xcb_dri3_query_version_reply(c,
42041 + xcb_dri3_query_version(c,
42042 + XCB_DRI3_MAJOR_VERSION,
42043 + XCB_DRI3_MINOR_VERSION),
42044 + &error);
42045 + free(error);
42046 + if (reply == NULL)
42047 + return -1;
42049 + *major = reply->major_version;
42050 + *minor = reply->minor_version;
42051 + free(reply);
42053 + return 0;
42054 +}
42056 +static int dri3_exists(Display *dpy)
42057 +{
42058 + const xcb_query_extension_reply_t *ext;
42059 + int major, minor;
42061 + ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id);
42062 + if (ext == NULL || !ext->present)
42063 + return 0;
42065 + if (dri3_query_version(dpy, &major, &minor) < 0)
42066 + return 0;
42068 + return major >= 0;
42069 +}
42071 +static int dri3_open(Display *dpy)
42072 +{
42073 + xcb_connection_t *c = XGetXCBConnection(dpy);
42074 + xcb_dri3_open_cookie_t cookie;
42075 + xcb_dri3_open_reply_t *reply;
42077 + if (!dri3_exists(dpy))
42078 + return -1;
42080 + cookie = xcb_dri3_open(c, RootWindow(dpy, DefaultScreen(dpy)), None);
42081 + reply = xcb_dri3_open_reply(c, cookie, NULL);
42083 + if (!reply)
42084 + return -1;
42086 + if (reply->nfd != 1)
42087 + return -1;
42089 + return xcb_dri3_open_reply_fds(c, reply)[0];
42090 +}
42092 +static void get_device_path(int fd, char *buf, int len)
42093 +{
42094 + struct stat remote, local;
42095 + int i;
42097 + if (fstat(fd, &remote))
42098 + goto out;
42100 + for (i = 0; i < 16; i++) {
42101 + snprintf(buf, len, "/dev/dri/card%d", i);
42102 + if (stat(buf, &local))
42103 + continue;
42105 + if (local.st_mode == remote.st_mode &&
42106 + local.st_rdev == remote.st_rdev)
42107 + return;
42109 + snprintf(buf, len, "/dev/dri/renderD%d", i + 128);
42110 + if (stat(buf, &local))
42111 + continue;
42113 + if (local.st_mode == remote.st_mode &&
42114 + local.st_rdev == remote.st_rdev)
42115 + return;
42116 + }
42118 +out:
42119 + strncpy(buf, "unknown path", len);
42120 +}
42122 +static void get_driver_name(int fd, char *name, int len)
42123 +{
42124 + drm_version_t version;
42126 + memset(name, 0, len);
42127 + memset(&version, 0, sizeof(version));
42128 + version.name_len = len;
42129 + version.name = name;
42131 + (void)drmIoctl(fd, DRM_IOCTL_VERSION, &version);
42132 +}
42134 +static int compute_refresh_rate_from_mode(long n, long d, unsigned flags,
42135 + int32_t *numerator,
42136 + int32_t *denominator)
42137 +{
42138 + int i;
42140 + /* The mode flags are only defined privately to the Xserver (in xf86str.h)
42141 + * but they at least bit compatible between VidMode, RandR and DRM.
42142 + */
42143 +# define V_INTERLACE 0x010
42144 +# define V_DBLSCAN 0x020
42146 + if (flags & V_INTERLACE)
42147 + n *= 2;
42148 + else if (flags & V_DBLSCAN)
42149 + d *= 2;
42151 + /* The OML_sync_control spec requires that if the refresh rate is a
42152 + * whole number, that the returned numerator be equal to the refresh
42153 + * rate and the denominator be 1.
42154 + */
42156 + if (n % d == 0) {
42157 + n /= d;
42158 + d = 1;
42159 + }
42160 + else {
42161 + static const unsigned f[] = { 13, 11, 7, 5, 3, 2, 0 };
42163 + /* This is a poor man's way to reduce a fraction. It's far from
42164 + * perfect, but it will work well enough for this situation.
42165 + */
42167 + for (i = 0; f[i] != 0; i++) {
42168 + while (n % f[i] == 0 && d % f[i] == 0) {
42169 + d /= f[i];
42170 + n /= f[i];
42171 + }
42172 + }
42173 + }
42175 + *numerator = n;
42176 + *denominator = d;
42177 + return 1;
42178 +}
42180 +static int RRGetMscRate(Display *dpy, int32_t *numerator, int32_t *denominator)
42181 +{
42182 + int ret = 0;
42183 + Window root = RootWindow(dpy, DefaultScreen(dpy));
42184 + XRRScreenResources *res;
42185 + int rr_event, rr_error;
42186 + RROutput primary;
42187 + RRMode mode = 0;
42188 + int n;
42190 + if (!XRRQueryExtension(dpy, &rr_event, &rr_error))
42191 + return ret;
42193 + res = XRRGetScreenResourcesCurrent(dpy, root);
42194 + if (res == NULL)
42195 + return ret;
42197 + /* Use the primary output if specified, otherwise
42198 + * use the mode on the first enabled crtc.
42199 + */
42200 + primary = XRRGetOutputPrimary(dpy, root);
42201 + if (primary) {
42202 + XRROutputInfo *output;
42204 + output = XRRGetOutputInfo(dpy, res, primary);
42205 + if (output != NULL) {
42206 + if (output->crtc) {
42207 + XRRCrtcInfo *crtc;
42209 + crtc = XRRGetCrtcInfo(dpy, res, output->crtc);
42210 + if (crtc) {
42211 + mode = crtc->mode;
42212 + XRRFreeCrtcInfo(crtc);
42213 + }
42214 + }
42215 + XRRFreeOutputInfo(output);
42216 + }
42217 + }
42219 + for (n = 0; mode == 0 && n < res->ncrtc; n++) {
42220 + XRRCrtcInfo *crtc;
42222 + crtc = XRRGetCrtcInfo(dpy, res, res->crtcs[n]);
42223 + if (crtc) {
42224 + mode = crtc->mode;
42225 + XRRFreeCrtcInfo(crtc);
42226 + }
42227 + }
42229 + for (n = 0; n < res->nmode; n++) {
42230 + if (res->modes[n].id == mode) {
42231 + ret = compute_refresh_rate_from_mode(res->modes[n].dotClock,
42232 + res->modes[n].hTotal*res->modes[n].vTotal,
42233 + res->modes[n].modeFlags,
42234 + numerator, denominator);
42235 + break;
42236 + }
42237 + }
42239 + XRRFreeScreenResources(res);
42240 + return ret;
42241 +}
42243 +static int VMGetMscRate(Display *dpy, int32_t *numerator, int32_t *denominator)
42244 +{
42245 + XF86VidModeModeLine mode_line;
42246 + int dot_clock;
42247 + int i;
42249 + if (XF86VidModeQueryVersion(dpy, &i, &i) &&
42250 + XF86VidModeGetModeLine(dpy, DefaultScreen(dpy), &dot_clock, &mode_line))
42251 + return compute_refresh_rate_from_mode(dot_clock * 1000,
42252 + mode_line.vtotal * mode_line.htotal,
42253 + mode_line.flags,
42254 + numerator, denominator);
42256 + return 0;
42257 +}
42259 +static int get_refresh_rate(Display *dpy,
42260 + int32_t *numerator,
42261 + int32_t *denominator)
42262 +{
42263 + if (RRGetMscRate(dpy, numerator, denominator))
42264 + return 1;
42266 + if (VMGetMscRate(dpy, numerator, denominator))
42267 + return 1;
42269 + return 0;
42270 +}
42272 +static void info(const char *dpyname)
42273 +{
42274 + Display *dpy;
42275 + int device;
42276 + int32_t numerator, denominator;
42278 + dpy = XOpenDisplay(dpyname);
42279 + if (dpy == NULL) {
42280 + printf("Unable to connect to display '%s'\n",
42281 + dpyname ?: getenv("DISPLAY") ?: "unset");
42282 + return;
42283 + }
42285 + printf("Display '%s'\n", DisplayString(dpy));
42286 + device = dri3_open(dpy);
42287 + if (device < 0) {
42288 + printf("\tUnable to connect to DRI3\n");
42289 + } else {
42290 + char device_path[1024];
42291 + char driver_name[1024];
42293 + get_device_path(device, device_path, sizeof(device_path));
42294 + get_driver_name(device, driver_name, sizeof(driver_name));
42296 + printf("Connected to DRI3, using fd %d which matches %s, driver %s\n",
42297 + device, device_path, driver_name);
42298 + close(device);
42299 + }
42301 + if (get_refresh_rate(dpy, &numerator, &denominator))
42302 + printf("\tPrimary refresh rate: %d/%d (%.1fHz)\n",
42303 + numerator, denominator, numerator/(float)denominator);
42305 + XCloseDisplay(dpy);
42306 +}
42308 +int main(int argc, char **argv)
42309 +{
42310 + int i;
42312 + if (argc > 1) {
42313 + for (i = 1; i < argc; i++)
42314 + info(argv[i]);
42315 + } else
42316 + info(NULL);
42318 + return 0;
42319 +}
42320 diff --git a/tools/virtual.c b/tools/virtual.c
42321 index 8e2b4a22..fc8db2b9 100644
42322 --- a/tools/virtual.c
42323 +++ b/tools/virtual.c
42324 @@ -31,6 +31,7 @@
42326 #include <X11/Xlibint.h>
42327 #include <X11/extensions/record.h>
42328 +#include <X11/extensions/scrnsaver.h>
42329 #include <X11/extensions/XShm.h>
42330 #if HAVE_X11_EXTENSIONS_SHMPROTO_H
42331 #include <X11/extensions/shmproto.h>
42332 @@ -79,13 +80,15 @@ static int verbose;
42333 #define DRAW 0x8
42334 #define DAMAGE 0x10
42335 #define CURSOR 0x20
42336 -#define POLL 0x40
42337 +#define SCREEN 0x40
42338 +#define POLL 0x80
42340 struct display {
42341 Display *dpy;
42342 struct clone *clone;
42343 struct context *ctx;
42345 + int saver_event, saver_error, saver_active;
42346 int damage_event, damage_error;
42347 int xfixes_event, xfixes_error;
42348 int rr_event, rr_error, rr_active;
42349 @@ -98,6 +101,7 @@ struct display {
42350 int width;
42351 int height;
42352 int depth;
42353 + int active;
42355 XRenderPictFormat *root_format;
42356 XRenderPictFormat *rgb16_format;
42357 @@ -111,7 +115,7 @@ struct display {
42358 Cursor invisible_cursor;
42359 Cursor visible_cursor;
42361 - XcursorImage cursor_image;
42362 + XcursorImage cursor_image; /* first only */
42363 int cursor_serial;
42364 int cursor_x;
42365 int cursor_y;
42366 @@ -123,6 +127,13 @@ struct display {
42367 int send;
42368 int skip_clone;
42369 int skip_frame;
42371 + struct {
42372 + int timeout;
42373 + int interval;
42374 + int prefer_blank;
42375 + int allow_exp;
42376 + } saver;
42377 };
42379 struct output {
42380 @@ -145,6 +156,7 @@ struct output {
42381 XRenderPictFormat *use_render;
42383 int x, y;
42384 + int width, height;
42385 XRRModeInfo mode;
42386 Rotation rotation;
42387 };
42388 @@ -218,6 +230,13 @@ static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Wi
42389 static int _x_error_occurred;
42391 static int
42392 +_io_error_handler(Display *display)
42393 +{
42394 + fprintf(stderr, "XIO error on display %s\n", DisplayString(display));
42395 + abort();
42396 +}
42398 +static int
42399 _check_error_handler(Display *display,
42400 XErrorEvent *event)
42402 @@ -243,6 +262,10 @@ can_use_shm(Display *dpy,
42403 XExtCodes *codes;
42404 int major, minor, has_shm, has_pixmap;
42406 + *shm_event = 0;
42407 + *shm_opcode = 0;
42408 + *shm_pixmap = 0;
42410 if (!XShmQueryExtension(dpy))
42411 return 0;
42413 @@ -320,6 +343,7 @@ can_use_shm(Display *dpy,
42414 #include <X11/Xlib-xcb.h>
42415 #include <X11/xshmfence.h>
42416 #include <xcb/xcb.h>
42417 +#include <xcb/xcbext.h>
42418 #include <xcb/dri3.h>
42419 #include <xcb/sync.h>
42420 static Pixmap dri3_create_pixmap(Display *dpy,
42421 @@ -357,6 +381,7 @@ static int dri3_query_version(Display *dpy, int *major, int *minor)
42423 xcb_connection_t *c = XGetXCBConnection(dpy);
42424 xcb_dri3_query_version_reply_t *reply;
42425 + xcb_generic_error_t *error;
42427 *major = *minor = -1;
42429 @@ -364,7 +389,8 @@ static int dri3_query_version(Display *dpy, int *major, int *minor)
42430 xcb_dri3_query_version(c,
42431 XCB_DRI3_MAJOR_VERSION,
42432 XCB_DRI3_MINOR_VERSION),
42433 - NULL);
42434 + &error);
42435 + free(error);
42436 if (reply == NULL)
42437 return -1;
42439 @@ -377,8 +403,13 @@ static int dri3_query_version(Display *dpy, int *major, int *minor)
42441 static int dri3_exists(Display *dpy)
42443 + const xcb_query_extension_reply_t *ext;
42444 int major, minor;
42446 + ext = xcb_get_extension_data(XGetXCBConnection(dpy), &xcb_dri3_id);
42447 + if (ext == NULL || !ext->present)
42448 + return 0;
42450 if (dri3_query_version(dpy, &major, &minor) < 0)
42451 return 0;
42453 @@ -809,6 +840,10 @@ static int clone_update_modes__fixed(struct clone *clone)
42454 RRMode id;
42455 int i, j, ret = ENOENT;
42457 + DBG(X11, ("%s-%s cloning modes fixed %dx%d\n",
42458 + DisplayString(clone->dst.dpy), clone->dst.name,
42459 + clone->dst.width, clone->dst.height));
42461 assert(clone->src.rr_output);
42463 res = _XRRGetScreenResourcesCurrent(clone->src.dpy, clone->src.window);
42464 @@ -837,8 +872,8 @@ static int clone_update_modes__fixed(struct clone *clone)
42466 /* Create matching mode for the real output on the virtual */
42467 memset(&mode, 0, sizeof(mode));
42468 - mode.width = clone->width;
42469 - mode.height = clone->height;
42470 + mode.width = clone->dst.width;
42471 + mode.height = clone->dst.height;
42472 mode.nameLength = sprintf(mode_name, "FAKE-%dx%d", mode.width, mode.height);
42473 mode.name = mode_name;
42475 @@ -942,6 +977,35 @@ out:
42476 return rr_output;
42479 +static int check_virtual(struct display *display)
42480 +{
42481 + XRRScreenResources *res;
42482 + int found = -ENOENT;
42483 + int i;
42485 + res = _XRRGetScreenResourcesCurrent(display->dpy, display->root);
42486 + if (res == NULL)
42487 + return -ENOMEM;
42489 + for (i = 0; found == -ENOENT && i < res->noutput; i++) {
42490 + XRROutputInfo *output;
42492 + output = XRRGetOutputInfo(display->dpy, res, res->outputs[i]);
42493 + if (output == NULL)
42494 + continue;
42496 + if (strcmp(output->name, "VIRTUAL1") == 0)
42497 + found = 0;
42499 + XRRFreeOutputInfo(output);
42500 + }
42501 + XRRFreeScreenResources(res);
42503 + DBG(XRR, ("%s(%s): has VIRTUAL1? %d\n",
42504 + __func__, DisplayString(display->dpy), found));
42505 + return found;
42506 +}
42508 static int stride_for_depth(int width, int depth)
42510 if (depth == 24)
42511 @@ -1082,20 +1146,20 @@ static int clone_init_xfer(struct clone *clone)
42512 width = 0;
42513 height = 0;
42514 } else if (clone->dri3.xid) {
42515 - width = clone->dst.display->width;
42516 - height = clone->dst.display->height;
42517 + width = clone->dst.width;
42518 + height = clone->dst.height;
42519 } else {
42520 width = mode_width(&clone->src.mode, clone->src.rotation);
42521 height = mode_height(&clone->src.mode, clone->src.rotation);
42524 + DBG(DRAW, ("%s-%s create xfer, %dx%d (currently %dx%d)\n",
42525 + DisplayString(clone->dst.dpy), clone->dst.name,
42526 + width, height, clone->width, clone->height));
42528 if (width == clone->width && height == clone->height)
42529 return 0;
42531 - DBG(DRAW, ("%s-%s create xfer, %dx%d\n",
42532 - DisplayString(clone->dst.dpy), clone->dst.name,
42533 - width, height));
42535 if (clone->shm.shmaddr) {
42536 if (clone->src.use_shm)
42537 XShmDetach(clone->src.dpy, &clone->src.shm);
42538 @@ -1225,6 +1289,56 @@ static void clone_update(struct clone *clone)
42539 clone->rr_update = 0;
42542 +static void screensaver_save(struct display *display)
42543 +{
42544 + display->saver_active =
42545 + XScreenSaverQueryExtension(display->dpy,
42546 + &display->saver_event,
42547 + &display->saver_error);
42548 + DBG(SCREEN,
42549 + ("%s screen saver active? %d [event=%d, error=%d]\n",
42550 + DisplayString(display->dpy),
42551 + display->saver_active,
42552 + display->saver_event,
42553 + display->saver_error));
42555 + XGetScreenSaver(display->dpy,
42556 + &display->saver.timeout,
42557 + &display->saver.interval,
42558 + &display->saver.prefer_blank,
42559 + &display->saver.allow_exp);
42561 + DBG(SCREEN,
42562 + ("%s saving screen saver defaults: timeout=%d interval=%d prefer_blank=%d allow_exp=%d\n",
42563 + DisplayString(display->dpy),
42564 + display->saver.timeout,
42565 + display->saver.interval,
42566 + display->saver.prefer_blank,
42567 + display->saver.allow_exp));
42568 +}
42570 +static void screensaver_disable(struct display *display)
42571 +{
42572 + DBG(SCREEN,
42573 + ("%s disabling screen saver\n", DisplayString(display->dpy)));
42575 + XSetScreenSaver(display->dpy, 0, 0, DefaultBlanking, DefaultExposures);
42576 + display_mark_flush(display);
42577 +}
42579 +static void screensaver_restore(struct display *display)
42580 +{
42581 + DBG(SCREEN,
42582 + ("%s restoring screen saver\n", DisplayString(display->dpy)));
42584 + XSetScreenSaver(display->dpy,
42585 + display->saver.timeout,
42586 + display->saver.interval,
42587 + display->saver.prefer_blank,
42588 + display->saver.allow_exp);
42589 + display_mark_flush(display);
42590 +}
42592 static int context_update(struct context *ctx)
42594 Display *dpy = ctx->display->dpy;
42595 @@ -1325,8 +1439,19 @@ static int context_update(struct context *ctx)
42596 struct clone *clone;
42597 int x1, x2, y1, y2;
42599 - if (display->rr_active == 0)
42600 + if (display->rr_active == 0) {
42601 + for (clone = display->clone; clone; clone = clone->next) {
42602 + struct output *output = &clone->src;
42603 + if (output->mode.id) {
42604 + clone->dst.mode.id = -1;
42605 + clone->dst.rr_crtc = -1;
42606 + } else {
42607 + clone->dst.mode.id = 0;
42608 + clone->dst.rr_crtc = 0;
42609 + }
42610 + }
42611 continue;
42612 + }
42614 x1 = y1 = INT_MAX;
42615 x2 = y2 = INT_MIN;
42616 @@ -1570,6 +1695,13 @@ ungrab:
42617 XUngrabServer(display->dpy);
42620 + for (n = 1; n < ctx->ndisplay; n++) {
42621 + struct display *display = &ctx->display[n];
42623 + display->active = 0;
42624 + screensaver_restore(display);
42625 + }
42627 ctx->active = NULL;
42628 for (n = 0; n < ctx->nclone; n++) {
42629 struct clone *clone = &ctx->clones[n];
42630 @@ -1580,7 +1712,10 @@ ungrab:
42631 continue;
42633 DBG(XRR, ("%s-%s: added to active list\n",
42634 - DisplayString(clone->dst.display->dpy), clone->dst.name));
42635 + DisplayString(clone->dst.display->dpy), clone->dst.name));
42637 + if (clone->dst.display->active++ == 0)
42638 + screensaver_disable(clone->dst.display);
42640 clone->active = ctx->active;
42641 ctx->active = clone;
42642 @@ -1599,14 +1734,17 @@ static Cursor display_load_invisible_cursor(struct display *display)
42644 static Cursor display_get_visible_cursor(struct display *display)
42646 - if (display->cursor_serial != display->cursor_image.size) {
42647 - DBG(CURSOR, ("%s updating cursor\n", DisplayString(display->dpy)));
42648 + struct display *first = display->ctx->display;
42650 + if (display->cursor_serial != first->cursor_serial) {
42651 + DBG(CURSOR, ("%s updating cursor %dx%d, serial %d\n",
42652 + DisplayString(display->dpy), first->cursor_image.width, first->cursor_image.height, first->cursor_serial));
42654 if (display->visible_cursor)
42655 XFreeCursor(display->dpy, display->visible_cursor);
42657 - display->visible_cursor = XcursorImageLoadCursor(display->dpy, &display->cursor_image);
42658 - display->cursor_serial = display->cursor_image.size;
42659 + display->visible_cursor = XcursorImageLoadCursor(display->dpy, &first->cursor_image);
42660 + display->cursor_serial = first->cursor_serial;
42663 return display->visible_cursor;
42664 @@ -1629,7 +1767,7 @@ static void display_load_visible_cursor(struct display *display, XFixesCursorIma
42665 display->cursor_image.height = cur->height;
42666 display->cursor_image.xhot = cur->xhot;
42667 display->cursor_image.yhot = cur->yhot;
42668 - display->cursor_image.size++;
42669 + display->cursor_serial++;
42671 n = cur->width*cur->height;
42672 src = cur->pixels;
42673 @@ -1637,11 +1775,24 @@ static void display_load_visible_cursor(struct display *display, XFixesCursorIma
42674 while (n--)
42675 *dst++ = *src++;
42677 - DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy)));
42678 - display->cursor_moved++;
42679 - if (display->cursor != display->invisible_cursor) {
42680 - display->cursor_visible++;
42681 - context_enable_timer(display->ctx);
42682 + if (verbose & CURSOR) {
42683 + int x, y;
42685 + printf("%s cursor image %dx%d, serial %d:\n",
42686 + DisplayString(display->dpy),
42687 + cur->width, cur->height,
42688 + display->cursor_serial);
42689 + dst = display->cursor_image.pixels;
42690 + for (y = 0; y < cur->height; y++) {
42691 + for (x = 0; x < cur->width; x++) {
42692 + if (x == cur->xhot && y == cur->yhot)
42693 + printf("+");
42694 + else
42695 + printf("%c", *dst ? *dst >> 24 >= 127 ? 'x' : '.' : ' ');
42696 + dst++;
42697 + }
42698 + printf("\n");
42699 + }
42703 @@ -1685,6 +1836,8 @@ static void display_flush_cursor(struct display *display)
42704 if (cursor == None)
42705 cursor = display->invisible_cursor;
42706 if (cursor != display->cursor) {
42707 + DBG(CURSOR, ("%s setting cursor shape %lx\n",
42708 + DisplayString(display->dpy), (long)cursor));
42709 XDefineCursor(display->dpy, display->root, cursor);
42710 display->cursor = cursor;
42712 @@ -1762,6 +1915,8 @@ static void get_src(struct clone *c, const XRectangle *clip)
42713 c->image.obdata = (char *)&c->src.shm;
42715 if (c->src.use_render) {
42716 + DBG(DRAW, ("%s-%s get_src via XRender\n",
42717 + DisplayString(c->dst.dpy), c->dst.name));
42718 XRenderComposite(c->src.dpy, PictOpSrc,
42719 c->src.win_picture, 0, c->src.pix_picture,
42720 clip->x, clip->y,
42721 @@ -1782,16 +1937,22 @@ static void get_src(struct clone *c, const XRectangle *clip)
42722 &c->image, 0, 0);
42724 } else if (c->src.pixmap) {
42725 + DBG(DRAW, ("%s-%s get_src XCopyArea (SHM/DRI3)\n",
42726 + DisplayString(c->dst.dpy), c->dst.name));
42727 XCopyArea(c->src.dpy, c->src.window, c->src.pixmap, c->src.gc,
42728 clip->x, clip->y,
42729 clip->width, clip->height,
42730 0, 0);
42731 XSync(c->src.dpy, False);
42732 } else if (c->src.use_shm) {
42733 + DBG(DRAW, ("%s-%s get_src XShmGetImage\n",
42734 + DisplayString(c->dst.dpy), c->dst.name));
42735 ximage_prepare(&c->image, clip->width, clip->height);
42736 XShmGetImage(c->src.dpy, c->src.window, &c->image,
42737 clip->x, clip->y, AllPlanes);
42738 } else {
42739 + DBG(DRAW, ("%s-%s get_src XGetSubImage (slow)\n",
42740 + DisplayString(c->dst.dpy), c->dst.name));
42741 ximage_prepare(&c->image, c->width, c->height);
42742 XGetSubImage(c->src.dpy, c->src.window,
42743 clip->x, clip->y, clip->width, clip->height,
42744 @@ -1838,7 +1999,7 @@ static void put_dst(struct clone *c, const XRectangle *clip)
42745 clip->width, clip->height);
42746 c->dst.display->send |= c->dst.use_shm;
42747 } else if (c->dst.pixmap) {
42748 - DBG(DRAW, ("%s-%s using SHM pixmap\n",
42749 + DBG(DRAW, ("%s-%s using SHM or DRI3 pixmap\n",
42750 DisplayString(c->dst.dpy), c->dst.name));
42751 c->dst.serial = NextRequest(c->dst.dpy);
42752 XCopyArea(c->dst.dpy, c->dst.pixmap, c->dst.window, c->dst.gc,
42753 @@ -1870,6 +2031,9 @@ static int clone_paint(struct clone *c)
42755 XRectangle clip;
42757 + if (c->width == 0 || c->height == 0)
42758 + return 0;
42760 DBG(DRAW, ("%s-%s paint clone, damaged (%d, %d), (%d, %d) [(%d, %d), (%d, %d)]\n",
42761 DisplayString(c->dst.dpy), c->dst.name,
42762 c->damaged.x1, c->damaged.y1,
42763 @@ -1944,6 +2108,10 @@ static int clone_paint(struct clone *c)
42764 clip.height = c->damaged.y2 - c->damaged.y1;
42765 get_src(c, &clip);
42767 + DBG(DRAW, ("%s-%s target offset %dx%d\n",
42768 + DisplayString(c->dst.dpy), c->dst.name,
42769 + c->dst.x - c->src.x, c->dst.y - c->src.y));
42771 clip.x += c->dst.x - c->src.x;
42772 clip.y += c->dst.y - c->src.y;
42773 put_dst(c, &clip);
42774 @@ -1969,8 +2137,9 @@ static void clone_damage(struct clone *c, const XRectangle *rec)
42775 if ((v = (int)rec->y + rec->height) > c->damaged.y2)
42776 c->damaged.y2 = v;
42778 - DBG(DAMAGE, ("%s-%s damaged: (%d, %d), (%d, %d)\n",
42779 + DBG(DAMAGE, ("%s-%s damaged: +(%d,%d)x(%d, %d) -> (%d, %d), (%d, %d)\n",
42780 DisplayString(c->dst.display->dpy), c->dst.name,
42781 + rec->x, rec->y, rec->width, rec->height,
42782 c->damaged.x1, c->damaged.y1,
42783 c->damaged.x2, c->damaged.y2));
42785 @@ -2252,6 +2421,8 @@ static int clone_init_depth(struct clone *clone)
42786 if (ret)
42787 return ret;
42789 + clone->depth = depth;
42791 DBG(X11, ("%s-%s using depth %d, requires xrender for src? %d, for dst? %d\n",
42792 DisplayString(clone->dst.dpy), clone->dst.name,
42793 clone->depth,
42794 @@ -2312,6 +2483,8 @@ static int add_display(struct context *ctx, Display *dpy)
42795 display->depth = DefaultDepth(dpy, DefaultScreen(dpy));
42796 display->visual = DefaultVisual(dpy, DefaultScreen(dpy));
42798 + XSelectInput(dpy, display->root, ExposureMask);
42800 display->has_shm = can_use_shm(dpy, display->root,
42801 &display->shm_event,
42802 &display->shm_opcode,
42803 @@ -2323,6 +2496,8 @@ static int add_display(struct context *ctx, Display *dpy)
42804 display->shm_opcode,
42805 display->has_shm_pixmap));
42807 + screensaver_save(display);
42809 display->rr_active = XRRQueryExtension(dpy, &display->rr_event, &display->rr_error);
42810 DBG(X11, ("%s: randr_active?=%d, event=%d, error=%d\n",
42811 DisplayString(dpy),
42812 @@ -2592,6 +2767,11 @@ static int last_display_add_clones__randr(struct context *ctx)
42813 return ret;
42816 + clone->dst.x = 0;
42817 + clone->dst.y = 0;
42818 + clone->dst.width = display->width;
42819 + clone->dst.height = display->height;
42821 ret = clone_update_modes__randr(clone);
42822 if (ret) {
42823 fprintf(stderr, "Failed to clone output \"%s\" from display \"%s\"\n",
42824 @@ -2668,8 +2848,8 @@ static int last_display_add_clones__xinerama(struct context *ctx)
42827 /* Replace the modes on the local VIRTUAL output with the remote Screen */
42828 - clone->width = xi[n].width;
42829 - clone->height = xi[n].height;
42830 + clone->dst.width = xi[n].width;
42831 + clone->dst.height = xi[n].height;
42832 clone->dst.x = xi[n].x_org;
42833 clone->dst.y = xi[n].y_org;
42834 clone->dst.rr_crtc = -1;
42835 @@ -2698,64 +2878,67 @@ static int last_display_add_clones__display(struct context *ctx)
42836 Display *dpy = display->dpy;
42837 struct clone *clone;
42838 Screen *scr;
42839 + int count, s;
42840 char buf[80];
42841 int ret;
42842 RROutput id;
42844 + count = ScreenCount(dpy);
42845 + DBG(X11, ("%s(%s) - %d screens\n", __func__, DisplayString(dpy), count));
42846 + for (s = 0; s < count; s++) {
42847 + clone = add_clone(ctx);
42848 + if (clone == NULL)
42849 + return -ENOMEM;
42851 - DBG(X11, ("%s(%s)\n", __func__, DisplayString(dpy)));
42852 - clone = add_clone(ctx);
42853 - if (clone == NULL)
42854 - return -ENOMEM;
42855 + clone->depth = 24;
42856 + clone->next = display->clone;
42857 + display->clone = clone;
42859 - clone->depth = 24;
42860 - clone->next = display->clone;
42861 - display->clone = clone;
42862 + id = claim_virtual(ctx->display, buf, ctx->nclone);
42863 + if (id == 0) {
42864 + fprintf(stderr, "Failed to find available VirtualHead \"%s\" for on display \"%s\"\n",
42865 + buf, DisplayString(dpy));
42866 + }
42867 + ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
42868 + if (ret) {
42869 + fprintf(stderr, "Failed to add display \"%s\"\n",
42870 + DisplayString(ctx->display->dpy));
42871 + return ret;
42872 + }
42874 - id = claim_virtual(ctx->display, buf, ctx->nclone);
42875 - if (id == 0) {
42876 - fprintf(stderr, "Failed to find available VirtualHead \"%s\" for on display \"%s\"\n",
42877 - buf, DisplayString(dpy));
42878 - }
42879 - ret = clone_output_init(clone, &clone->src, ctx->display, buf, id);
42880 - if (ret) {
42881 - fprintf(stderr, "Failed to add display \"%s\"\n",
42882 - DisplayString(ctx->display->dpy));
42883 - return ret;
42884 - }
42885 + sprintf(buf, "SCREEN%d", s);
42886 + ret = clone_output_init(clone, &clone->dst, display, buf, 0);
42887 + if (ret) {
42888 + fprintf(stderr, "Failed to add display \"%s\"\n",
42889 + DisplayString(dpy));
42890 + return ret;
42891 + }
42893 - sprintf(buf, "WHOLE");
42894 - ret = clone_output_init(clone, &clone->dst, display, buf, 0);
42895 - if (ret) {
42896 - fprintf(stderr, "Failed to add display \"%s\"\n",
42897 - DisplayString(dpy));
42898 - return ret;
42899 - }
42900 + ret = clone_init_depth(clone);
42901 + if (ret) {
42902 + fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
42903 + DisplayString(dpy));
42904 + return ret;
42905 + }
42907 - ret = clone_init_depth(clone);
42908 - if (ret) {
42909 - fprintf(stderr, "Failed to negotiate image format for display \"%s\"\n",
42910 - DisplayString(dpy));
42911 - return ret;
42912 - }
42913 + /* Replace the modes on the local VIRTUAL output with the remote Screen */
42914 + scr = ScreenOfDisplay(dpy, s);
42915 + clone->dst.width = scr->width;
42916 + clone->dst.height = scr->height;
42917 + clone->dst.x = 0;
42918 + clone->dst.y = 0;
42919 + clone->dst.rr_crtc = -1;
42920 + ret = clone_update_modes__fixed(clone);
42921 + if (ret) {
42922 + fprintf(stderr, "Failed to clone display \"%s\"\n",
42923 + DisplayString(dpy));
42924 + return ret;
42925 + }
42927 - /* Replace the modes on the local VIRTUAL output with the remote Screen */
42928 - scr = ScreenOfDisplay(dpy, DefaultScreen(dpy));
42929 - clone->width = scr->width;
42930 - clone->height = scr->height;
42931 - clone->dst.x = 0;
42932 - clone->dst.y = 0;
42933 - clone->dst.rr_crtc = -1;
42934 - ret = clone_update_modes__fixed(clone);
42935 - if (ret) {
42936 - fprintf(stderr, "Failed to clone display \"%s\"\n",
42937 - DisplayString(dpy));
42938 - return ret;
42939 + clone->active = ctx->active;
42940 + ctx->active = clone;
42943 - clone->active = ctx->active;
42944 - ctx->active = clone;
42946 return 0;
42949 @@ -3168,6 +3351,33 @@ static void context_cleanup(struct context *ctx)
42950 XCloseDisplay(dpy);
42953 +static void update_cursor_image(struct context *ctx)
42954 +{
42955 + XFixesCursorImage *cur;
42956 + int i;
42958 + DBG(CURSOR, ("%s cursor changed\n",
42959 + DisplayString(ctx->display->dpy)));
42961 + cur = XFixesGetCursorImage(ctx->display->dpy);
42962 + if (cur == NULL)
42963 + return;
42965 + display_load_visible_cursor(&ctx->display[0], cur);
42966 + for (i = 1; i < ctx->ndisplay; i++) {
42967 + struct display *display = &ctx->display[i];
42969 + DBG(CURSOR, ("%s marking cursor changed\n", DisplayString(display->dpy)));
42970 + display->cursor_moved++;
42971 + if (display->cursor != display->invisible_cursor) {
42972 + display->cursor_visible++;
42973 + context_enable_timer(display->ctx);
42974 + }
42975 + }
42977 + XFree(cur);
42978 +}
42980 static int done;
42982 static void signal_handler(int sig)
42983 @@ -3182,6 +3392,7 @@ int main(int argc, char **argv)
42984 uint64_t count;
42985 int daemonize = 1, bumblebee = 0, siblings = 0, singleton = 1;
42986 int i, ret, open, fail;
42987 + int idle;
42989 signal(SIGPIPE, SIG_IGN);
42991 @@ -3228,6 +3439,7 @@ int main(int argc, char **argv)
42992 return -ret;
42994 XSetErrorHandler(_check_error_handler);
42995 + XSetIOErrorHandler(_io_error_handler);
42997 ret = add_fd(&ctx, display_open(&ctx, src_name));
42998 if (ret) {
42999 @@ -3237,6 +3449,13 @@ int main(int argc, char **argv)
43000 goto out;
43003 + ret = check_virtual(ctx.display);
43004 + if (ret) {
43005 + fprintf(stderr, "No VIRTUAL outputs on \"%s\".\n",
43006 + DisplayString(ctx.display->dpy));
43007 + goto out;
43008 + }
43010 if (singleton) {
43011 XSelectInput(ctx.display->dpy, ctx.display->root, PropertyChangeMask);
43012 if (first_display_has_singleton(&ctx)) {
43013 @@ -3291,6 +3510,11 @@ int main(int argc, char **argv)
43014 if (ret)
43015 goto out;
43017 + if (ctx.display->saver_active)
43018 + XScreenSaverSelectInput(ctx.display->dpy,
43019 + ctx.display->root,
43020 + ScreenSaverNotifyMask);
43022 if ((ctx.display->rr_event | ctx.display->rr_error) == 0) {
43023 fprintf(stderr, "RandR extension not supported by %s\n", DisplayString(ctx.display->dpy));
43024 ret = EINVAL;
43025 @@ -3348,25 +3572,60 @@ int main(int argc, char **argv)
43026 signal(SIGTERM, signal_handler);
43028 ctx.command_continuation = 0;
43029 + update_cursor_image(&ctx);
43031 + idle = 0;
43032 while (!done) {
43033 XEvent e;
43034 int reconfigure = 0;
43035 int rr_update = 0;
43037 - DBG(POLL, ("polling - enable timer? %d, nfd=%d, ndisplay=%d\n", ctx.timer_active, ctx.nfd, ctx.ndisplay));
43038 - ret = poll(ctx.pfd + !ctx.timer_active, ctx.nfd - !ctx.timer_active, -1);
43039 - if (ret <= 0)
43040 - break;
43041 + if (idle) {
43042 + DBG(POLL, ("polling - enable timer? %d, nfd=%d, ndisplay=%d\n", ctx.timer_active, ctx.nfd, ctx.ndisplay));
43043 + ret = poll(ctx.pfd + !ctx.timer_active, ctx.nfd - !ctx.timer_active, -1);
43044 + if (ret <= 0)
43045 + break;
43047 + DBG(POLL, ("poll reports %d fd awake\n", ret));
43048 + }
43049 + idle = 1;
43051 /* pfd[0] is the timer, pfd[1] is the local display, pfd[2] is the mouse, pfd[3+] are the remotes */
43053 - DBG(POLL, ("poll reports %d fd awake\n", ret));
43054 if (ctx.pfd[1].revents || XPending(ctx.display[0].dpy)) {
43055 DBG(POLL,("%s woken up\n", DisplayString(ctx.display[0].dpy)));
43056 + ctx.pfd[1].revents = 0;
43057 + idle = 0;
43059 do {
43060 XNextEvent(ctx.display->dpy, &e);
43062 - if (e.type == ctx.display->damage_event + XDamageNotify ) {
43063 + DBG(POLL, ("%s received event %d\n", DisplayString(ctx.display[0].dpy), e.type));
43065 + if (e.type == ctx.display->saver_event + ScreenSaverNotify) {
43066 + const XScreenSaverNotifyEvent *se = (const XScreenSaverNotifyEvent *)&e;
43067 + DBG(SCREEN,
43068 + ("%s screen saver: state=%d, kind=%d, forced=%d\n",
43069 + DisplayString(ctx.display->dpy),
43070 + se->state, se->kind, se->forced));
43071 + for (i = 1; i < ctx.ndisplay; i++) {
43072 + struct display *display = &ctx.display[i];
43074 + if (!display->active)
43075 + continue;
43077 + DBG(SCREEN,
43078 + ("%s %s screen saver\n",
43079 + DisplayString(display->dpy),
43080 + se->state == ScreenSaverOn ? "activating" : "resetting\n"));
43082 + if (se->state == ScreenSaverOn)
43083 + XActivateScreenSaver(display->dpy);
43084 + else
43085 + XResetScreenSaver(display->dpy);
43086 + XFlush(display->dpy);
43087 + }
43088 + } else if (e.type == ctx.display->damage_event + XDamageNotify) {
43089 const XDamageNotifyEvent *de = (const XDamageNotifyEvent *)&e;
43090 struct clone *clone;
43092 @@ -3380,19 +3639,7 @@ int main(int argc, char **argv)
43093 if (ctx.active)
43094 context_enable_timer(&ctx);
43095 } else if (e.type == ctx.display->xfixes_event + XFixesCursorNotify) {
43096 - XFixesCursorImage *cur;
43098 - DBG(CURSOR, ("%s cursor changed\n",
43099 - DisplayString(ctx.display->dpy)));
43101 - cur = XFixesGetCursorImage(ctx.display->dpy);
43102 - if (cur == NULL)
43103 - continue;
43105 - for (i = 1; i < ctx.ndisplay; i++)
43106 - display_load_visible_cursor(&ctx.display[i], cur);
43108 - XFree(cur);
43109 + update_cursor_image(&ctx);
43110 } else if (e.type == ctx.display->rr_event + RRScreenChangeNotify) {
43111 DBG(XRR, ("%s screen changed (reconfigure pending? %d)\n",
43112 DisplayString(ctx.display->dpy), reconfigure));
43113 @@ -3426,13 +3673,41 @@ int main(int argc, char **argv)
43114 if (ctx.pfd[i+2].revents == 0 && !XPending(ctx.display[i].dpy))
43115 continue;
43117 + ctx.pfd[i+2].revents = 0;
43118 + idle = 0;
43120 DBG(POLL, ("%s woken up\n", DisplayString(ctx.display[i].dpy)));
43121 do {
43122 XNextEvent(ctx.display[i].dpy, &e);
43124 DBG(POLL, ("%s received event %d\n", DisplayString(ctx.display[i].dpy), e.type));
43125 - if (ctx.display[i].rr_active && e.type == ctx.display[i].rr_event + RRNotify) {
43126 - XRRNotifyEvent *re = (XRRNotifyEvent *)&e;
43127 + if (e.type == Expose) {
43128 + const XExposeEvent *xe = (XExposeEvent *)&e;
43129 + struct clone *clone;
43130 + int damaged = 0;
43132 + DBG(DAMAGE, ("%s exposed: (%d, %d)x(%d, %d)\n",
43133 + DisplayString(ctx.display[i].dpy),
43134 + xe->x, xe->y, xe->width, xe->height));
43136 + for (clone = ctx.active; clone; clone = clone->active) {
43137 + XRectangle r;
43139 + if (clone->dst.display != &ctx.display[i])
43140 + continue;
43142 + r.x = clone->src.x + xe->x;
43143 + r.y = clone->src.y + xe->y;
43144 + r.width = xe->width;
43145 + r.height = xe->height;
43146 + clone_damage(clone, &r);
43147 + damaged++;
43148 + }
43150 + if (damaged)
43151 + context_enable_timer(&ctx);
43152 + } else if (ctx.display[i].rr_active && e.type == ctx.display[i].rr_event + RRNotify) {
43153 + const XRRNotifyEvent *re = (XRRNotifyEvent *)&e;
43155 DBG(XRR, ("%s received RRNotify, type %d\n", DisplayString(ctx.display[i].dpy), re->subtype));
43156 if (re->subtype == RRNotify_OutputChange) {
43157 @@ -3480,6 +3755,7 @@ int main(int argc, char **argv)
43159 DBG(TIMER, ("%s timer still active? %d\n", DisplayString(ctx.display->dpy), ret != 0));
43160 ctx.timer_active = ret != 0;
43161 + idle = 0;