1 |
/* |
/* |
2 |
* Copyright (C) 2006 Anders Gavare. All rights reserved. |
* Copyright (C) 2006-2007 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: dev_pvr.c,v 1.17 2006/11/02 05:43:44 debug Exp $ |
* $Id: dev_pvr.c,v 1.24 2007/06/15 19:57:33 debug Exp $ |
29 |
* |
* |
30 |
* PowerVR CLX2 (Graphics controller used in the Dreamcast). Implemented by |
* COMMENT: PowerVR CLX2 (graphics controller used in the Dreamcast) |
31 |
* reading http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt and |
* |
32 |
|
* Implemented by reading http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt and |
33 |
* http://mc.pp.se/dc/pvr.html, source code of various demos and KalistOS, |
* http://mc.pp.se/dc/pvr.html, source code of various demos and KalistOS, |
34 |
* and doing a lot of guessing. |
* and doing a lot of guessing. |
35 |
* |
* |
43 |
* Color clipping. |
* Color clipping. |
44 |
* Wire-frame when running on a host without XGL? |
* Wire-frame when running on a host without XGL? |
45 |
* |
* |
|
* x) Border? |
|
|
* |
|
46 |
* Multiple lists of various kinds (6?). |
* Multiple lists of various kinds (6?). |
47 |
* Lists growing downwards! |
* Lists growing downwards! |
48 |
* Pixel clip for rendering. |
* Pixel clip for rendering. |
74 |
#define PVR_FB_TICK_SHIFT 19 |
#define PVR_FB_TICK_SHIFT 19 |
75 |
|
|
76 |
#define PVR_VBLANK_HZ 60.0 |
#define PVR_VBLANK_HZ 60.0 |
77 |
|
#define PVR_MARGIN 16 |
78 |
|
|
79 |
struct pvr_data { |
struct pvr_data { |
80 |
struct vfb_data *fb; |
struct vfb_data *fb; |
103 |
int pixelmode; |
int pixelmode; |
104 |
int line_double; |
int line_double; |
105 |
int display_enabled; |
int display_enabled; |
106 |
|
/* BRDCOLR: */ |
107 |
|
int border_updated; |
108 |
/* SYNCCONF: */ |
/* SYNCCONF: */ |
109 |
int video_enabled; |
int video_enabled; |
110 |
int broadcast_standard; |
int broadcast_standard; |
163 |
*/ |
*/ |
164 |
static void pvr_geometry_updated(struct pvr_data *d) |
static void pvr_geometry_updated(struct pvr_data *d) |
165 |
{ |
{ |
166 |
|
/* Make sure to redraw border on geometry changes. */ |
167 |
|
d->border_updated = 1; |
168 |
|
|
169 |
d->xsize = (REG(PVRREG_DIWSIZE) >> DIWSIZE_DPL_SHIFT) & DIWSIZE_MASK; |
d->xsize = (REG(PVRREG_DIWSIZE) >> DIWSIZE_DPL_SHIFT) & DIWSIZE_MASK; |
170 |
d->ysize = (REG(PVRREG_DIWSIZE) >> DIWSIZE_LPF_SHIFT) & DIWSIZE_MASK; |
d->ysize = (REG(PVRREG_DIWSIZE) >> DIWSIZE_LPF_SHIFT) & DIWSIZE_MASK; |
171 |
|
|
420 |
|
|
421 |
DEVICE_ACCESS(pvr_ta) |
DEVICE_ACCESS(pvr_ta) |
422 |
{ |
{ |
423 |
struct pvr_data *d = (struct pvr_data *) extra; |
struct pvr_data *d = extra; |
424 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
425 |
|
|
426 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
445 |
|
|
446 |
DEVICE_ACCESS(pvr) |
DEVICE_ACCESS(pvr) |
447 |
{ |
{ |
448 |
struct pvr_data *d = (struct pvr_data *) extra; |
struct pvr_data *d = extra; |
449 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
450 |
|
|
451 |
if (writeflag == MEM_WRITE) |
if (writeflag == MEM_WRITE) |
478 |
|
|
479 |
case PVRREG_RESET: |
case PVRREG_RESET: |
480 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
481 |
debug("[ pvr: RESET "); |
if (idata != 0) { |
482 |
if (idata & PVR_RESET_PVR) |
debug("[ pvr: RESET "); |
483 |
pvr_reset(d); |
if (idata & PVR_RESET_PVR) |
484 |
if (idata & PVR_RESET_TA) |
pvr_reset(d); |
485 |
pvr_reset_ta(d); |
if (idata & PVR_RESET_TA) |
486 |
debug("]\n"); |
pvr_reset_ta(d); |
487 |
|
debug("]\n"); |
488 |
|
} |
489 |
idata = 0; |
idata = 0; |
490 |
DEFAULT_WRITE; |
DEFAULT_WRITE; |
491 |
} |
} |
548 |
debug("[ pvr: BRDCOLR set to 0x%06"PRIx32" ]\n", |
debug("[ pvr: BRDCOLR set to 0x%06"PRIx32" ]\n", |
549 |
(int)idata); |
(int)idata); |
550 |
DEFAULT_WRITE; |
DEFAULT_WRITE; |
551 |
|
d->border_updated = 1; |
552 |
} |
} |
553 |
break; |
break; |
554 |
|
|
987 |
* Framebuffer update: |
* Framebuffer update: |
988 |
*/ |
*/ |
989 |
|
|
990 |
|
/* Border changed? */ |
991 |
|
if (d->border_updated) { |
992 |
|
/* Fill border with border color: */ |
993 |
|
int rgb = REG(PVRREG_BRDCOLR), addr = 0; |
994 |
|
int x, y, b = rgb & 0xff, g = (rgb >> 8) & 0xff, r = rgb >> 16; |
995 |
|
int skiplen = (d->fb->xsize-2*PVR_MARGIN) * d->fb->bit_depth/8; |
996 |
|
|
997 |
|
for (y=0; y<d->fb->ysize; y++) { |
998 |
|
int xskip = y < PVR_MARGIN || y >= |
999 |
|
d->fb->ysize - PVR_MARGIN? -1 : PVR_MARGIN; |
1000 |
|
for (x=0; x<d->fb->xsize; x++) { |
1001 |
|
if (x == xskip) { |
1002 |
|
x = d->fb->xsize - PVR_MARGIN; |
1003 |
|
addr += skiplen; |
1004 |
|
} |
1005 |
|
fb[addr] = r; |
1006 |
|
fb[addr+1] = g; |
1007 |
|
fb[addr+2] = b; |
1008 |
|
addr += 3; |
1009 |
|
} |
1010 |
|
} |
1011 |
|
|
1012 |
|
/* Full redraw of the framebuffer: */ |
1013 |
|
d->fb->update_x1 = 0; d->fb->update_x2 = d->fb->xsize - 1; |
1014 |
|
d->fb->update_y1 = 0; d->fb->update_y2 = d->fb->ysize - 1; |
1015 |
|
} |
1016 |
|
|
1017 |
memory_device_dyntrans_access(cpu, cpu->mem, extra, &low, &high); |
memory_device_dyntrans_access(cpu, cpu->mem, extra, &low, &high); |
1018 |
if ((int64_t)low != -1) |
if ((int64_t)low != -1) |
1019 |
extend_update_region(d, low, high); |
extend_update_region(d, low, high); |
1022 |
return; |
return; |
1023 |
|
|
1024 |
/* Copy (part of) the VRAM to the framebuffer: */ |
/* Copy (part of) the VRAM to the framebuffer: */ |
1025 |
if (d->fb_update_x2 >= d->fb->xsize) |
if (d->fb_update_x2 >= d->xsize) |
1026 |
d->fb_update_x2 = d->fb->xsize - 1; |
d->fb_update_x2 = d->xsize - 1; |
1027 |
if (d->fb_update_y2 >= d->fb->ysize) |
if (d->fb_update_y2 >= d->ysize) |
1028 |
d->fb_update_y2 = d->fb->ysize - 1; |
d->fb_update_y2 = d->ysize - 1; |
1029 |
|
|
1030 |
vram_ofs += d->fb_update_y1 * bytes_per_line; |
vram_ofs += d->fb_update_y1 * bytes_per_line; |
1031 |
vram_ofs += d->fb_update_x1 * d->bytes_per_pixel; |
vram_ofs += d->fb_update_x1 * d->bytes_per_pixel; |
1032 |
pixels_to_copy = (d->fb_update_x2 - d->fb_update_x1 + 1); |
pixels_to_copy = (d->fb_update_x2 - d->fb_update_x1 + 1); |
1033 |
fb_ofs = d->fb_update_y1 * d->fb->bytes_per_line; |
fb_ofs = (d->fb_update_y1 + PVR_MARGIN) * d->fb->bytes_per_line; |
1034 |
fb_ofs += d->fb_update_x1 * d->fb->bit_depth / 8; |
fb_ofs += (d->fb_update_x1 + PVR_MARGIN) * d->fb->bit_depth / 8; |
1035 |
|
|
1036 |
/* Copy the actual pixels: (Four manually inlined, for speed.) */ |
/* Copy the actual pixels: (Four manually inlined, for speed.) */ |
1037 |
|
|
1097 |
* just written to: |
* just written to: |
1098 |
*/ |
*/ |
1099 |
|
|
1100 |
|
/* Offset to take the margin into account first... */ |
1101 |
|
d->fb_update_x1 += PVR_MARGIN; d->fb_update_y1 += PVR_MARGIN; |
1102 |
|
d->fb_update_x2 += PVR_MARGIN; d->fb_update_y2 += PVR_MARGIN; |
1103 |
|
|
1104 |
if (d->fb_update_x1 < d->fb->update_x1 || d->fb->update_x1 < 0) |
if (d->fb_update_x1 < d->fb->update_x1 || d->fb->update_x1 < 0) |
1105 |
d->fb->update_x1 = d->fb_update_x1; |
d->fb->update_x1 = d->fb_update_x1; |
1106 |
if (d->fb_update_x2 > d->fb->update_x2 || d->fb->update_x2 < 0) |
if (d->fb_update_x2 > d->fb->update_x2 || d->fb->update_x2 < 0) |
1120 |
{ |
{ |
1121 |
struct pvr_data_alt *d_alt = extra; |
struct pvr_data_alt *d_alt = extra; |
1122 |
struct pvr_data *d = d_alt->d; |
struct pvr_data *d = d_alt->d; |
1123 |
int i; |
size_t i; |
1124 |
|
|
1125 |
if (writeflag == MEM_READ) { |
if (writeflag == MEM_READ) { |
1126 |
/* Copy from real vram: */ |
/* Copy from real vram: */ |
1175 |
DEVINIT(pvr) |
DEVINIT(pvr) |
1176 |
{ |
{ |
1177 |
struct machine *machine = devinit->machine; |
struct machine *machine = devinit->machine; |
1178 |
struct pvr_data *d = malloc(sizeof(struct pvr_data)); |
struct pvr_data *d; |
1179 |
struct pvr_data_alt *d_alt = malloc(sizeof(struct pvr_data_alt)); |
struct pvr_data_alt *d_alt; |
1180 |
if (d == NULL) { |
|
1181 |
fprintf(stderr, "out of memory\n"); |
CHECK_ALLOCATION(d = malloc(sizeof(struct pvr_data))); |
|
exit(1); |
|
|
} |
|
1182 |
memset(d, 0, sizeof(struct pvr_data)); |
memset(d, 0, sizeof(struct pvr_data)); |
1183 |
|
|
1184 |
|
CHECK_ALLOCATION(d_alt = malloc(sizeof(struct pvr_data_alt))); |
1185 |
memset(d_alt, 0, sizeof(struct pvr_data_alt)); |
memset(d_alt, 0, sizeof(struct pvr_data_alt)); |
1186 |
|
|
1187 |
d_alt->d = d; |
d_alt->d = d; |
1212 |
d->bytes_per_pixel = 2; |
d->bytes_per_pixel = 2; |
1213 |
|
|
1214 |
d->fb = dev_fb_init(machine, machine->memory, INTERNAL_FB_ADDR, |
d->fb = dev_fb_init(machine, machine->memory, INTERNAL_FB_ADDR, |
1215 |
VFB_GENERIC, 640,480, 640,480, 24, "Dreamcast PVR"); |
VFB_GENERIC, d->xsize + PVR_MARGIN*2, d->ysize + PVR_MARGIN*2, |
1216 |
|
d->xsize + PVR_MARGIN*2, d->ysize + PVR_MARGIN*2, |
1217 |
|
24, "Dreamcast PVR"); |
1218 |
|
|
1219 |
d->vblank_timer = timer_add(PVR_VBLANK_HZ, pvr_vblank_timer_tick, d); |
d->vblank_timer = timer_add(PVR_VBLANK_HZ, pvr_vblank_timer_tick, d); |
1220 |
|
|
1222 |
pvr_reset_ta(d); |
pvr_reset_ta(d); |
1223 |
|
|
1224 |
machine_add_tickfunction(machine, dev_pvr_fb_tick, d, |
machine_add_tickfunction(machine, dev_pvr_fb_tick, d, |
1225 |
PVR_FB_TICK_SHIFT, 0.0); |
PVR_FB_TICK_SHIFT); |
1226 |
|
|
1227 |
return 1; |
return 1; |
1228 |
} |
} |