Add patch that contain Mali fixes.
[deb_xorg-server.git] / fb / fbseg.c
1 /*
2 * Copyright © 1998 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Keith Packard makes no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23 #ifdef HAVE_DIX_CONFIG_H
24 #include <dix-config.h>
25 #endif
26
27 #include <stdlib.h>
28
29 #include "fb.h"
30 #include "miline.h"
31
32 #define fbBresShiftMask(mask,dir,bpp) ((bpp == FB_STIP_UNIT) ? 0 : \
33 ((dir < 0) ? FbStipLeft(mask,bpp) : \
34 FbStipRight(mask,bpp)))
35
36 void
37 fbBresSolid(DrawablePtr pDrawable,
38 GCPtr pGC,
39 int dashOffset,
40 int signdx,
41 int signdy,
42 int axis, int x1, int y1, int e, int e1, int e3, int len)
43 {
44 FbStip *dst;
45 FbStride dstStride;
46 int dstBpp;
47 int dstXoff, dstYoff;
48 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
49 FbStip and = (FbStip) pPriv->and;
50 FbStip xor = (FbStip) pPriv->xor;
51 FbStip mask, mask0;
52 FbStip bits;
53
54 fbGetStipDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
55 dst += ((y1 + dstYoff) * dstStride);
56 x1 = (x1 + dstXoff) * dstBpp;
57 dst += x1 >> FB_STIP_SHIFT;
58 x1 &= FB_STIP_MASK;
59 mask0 = FbStipMask(0, dstBpp);
60 mask = FbStipRight(mask0, x1);
61 if (signdx < 0)
62 mask0 = FbStipRight(mask0, FB_STIP_UNIT - dstBpp);
63 if (signdy < 0)
64 dstStride = -dstStride;
65 if (axis == X_AXIS) {
66 bits = 0;
67 while (len--) {
68 if (e >= 0) {
69 WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, bits));
70 bits = 0;
71 dst += dstStride;
72 e += e3;
73 }
74 bits |= mask;
75 mask = fbBresShiftMask(mask, signdx, dstBpp);
76 if (!mask) {
77 WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits));
78 bits = 0;
79 dst += signdx;
80 mask = mask0;
81 }
82 e += e1;
83 }
84 if (bits)
85 WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits));
86 }
87 else {
88 while (len--) {
89 if (e >= 0) {
90 e += e3;
91 mask = fbBresShiftMask(mask, signdx, dstBpp);
92 if (!mask) {
93 dst += signdx;
94 mask = mask0;
95 }
96 }
97 WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, mask));
98 dst += dstStride;
99 e += e1;
100 }
101 }
102
103 fbFinishAccess(pDrawable);
104 }
105
106 void
107 fbBresDash(DrawablePtr pDrawable,
108 GCPtr pGC,
109 int dashOffset,
110 int signdx,
111 int signdy, int axis, int x1, int y1, int e, int e1, int e3, int len)
112 {
113 FbStip *dst;
114 FbStride dstStride;
115 int dstBpp;
116 int dstXoff, dstYoff;
117 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
118 FbStip and = (FbStip) pPriv->and;
119 FbStip xor = (FbStip) pPriv->xor;
120 FbStip bgand = (FbStip) pPriv->bgand;
121 FbStip bgxor = (FbStip) pPriv->bgxor;
122 FbStip mask, mask0;
123
124 FbDashDeclare;
125 int dashlen;
126 Bool even;
127 Bool doOdd;
128
129 fbGetStipDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
130 doOdd = pGC->lineStyle == LineDoubleDash;
131
132 FbDashInit(pGC, pPriv, dashOffset, dashlen, even);
133
134 dst += ((y1 + dstYoff) * dstStride);
135 x1 = (x1 + dstXoff) * dstBpp;
136 dst += x1 >> FB_STIP_SHIFT;
137 x1 &= FB_STIP_MASK;
138 mask0 = FbStipMask(0, dstBpp);
139 mask = FbStipRight(mask0, x1);
140 if (signdx < 0)
141 mask0 = FbStipRight(mask0, FB_STIP_UNIT - dstBpp);
142 if (signdy < 0)
143 dstStride = -dstStride;
144 while (len--) {
145 if (even)
146 WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, mask));
147 else if (doOdd)
148 WRITE(dst, FbDoMaskRRop(READ(dst), bgand, bgxor, mask));
149 if (axis == X_AXIS) {
150 mask = fbBresShiftMask(mask, signdx, dstBpp);
151 if (!mask) {
152 dst += signdx;
153 mask = mask0;
154 }
155 e += e1;
156 if (e >= 0) {
157 dst += dstStride;
158 e += e3;
159 }
160 }
161 else {
162 dst += dstStride;
163 e += e1;
164 if (e >= 0) {
165 e += e3;
166 mask = fbBresShiftMask(mask, signdx, dstBpp);
167 if (!mask) {
168 dst += signdx;
169 mask = mask0;
170 }
171 }
172 }
173 FbDashStep(dashlen, even);
174 }
175
176 fbFinishAccess(pDrawable);
177 }
178
179 void
180 fbBresFill(DrawablePtr pDrawable,
181 GCPtr pGC,
182 int dashOffset,
183 int signdx,
184 int signdy, int axis, int x1, int y1, int e, int e1, int e3, int len)
185 {
186 while (len--) {
187 fbFill(pDrawable, pGC, x1, y1, 1, 1);
188 if (axis == X_AXIS) {
189 x1 += signdx;
190 e += e1;
191 if (e >= 0) {
192 e += e3;
193 y1 += signdy;
194 }
195 }
196 else {
197 y1 += signdy;
198 e += e1;
199 if (e >= 0) {
200 e += e3;
201 x1 += signdx;
202 }
203 }
204 }
205 }
206
207 static void
208 fbSetFg(DrawablePtr pDrawable, GCPtr pGC, Pixel fg)
209 {
210 if (fg != pGC->fgPixel) {
211 ChangeGCVal val;
212
213 val.val = fg;
214 ChangeGC(NullClient, pGC, GCForeground, &val);
215 ValidateGC(pDrawable, pGC);
216 }
217 }
218
219 void
220 fbBresFillDash(DrawablePtr pDrawable,
221 GCPtr pGC,
222 int dashOffset,
223 int signdx,
224 int signdy,
225 int axis, int x1, int y1, int e, int e1, int e3, int len)
226 {
227 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
228
229 FbDashDeclare;
230 int dashlen;
231 Bool even;
232 Bool doOdd;
233 Bool doBg;
234 Pixel fg, bg;
235
236 fg = pGC->fgPixel;
237 bg = pGC->bgPixel;
238
239 /* whether to fill the odd dashes */
240 doOdd = pGC->lineStyle == LineDoubleDash;
241 /* whether to switch fg to bg when filling odd dashes */
242 doBg = doOdd && (pGC->fillStyle == FillSolid ||
243 pGC->fillStyle == FillStippled);
244
245 /* compute current dash position */
246 FbDashInit(pGC, pPriv, dashOffset, dashlen, even);
247
248 while (len--) {
249 if (even || doOdd) {
250 if (doBg) {
251 if (even)
252 fbSetFg(pDrawable, pGC, fg);
253 else
254 fbSetFg(pDrawable, pGC, bg);
255 }
256 fbFill(pDrawable, pGC, x1, y1, 1, 1);
257 }
258 if (axis == X_AXIS) {
259 x1 += signdx;
260 e += e1;
261 if (e >= 0) {
262 e += e3;
263 y1 += signdy;
264 }
265 }
266 else {
267 y1 += signdy;
268 e += e1;
269 if (e >= 0) {
270 e += e3;
271 x1 += signdx;
272 }
273 }
274 FbDashStep(dashlen, even);
275 }
276 if (doBg)
277 fbSetFg(pDrawable, pGC, fg);
278 }
279
280 static void
281 fbBresSolid24RRop(DrawablePtr pDrawable,
282 GCPtr pGC,
283 int dashOffset,
284 int signdx,
285 int signdy,
286 int axis, int x1, int y1, int e, int e1, int e3, int len)
287 {
288 FbStip *dst;
289 FbStride dstStride;
290 int dstBpp;
291 int dstXoff, dstYoff;
292 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
293 FbStip and = pPriv->and;
294 FbStip xor = pPriv->xor;
295 FbStip leftMask, rightMask;
296 int nl;
297 FbStip *d;
298 int x;
299 int rot;
300 FbStip andT, xorT;
301
302 fbGetStipDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
303 dst += ((y1 + dstYoff) * dstStride);
304 x1 = (x1 + dstXoff) * 24;
305 if (signdy < 0)
306 dstStride = -dstStride;
307 signdx *= 24;
308 while (len--) {
309 d = dst + (x1 >> FB_STIP_SHIFT);
310 x = x1 & FB_STIP_MASK;
311 rot = FbFirst24Rot(x);
312 andT = FbRot24Stip(and, rot);
313 xorT = FbRot24Stip(xor, rot);
314 FbMaskStip(x, 24, leftMask, nl, rightMask);
315 if (leftMask) {
316 WRITE(d, FbDoMaskRRop(READ(d), andT, xorT, leftMask));
317 d++;
318 andT = FbNext24Stip(andT);
319 xorT = FbNext24Stip(xorT);
320 }
321 if (rightMask)
322 WRITE(d, FbDoMaskRRop(READ(d), andT, xorT, rightMask));
323 if (axis == X_AXIS) {
324 x1 += signdx;
325 e += e1;
326 if (e >= 0) {
327 e += e3;
328 dst += dstStride;
329 }
330 }
331 else {
332 dst += dstStride;
333 e += e1;
334 if (e >= 0) {
335 e += e3;
336 x1 += signdx;
337 }
338 }
339 }
340
341 fbFinishAccess(pDrawable);
342 }
343
344 static void
345 fbBresDash24RRop(DrawablePtr pDrawable,
346 GCPtr pGC,
347 int dashOffset,
348 int signdx,
349 int signdy,
350 int axis, int x1, int y1, int e, int e1, int e3, int len)
351 {
352 FbStip *dst;
353 FbStride dstStride;
354 int dstBpp;
355 int dstXoff, dstYoff;
356 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
357 FbStip andT, xorT;
358 FbStip fgand = pPriv->and;
359 FbStip fgxor = pPriv->xor;
360 FbStip bgand = pPriv->bgand;
361 FbStip bgxor = pPriv->bgxor;
362 FbStip leftMask, rightMask;
363 int nl;
364 FbStip *d;
365 int x;
366 int rot;
367
368 FbDashDeclare;
369 int dashlen;
370 Bool even;
371 Bool doOdd;
372
373 fbGetStipDrawable(pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
374 doOdd = pGC->lineStyle == LineDoubleDash;
375
376 /* compute current dash position */
377 FbDashInit(pGC, pPriv, dashOffset, dashlen, even);
378
379 dst += ((y1 + dstYoff) * dstStride);
380 x1 = (x1 + dstXoff) * 24;
381 if (signdy < 0)
382 dstStride = -dstStride;
383 signdx *= 24;
384 while (len--) {
385 if (even || doOdd) {
386 if (even) {
387 andT = fgand;
388 xorT = fgxor;
389 }
390 else {
391 andT = bgand;
392 xorT = bgxor;
393 }
394 d = dst + (x1 >> FB_STIP_SHIFT);
395 x = x1 & FB_STIP_MASK;
396 rot = FbFirst24Rot(x);
397 andT = FbRot24Stip(andT, rot);
398 xorT = FbRot24Stip(xorT, rot);
399 FbMaskStip(x, 24, leftMask, nl, rightMask);
400 if (leftMask) {
401 WRITE(d, FbDoMaskRRop(READ(d), andT, xorT, leftMask));
402 d++;
403 andT = FbNext24Stip(andT);
404 xorT = FbNext24Stip(xorT);
405 }
406 if (rightMask)
407 WRITE(d, FbDoMaskRRop(READ(d), andT, xorT, rightMask));
408 }
409 if (axis == X_AXIS) {
410 x1 += signdx;
411 e += e1;
412 if (e >= 0) {
413 e += e3;
414 dst += dstStride;
415 }
416 }
417 else {
418 dst += dstStride;
419 e += e1;
420 if (e >= 0) {
421 e += e3;
422 x1 += signdx;
423 }
424 }
425 FbDashStep(dashlen, even);
426 }
427
428 fbFinishAccess(pDrawable);
429 }
430
431 /*
432 * For drivers that want to bail drawing some lines, this
433 * function takes care of selecting the appropriate rasterizer
434 * based on the contents of the specified GC.
435 */
436
437 FbBres *
438 fbSelectBres(DrawablePtr pDrawable, GCPtr pGC)
439 {
440 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
441 int dstBpp = pDrawable->bitsPerPixel;
442 FbBres *bres;
443
444 if (pGC->lineStyle == LineSolid) {
445 bres = fbBresFill;
446 if (pGC->fillStyle == FillSolid) {
447 bres = fbBresSolid;
448 if (dstBpp == 24)
449 bres = fbBresSolid24RRop;
450 if (pPriv->and == 0) {
451 switch (dstBpp) {
452 case 8:
453 bres = fbBresSolid8;
454 break;
455 case 16:
456 bres = fbBresSolid16;
457 break;
458 case 24:
459 bres = fbBresSolid24;
460 break;
461 case 32:
462 bres = fbBresSolid32;
463 break;
464 }
465 }
466 }
467 }
468 else {
469 bres = fbBresFillDash;
470 if (pGC->fillStyle == FillSolid) {
471 bres = fbBresDash;
472 if (dstBpp == 24)
473 bres = fbBresDash24RRop;
474 if (pPriv->and == 0 &&
475 (pGC->lineStyle == LineOnOffDash || pPriv->bgand == 0)) {
476 switch (dstBpp) {
477 case 8:
478 bres = fbBresDash8;
479 break;
480 case 16:
481 bres = fbBresDash16;
482 break;
483 case 24:
484 bres = fbBresDash24;
485 break;
486 case 32:
487 bres = fbBresDash32;
488 break;
489 }
490 }
491 }
492 }
493 return bres;
494 }
495
496 void
497 fbBres(DrawablePtr pDrawable,
498 GCPtr pGC,
499 int dashOffset,
500 int signdx,
501 int signdy, int axis, int x1, int y1, int e, int e1, int e3, int len)
502 {
503 (*fbSelectBres(pDrawable, pGC)) (pDrawable, pGC, dashOffset,
504 signdx, signdy, axis, x1, y1,
505 e, e1, e3, len);
506 }
507
508 void
509 fbSegment(DrawablePtr pDrawable,
510 GCPtr pGC,
511 int x1, int y1, int x2, int y2, Bool drawLast, int *dashOffset)
512 {
513 FbBres *bres;
514 RegionPtr pClip = fbGetCompositeClip(pGC);
515 BoxPtr pBox;
516 int nBox;
517 int adx; /* abs values of dx and dy */
518 int ady;
519 int signdx; /* sign of dx and dy */
520 int signdy;
521 int e, e1, e2, e3; /* bresenham error and increments */
522 int len; /* length of segment */
523 int axis; /* major axis */
524 int octant;
525 int dashoff;
526 int doff;
527 unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
528 unsigned int oc1; /* outcode of point 1 */
529 unsigned int oc2; /* outcode of point 2 */
530
531 nBox = RegionNumRects(pClip);
532 pBox = RegionRects(pClip);
533
534 bres = fbSelectBres(pDrawable, pGC);
535
536 CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy, 1, 1, octant);
537
538 if (adx > ady) {
539 axis = X_AXIS;
540 e1 = ady << 1;
541 e2 = e1 - (adx << 1);
542 e = e1 - adx;
543 len = adx;
544 }
545 else {
546 axis = Y_AXIS;
547 e1 = adx << 1;
548 e2 = e1 - (ady << 1);
549 e = e1 - ady;
550 SetYMajorOctant(octant);
551 len = ady;
552 }
553
554 FIXUP_ERROR(e, octant, bias);
555
556 /*
557 * Adjust error terms to compare against zero
558 */
559 e3 = e2 - e1;
560 e = e - e1;
561
562 /* we have bresenham parameters and two points.
563 all we have to do now is clip and draw.
564 */
565
566 if (drawLast)
567 len++;
568 dashoff = *dashOffset;
569 *dashOffset = dashoff + len;
570 while (nBox--) {
571 oc1 = 0;
572 oc2 = 0;
573 OUTCODES(oc1, x1, y1, pBox);
574 OUTCODES(oc2, x2, y2, pBox);
575 if ((oc1 | oc2) == 0) {
576 (*bres) (pDrawable, pGC, dashoff,
577 signdx, signdy, axis, x1, y1, e, e1, e3, len);
578 break;
579 }
580 else if (oc1 & oc2) {
581 pBox++;
582 }
583 else {
584 int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
585 int clip1 = 0, clip2 = 0;
586 int clipdx, clipdy;
587 int err;
588
589 if (miZeroClipLine(pBox->x1, pBox->y1, pBox->x2 - 1,
590 pBox->y2 - 1,
591 &new_x1, &new_y1, &new_x2, &new_y2,
592 adx, ady, &clip1, &clip2,
593 octant, bias, oc1, oc2) == -1) {
594 pBox++;
595 continue;
596 }
597
598 if (axis == X_AXIS)
599 len = abs(new_x2 - new_x1);
600 else
601 len = abs(new_y2 - new_y1);
602 if (clip2 != 0 || drawLast)
603 len++;
604 if (len) {
605 /* unwind bresenham error term to first point */
606 doff = dashoff;
607 err = e;
608 if (clip1) {
609 clipdx = abs(new_x1 - x1);
610 clipdy = abs(new_y1 - y1);
611 if (axis == X_AXIS) {
612 doff += clipdx;
613 err += e3 * clipdy + e1 * clipdx;
614 }
615 else {
616 doff += clipdy;
617 err += e3 * clipdx + e1 * clipdy;
618 }
619 }
620 (*bres) (pDrawable, pGC, doff,
621 signdx, signdy, axis, new_x1, new_y1,
622 err, e1, e3, len);
623 }
624 pBox++;
625 }
626 } /* while (nBox--) */
627 }