mirror of https://github.com/xemu-project/xemu.git
initial support for PVIDEO
This commit is contained in:
parent
b6bf7e751c
commit
7eb49195f0
|
@ -1691,8 +1691,9 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
|||
if (s->line_offset != s->last_line_offset ||
|
||||
disp_width != s->last_width ||
|
||||
height != s->last_height ||
|
||||
s->last_depth != depth) {
|
||||
if (depth == 32 || (depth == 16 && !byteswap)) {
|
||||
s->last_depth != depth ||
|
||||
s->enable_overlay != s->last_enable_overlay) {
|
||||
if (!s->enable_overlay && (depth == 32 || (depth == 16 && !byteswap))) {
|
||||
surface = qemu_create_displaysurface_from(disp_width,
|
||||
height, depth, s->line_offset,
|
||||
s->vram_ptr + (s->start_addr * 4), byteswap);
|
||||
|
@ -1707,8 +1708,9 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
|||
s->last_height = height;
|
||||
s->last_line_offset = s->line_offset;
|
||||
s->last_depth = depth;
|
||||
s->last_enable_overlay = s->enable_overlay;
|
||||
full_update = 1;
|
||||
} else if (is_buffer_shared(surface) &&
|
||||
} else if (!s->enable_overlay && is_buffer_shared(surface) &&
|
||||
(full_update || surface_data(surface) != s->vram_ptr
|
||||
+ (s->start_addr * 4))) {
|
||||
surface = qemu_create_displaysurface_from(disp_width,
|
||||
|
@ -1815,6 +1817,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
|||
page_max = page1;
|
||||
if (!(is_buffer_shared(surface))) {
|
||||
vga_draw_line(s, d, s->vram_ptr + addr, width);
|
||||
if (s->overlay_draw_line)
|
||||
s->overlay_draw_line(s, d, y);
|
||||
if (s->cursor_draw_line)
|
||||
s->cursor_draw_line(s, d, y);
|
||||
}
|
||||
|
|
|
@ -156,9 +156,12 @@ typedef struct VGACommonState {
|
|||
bool full_update_text;
|
||||
bool full_update_gfx;
|
||||
/* hardware mouse cursor support */
|
||||
bool enable_overlay;
|
||||
bool last_enable_overlay;
|
||||
uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32];
|
||||
void (*cursor_invalidate)(struct VGACommonState *s);
|
||||
void (*cursor_draw_line)(struct VGACommonState *s, uint8_t *d, int y);
|
||||
void (*overlay_draw_line)(struct VGACommonState *s, uint8_t *d, int y);
|
||||
/* tell for each page if it has been updated since the last time */
|
||||
uint32_t last_palette[256];
|
||||
uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
|
||||
|
|
188
hw/xbox/nv2a.c
188
hw/xbox/nv2a.c
|
@ -20,6 +20,7 @@
|
|||
#include "hw/i386/pc.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/display/vga.h"
|
||||
#include "hw/display/vga_int.h"
|
||||
#include "qemu/queue.h"
|
||||
|
@ -294,6 +295,42 @@
|
|||
#define NV_PCRTC_CONFIG 0x00000804
|
||||
|
||||
|
||||
#define NV_PVIDEO_INTR 0x00000100
|
||||
# define NV_PVIDEO_INTR_BUFFER_0 (1 << 0)
|
||||
# define NV_PVIDEO_INTR_BUFFER_1 (1 << 4)
|
||||
#define NV_PVIDEO_INTR_EN 0x00000140
|
||||
# define NV_PVIDEO_INTR_EN_BUFFER_0 (1 << 0)
|
||||
# define NV_PVIDEO_INTR_EN_BUFFER_1 (1 << 4)
|
||||
#define NV_PVIDEO_BUFFER 0x00000700
|
||||
# define NV_PVIDEO_BUFFER_0_USE (1 << 0)
|
||||
# define NV_PVIDEO_BUFFER_1_USE (1 << 4)
|
||||
#define NV_PVIDEO_STOP 0x00000704
|
||||
#define NV_PVIDEO_BASE 0x00000900
|
||||
#define NV_PVIDEO_LIMIT 0x00000908
|
||||
#define NV_PVIDEO_LUMINANCE 0x00000910
|
||||
#define NV_PVIDEO_CHROMINANCE 0x00000918
|
||||
#define NV_PVIDEO_OFFSET 0x00000920
|
||||
#define NV_PVIDEO_SIZE_IN 0x00000928
|
||||
# define NV_PVIDEO_SIZE_IN_WIDTH 0x000007FF
|
||||
# define NV_PVIDEO_SIZE_IN_HEIGHT 0x07FF0000
|
||||
#define NV_PVIDEO_POINT_IN 0x00000930
|
||||
# define NV_PVIDEO_POINT_IN_S 0x00007FFF
|
||||
# define NV_PVIDEO_POINT_IN_T 0xFFFE0000
|
||||
#define NV_PVIDEO_DS_DX 0x00000938
|
||||
#define NV_PVIDEO_DT_DY 0x00000940
|
||||
#define NV_PVIDEO_POINT_OUT 0x00000948
|
||||
# define NV_PVIDEO_POINT_OUT_X 0x00000FFF
|
||||
# define NV_PVIDEO_POINT_OUT_Y 0x0FFF0000
|
||||
#define NV_PVIDEO_SIZE_OUT 0x00000950
|
||||
# define NV_PVIDEO_SIZE_OUT_WIDTH 0x00000FFF
|
||||
# define NV_PVIDEO_SIZE_OUT_HEIGHT 0x0FFF0000
|
||||
#define NV_PVIDEO_FORMAT 0x00000958
|
||||
# define NV_PVIDEO_FORMAT_PITCH 0x00001FFF
|
||||
# define NV_PVIDEO_FORMAT_COLOR 0x00030000
|
||||
# define NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8 1
|
||||
# define NV_PVIDEO_FORMAT_DISPLAY (1 << 20)
|
||||
|
||||
|
||||
#define NV_PTIMER_INTR_0 0x00000100
|
||||
# define NV_PTIMER_INTR_0_ALARM (1 << 0)
|
||||
#define NV_PTIMER_INTR_EN_0 0x00000140
|
||||
|
@ -1021,6 +1058,10 @@ typedef struct NV2AState {
|
|||
Cache1State cache1;
|
||||
} pfifo;
|
||||
|
||||
struct {
|
||||
uint32_t regs[0x1000];
|
||||
} pvideo;
|
||||
|
||||
struct {
|
||||
uint32_t pending_interrupts;
|
||||
uint32_t enabled_interrupts;
|
||||
|
@ -3560,16 +3601,56 @@ static void prma_write(void *opaque, hwaddr addr,
|
|||
}
|
||||
|
||||
|
||||
static uint64_t pvideo_read(void *opaque,
|
||||
hwaddr addr, unsigned int size)
|
||||
static void pvideo_vga_invalidate(NV2AState *d)
|
||||
{
|
||||
reg_log_read(NV_PVIDEO, addr, 0);
|
||||
return 0;
|
||||
int y1 = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_OUT],
|
||||
NV_PVIDEO_POINT_OUT_Y);
|
||||
int y2 = y1 + GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_OUT],
|
||||
NV_PVIDEO_SIZE_OUT_HEIGHT);
|
||||
NV2A_DPRINTF("pvideo_vga_invalidate %d %d\n", y1, y2);
|
||||
vga_invalidate_scanlines(&d->vga, y1, y2);
|
||||
}
|
||||
|
||||
static uint64_t pvideo_read(void *opaque,
|
||||
hwaddr addr, unsigned int size)
|
||||
{
|
||||
NV2AState *d = opaque;
|
||||
|
||||
uint64_t r = 0;
|
||||
switch (addr) {
|
||||
case NV_PVIDEO_STOP:
|
||||
r = 0;
|
||||
break;
|
||||
default:
|
||||
r = d->pvideo.regs[addr];
|
||||
break;
|
||||
}
|
||||
|
||||
reg_log_read(NV_PVIDEO, addr, r);
|
||||
return r;
|
||||
}
|
||||
static void pvideo_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned int size)
|
||||
uint64_t val, unsigned int size)
|
||||
{
|
||||
NV2AState *d = opaque;
|
||||
|
||||
reg_log_write(NV_PVIDEO, addr, val);
|
||||
|
||||
switch (addr) {
|
||||
case NV_PVIDEO_BUFFER:
|
||||
d->pvideo.regs[addr] = val;
|
||||
d->vga.enable_overlay = true;
|
||||
pvideo_vga_invalidate(d);
|
||||
break;
|
||||
case NV_PVIDEO_STOP:
|
||||
d->pvideo.regs[NV_PVIDEO_BUFFER] = 0;
|
||||
d->vga.enable_overlay = false;
|
||||
pvideo_vga_invalidate(d);
|
||||
break;
|
||||
default:
|
||||
d->pvideo.regs[addr] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -4430,6 +4511,102 @@ static void pgraph_method_log(unsigned int subchannel,
|
|||
last = method;
|
||||
}
|
||||
|
||||
static uint8_t cliptobyte(int x)
|
||||
{
|
||||
return (uint8_t)((x < 0) ? 0 : ((x > 255) ? 255 : x));
|
||||
}
|
||||
|
||||
static void nv2a_overlay_draw_line(VGACommonState *vga, uint8_t *line, int y)
|
||||
{
|
||||
NV2A_DPRINTF("nv2a_overlay_draw_line\n");
|
||||
|
||||
NV2AState *d = container_of(vga, NV2AState, vga);
|
||||
DisplaySurface *surface = qemu_console_surface(d->vga.con);
|
||||
|
||||
int surf_bpp = surface_bytes_per_pixel(surface);
|
||||
int surf_width = surface_width(surface);
|
||||
|
||||
if (!(d->pvideo.regs[NV_PVIDEO_BUFFER] & NV_PVIDEO_BUFFER_0_USE)) return;
|
||||
|
||||
hwaddr base = d->pvideo.regs[NV_PVIDEO_BASE];
|
||||
hwaddr limit = d->pvideo.regs[NV_PVIDEO_LIMIT];
|
||||
hwaddr offset = d->pvideo.regs[NV_PVIDEO_OFFSET];
|
||||
|
||||
int in_width = GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_IN],
|
||||
NV_PVIDEO_SIZE_IN_WIDTH);
|
||||
int in_height = GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_IN],
|
||||
NV_PVIDEO_SIZE_IN_HEIGHT);
|
||||
int in_s = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_IN],
|
||||
NV_PVIDEO_POINT_IN_S);
|
||||
int in_t = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_IN],
|
||||
NV_PVIDEO_POINT_IN_T);
|
||||
int in_pitch = GET_MASK(d->pvideo.regs[NV_PVIDEO_FORMAT],
|
||||
NV_PVIDEO_FORMAT_PITCH);
|
||||
int in_color = GET_MASK(d->pvideo.regs[NV_PVIDEO_FORMAT],
|
||||
NV_PVIDEO_FORMAT_COLOR);
|
||||
|
||||
// TODO: support other color formats
|
||||
assert(in_color == NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8);
|
||||
|
||||
int out_width = GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_OUT],
|
||||
NV_PVIDEO_SIZE_OUT_WIDTH);
|
||||
int out_height = GET_MASK(d->pvideo.regs[NV_PVIDEO_SIZE_OUT],
|
||||
NV_PVIDEO_SIZE_OUT_HEIGHT);
|
||||
int out_x = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_OUT],
|
||||
NV_PVIDEO_POINT_OUT_X);
|
||||
int out_y = GET_MASK(d->pvideo.regs[NV_PVIDEO_POINT_OUT],
|
||||
NV_PVIDEO_POINT_OUT_Y);
|
||||
|
||||
|
||||
if (y < out_y || y >= out_y + out_height) return;
|
||||
|
||||
// TODO: scaling, color keys
|
||||
|
||||
int in_y = y - out_y;
|
||||
if (in_y >= in_height) return;
|
||||
|
||||
assert(offset + in_pitch * (in_y + 1) <= limit);
|
||||
uint8_t *in_line = d->vram_ptr + base + offset + in_pitch * in_y;
|
||||
|
||||
int x;
|
||||
for (x=0; x<out_width; x++) {
|
||||
int ox = out_x + x;
|
||||
if (ox >= surf_width) break;
|
||||
int ix = in_s + x;
|
||||
if (ix >= in_width) break;
|
||||
|
||||
// YUY2 to RGB
|
||||
int c, d, e;
|
||||
c = (int)in_line[ix * 2] - 16;
|
||||
if (ix % 2) {
|
||||
d = (int)in_line[ix * 2 - 1] - 128;
|
||||
e = (int)in_line[ix * 2 + 1] - 128;
|
||||
} else {
|
||||
d = (int)in_line[ix * 2 + 1] - 128;
|
||||
e = (int)in_line[ix * 2 + 3] - 128;
|
||||
}
|
||||
int r, g, b;
|
||||
r = cliptobyte((298 * c + 409 * e + 128) >> 8);
|
||||
g = cliptobyte((298 * c - 100 * d - 208 * e + 128) >> 8);
|
||||
b = cliptobyte((298 * c + 516 * d + 128) >> 8);
|
||||
|
||||
unsigned int pixel = vga->rgb_to_pixel(r, g, b);
|
||||
switch (surf_bpp) {
|
||||
case 1:
|
||||
((uint8_t*)line)[ox] = pixel;
|
||||
break;
|
||||
case 2:
|
||||
((uint16_t*)line)[ox] = pixel;
|
||||
break;
|
||||
case 4:
|
||||
((uint32_t*)line)[ox] = pixel;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int nv2a_get_bpp(VGACommonState *s)
|
||||
{
|
||||
|
@ -4531,6 +4708,7 @@ static int nv2a_initfn(PCIDevice *dev)
|
|||
vga_common_init(vga, OBJECT(dev));
|
||||
vga->get_bpp = nv2a_get_bpp;
|
||||
vga->get_offsets = nv2a_get_offsets;
|
||||
vga->overlay_draw_line = nv2a_overlay_draw_line;
|
||||
|
||||
d->hw_ops = *vga->hw_ops;
|
||||
d->hw_ops.gfx_update = nv2a_vga_gfx_update;
|
||||
|
|
Loading…
Reference in New Issue