arch/m68k-amiga: Provide a CopyBoxMasked() implementation
[AROS.git] / arch / m68k-amiga / hidd / gfx / blitter.c
blob712033ceb416451facb2e2f466d1a81cc7636106
2 #include <proto/exec.h>
3 #include <proto/graphics.h>
5 #include <exec/libraries.h>
6 #include <hardware/custom.h>
7 #include <hardware/intbits.h>
8 #include <hidd/graphics.h>
10 #include "amigavideogfx.h"
11 #include "amigavideobitmap.h"
12 #include "blitter.h"
14 #define DEBUG 0
15 #include <aros/debug.h>
17 #define ABC 0x80
18 #define ABNC 0x40
19 #define ANBC 0x20
20 #define ANBNC 0x10
21 #define NABC 0x08
22 #define NABNC 0x04
23 #define NANBC 0x02
24 #define NANBNC 0x01
26 static void startblitter(struct amigavideo_staticdata *data, UWORD w, UWORD h)
28 volatile struct Custom *custom = (struct Custom*)0xdff000;
30 if (data->ecs_agnus) {
31 custom->bltsizv = h;
32 custom->bltsizh = w;
33 } else {
34 if (h > 1024 || w > 64)
35 return;
36 custom->bltsize = (h << 6) | (w & 63);
39 static const UWORD leftmask[] = {
40 0xffff, 0x7fff, 0x3fff, 0x1fff,
41 0x0fff, 0x07ff, 0x03ff, 0x01ff,
42 0x00ff, 0x007f, 0x003f, 0x001f,
43 0x000f, 0x0007, 0x0003, 0x0001
45 static const UWORD rightmask[] = {
46 0x8000, 0xc000, 0xe000, 0xf000,
47 0xf800, 0xfc00, 0xfe00, 0xff00,
48 0xff80, 0xffc0, 0xffe0, 0xfff0,
49 0xfff8, 0xfffc, 0xfffe, 0xffff
52 static const UBYTE copy_minterm[] = { 0xff, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff };
53 // A-DAT = edge masking
54 // B = source
55 // C = destination
56 // D = destination
57 // 0: zero (->fillrect)
58 // 1: src AND dst /AC + ABC
59 // 2: src AND NOT dst /AC + AB/C
60 // 3: src /AC + AB
61 // 4: NOT src AND dst /AC + A/B/C
62 // 5: dst (nop)
63 // 6: src XOR dst /AC + A
64 // 7: copy source and blit thru mask
65 // 8:
66 // 9:
67 // 10: NOT dst (->fillrect)
68 // 11:
69 // 12:
70 // 13:
71 // 14:
72 // 15: one (->fillrect)
74 BOOL blit_copybox(struct amigavideo_staticdata *data, struct amigabm_data *srcbm, struct amigabm_data *dstbm,
75 WORD srcx, WORD srcy, WORD w, WORD h, WORD dstx, WORD dsty, HIDDT_DrawMode mode)
77 volatile struct Custom *custom = (struct Custom*)0xdff000;
78 struct GfxBase *GfxBase = data->gfxbase;
79 ULONG srcoffset, dstoffset;
80 BYTE shift, i;
81 WORD srcwidth, dstwidth, width;
82 WORD srcx2, dstx2;
83 UWORD shifta, shiftb;
84 UWORD afwm, alwm;
85 UWORD bltcon0;
86 BOOL reverse = FALSE;
87 BOOL intersect = FALSE;
89 if (USE_BLITTER == 0)
90 return FALSE;
92 srcx2 = srcx + w - 1;
93 dstx2 = dstx + w - 1;
94 if (copy_minterm[mode] == 0xff)
95 return blit_fillrect(data, dstbm, dstx, dsty, dstx2, dsty + h - 1, 0, mode);
97 if (copy_minterm[mode] == 0)
98 return FALSE;
100 //D(bug("%x %x %dx%d %dx%d %dx%d %d\n", srcbm, dstbm, srcx, srcy, dstx, dsty, w, h, mode));
102 if (srcbm == dstbm) {
103 intersect = !(srcx > dstx2 || srcx2 < dstx || srcy > dsty + h - 1 || srcy + h - 1 < dsty);
106 srcoffset = srcbm->bytesperrow * srcy + (srcx / 16) * 2;
107 dstoffset = dstbm->bytesperrow * dsty + (dstx / 16) * 2;
108 shift = (dstx & 15) - (srcx & 15);
110 if (intersect) {
111 // do we need >16 bit edge mask? (not handled yet)
112 if (dstoffset < srcoffset && shift < 0) // asc + desc
113 return FALSE;
114 if (dstoffset > srcoffset && shift > 0) // desc + asc
115 return FALSE;
118 if (shift < 0) {
119 reverse = TRUE;
120 shift = -shift;
121 } else if (intersect && dstoffset > srcoffset) {
122 reverse = TRUE;
125 srcwidth = srcx2 / 16 - srcx / 16 + 1;
126 dstwidth = dstx2 / 16 - dstx / 16 + 1;
127 srcx &= 15;
128 dstx &= 15;
129 dstx2 &= 15;
130 srcx2 &= 15;
132 if (reverse) {
133 if (dstwidth >= srcwidth) {
134 width = dstwidth;
135 shifta = 0;
136 shiftb = shift << 12;
137 alwm = leftmask[dstx];
138 afwm = rightmask[dstx2];
139 } else {
140 width = srcwidth;
141 shifta = shift << 12;
142 shiftb = shift << 12;
143 alwm = leftmask[srcx];
144 afwm = rightmask[srcx2];
146 srcoffset += srcbm->bytesperrow * (h - 1) + (width - 1) * 2;
147 dstoffset += dstbm->bytesperrow * (h - 1) + (width - 1) * 2;
148 } else {
149 if (dstwidth >= srcwidth) {
150 width = dstwidth;
151 shifta = 0;
152 shiftb = shift << 12;
153 afwm = leftmask[dstx];
154 alwm = rightmask[dstx2];
155 } else {
156 width = srcwidth;
157 shifta = shift << 12;
158 shiftb = shift << 12;
159 afwm = leftmask[srcx];
160 alwm = rightmask[srcx2];
164 //D(bug("shift=%d rev=%d sw=%d dw=%d %04x %04x\n", shift, reverse, srcwidth, dstwidth, afwm, alwm));
166 OwnBlitter();
167 WaitBlit();
169 custom->bltafwm = afwm;
170 custom->bltalwm = alwm;
171 custom->bltbmod = srcbm->bytesperrow - width * 2;
172 custom->bltcmod = dstbm->bytesperrow - width * 2;
173 custom->bltdmod = dstbm->bytesperrow - width * 2;
174 custom->bltcon1 = (reverse ? 0x0002 : 0x0000) | shiftb;
175 bltcon0 = 0x0700 | copy_minterm[mode] | shifta;
176 custom->bltadat = 0xffff;
178 for (i = 0; i < dstbm->depth; i++) {
179 UWORD bltcon0b = bltcon0;
180 if (dstbm->planes[i] == (UBYTE*)0x00000000 || dstbm->planes[i] == (UBYTE*)0xffffffff)
181 continue;
182 WaitBlit();
183 if (i >= srcbm->depth || srcbm->planes[i] == (UBYTE*)0x00000000) {
184 bltcon0b &= ~0x0400;
185 custom->bltbdat = 0x0000;
186 } else if (srcbm->planes[i] == (UBYTE*)0xffffffff) {
187 bltcon0b &= ~0x0400;
188 custom->bltbdat = 0xffff;
189 } else {
190 custom->bltbpt = (APTR)(srcbm->planes[i] + srcoffset);
192 custom->bltcon0 = bltcon0b;
193 custom->bltcpt = (APTR)(dstbm->planes[i] + dstoffset);
194 custom->bltdpt = (APTR)(dstbm->planes[i] + dstoffset);
195 startblitter(data, width, h);
198 WaitBlit();
199 DisownBlitter();
201 return TRUE;
204 BOOL blit_copybox_mask(struct amigavideo_staticdata *data, struct amigabm_data *srcbm, struct amigabm_data *dstbm,
205 WORD srcx, WORD srcy, WORD w, WORD h, WORD dstx, WORD dsty, HIDDT_DrawMode mode, APTR maskplane)
207 UBYTE *maskptr;
208 volatile struct Custom *custom = (struct Custom*)0xdff000;
209 struct GfxBase *GfxBase = data->gfxbase;
210 ULONG srcoffset, dstoffset;
211 BYTE shift, i;
212 WORD srcwidth, dstwidth, width;
213 WORD srcx2, dstx2;
214 UWORD bltshift;
215 UWORD afwm, alwm;
216 UWORD bltcon0;
217 BOOL reverse = FALSE;
218 BOOL intersect = FALSE;
220 if (USE_BLITTER == 0)
221 return FALSE;
223 srcx2 = srcx + w - 1;
224 dstx2 = dstx + w - 1;
226 D(bug("CopyBoxMasked %x %x %dx%d %dx%d %dx%d %d %x\n", srcbm, dstbm, srcx, srcy, dstx, dsty, w, h, mode, maskplane));
228 if (srcbm == dstbm) {
229 intersect = !(srcx > dstx2 || srcx2 < dstx || srcy > dsty + h - 1 || srcy + h - 1 < dsty);
232 srcoffset = srcbm->bytesperrow * srcy + (srcx / 16) * 2;
233 dstoffset = dstbm->bytesperrow * dsty + (dstx / 16) * 2;
234 shift = (dstx & 15) - (srcx & 15);
236 if (intersect) {
237 // do we need >16 bit edge mask? (not handled yet)
238 if (dstoffset < srcoffset && shift < 0) // asc + desc
239 return FALSE;
240 if (dstoffset > srcoffset && shift > 0) // desc + asc
241 return FALSE;
244 if (shift < 0) {
245 reverse = TRUE;
246 shift = -shift;
247 } else if (intersect && dstoffset > srcoffset) {
248 reverse = TRUE;
251 srcwidth = srcx2 / 16 - srcx / 16 + 1;
252 dstwidth = dstx2 / 16 - dstx / 16 + 1;
253 srcx &= 15;
254 dstx &= 15;
255 dstx2 &= 15;
256 srcx2 &= 15;
258 bltshift = shift << 12;
259 if (reverse) {
260 if (dstwidth > srcwidth) {
261 width = dstwidth;
262 alwm = 0xffff;
263 afwm = 0x0000;
264 } else {
265 width = srcwidth;
266 alwm = 0xffff;
267 afwm = 0xffff;
269 srcoffset += srcbm->bytesperrow * (h - 1) + (width - 1) * 2;
270 dstoffset += dstbm->bytesperrow * (h - 1) + (width - 1) * 2;
271 maskptr = (UBYTE*)maskplane + (h - 1) * (width - 1) * 2;
272 } else {
273 if (dstwidth > srcwidth) {
274 width = dstwidth;
275 afwm = 0xffff;
276 alwm = 0x0000;
277 } else {
278 width = srcwidth;
279 afwm = 0xffff;
280 alwm = 0xffff;
282 maskptr = maskplane;
285 D(bug("shift=%d rev=%d sw=%d dw=%d sbpr=%d %04x %04x\n", shift, reverse, srcwidth, dstwidth, srcbm->bytesperrow, afwm, alwm));
287 OwnBlitter();
288 WaitBlit();
290 custom->bltafwm = afwm;
291 custom->bltalwm = alwm;
292 custom->bltamod = srcbm->bytesperrow - dstwidth * 2;
293 custom->bltbmod = srcbm->bytesperrow - width * 2;
294 custom->bltcmod = dstbm->bytesperrow - width * 2;
295 custom->bltdmod = dstbm->bytesperrow - width * 2;
296 custom->bltcon1 = (reverse ? 0x0002 : 0x0000) | bltshift;
297 bltcon0 = 0x0f00 | 0x00ca | bltshift;
299 for (i = 0; i < dstbm->depth; i++) {
300 UWORD bltcon0b = bltcon0;
301 if (dstbm->planes[i] == (UBYTE*)0x00000000 || dstbm->planes[i] == (UBYTE*)0xffffffff)
302 continue;
303 WaitBlit();
304 if (i >= srcbm->depth || srcbm->planes[i] == (UBYTE*)0x00000000) {
305 bltcon0b &= ~0x0400;
306 custom->bltbdat = 0x0000;
307 } else if (srcbm->planes[i] == (UBYTE*)0xffffffff) {
308 bltcon0b &= ~0x0400;
309 custom->bltbdat = 0xffff;
310 } else {
311 custom->bltbpt = (APTR)(srcbm->planes[i] + srcoffset);
313 custom->bltcon0 = bltcon0b;
314 custom->bltapt = (APTR)maskptr;
315 custom->bltcpt = (APTR)(dstbm->planes[i] + dstoffset);
316 custom->bltdpt = (APTR)(dstbm->planes[i] + dstoffset);
317 startblitter(data, width, h);
320 WaitBlit();
321 DisownBlitter();
323 return TRUE;
326 static const UBYTE fill_minterm[] = { 0xca, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0xca };
328 // copy: /AC + AB = (NABC | NANBC) | (ABNC | ABC) = 0xCA
329 // invert: /AC + A/C = (NABC | NANBC) | (ABNC | ANBNC) = 0x5A
331 // A-DAT = edge masking
332 // B-DAT = pixel value (ones or zeros, not used when invert mode)
333 // C = source
334 // D = destination
336 BOOL blit_fillrect(struct amigavideo_staticdata *data, struct amigabm_data *bm, WORD x1,WORD y1,WORD x2,WORD y2, HIDDT_Pixel pixel, HIDDT_DrawMode mode)
338 volatile struct Custom *custom = (struct Custom*)0xdff000;
339 struct GfxBase *GfxBase = data->gfxbase;
340 ULONG offset;
341 WORD width, height;
342 UBYTE i;
344 if (USE_BLITTER == 0)
345 return FALSE;
347 D(bug("fillrect(%dx%d,%dx%d,%d,%d)\n", x1, y1, x2, y2, pixel, mode));
348 D(bug("bm = %dx%dx%d bpr=%d\n", bm->width, bm->height, bm->depth, bm->bytesperrow));
350 if (fill_minterm[mode] == 0)
351 return FALSE;
353 offset = bm->bytesperrow * y1 + (x1 / 16) * 2;
354 width = x2 / 16 - x1 / 16 + 1;
355 height = y2 - y1 + 1;
357 OwnBlitter();
358 WaitBlit();
360 custom->bltafwm = leftmask[x1 & 15];
361 custom->bltalwm = rightmask[x2 & 15];
362 custom->bltcmod = bm->bytesperrow - width * 2;
363 custom->bltdmod = bm->bytesperrow - width * 2;
364 custom->bltcon1 = 0x0000;
365 custom->bltcon0 = 0x0300 | fill_minterm[mode];
366 custom->bltadat = 0xffff;
368 if (mode == vHidd_GC_DrawMode_Clear)
369 pixel = 0x00;
370 else if (mode == vHidd_GC_DrawMode_Set)
371 pixel = 0xff;
373 for (i = 0; i < bm->depth; i++) {
374 if (bm->planes[i] != (UBYTE*)0x00000000 && bm->planes[i] != (UBYTE*)0xffffffff) {
375 WaitBlit();
376 custom->bltbdat = (pixel & 1) ? 0xffff : 0x0000;
377 custom->bltcpt = (APTR)(bm->planes[i] + offset);
378 custom->bltdpt = (APTR)(bm->planes[i] + offset);
379 startblitter(data, width, height);
381 pixel >>= 1;
384 WaitBlit();
385 DisownBlitter();
387 return TRUE;
390 #if 0
391 struct pHidd_BitMap_PutTemplate
393 OOP_MethodID mID;
394 OOP_Object *gc;
395 UBYTE *Template;
396 ULONG modulo;
397 WORD srcx;
398 WORD x, y;
399 WORD width, height;
400 BOOL inverttemplate;
402 #endif
404 // A-DAT = edge masking
405 // B = template
406 // C = destination
407 // D = destination
409 BOOL blit_puttemplate(struct amigavideo_staticdata *data, struct amigabm_data *bm, struct pHidd_BitMap_PutTemplate *tmpl)
411 volatile struct Custom *custom = (struct Custom*)0xdff000;
412 struct GfxBase *GfxBase = data->gfxbase;
413 OOP_Object *gc = tmpl->gc;
414 HIDDT_Pixel fgpen = GC_FG(tmpl->gc);
415 HIDDT_Pixel bgpen = GC_BG(tmpl->gc);
417 UBYTE type, i;
418 BYTE shift;
419 UWORD shifta, shiftb;
420 UWORD afwm, alwm;
421 ULONG srcoffset, dstoffset;
422 WORD width, srcwidth, dstwidth;
423 BOOL reverse;
424 WORD height = tmpl->height;
425 WORD dstx = tmpl->x;
426 WORD dsty = tmpl->y;
427 WORD dstx2 = tmpl->x + tmpl->width - 1;
428 WORD srcx = tmpl->srcx;
429 WORD srcx2 = srcx + tmpl->width - 1;
431 if (USE_BLITTER == 0)
432 return FALSE;
434 if (GC_COLEXP(gc) == vHidd_GC_ColExp_Transparent)
435 type = 0;
436 else if (GC_DRMD(gc) == vHidd_GC_DrawMode_Invert)
437 type = 2;
438 else
439 type = 4;
440 if (tmpl->inverttemplate)
441 type++;
443 D(bug("puttemplate: %x x=%d y=%d w=%d h=%d type=%d fg=%d bg=%d\n",
444 tmpl->Template, tmpl->x, tmpl->y, tmpl->width, tmpl->height, type, fgpen, bgpen));
446 srcoffset = 0;
447 dstoffset = bm->bytesperrow * dsty + (dstx / 16) * 2;
449 srcwidth = srcx2 / 16;
450 dstwidth = dstx2 / 16 - dstx / 16 + 1;
452 dstx &= 15;
453 dstx2 &= 15;
454 srcx &= 15;
455 srcx2 &= 15;
457 shift = dstx - srcx;
458 if (shift < 0) {
459 reverse = TRUE;
460 shift = -shift;
461 if (dstwidth >= srcwidth) {
462 width = dstwidth;
463 shifta = 0;
464 shiftb = shift << 12;
465 alwm = leftmask[dstx];
466 afwm = rightmask[dstx2];
467 } else {
468 width = srcwidth;
469 shifta = shift << 12;
470 shiftb = shift << 12;
471 alwm = leftmask[srcx];
472 afwm = rightmask[srcx2];
474 srcoffset += tmpl->modulo * (height - 1) + (width - 1) * 2;
475 dstoffset += bm->bytesperrow * (height - 1) + (width - 1) * 2;
476 } else {
477 reverse = FALSE;
478 if (dstwidth >= srcwidth) {
479 width = dstwidth;
480 shifta = 0;
481 shiftb = shift << 12;
482 afwm = leftmask[dstx];
483 alwm = rightmask[dstx2];
484 } else {
485 width = srcwidth;
486 shifta = shift << 12;
487 shiftb = shift << 12;
488 afwm = leftmask[srcx];
489 alwm = rightmask[srcx2];
493 OwnBlitter();
494 WaitBlit();
496 custom->bltafwm = afwm;
497 custom->bltalwm = alwm;
498 custom->bltbmod = tmpl->modulo - width * 2;
499 custom->bltcmod = bm->bytesperrow - width * 2;
500 custom->bltdmod = bm->bytesperrow - width * 2;
501 custom->bltadat = 0xffff;
503 for (i = 0; i < bm->depth; i++) {
504 UBYTE minterm;
505 UWORD chmask, shiftbv;
506 UBYTE fg, bg, tg;
508 fg = fgpen & 1;
509 bg = bgpen & 1;
510 fgpen >>= 1;
511 bgpen >>= 1;
513 if (bm->planes[i] == (UBYTE*)0x00000000 || bm->planes[i] == (UBYTE*)0xffffffff)
514 continue;
516 chmask = 0x0700;
517 shiftbv = shiftb;
519 /* not guaranteed to be correct, last time I played with minterms
520 * was something like 20 years ago..
522 switch (type)
524 case 0: // JAM1:
525 minterm = (NABC | NANBC) | (fg ? ABC | ABNC | ANBC : ANBC);
526 break;
527 case 1: // JAM1 | INVERSVID
528 minterm = (NABC | NANBC) | (fg ? ANBC | ANBNC | ABC : ABC);
529 break;
530 case 2: // COMPLEMENT:
531 minterm = (NABC | NANBC) | (ANBC | ABNC);
532 break;
533 case 3: // COMPLEMENT | INVERSVID:
534 minterm = (NABC | NANBC) | (ABC | ANBNC);
535 break;
536 case 5: // JAM2 | INVERSVID
537 tg = fg;
538 fg = bg;
539 bg = tg;
540 case 4: // JAM2
541 if (fg && bg) {
542 minterm = (NABC | NANBC) | (ABC | ABNC);
543 chmask = 0x0300;
544 shiftbv = 0;
545 } else if (!fg && !bg) {
546 minterm = (NABC | NANBC);
547 chmask = 0x0300;
548 shiftbv = 0;
549 } else if (fg) {
550 minterm = (NABC | NANBC) | (ABC | ABNC);
551 } else {
552 minterm = (NABC | NANBC) | (ANBC | ANBNC);
554 break;
557 WaitBlit();
558 custom->bltcon0 = shifta | chmask | minterm;
559 custom->bltcon1 = (reverse ? 0x0002 : 0x0000) | shiftbv;
560 custom->bltbdat = 0xffff;
561 custom->bltbpt = (APTR)(tmpl->Template + srcoffset);
562 custom->bltcpt = (APTR)(bm->planes[i] + dstoffset);
563 custom->bltdpt = (APTR)(bm->planes[i] + dstoffset);
564 startblitter(data, width, height);
567 WaitBlit();
568 DisownBlitter();
570 return TRUE;
573 BOOL blit_putpattern(struct amigavideo_staticdata *csd, struct amigabm_data *bm, struct pHidd_BitMap_PutPattern *pat)
575 UBYTE type;
576 UBYTE fg = GC_FG(pat->gc);
577 UBYTE bg = GC_BG(pat->gc);
579 /* These are unused for the moment. */
580 (void)fg;
581 (void)bg;
583 if (USE_BLITTER == 0 || 1)
584 return FALSE;
586 if (pat->mask)
587 return FALSE;
588 if (pat->patterndepth > 1)
589 return FALSE;
591 if (GC_COLEXP(pat->gc) == vHidd_GC_ColExp_Transparent)
592 type = 0;
593 else if (GC_DRMD(pat->gc) == vHidd_GC_DrawMode_Invert)
594 type = 2;
595 else
596 type = 4;
597 if (pat->invertpattern)
598 type++;
600 return FALSE;