Imported Upstream version 1.15.1
[deb_xorg-server.git] / hw / xfree86 / modes / xf86Rotate.c
CommitLineData
a09e091a
JB
1/*
2 * Copyright © 2006 Keith Packard
3 * Copyright © 2011 Aaron Plattner
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting documentation, and
9 * that the name of the copyright holders not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission. The copyright holders make no representations
12 * about the suitability of this software for any purpose. It is provided "as
13 * is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 * OF THIS SOFTWARE.
22 */
23
24#ifdef HAVE_XORG_CONFIG_H
25#include <xorg-config.h>
26#else
27#ifdef HAVE_CONFIG_H
28#include <config.h>
29#endif
30#endif
31
32#include <stddef.h>
33#include <string.h>
34#include <stdio.h>
35
36#include "xf86.h"
37#include "xf86DDC.h"
38#include "fb.h"
39#include "windowstr.h"
40#include "xf86Crtc.h"
41#include "xf86Modes.h"
42#include "xf86RandR12.h"
43#include "X11/extensions/render.h"
44#include "X11/extensions/dpmsconst.h"
45#include "X11/Xatom.h"
46
47/* borrowed from composite extension, move to Render and publish? */
48
49#define F(x) IntToxFixed(x)
50
51#define toF(x) ((float) (x) / 65536.0f)
52
53static void
54xf86RotateCrtcRedisplay(xf86CrtcPtr crtc, RegionPtr region)
55{
56 ScrnInfoPtr scrn = crtc->scrn;
57 ScreenPtr screen = scrn->pScreen;
58 WindowPtr root = screen->root;
59 PixmapPtr dst_pixmap = crtc->rotatedPixmap;
60 PictFormatPtr format = PictureWindowFormat(screen->root);
61 int error;
62 PicturePtr src, dst;
63 int n = RegionNumRects(region);
64 BoxPtr b = RegionRects(region);
65 XID include_inferiors = IncludeInferiors;
66
67 if (crtc->driverIsPerformingTransform)
68 return;
69
70 src = CreatePicture(None,
71 &root->drawable,
72 format,
73 CPSubwindowMode,
74 &include_inferiors, serverClient, &error);
75 if (!src)
76 return;
77
78 dst = CreatePicture(None,
79 &dst_pixmap->drawable,
80 format, 0L, NULL, serverClient, &error);
81 if (!dst)
82 return;
83
84 error = SetPictureTransform(src, &crtc->crtc_to_framebuffer);
85 if (error)
86 return;
87 if (crtc->transform_in_use && crtc->filter)
88 SetPicturePictFilter(src, crtc->filter, crtc->params, crtc->nparams);
89
90 if (crtc->shadowClear) {
91 CompositePicture(PictOpSrc,
92 src, NULL, dst,
93 0, 0, 0, 0, 0, 0,
94 crtc->mode.HDisplay, crtc->mode.VDisplay);
95 crtc->shadowClear = FALSE;
96 }
97 else {
98 while (n--) {
99 BoxRec dst_box;
100
101 dst_box = *b;
102 dst_box.x1 -= crtc->filter_width >> 1;
103 dst_box.x2 += crtc->filter_width >> 1;
104 dst_box.y1 -= crtc->filter_height >> 1;
105 dst_box.y2 += crtc->filter_height >> 1;
106 pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &dst_box);
107 CompositePicture(PictOpSrc,
108 src, NULL, dst,
109 dst_box.x1, dst_box.y1, 0, 0, dst_box.x1,
110 dst_box.y1, dst_box.x2 - dst_box.x1,
111 dst_box.y2 - dst_box.y1);
112 b++;
113 }
114 }
115 FreePicture(src, None);
116 FreePicture(dst, None);
117}
118
119static void
120xf86CrtcDamageShadow(xf86CrtcPtr crtc)
121{
122 ScrnInfoPtr pScrn = crtc->scrn;
123 BoxRec damage_box;
124 RegionRec damage_region;
125 ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
126
127 damage_box.x1 = 0;
128 damage_box.x2 = crtc->mode.HDisplay;
129 damage_box.y1 = 0;
130 damage_box.y2 = crtc->mode.VDisplay;
131 if (!pixman_transform_bounds(&crtc->crtc_to_framebuffer, &damage_box)) {
132 damage_box.x1 = 0;
133 damage_box.y1 = 0;
134 damage_box.x2 = pScreen->width;
135 damage_box.y2 = pScreen->height;
136 }
137 if (damage_box.x1 < 0)
138 damage_box.x1 = 0;
139 if (damage_box.y1 < 0)
140 damage_box.y1 = 0;
141 if (damage_box.x2 > pScreen->width)
142 damage_box.x2 = pScreen->width;
143 if (damage_box.y2 > pScreen->height)
144 damage_box.y2 = pScreen->height;
145 RegionInit(&damage_region, &damage_box, 1);
146 DamageDamageRegion(&(*pScreen->GetScreenPixmap) (pScreen)->drawable,
147 &damage_region);
148 RegionUninit(&damage_region);
149 crtc->shadowClear = TRUE;
150}
151
152static void
153xf86RotatePrepare(ScreenPtr pScreen)
154{
155 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
156 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
157 int c;
158
159 for (c = 0; c < xf86_config->num_crtc; c++) {
160 xf86CrtcPtr crtc = xf86_config->crtc[c];
161
162 if (crtc->rotatedData && !crtc->rotatedPixmap) {
163 crtc->rotatedPixmap = crtc->funcs->shadow_create(crtc,
164 crtc->rotatedData,
165 crtc->mode.
166 HDisplay,
167 crtc->mode.
168 VDisplay);
169 if (!xf86_config->rotation_damage_registered) {
170 /* Hook damage to screen pixmap */
171 DamageRegister(&pScreen->root->drawable,
172 xf86_config->rotation_damage);
173 xf86_config->rotation_damage_registered = TRUE;
174 EnableLimitedSchedulingLatency();
175 }
176
177 xf86CrtcDamageShadow(crtc);
178 }
179 }
180}
181
182static Bool
183xf86RotateRedisplay(ScreenPtr pScreen)
184{
185 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
186 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
187 DamagePtr damage = xf86_config->rotation_damage;
188 RegionPtr region;
189
190 if (!damage)
191 return FALSE;
192 xf86RotatePrepare(pScreen);
193 region = DamageRegion(damage);
194 if (RegionNotEmpty(region)) {
195 int c;
196 SourceValidateProcPtr SourceValidate;
197
198 /*
199 * SourceValidate is used by the software cursor code
200 * to pull the cursor off of the screen when reading
201 * bits from the frame buffer. Bypassing this function
202 * leaves the software cursor in place
203 */
204 SourceValidate = pScreen->SourceValidate;
205 pScreen->SourceValidate = NULL;
206
207 for (c = 0; c < xf86_config->num_crtc; c++) {
208 xf86CrtcPtr crtc = xf86_config->crtc[c];
209
210 if (crtc->transform_in_use && crtc->enabled) {
211 RegionRec crtc_damage;
212
213 /* compute portion of damage that overlaps crtc */
214 RegionInit(&crtc_damage, &crtc->bounds, 1);
215 RegionIntersect(&crtc_damage, &crtc_damage, region);
216
217 /* update damaged region */
218 if (RegionNotEmpty(&crtc_damage))
219 xf86RotateCrtcRedisplay(crtc, &crtc_damage);
220
221 RegionUninit(&crtc_damage);
222 }
223 }
224 pScreen->SourceValidate = SourceValidate;
225 DamageEmpty(damage);
226 }
227 return TRUE;
228}
229
230static void
231xf86RotateBlockHandler(ScreenPtr pScreen,
232 pointer pTimeout, pointer pReadmask)
233{
234 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
235 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
236 Bool rotation_active;
237
238 rotation_active = xf86RotateRedisplay(pScreen);
239 pScreen->BlockHandler = xf86_config->BlockHandler;
240 (*pScreen->BlockHandler) (pScreen, pTimeout, pReadmask);
241 /* cannot avoid re-wrapping until all wrapping is audited */
242 xf86_config->BlockHandler = pScreen->BlockHandler;
243 pScreen->BlockHandler = xf86RotateBlockHandler;
244}
245
246void
247xf86RotateDestroy(xf86CrtcPtr crtc)
248{
249 ScrnInfoPtr pScrn = crtc->scrn;
250 ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
251 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
252 int c;
253
254 /* Free memory from rotation */
255 if (crtc->rotatedPixmap || crtc->rotatedData) {
256 crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
257 crtc->rotatedData);
258 crtc->rotatedPixmap = NULL;
259 crtc->rotatedData = NULL;
260 }
261
262 for (c = 0; c < xf86_config->num_crtc; c++)
263 if (xf86_config->crtc[c]->rotatedData)
264 return;
265
266 /*
267 * Clean up damage structures when no crtcs are rotated
268 */
269 if (xf86_config->rotation_damage) {
270 DrawablePtr screenDrawable = NULL;
271 if (pScreen && pScreen->root)
272 screenDrawable = &pScreen->root->drawable;
273 /* Free damage structure */
274 if (xf86_config->rotation_damage_registered) {
275 xf86_config->rotation_damage_registered = FALSE;
276 DisableLimitedSchedulingLatency();
277 }
278 DamageDestroy(xf86_config->rotation_damage);
279 xf86_config->rotation_damage = NULL;
280 }
281}
282
283void
284xf86RotateFreeShadow(ScrnInfoPtr pScrn)
285{
286 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
287 int c;
288
289 for (c = 0; c < config->num_crtc; c++) {
290 xf86CrtcPtr crtc = config->crtc[c];
291
292 if (crtc->rotatedPixmap || crtc->rotatedData) {
293 crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
294 crtc->rotatedData);
295 crtc->rotatedPixmap = NULL;
296 crtc->rotatedData = NULL;
297 }
298 }
299}
300
301void
302xf86RotateCloseScreen(ScreenPtr screen)
303{
304 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
305 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
306 int c;
307
308 for (c = 0; c < xf86_config->num_crtc; c++)
309 xf86RotateDestroy(xf86_config->crtc[c]);
310}
311
312static Bool
313xf86CrtcFitsScreen(xf86CrtcPtr crtc, struct pict_f_transform *crtc_to_fb)
314{
315 ScrnInfoPtr pScrn = crtc->scrn;
316 BoxRec b;
317
318 /* When called before PreInit, the driver is
319 * presumably doing load detect
320 */
321 if (pScrn->is_gpu) {
322 ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
323 if (pScreen->current_master)
324 pScrn = xf86ScreenToScrn(pScreen->current_master);
325 }
326
327 if (pScrn->virtualX == 0 || pScrn->virtualY == 0)
328 return TRUE;
329
330 b.x1 = 0;
331 b.y1 = 0;
332 b.x2 = crtc->mode.HDisplay;
333 b.y2 = crtc->mode.VDisplay;
334 if (crtc_to_fb)
335 pixman_f_transform_bounds(crtc_to_fb, &b);
336 else {
337 b.x1 += crtc->x;
338 b.y1 += crtc->y;
339 b.x2 += crtc->x;
340 b.y2 += crtc->y;
341 }
342
343 return (0 <= b.x1 && b.x2 <= pScrn->virtualX &&
344 0 <= b.y1 && b.y2 <= pScrn->virtualY);
345}
346
347Bool
348xf86CrtcRotate(xf86CrtcPtr crtc)
349{
350 ScrnInfoPtr pScrn = crtc->scrn;
351 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
352 ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
353 PictTransform crtc_to_fb;
354 struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc;
355 xFixed *new_params = NULL;
356 int new_nparams = 0;
357 PictFilterPtr new_filter = NULL;
358 int new_width = 0;
359 int new_height = 0;
360 RRTransformPtr transform = NULL;
361 Bool damage = FALSE;
362
363 if (crtc->transformPresent)
364 transform = &crtc->transform;
365
366 if (!RRTransformCompute(crtc->x, crtc->y,
367 crtc->mode.HDisplay, crtc->mode.VDisplay,
368 crtc->rotation,
369 transform,
370 &crtc_to_fb,
371 &f_crtc_to_fb,
372 &f_fb_to_crtc) &&
373 xf86CrtcFitsScreen(crtc, &f_crtc_to_fb)) {
374 /*
375 * If the untranslated transformation is the identity,
376 * disable the shadow buffer
377 */
378 xf86RotateDestroy(crtc);
379 crtc->transform_in_use = FALSE;
380 free(new_params);
381 new_params = NULL;
382 new_nparams = 0;
383 new_filter = NULL;
384 new_width = 0;
385 new_height = 0;
386 }
387 else {
388 if (crtc->driverIsPerformingTransform) {
389 xf86RotateDestroy(crtc);
390 }
391 else {
392 /*
393 * these are the size of the shadow pixmap, which
394 * matches the mode, not the pre-rotated copy in the
395 * frame buffer
396 */
397 int width = crtc->mode.HDisplay;
398 int height = crtc->mode.VDisplay;
399 void *shadowData = crtc->rotatedData;
400 PixmapPtr shadow = crtc->rotatedPixmap;
401 int old_width = shadow ? shadow->drawable.width : 0;
402 int old_height = shadow ? shadow->drawable.height : 0;
403
404 /* Allocate memory for rotation */
405 if (old_width != width || old_height != height) {
406 if (shadow || shadowData) {
407 crtc->funcs->shadow_destroy(crtc, shadow, shadowData);
408 crtc->rotatedPixmap = NULL;
409 crtc->rotatedData = NULL;
410 }
411 shadowData = crtc->funcs->shadow_allocate(crtc, width, height);
412 if (!shadowData)
413 goto bail1;
414 crtc->rotatedData = shadowData;
415 /* shadow will be damaged in xf86RotatePrepare */
416 }
417 else {
418 /* mark shadowed area as damaged so it will be repainted */
419 damage = TRUE;
420 }
421
422 if (!xf86_config->rotation_damage) {
423 /* Create damage structure */
424 xf86_config->rotation_damage = DamageCreate(NULL, NULL,
425 DamageReportNone,
426 TRUE, pScreen,
427 pScreen);
428 if (!xf86_config->rotation_damage)
429 goto bail2;
430
431 /* Wrap block handler */
432 if (!xf86_config->BlockHandler) {
433 xf86_config->BlockHandler = pScreen->BlockHandler;
434 pScreen->BlockHandler = xf86RotateBlockHandler;
435 }
436 }
437
438 if (0) {
439 bail2:
440 if (shadow || shadowData) {
441 crtc->funcs->shadow_destroy(crtc, shadow, shadowData);
442 crtc->rotatedPixmap = NULL;
443 crtc->rotatedData = NULL;
444 }
445 bail1:
446 if (old_width && old_height)
447 crtc->rotatedPixmap =
448 crtc->funcs->shadow_create(crtc, NULL, old_width,
449 old_height);
450 return FALSE;
451 }
452 }
453#ifdef RANDR_12_INTERFACE
454 if (transform) {
455 if (transform->nparams) {
456 new_params = malloc(transform->nparams * sizeof(xFixed));
457 if (new_params) {
458 memcpy(new_params, transform->params,
459 transform->nparams * sizeof(xFixed));
460 new_nparams = transform->nparams;
461 new_filter = transform->filter;
462 }
463 }
464 else
465 new_filter = transform->filter;
466 if (new_filter) {
467 new_width = new_filter->width;
468 new_height = new_filter->height;
469 }
470 }
471#endif
472 crtc->transform_in_use = TRUE;
473 }
474 crtc->crtc_to_framebuffer = crtc_to_fb;
475 crtc->f_crtc_to_framebuffer = f_crtc_to_fb;
476 crtc->f_framebuffer_to_crtc = f_fb_to_crtc;
477 free(crtc->params);
478 crtc->params = new_params;
479 crtc->nparams = new_nparams;
480 crtc->filter = new_filter;
481 crtc->filter_width = new_width;
482 crtc->filter_height = new_height;
483 crtc->bounds.x1 = 0;
484 crtc->bounds.x2 = crtc->mode.HDisplay;
485 crtc->bounds.y1 = 0;
486 crtc->bounds.y2 = crtc->mode.VDisplay;
487 pixman_f_transform_bounds(&f_crtc_to_fb, &crtc->bounds);
488
489 if (damage)
490 xf86CrtcDamageShadow(crtc);
491
492 /* All done */
493 return TRUE;
494}