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.20 2006/12/30 13:30:59 debug Exp $ |
29 |
* |
* |
30 |
* PowerVR CLX2 (Graphics controller used in the Dreamcast). Implemented by |
* PowerVR CLX2 (Graphics controller used in the Dreamcast). Implemented by |
31 |
* reading http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt and |
* reading http://www.ludd.luth.se/~jlo/dc/powervr-reg.txt and |
42 |
* Color clipping. |
* Color clipping. |
43 |
* Wire-frame when running on a host without XGL? |
* Wire-frame when running on a host without XGL? |
44 |
* |
* |
|
* x) Border? |
|
|
* |
|
45 |
* Multiple lists of various kinds (6?). |
* Multiple lists of various kinds (6?). |
46 |
* Lists growing downwards! |
* Lists growing downwards! |
47 |
* Pixel clip for rendering. |
* Pixel clip for rendering. |
73 |
#define PVR_FB_TICK_SHIFT 19 |
#define PVR_FB_TICK_SHIFT 19 |
74 |
|
|
75 |
#define PVR_VBLANK_HZ 60.0 |
#define PVR_VBLANK_HZ 60.0 |
76 |
|
#define PVR_MARGIN 16 |
77 |
|
|
78 |
struct pvr_data { |
struct pvr_data { |
79 |
struct vfb_data *fb; |
struct vfb_data *fb; |
102 |
int pixelmode; |
int pixelmode; |
103 |
int line_double; |
int line_double; |
104 |
int display_enabled; |
int display_enabled; |
105 |
|
/* BRDCOLR: */ |
106 |
|
int border_updated; |
107 |
/* SYNCCONF: */ |
/* SYNCCONF: */ |
108 |
int video_enabled; |
int video_enabled; |
109 |
int broadcast_standard; |
int broadcast_standard; |
162 |
*/ |
*/ |
163 |
static void pvr_geometry_updated(struct pvr_data *d) |
static void pvr_geometry_updated(struct pvr_data *d) |
164 |
{ |
{ |
165 |
|
/* Make sure to redraw border on geometry changes. */ |
166 |
|
d->border_updated = 1; |
167 |
|
|
168 |
d->xsize = (REG(PVRREG_DIWSIZE) >> DIWSIZE_DPL_SHIFT) & DIWSIZE_MASK; |
d->xsize = (REG(PVRREG_DIWSIZE) >> DIWSIZE_DPL_SHIFT) & DIWSIZE_MASK; |
169 |
d->ysize = (REG(PVRREG_DIWSIZE) >> DIWSIZE_LPF_SHIFT) & DIWSIZE_MASK; |
d->ysize = (REG(PVRREG_DIWSIZE) >> DIWSIZE_LPF_SHIFT) & DIWSIZE_MASK; |
170 |
|
|
477 |
|
|
478 |
case PVRREG_RESET: |
case PVRREG_RESET: |
479 |
if (writeflag == MEM_WRITE) { |
if (writeflag == MEM_WRITE) { |
480 |
debug("[ pvr: RESET "); |
if (idata != 0) { |
481 |
if (idata & PVR_RESET_PVR) |
debug("[ pvr: RESET "); |
482 |
pvr_reset(d); |
if (idata & PVR_RESET_PVR) |
483 |
if (idata & PVR_RESET_TA) |
pvr_reset(d); |
484 |
pvr_reset_ta(d); |
if (idata & PVR_RESET_TA) |
485 |
debug("]\n"); |
pvr_reset_ta(d); |
486 |
|
debug("]\n"); |
487 |
|
} |
488 |
idata = 0; |
idata = 0; |
489 |
DEFAULT_WRITE; |
DEFAULT_WRITE; |
490 |
} |
} |
547 |
debug("[ pvr: BRDCOLR set to 0x%06"PRIx32" ]\n", |
debug("[ pvr: BRDCOLR set to 0x%06"PRIx32" ]\n", |
548 |
(int)idata); |
(int)idata); |
549 |
DEFAULT_WRITE; |
DEFAULT_WRITE; |
550 |
|
d->border_updated = 1; |
551 |
} |
} |
552 |
break; |
break; |
553 |
|
|
986 |
* Framebuffer update: |
* Framebuffer update: |
987 |
*/ |
*/ |
988 |
|
|
989 |
|
/* Border changed? */ |
990 |
|
if (d->border_updated) { |
991 |
|
/* Fill border with border color: */ |
992 |
|
int rgb = REG(PVRREG_BRDCOLR), addr = 0; |
993 |
|
int x, y, b = rgb & 0xff, g = (rgb >> 8) & 0xff, r = rgb >> 16; |
994 |
|
int skiplen = (d->fb->xsize-2*PVR_MARGIN) * d->fb->bit_depth/8; |
995 |
|
|
996 |
|
for (y=0; y<d->fb->ysize; y++) { |
997 |
|
int xskip = y < PVR_MARGIN || y >= |
998 |
|
d->fb->ysize - PVR_MARGIN? -1 : PVR_MARGIN; |
999 |
|
for (x=0; x<d->fb->xsize; x++) { |
1000 |
|
if (x == xskip) { |
1001 |
|
x = d->fb->xsize - PVR_MARGIN; |
1002 |
|
addr += skiplen; |
1003 |
|
} |
1004 |
|
fb[addr] = r; |
1005 |
|
fb[addr+1] = g; |
1006 |
|
fb[addr+2] = b; |
1007 |
|
addr += 3; |
1008 |
|
} |
1009 |
|
} |
1010 |
|
|
1011 |
|
/* Full redraw of the framebuffer: */ |
1012 |
|
d->fb->update_x1 = 0; d->fb->update_x2 = d->fb->xsize - 1; |
1013 |
|
d->fb->update_y1 = 0; d->fb->update_y2 = d->fb->ysize - 1; |
1014 |
|
} |
1015 |
|
|
1016 |
memory_device_dyntrans_access(cpu, cpu->mem, extra, &low, &high); |
memory_device_dyntrans_access(cpu, cpu->mem, extra, &low, &high); |
1017 |
if ((int64_t)low != -1) |
if ((int64_t)low != -1) |
1018 |
extend_update_region(d, low, high); |
extend_update_region(d, low, high); |
1021 |
return; |
return; |
1022 |
|
|
1023 |
/* Copy (part of) the VRAM to the framebuffer: */ |
/* Copy (part of) the VRAM to the framebuffer: */ |
1024 |
if (d->fb_update_x2 >= d->fb->xsize) |
if (d->fb_update_x2 >= d->xsize) |
1025 |
d->fb_update_x2 = d->fb->xsize - 1; |
d->fb_update_x2 = d->xsize - 1; |
1026 |
if (d->fb_update_y2 >= d->fb->ysize) |
if (d->fb_update_y2 >= d->ysize) |
1027 |
d->fb_update_y2 = d->fb->ysize - 1; |
d->fb_update_y2 = d->ysize - 1; |
1028 |
|
|
1029 |
vram_ofs += d->fb_update_y1 * bytes_per_line; |
vram_ofs += d->fb_update_y1 * bytes_per_line; |
1030 |
vram_ofs += d->fb_update_x1 * d->bytes_per_pixel; |
vram_ofs += d->fb_update_x1 * d->bytes_per_pixel; |
1031 |
pixels_to_copy = (d->fb_update_x2 - d->fb_update_x1 + 1); |
pixels_to_copy = (d->fb_update_x2 - d->fb_update_x1 + 1); |
1032 |
fb_ofs = d->fb_update_y1 * d->fb->bytes_per_line; |
fb_ofs = (d->fb_update_y1 + PVR_MARGIN) * d->fb->bytes_per_line; |
1033 |
fb_ofs += d->fb_update_x1 * d->fb->bit_depth / 8; |
fb_ofs += (d->fb_update_x1 + PVR_MARGIN) * d->fb->bit_depth / 8; |
1034 |
|
|
1035 |
/* Copy the actual pixels: (Four manually inlined, for speed.) */ |
/* Copy the actual pixels: (Four manually inlined, for speed.) */ |
1036 |
|
|
1096 |
* just written to: |
* just written to: |
1097 |
*/ |
*/ |
1098 |
|
|
1099 |
|
/* Offset to take the margin into account first... */ |
1100 |
|
d->fb_update_x1 += PVR_MARGIN; d->fb_update_y1 += PVR_MARGIN; |
1101 |
|
d->fb_update_x2 += PVR_MARGIN; d->fb_update_y2 += PVR_MARGIN; |
1102 |
|
|
1103 |
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) |
1104 |
d->fb->update_x1 = d->fb_update_x1; |
d->fb->update_x1 = d->fb_update_x1; |
1105 |
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) |
1211 |
d->bytes_per_pixel = 2; |
d->bytes_per_pixel = 2; |
1212 |
|
|
1213 |
d->fb = dev_fb_init(machine, machine->memory, INTERNAL_FB_ADDR, |
d->fb = dev_fb_init(machine, machine->memory, INTERNAL_FB_ADDR, |
1214 |
VFB_GENERIC, 640,480, 640,480, 24, "Dreamcast PVR"); |
VFB_GENERIC, d->xsize + PVR_MARGIN*2, d->ysize + PVR_MARGIN*2, |
1215 |
|
d->xsize + PVR_MARGIN*2, d->ysize + PVR_MARGIN*2, |
1216 |
|
24, "Dreamcast PVR"); |
1217 |
|
|
1218 |
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); |
1219 |
|
|