amiga_imgv

view src/amiga/gfx.c @ 11:3d9aaefb8ba6

interlace mode
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 30 Oct 2017 15:24:23 +0200
parents ae0ada629b03
children
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <proto/exec.h>
5 #include <exec/interrupts.h>
6 #include "gfx.h"
7 #include "copper.h"
8 #include "hwregs.h"
9 #include "logger.h"
10 #include "image.h"
12 static int scr_width, scr_height;
13 static int fb_width, fb_height;
14 static int num_bitplanes;
15 static unsigned int init_flags;
16 /* updated by vblank_intr to indicate the current field in interlaced mode */
17 static unsigned short scr_field;
18 static uint32_t *coplist_bplptr[6];
20 static uint16_t prev_intena, prev_intreq, prev_adkcon, prev_dmacon;
22 static unsigned char *framebuf;
23 static unsigned long fbsize;
24 static int own_framebuf;
26 static unsigned int short_fields, long_fields;
28 static struct Interrupt *vbint;
30 static __amigainterrupt void vblank_intr();
32 int gfx_init(int nbpl, unsigned int flags)
33 {
34 uint16_t bplcon0;
36 init_flags = flags;
37 num_bitplanes = nbpl;
38 scr_width = fb_width = (flags & GFX_HIRES) ? 640 : 320;
39 scr_height = fb_height = (flags & GFX_ILACE) ? 512 : 256;
41 Forbid();
43 prev_dmacon = REG_DMACONR;
44 REG_DMACON = CLRBITS(DMA_ALL);
46 prev_intena = REG_INTENAR;
47 prev_intreq = REG_INTREQR;
48 prev_adkcon = REG_ADKCONR;
50 if(init_copper(1400, 0) == -1) {
51 return -1;
52 }
54 /* setup vblank interrupt handler */
55 if(!(vbint = malloc(sizeof *vbint))) {
56 gfx_shutdown();
57 return -1;
58 }
59 vbint->is_Node.ln_Type = NT_INTERRUPT;
60 vbint->is_Node.ln_Pri = -60;
61 vbint->is_Node.ln_Name = "imgv_vblank_intr";
62 vbint->is_Data = 0;
63 vbint->is_Code = vblank_intr;
65 AddIntServer(INTR_VERTB, vbint);
67 if(!gfx_set_framebuffer(0, scr_width, scr_height)) {
68 gfx_shutdown();
69 return -1;
70 }
72 bplcon0 = BPLCON0_COUNT(nbpl) | BPLCON0_COLOR;
73 if(flags & GFX_HIRES) bplcon0 |= BPLCON0_HIRES;
74 if(flags & GFX_ILACE) bplcon0 |= BPLCON0_LACE;
75 if(flags & GFX_HAM) bplcon0 |= BPLCON0_HOMOD;
76 if(flags & GFX_DBLPF) bplcon0 |= BPLCON0_DBLPF;
78 REG_BPLCON0 = bplcon0;
79 REG_BPLCON1 = 0; /* h-scroll */
80 REG_DIWSTART = 0x2c81; /* 81h horiz start, 2ch vertical start */
81 REG_DIWSTOP = 0x2cc1;
82 REG_DDFSTART = (flags & GFX_HIRES) ? 0x3c : 0x38;
83 REG_DDFSTOP = (flags & GFX_HIRES) ? 0xd4 : 0xd0;
85 gfx_wait_vblank();
86 gfx_begin_copperlist();
87 add_copper(COPPER_END);
89 logmsg("starting DMA\n");
90 REG_DMACON = SETBITS(DMA_BPL | DMA_COPPER | DMA_MASTER);
91 return 0;
92 }
94 void gfx_shutdown(void)
95 {
96 REG_DMACON = CLRBITS(DMA_ALL);
97 REG_DMACON = SETBITS(prev_dmacon);
99 REG_INTREQ = CLRBITS(0x7fff);
100 REG_INTREQ = SETBITS(prev_intreq);
102 REG_ADKCON = CLRBITS(0x7fff);
103 REG_ADKCON = SETBITS(prev_adkcon);
105 REG_INTENA = CLRBITS(INTEN_ALL);
106 REG_INTENA = SETBITS(prev_intena);
108 if(framebuf && own_framebuf) {
109 FreeMem(framebuf, fbsize);
110 }
111 framebuf = 0;
113 if(vbint) {
114 RemIntServer(INTR_VERTB, vbint);
115 free(vbint);
116 vbint = 0;
117 }
119 cleanup_copper();
120 Permit();
122 if(init_flags & GFX_ILACE) {
123 printf("fields shown - long: %u / short: %u\n", long_fields, short_fields);
124 }
125 }
127 int gfx_screen_width(void)
128 {
129 return scr_width;
130 }
132 int gfx_screen_height(void)
133 {
134 return scr_height;
135 }
137 void *gfx_set_framebuffer(void *fb, int width, int height)
138 {
139 /*unsigned int bpl_scanline_sz = width / 8;*/
140 unsigned long sz = width * height / 8 * num_bitplanes;
141 uint32_t bpladdr;
142 uint16_t bplmod;
144 if(framebuf && own_framebuf) {
145 FreeMem(framebuf, fbsize);
146 }
148 if(fb) {
149 framebuf = fb;
150 own_framebuf = 0;
151 } else {
152 if(!(framebuf = AllocMem(sz, MEMF_CHIP | MEMF_CLEAR))) {
153 logmsg("gfx_set_framebuffer failed to allocate %lu bytes of chip mem for framebuffer\n", sz);
154 return 0;
155 }
156 own_framebuf = 1;
157 }
159 fb_width = width;
160 fb_height = height;
161 fbsize = sz;
163 bpladdr = (uint32_t)framebuf;
164 logmsg("bitplane address: %lx\n", (unsigned long)bpladdr);
166 bplmod = (fb_width - scr_width) / 8 + fb_width / 8 * (num_bitplanes - 1);
167 if(init_flags & GFX_ILACE) {
168 bplmod += fb_width / 8 * num_bitplanes;
169 }
170 REG_BPL1MOD = bplmod;
171 REG_BPL2MOD = bplmod;
173 /*
174 REG32_BPL1PT = bpladdr; bpladdr += bpl_scanline_sz;
175 REG32_BPL2PT = bpladdr; bpladdr += bpl_scanline_sz;
176 REG32_BPL3PT = bpladdr; bpladdr += bpl_scanline_sz;
177 REG32_BPL4PT = bpladdr; bpladdr += bpl_scanline_sz;
178 REG32_BPL5PT = bpladdr; bpladdr += bpl_scanline_sz;
179 REG32_BPL6PT = bpladdr;
180 */
181 return framebuf;
182 }
184 void *gfx_get_framebuffer(void)
185 {
186 return framebuf;
187 }
189 int gfx_framebuffer_width(void)
190 {
191 return fb_width;
192 }
194 int gfx_framebuffer_height(void)
195 {
196 return fb_height;
197 }
199 void gfx_begin_copperlist(void)
200 {
201 int i;
202 uint32_t bpladdr;
203 uint16_t reg_bplptr = REGN_BPL1PTH;
204 bpladdr = (uint32_t)framebuf;
206 REG_INTENA = CLRBITS(INTEN_VERTB);
208 for(i=0; i<num_bitplanes; i++) {
209 add_copper(COPPER_VWAIT_OVERSCAN(10));
210 coplist_bplptr[i] = copperlist_end;
211 add_copper(COPPER_MOVE(reg_bplptr, bpladdr >> 16));
212 reg_bplptr += 2;
213 add_copper(COPPER_MOVE(reg_bplptr, bpladdr));
214 reg_bplptr += 2;
215 bpladdr += fb_width / 8;
216 }
217 REG_INTENA = SETBITS(INTEN_VERTB);
218 }
220 static int mouse_bnstate(void)
221 {
222 return (REG_CIAA_PORTA & CIAA_PA_FIR0) ? 0 : 1;
223 }
225 int gfx_next_event(union gfx_event *ev, int block)
226 {
227 /* TODO */
228 if(block) {
229 while(!mouse_bnstate());
230 ev->type = GFX_EV_QUIT;
231 return 1;
232 }
234 if(mouse_bnstate()) {
235 ev->type = GFX_EV_QUIT;
236 return 1;
237 }
239 return 0;
240 }
242 void gfx_wait_vpos(int x)
243 {
244 x <<= 8;
245 while((REG32_VPOSR & 0x1ff00) < x);
246 }
248 void gfx_wait_vblank(void)
249 {
250 gfx_wait_vpos(300);
251 }
253 void gfx_show_image(struct ham_image *img)
254 {
255 int i, j, k, fbwidth, fbheight, ncolors, prev_line;
256 unsigned char *fbptr = gfx_get_framebuffer();
257 struct palchange *chg = img->chglist;
259 fbwidth = gfx_framebuffer_width();
260 fbheight = gfx_framebuffer_height();
262 logmsg("showing ham image %dx%d\n", fbwidth, fbheight);
264 memcpy(fbptr, img->pixels, fbwidth * fbheight / 8 * num_bitplanes);
266 /* create copper list that handles the palette */
267 clear_copper();
268 gfx_begin_copperlist();
269 /* initial palette at the start of frame */
270 for(i=0; i<16; i++) {
271 add_copper(COPPER_MOVE(REGN_COLOR(i), img->palette[i]));
272 logmsg("copper palette[%d]: %x\n", i, (unsigned int)img->palette[i]);
273 }
274 /* add copper instructions for palette changes according to the image changelist */
275 prev_line = -1;
276 while(chg) {
277 assert(chg->line >= prev_line);
278 if(chg->line != prev_line) {
279 if(chg->line > 255 && prev_line < 255) {
280 add_copper(COPPER_VWAIT(255));
281 }
282 prev_line = chg->line;
283 add_copper(COPPER_VWAIT(chg->line));
284 }
285 add_copper(COPPER_MOVE(REGN_COLOR(chg->entry >> 12), chg->entry & 0xfff));
286 chg = chg->next;
287 }
288 add_copper(COPPER_END);
289 }
291 static __amigainterrupt void vblank_intr()
292 {
293 if(init_flags & GFX_ILACE) {
294 int i;
295 uint32_t bpladdr;
296 uint16_t reg_bplptr = REGN_BPL1PTH;
297 bpladdr = (uint32_t)framebuf;
299 /* 0: when long frame flag is set in VPOS */
300 scr_field = REG_VPOSR & 0x8000;
301 if(scr_field) {
302 bpladdr += fb_width / 8 * num_bitplanes;
303 ++long_fields;
304 } else {
305 ++short_fields;
306 }
308 if(coplist_bplptr[0]) {
309 for(i=0; i<num_bitplanes; i++) {
310 coplist_bplptr[i][0] = COPPER_MOVE(reg_bplptr, bpladdr >> 16);
311 reg_bplptr += 2;
312 coplist_bplptr[i][1] = COPPER_MOVE(reg_bplptr, bpladdr);
313 reg_bplptr += 2;
314 bpladdr += fb_width / 8;
315 }
316 }
317 }
318 /* TODO read mouse */
319 }