amiga_imgv

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