2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
6 #include <proto/exec.h>
7 #include <proto/graphics.h>
10 #include <exec/libraries.h>
11 #include <hardware/custom.h>
12 #include <hardware/intbits.h>
13 #include <hardware/cia.h>
14 #include <hidd/graphics.h>
15 #include <graphics/modeid.h>
17 #include "amigavideogfx.h"
18 #include "amigavideobitmap.h"
22 #include <aros/debug.h>
24 static const UBYTE fetchunits
[] = { 3,3,3,0, 4,3,3,0, 5,4,3,0 };
25 static const UBYTE fm_maxplanes
[] = { 3,2,1,0, 3,3,2,0, 3,3,3,0 };
27 /* reset to OCS defaults */
28 void resetcustom(struct amigavideo_staticdata
*data
)
30 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
31 struct GfxBase
*GfxBase
= (APTR
)data
->cs_GfxBase
;
33 custom
->fmode
= 0x0000;
34 custom
->bplcon0
= 0x0200;
35 custom
->bplcon1
= 0x0000;
36 custom
->bplcon2
= 0x0024;
37 custom
->bplcon3
= 0x0c00;
38 custom
->bplcon4
= 0x0011;
39 custom
->vposw
= 0x8000;
40 custom
->color
[0] = 0x0444;
42 // Use AGA modes and create AGA copperlists only if AGA is "enabled"
43 data
->aga_enabled
= data
->aga
&& GfxBase
->ChipRevBits0
== SETCHIPREV_AA
;
46 static void waitvblank(struct amigavideo_staticdata
*data
)
48 // ugly busy loop for now..
49 UWORD fc
= data
->framecounter
;
50 while (fc
== data
->framecounter
);
53 static void setnullsprite(struct amigavideo_staticdata
*data
)
55 if (data
->copper1_spritept
) {
56 UWORD
*p
= data
->sprite_null
;
57 data
->copper1_spritept
[0] = (UWORD
)(((ULONG
)p
) >> 16);
58 data
->copper1_spritept
[2] = (UWORD
)(((ULONG
)p
) >> 0);
62 void resetsprite(struct amigavideo_staticdata
*data
)
64 UWORD
*sprite
= data
->sprite
;
67 FreeMem(sprite
, data
->spritedatasize
);
68 data
->sprite_width
= data
->sprite_height
= 0;
71 static void setfmode(struct amigavideo_staticdata
*data
)
74 fmode
= data
->fmode_bpl
== 2 ? 3 : data
->fmode_bpl
;
75 fmode
|= (data
->fmode_spr
== 2 ? 3 : data
->fmode_spr
) << 2;
76 if (data
->copper2
.copper2_fmode
) {
77 *data
->copper2
.copper2_fmode
= fmode
;
79 *data
->copper2i
.copper2_fmode
= fmode
;
83 static void setcoppercolors(struct amigavideo_staticdata
*data
)
87 if (!data
->copper2
.copper2_palette
)
89 if (data
->aga
&& data
->aga_enabled
) {
91 for (i
= 0; i
< data
->use_colors
; i
++) {
93 UBYTE r
= data
->palette
[i
* 3 + 0];
94 UBYTE g
= data
->palette
[i
* 3 + 1];
95 UBYTE b
= data
->palette
[i
* 3 + 2];
98 valhi
= ((r
& 0xf0) << 4) | ((g
& 0xf0)) | ((b
& 0xf0) >> 4);
99 vallo
= ((r
& 0x0f) << 8) | ((g
& 0x0f) << 4) | ((b
& 0x0f));
100 data
->copper2
.copper2_palette
[i
* 2 + off
] = valhi
;
101 data
->copper2
.copper2_palette_aga_lo
[i
* 2 + off
] = vallo
;
102 if (data
->interlace
) {
103 data
->copper2i
.copper2_palette
[i
* 2 + off
] = valhi
;
104 data
->copper2i
.copper2_palette_aga_lo
[i
* 2 + off
] = vallo
;
107 } else if (data
->res
== 2 && !data
->aga
) {
108 /* ECS "scrambled" superhires */
109 for (i
= 0; i
< data
->use_colors
; i
++) {
110 UBYTE offset
= i
< 16 ? 0 : 16;
111 UBYTE c1
= (i
& 3) + offset
;
112 UBYTE c2
= ((i
>> 2) & 3) + offset
;
113 UWORD val1
= ((data
->palette
[c1
* 3 + 0] >> 4) << 8) | ((data
->palette
[c1
* 3 + 1] >> 4) << 4) | ((data
->palette
[c1
* 3 + 2] >> 4) << 0);
114 UWORD val2
= ((data
->palette
[c2
* 3 + 0] >> 4) << 8) | ((data
->palette
[c2
* 3 + 1] >> 4) << 4) | ((data
->palette
[c2
* 3 + 2] >> 4) << 0);
115 UWORD val
= (val1
& 0xccc) | ((val2
& 0xccc) >> 2);
116 data
->copper2
.copper2_palette
[i
* 2 + 1] = val
;
118 data
->copper2i
.copper2_palette
[i
* 2 + 1] = val
;
122 for (i
= 0; i
< data
->use_colors
; i
++) {
123 UWORD val
= ((data
->palette
[i
* 3 + 0] >> 4) << 8) | ((data
->palette
[i
* 3 + 1] >> 4) << 4) | ((data
->palette
[i
* 3 + 2] >> 4) << 0);
124 data
->copper2
.copper2_palette
[i
* 2 + 1] = val
;
126 data
->copper2i
.copper2_palette
[i
* 2 + 1] = val
;
131 static void setpalntsc(struct amigavideo_staticdata
*data
, ULONG modeid
)
133 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
134 struct GfxBase
*GfxBase
= (APTR
)data
->cs_GfxBase
;
136 data
->palmode
= (GfxBase
->DisplayFlags
& NTSC
) == 0;
137 if (!data
->ecs_agnus
)
139 if ((modeid
& MONITOR_ID_MASK
) == PAL_MONITOR_ID
) {
140 custom
->beamcon0
= 0x0020;
141 data
->palmode
= TRUE
;
142 } else if ((modeid
& MONITOR_ID_MASK
) == NTSC_MONITOR_ID
) {
143 custom
->beamcon0
= 0x0000;
144 data
->palmode
= FALSE
;
146 custom
->beamcon0
= (GfxBase
->DisplayFlags
& NTSC
) ? 0x0000 : 0x0020;
150 void resetmode(struct amigavideo_staticdata
*data
)
152 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
153 struct GfxBase
*GfxBase
= (APTR
)data
->cs_GfxBase
;
155 D(bug("resetmode\n"));
159 custom
->dmacon
= 0x0100;
162 custom
->cop2lc
= (ULONG
)data
->copper2_backup
;
167 FreeVec(data
->copper2
.copper2
);
168 data
->copper2
.copper2
= NULL
;
169 FreeVec(data
->copper2i
.copper2
);
170 data
->copper2i
.copper2
= NULL
;
172 GfxBase
->LOFlist
= GfxBase
->SHFlist
= data
->copper2_backup
;
179 /* Use nominal screen height. Overscan is not supported yet. */
180 static WORD
limitheight(struct amigavideo_staticdata
*data
, WORD y
, BOOL lace
, BOOL maxlimit
)
185 if (maxlimit
&& y
> 311)
187 else if (!maxlimit
&& y
> 256)
190 if (maxlimit
&& y
> 261)
192 else if (!maxlimit
&& y
> 200)
200 static void setcopperscroll2(struct amigavideo_staticdata
*data
, struct amigabm_data
*bm
, struct copper2data
*c2d
, BOOL odd
)
202 UWORD
*copptr
= c2d
->copper2_scroll
, *copbpl
;
203 WORD xscroll
, yscroll
;
205 WORD ystart
, yend
, i
, xdelay
;
206 WORD xmaxscroll
, modulo
, ddfstrt
, fmodewidth
, minearly
;
209 fmodewidth
= 16 << data
->fmode_bpl
;
211 y
= data
->starty
+ (bm
->topedge
>> data
->interlace
);
219 xmaxscroll
= 1 << (1 + data
->fmode_bpl
);
220 xdelay
= x
& (fmodewidth
- 1);
223 yend
= y
+ (bm
->displayheight
>> data
->interlace
);
224 yend
= limitheight(data
, yend
, FALSE
, TRUE
);
225 ystart
= y
- data
->extralines
;
227 modulo
= (data
->interlace
? bm
->bytesperrow
: 0) + data
->modulo
;
228 ddfstrt
= data
->ddfstrt
;
230 offset
= ((xscroll
+ (xmaxscroll
<< 3) - 1) >> 3) & ~(xmaxscroll
- 1);
231 offset
-= (yscroll
* bm
->bytesperrow
) << (data
->interlace
? 1 : 0);
233 minearly
= 1 << fetchunits
[data
->fmode_bpl
* 4 + data
->res
];
236 modulo
-= (minearly
<< data
->res
) / 4;
237 offset
-= (minearly
<< data
->res
) / 4;
240 copptr
[1] = (y
<< 8) | (data
->startx
); //(y << 8) + (x + 1);
241 copptr
[3] = (yend
<< 8) | ((data
->startx
+ 0x140) & 0xff); //((y + (bm->rows >> data->interlace)) << 8) + ((x + 1 + (bm->width >> data->res)) & 0x00ff);
242 copptr
[5] = ((y
>> 8) & 7) | (((yend
>> 8) & 7) << 8) | 0x2000;
244 copbpl
= c2d
->copper2_bpl
;
245 for (i
= 0; i
< bm
->depth
; i
++) {
246 ULONG pptr
= (ULONG
)(bm
->pbm
->Planes
[data
->bploffsets
[i
]]);
247 if (data
->interlace
&& odd
)
248 pptr
+= bm
->bytesperrow
;
250 copbpl
[1] = (UWORD
)(pptr
>> 16);
251 copbpl
[3] = (UWORD
)(pptr
>> 0);
255 xdelay
<<= 2 - data
->res
;
257 (((xdelay
>> 2) & 0x0f) << 0) | (((xdelay
>> 2) & 0x0f) << 4)
258 | ((xdelay
>> 6) << 10) | ((xdelay
>> 6) << 14)
259 | ((xdelay
& 3) << 8) | ((xdelay
& 3) << 12);
262 copptr
[9] = data
->ddfstop
;
266 yend
= y
+ bm
->displayheight
+ yscroll
;
267 yend
= limitheight(data
, yend
, FALSE
, TRUE
);
268 copptr
= c2d
->copper2_bplcon0
;
269 copptr
[4] = (yend
<< 8) | 0x05;
270 if (yend
< 256 || ystart
>= 256) {
278 copptr
= c2d
->copper2
;
283 copptr
[2] = (ystart
<< 8) | 0x05;
284 copptr
= c2d
->copper2_bplcon0
;
285 copptr
[-2] = (y
<< 8) | 0x05;
288 static void setcopperscroll(struct amigavideo_staticdata
*data
, struct amigabm_data
*bm
)
290 setcopperscroll2(data
, bm
, &data
->copper2
, FALSE
);
292 setcopperscroll2(data
, bm
, &data
->copper2i
, TRUE
);
295 static UWORD
get_copper_list_length(struct amigavideo_staticdata
*data
, UBYTE depth
)
299 if (data
->aga
&& data
->aga_enabled
) {
300 v
= 1000 + ((1 << depth
) + 1 + (1 << depth
) / 32 + 1) * 2;
307 static void createcopperlist(struct amigavideo_staticdata
*data
, struct amigabm_data
*bm
, struct copper2data
*c2d
, BOOL lace
)
311 UWORD bplcon0
, bplcon0_res
;
315 D(bug("Copperlist%d %p\n", lace
? 2 : 1, c
));
318 bplcon0_res
= 0x8000;
319 else if (data
->res
== 2)
320 bplcon0_res
= 0x0040;
324 data
->bplcon0_null
= 0x0201 | (data
->interlace
? 4 : 0) | bplcon0_res
;
325 data
->bplcon3
= ((data
->sprite_res
+ 1) << 6) | 2; // spriteres + bordersprite
333 *c
++ = data
->bplcon0_null
;
335 c2d
->copper2_bpl
= c
;
336 for (i
= 0; i
< bm
->depth
; i
++) {
337 pptr
= (ULONG
)(bm
->pbm
->Planes
[data
->bploffsets
[i
]]);
339 pptr
+= bm
->bytesperrow
;
341 *c
++ = (UWORD
)(pptr
>> 16);
343 *c
++ = (UWORD
)(pptr
>> 0);
346 data
->use_colors
= 1 << bm
->depth
;
347 // need to update sprite colors
348 if (data
->use_colors
< 16 + 4)
349 data
->use_colors
= 16 + 4;
350 if (data
->res
== 2 && !data
->aga
)
351 data
->use_colors
= 32; /* ECS "scrambled" superhires */
353 if (data
->use_colors
> 32 && (data
->modeid
& EXTRAHALFBRITE_KEY
))
354 data
->use_colors
= 32;
355 if (data
->modeid
& HAM_KEY
) {
357 data
->use_colors
= 16 + 4;
359 data
->use_colors
= 64;
362 c2d
->copper2_scroll
= c
;
380 *c
++ = 0x0024 | ((data
->aga
&& !(data
->modeid
& EXTRAHALFBRITE_KEY
)) ? 0x0200 : 0);
382 c2d
->copper2_fmode
= NULL
;
383 if (data
->aga
&& data
->aga_enabled
) {
387 c2d
->copper2_fmode
= c
;
391 bplcon0
= data
->bplcon0_null
;
395 bplcon0
|= bm
->depth
<< 12;
396 if (data
->modeid
& HAM_KEY
)
399 c2d
->copper2_palette
= c
;
400 if (data
->aga
&& data
->aga_enabled
) {
402 for (i
= 0; i
< data
->use_colors
; i
++) {
406 *c
++ = data
->bplcon3
| ((i
/ 32) << 13);
408 *c
++ = 0x180 + agac
* 2;
411 c2d
->copper2_palette_aga_lo
= c
;
413 for (i
= 0; i
< data
->use_colors
; i
++) {
417 *c
++ = data
->bplcon3
| ((i
/ 32) << 13) | 0x0200;
419 *c
++ = 0x180 + agac
* 2;
423 *c
++ = data
->bplcon3
;
426 for (i
= 0; i
< data
->use_colors
; i
++) {
427 *c
++ = 0x180 + i
* 2;
432 data
->extralines
= (c
- c2d
->copper2
) / 112 + 1;
436 c2d
->copper2_bplcon0
= c
;
446 *c
++ = data
->bplcon0_null
;
448 if (data
->interlace
) {
449 ULONG nextptr
= (ULONG
)(lace
? data
->copper2
.copper2
: data
->copper2i
.copper2
);
451 *c
++ = (UWORD
)(nextptr
>> 16);
453 *c
++ = (UWORD
)(nextptr
>> 0);
460 BOOL
setbitmap(struct amigavideo_staticdata
*data
, struct amigabm_data
*bm
)
462 data
->width
= bm
->width
;
463 data
->height
= data
->interlace
? (bm
->height
+ 1) / 2 : bm
->height
;
464 data
->modulo
= bm
->bytesperrow
- data
->modulopre
/ (4 >> data
->res
);
465 data
->modulo
&= ~((2 << data
->fmode_bpl
) - 1);
466 data
->updatescroll
= bm
;
467 data
->depth
= bm
->depth
;
468 setcopperscroll(data
, bm
);
470 D(bug("setbitmap bm=%x mode=%08x w=%d h=%d d=%d bpr=%d\n",
471 bm
, data
->modeid
, bm
->width
, bm
->height
, bm
->depth
, bm
->bytesperrow
));
475 BOOL
setmode(struct amigavideo_staticdata
*data
, struct amigabm_data
*bm
)
477 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
478 struct GfxBase
*GfxBase
= (APTR
)data
->cs_GfxBase
;
479 UWORD ddfstrt
, ddfstop
;
480 UBYTE fetchunit
, maxplanes
;
481 UWORD bplwidth
, viewwidth
;
484 if (data
->disp
== bm
)
490 if ((data
->modeid
& SUPER_KEY
) == SUPER_KEY
)
492 else if ((data
->modeid
& SUPER_KEY
) == HIRES_KEY
)
494 data
->interlace
= (data
->modeid
& LORESLACE_KEY
) ? 1 : 0;
495 data
->fmode_bpl
= data
->aga
&& data
->aga_enabled
? 2 : 0;
497 fetchunit
= fetchunits
[data
->fmode_bpl
* 4 + data
->res
];
498 maxplanes
= fm_maxplanes
[data
->fmode_bpl
* 4 + data
->res
];
500 D(bug("res %d fmode %d depth %d maxplanes %d aga %d agae %d\n",
501 data
->res
, data
->fmode_bpl
, bm
->depth
, maxplanes
, data
->aga
, data
->aga_enabled
));
503 if (bm
->depth
> (1 << maxplanes
)) {
504 if (data
->aga
&& !data
->aga_enabled
) {
505 // Enable AGA if requesting AGA only mode.
506 // This is a compatibility hack because our display
507 // database currently contains all AGA modes even if AGA
509 GfxBase
->ChipRevBits0
= SETCHIPREV_AA
;
510 data
->aga_enabled
= TRUE
;
511 data
->fmode_bpl
= data
->aga
&& data
->aga_enabled
? 2 : 0;
512 fetchunit
= fetchunits
[data
->fmode_bpl
* 4 + data
->res
];
513 maxplanes
= fm_maxplanes
[data
->fmode_bpl
* 4 + data
->res
];
515 if (bm
->depth
> (1 << maxplanes
))
519 viewwidth
= bm
->width
;
520 // use nominal width for now
521 if ((viewwidth
<< data
->res
) > 320)
522 viewwidth
= 320 << data
->res
;
524 D(bug("setmode bm=%x mode=%08x w=%d h=%d d=%d bpr=%d fu=%d\n",
525 bm
, data
->modeid
, bm
->width
, bm
->height
, bm
->depth
, bm
->bytesperrow
, fetchunit
));
527 bplwidth
= viewwidth
>> (data
->res
+ 1);
528 ddfstrt
= (data
->startx
/ 2) & ~((1 << fetchunit
) - 1);
529 ddfstop
= ddfstrt
+ ((bplwidth
+ ((1 << fetchunit
) - 1) - 2 * (1 << fetchunit
)) & ~((1 << fetchunit
) - 1));
530 data
->modulopre
= ddfstop
+ 2 * (1 << fetchunit
) - ddfstrt
;
531 ddfstrt
-= 1 << maxplanes
;
532 data
->ddfstrt
= ddfstrt
;
533 data
->ddfstop
= ddfstop
;
535 for (i
= 0; i
< 8; i
++)
536 data
->bploffsets
[i
] = i
;
537 if ((data
->modeid
& HAM_KEY
) && bm
->depth
> 6) {
538 data
->bploffsets
[0] = 6;
539 data
->bploffsets
[1] = 7;
540 for (i
= 0; i
< 6; i
++)
541 data
->bploffsets
[i
+ 2] = i
;
544 data
->copper2
.copper2
= AllocVec(get_copper_list_length(data
, bm
->depth
), MEMF_CLEAR
| MEMF_CHIP
);
546 data
->copper2i
.copper2
= AllocVec(get_copper_list_length(data
, bm
->depth
), MEMF_CLEAR
| MEMF_CHIP
);
547 createcopperlist(data
, bm
, &data
->copper2
, FALSE
);
548 if (data
->interlace
) {
549 createcopperlist(data
, bm
, &data
->copper2i
, TRUE
);
553 setpalntsc(data
, data
->modeid
);
554 custom
->bplcon0
= data
->bplcon0_null
;
556 bm
->displaywidth
= viewwidth
;
557 bm
->displayheight
= limitheight(data
, bm
->height
, data
->interlace
, FALSE
);
561 GfxBase
->LOFlist
= data
->copper2
.copper2
;
562 GfxBase
->SHFlist
= data
->interlace
? data
->copper2i
.copper2
: data
->copper2
.copper2
;
563 custom
->dmacon
= 0x8100;
565 setcoppercolors(data
);
566 setspritepos(data
, data
->spritex
, data
->spritey
);
572 BOOL
setsprite(struct amigavideo_staticdata
*data
, WORD width
, WORD height
, struct pHidd_Gfx_SetCursorShape
*shape
)
574 OOP_MethodID HiddBitMapBase
= data
->cs_HiddBitMapBase
;
576 UWORD bitmapwidth
= width
;
579 if (data
->aga
&& data
->aga_enabled
&& width
> 16)
583 fetchsize
= 2 << data
->fmode_spr
;
584 width
= 16 << data
->fmode_spr
;
586 if (width
!= data
->sprite_width
|| height
!= data
->sprite_height
) {
588 data
->spritedatasize
= fetchsize
* 2 + fetchsize
* height
* 2 + fetchsize
* 2;
589 data
->sprite
= AllocMem(data
->spritedatasize
, MEMF_CHIP
| MEMF_CLEAR
);
592 data
->sprite_width
= width
;
593 data
->sprite_height
= height
;
594 data
->sprite_offset_x
= shape
->xoffset
;
595 data
->sprite_offset_y
= shape
->yoffset
;
599 for(y
= 0; y
< height
; y
++) {
601 for (xx
= 0, xxx
= 0; xx
< width
; xx
+= 16, xxx
++) {
602 UWORD pix1
= 0, pix2
= 0;
603 for(x
= 0; x
< 16; x
++) {
605 if (xx
+ x
< bitmapwidth
)
606 c
= HIDD_BM_GetPixel(shape
->shape
, xx
+ x
, y
);
608 /* Sprite alignment grid */
609 if (xx
+ x
== 0 || xx
+ x
== width
- 1 || y
== 0 || y
== height
- 1) {
617 pix1
|= (c
& 1) ? 1 : 0;
618 pix2
|= (c
& 2) ? 1 : 0;
621 p
[xxx
+ fetchsize
/ 2] = pix2
;
625 setspritepos(data
, data
->spritex
, data
->spritey
);
626 setspritevisible(data
, data
->cursorvisible
);
630 void setspritepos(struct amigavideo_staticdata
*data
, WORD x
, WORD y
)
636 if (!data
->sprite
|| data
->sprite_height
== 0)
639 x
+= data
->sprite_offset_x
<< data
->res
;
640 x
<<= (2 - data
->res
); // convert x to shres coordinates
641 x
+= (data
->startx
- 1) << 2; // display left edge offset
644 y
/= 2; // y is always in nonlaced
646 y
+= data
->sprite_offset_y
;
648 pos
= (y
<< 8) | (x
>> 3);
649 ctl
= ((y
+ data
->sprite_height
) << 8);
650 ctl
|= ((y
>> 8) << 2) | (((y
+ data
->sprite_height
) >> 8) << 1) | ((x
>> 2) & 1) | ((x
& 3) << 3);
651 data
->spritepos
= pos
;
652 data
->spritectl
= ctl
;
655 void setspritevisible(struct amigavideo_staticdata
*data
, BOOL visible
)
657 data
->cursorvisible
= visible
;
659 if (data
->copper1_spritept
) {
660 UWORD
*p
= data
->sprite
;
662 data
->copper1_spritept
[0] = (UWORD
)(((ULONG
)p
) >> 16);
663 data
->copper1_spritept
[2] = (UWORD
)(((ULONG
)p
) >> 0);
670 BOOL
setcolors(struct amigavideo_staticdata
*data
, struct pHidd_BitMap_SetColors
*msg
, BOOL visible
)
673 if (msg
->firstColor
+ msg
->numColors
> data
->max_colors
)
676 for (i
= msg
->firstColor
; j
< msg
->numColors
; i
++, j
++) {
677 UBYTE red
, green
, blue
;
678 red
= msg
->colors
[j
].red
>> 8;
679 green
= msg
->colors
[j
].green
>> 8;
680 blue
= msg
->colors
[j
].blue
>> 8;
681 data
->palette
[i
* 3 + 0] = red
;
682 data
->palette
[i
* 3 + 1] = green
;
683 data
->palette
[i
* 3 + 2] = blue
;
684 //bug("%d: %02x %02x %02x\n", i, red, green, blue);
687 setcoppercolors(data
);
690 void setscroll(struct amigavideo_staticdata
*data
, struct amigabm_data
*bm
)
692 data
->updatescroll
= bm
;
695 /* Convert Z flag to normal C-style return variable. Fun. */
696 UBYTE
bltnode_wrapper(void)
701 " move.l 4(%%a1),-(%%sp)\n"
710 #define BEAMSYNC_ALARM 0x0f00
711 /* AOS must use some GfxBase flags field for these. Later.. */
712 #define bqvar GfxBase->pad3
714 #define BQ_BEAMSYNC 2
715 #define BQ_BEAMSYNCWAITING 4
718 static AROS_INTH1(gfx_blit
, struct GfxBase
*, GfxBase
)
722 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
723 struct bltnode
*bn
= NULL
;
727 dmaconr
= custom
->dmaconr
;
728 dmaconr
= custom
->dmaconr
;
729 if (dmaconr
& 0x4000) {
730 /* Blitter still active? Wait for next interrupt. */
734 if (GfxBase
->blthd
== NULL
&& GfxBase
->bsblthd
== NULL
) {
735 custom
->intena
= INTF_BLIT
;
739 /* Was last blit in this node? */
740 if (bqvar
& BQ_NEXT
) {
741 bqvar
&= ~(BQ_NEXT
| BQ_MISSED
);
742 if (bqvar
& BQ_BEAMSYNC
)
743 bn
= GfxBase
->bsblthd
;
746 if (bn
->stat
== CLEANUP
)
747 AROS_UFC2(UBYTE
, bn
->cleanup
,
748 AROS_UFCA(struct Custom
*, custom
, A0
),
749 AROS_UFCA(struct bltnode
*, bn
, A1
));
752 if (bqvar
& BQ_BEAMSYNC
)
753 GfxBase
->bsblthd
= bn
;
758 if (GfxBase
->bsblthd
) {
759 bn
= GfxBase
->bsblthd
;
760 bqvar
|= BQ_BEAMSYNC
;
761 } else if (GfxBase
->blthd
) {
763 bqvar
&= ~BQ_BEAMSYNC
;
767 /* Last blit finished */
769 custom
->intena
= INTF_BLIT
;
770 GfxBase
->blthd
= GfxBase
->bsblthd
= NULL
;
775 if (bqvar
& BQ_BEAMSYNC
) {
776 UWORD vpos
= VBeamPos();
777 bqvar
&= ~BQ_BEAMSYNCWAITING
;
778 if (!(bqvar
& BQ_MISSED
) && bn
->beamsync
> vpos
) {
779 volatile struct CIA
*ciab
= (struct CIA
*)0xbfd000;
780 UWORD w
= BEAMSYNC_ALARM
- (bn
->beamsync
- vpos
);
781 bqvar
|= BQ_BEAMSYNCWAITING
;
782 ciab
->ciacrb
&= ~0x80;
784 ciab
->ciatodmid
= w
>> 8;
790 v
= AROS_UFC2(UBYTE
, bltnode_wrapper
,
791 AROS_UFCA(struct Custom
*, custom
, A0
),
792 AROS_UFCA(struct bltnode
*, bn
, A1
));
794 dmaconr
= custom
->dmaconr
;
795 dmaconr
= custom
->dmaconr
;
796 if (!(dmaconr
& 0x4000)) {
797 /* Eh? Blitter not active?, better fake the interrupt. */
798 custom
->intreq
= INTF_SETCLR
| INTF_BLIT
;
802 /* Handle same node again next time */
813 static AROS_INTH1(gfx_beamsync
, struct amigavideo_staticdata
*, data
)
817 struct GfxBase
*GfxBase
= (APTR
)data
->cs_GfxBase
;
819 if (bqvar
& BQ_BEAMSYNCWAITING
) {
820 /* We only need to trigger blitter interrupt */
821 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
822 custom
->intreq
= INTF_SETCLR
| INTF_BLIT
;
830 static AROS_INTH1(gfx_vblank
, struct amigavideo_staticdata
*, data
)
834 struct GfxBase
*GfxBase
= (APTR
)data
->cs_GfxBase
;
835 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
836 BOOL lof
= (custom
->vposr
& 0x8000) != 0;
838 if (data
->interlace
) {
839 custom
->cop2lc
= (ULONG
)(lof
? GfxBase
->LOFlist
: GfxBase
->SHFlist
);
841 custom
->cop2lc
= (ULONG
)GfxBase
->LOFlist
;
842 /* We may be in SHF mode after switching interlace off. Fix it here. */
844 custom
->vposw
= custom
->vposr
| 0x8000;
847 data
->framecounter
++;
849 UWORD
*p
= data
->sprite
;
850 p
[0] = data
->spritepos
;
851 p
[1 << data
->fmode_spr
] = data
->spritectl
;
854 if (data
->updatescroll
) {
855 setcopperscroll(data
, data
->updatescroll
);
856 data
->updatescroll
= NULL
;
859 if (bqvar
& BQ_BEAMSYNC
)
867 void initcustom(struct amigavideo_staticdata
*data
)
872 struct GfxBase
*GfxBase
;
873 struct Library
*OOPBase
;
874 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
875 volatile struct CIA
*ciab
= (struct CIA
*)0xbfd000;
877 /* Reset audio registers to values that help emulation
878 * if some program enables audio DMA without setting period
879 * or length. Very high period emulation is very CPU intensive.
881 for (i
= 0; i
< 4; i
++) {
882 custom
->aud
[i
].ac_vol
= 0;
883 custom
->aud
[i
].ac_per
= 100;
884 custom
->aud
[i
].ac_len
= 1000;
890 /* data->cs_OOPBase was already set up.
891 * See amigavideo.conf's 'oopbase_field' config
893 OOPBase
= data
->cs_OOPBase
;
894 data
->cs_HiddBitMapBase
= OOP_GetMethodID(IID_Hidd_BitMap
, 0);
895 data
->cs_HiddGfxBase
= OOP_GetMethodID(IID_Hidd_Gfx
, 0);
897 data
->cs_UtilityBase
= TaggedOpenLibrary(TAGGEDOPEN_UTILITY
);
898 if (!data
->cs_UtilityBase
)
899 Alert(AT_DeadEnd
| AN_Hidd
| AG_OpenLib
| AO_UtilityLib
);
900 data
->cs_GfxBase
= TaggedOpenLibrary(TAGGEDOPEN_GRAPHICS
);
901 if (!data
->cs_GfxBase
)
902 Alert(AT_DeadEnd
| AN_Hidd
| AG_OpenLib
| AO_GraphicsLib
);
903 GfxBase
= ((struct GfxBase
*)data
->cs_GfxBase
);
904 GfxBase
->cia
= OpenResource("ciab.resource");
906 data
->inter
.is_Code
= (APTR
)gfx_vblank
;
907 data
->inter
.is_Data
= data
;
908 data
->inter
.is_Node
.ln_Name
= "GFX VBlank server";
909 data
->inter
.is_Node
.ln_Pri
= 25;
910 data
->inter
.is_Node
.ln_Type
= NT_INTERRUPT
;
911 AddIntServer(INTB_VERTB
, &data
->inter
);
913 /* There are programs that take over the system and
914 * assume SysBase->IntVects[BLITTER].iv_Data = GfxBase!
916 GfxBase
->bltsrv
.is_Code
= (APTR
)gfx_blit
;
917 GfxBase
->bltsrv
.is_Data
= GfxBase
;
918 GfxBase
->bltsrv
.is_Node
.ln_Name
= "Blitter";
919 GfxBase
->bltsrv
.is_Node
.ln_Type
= NT_INTERRUPT
;
920 SetIntVector(INTB_BLIT
, &GfxBase
->bltsrv
);
921 custom
->intena
= INTF_BLIT
;
923 // CIA-B TOD counts scanlines */
924 GfxBase
->timsrv
.is_Code
= (APTR
)gfx_beamsync
;
925 GfxBase
->timsrv
.is_Data
= data
;
926 GfxBase
->timsrv
.is_Node
.ln_Name
= "Beamsync";
927 GfxBase
->timsrv
.is_Node
.ln_Type
= NT_INTERRUPT
;
929 AddICRVector(GfxBase
->cia
, 2, &GfxBase
->timsrv
);
930 AbleICR(GfxBase
->cia
, 1 << 2);
931 ciab
->ciacrb
|= 0x80;
933 /* TOD/ALARM CIA bug: http://eab.abime.net/showpost.php?p=277315&postcount=10 */
934 ciab
->ciatodmid
= BEAMSYNC_ALARM
>> 8;
935 ciab
->ciatodlow
= BEAMSYNC_ALARM
& 0xff;
936 ciab
->ciacrb
&= ~0x80;
940 AbleICR(GfxBase
->cia
, 0x80 | (1 << 2));
943 GfxBase
->NormalDisplayColumns
= 640;
944 GfxBase
->NormalDisplayRows
= (GfxBase
->DisplayFlags
& NTSC
) ? 200 : 256;
945 GfxBase
->MaxDisplayColumn
= 640;
946 GfxBase
->MaxDisplayRow
= (GfxBase
->DisplayFlags
& NTSC
) ? 200 : 256;
951 vposr
= custom
->vposr
& 0x7f00;
952 data
->aga
= vposr
>= 0x2200;
953 data
->ecs_agnus
= vposr
>= 0x2000;
954 val
= custom
->deniseid
;
955 custom
->deniseid
= custom
->dmaconr
;;
956 if (val
== custom
->deniseid
) {
957 custom
->deniseid
= custom
->dmaconr
^ 0x8000;
958 if (val
== custom
->deniseid
) {
959 if ((val
& (2 + 8)) == 8)
960 data
->ecs_denise
= TRUE
;
963 data
->max_colors
= data
->aga
? 256 : 32;
964 data
->palette
= AllocVec(data
->max_colors
* 3, MEMF_CLEAR
);
965 data
->copper1
= AllocVec(22 * 2 * sizeof(WORD
), MEMF_CLEAR
| MEMF_CHIP
);
966 data
->sprite_null
= AllocMem(2 * 8, MEMF_CLEAR
| MEMF_CHIP
);
967 data
->sprite_res
= 0; /* lores */
969 for (i
= 0; i
< 8; i
++) {
970 *c
++ = 0x0120 + i
* 4;
972 data
->copper1_spritept
= c
;
973 *c
++ = (UWORD
)(((ULONG
)data
->sprite_null
) >> 16);
974 *c
++ = 0x0122 + i
* 4;
975 *c
++ = (UWORD
)(((ULONG
)data
->sprite_null
) >> 0);
981 data
->copper2_backup
= c
;
984 custom
->cop1lc
= (ULONG
)data
->copper1
;
985 custom
->cop2lc
= (ULONG
)data
->copper2_backup
;
986 custom
->dmacon
= 0x8000 | 0x0080 | 0x0040 | 0x0020;
988 GfxBase
->copinit
= (struct copinit
*)data
->copper1
;
990 D(bug("Copperlist0 %p\n", data
->copper1
));