struct vga_internal {
- struct vm_device *dev;
+ struct vm_device *dev;
bool passthrough;
bool skip_next_passthrough_out; // for word access
};
+typedef enum {PLANAR_SHIFT, PACKED_SHIFT, C256_SHIFT} shift_mode_t;
+
static void find_text_char_dim(struct vga_internal *vga, uint32_t *w, uint32_t *h)
{
}
-static void find_graphics_cursor_pos(struct vga_internal *vga, uint32_t *width, uint32_t *height)
+static void find_graphics_cursor_pos(struct vga_internal *vga, uint32_t *x, uint32_t *y)
{
-
+ // todo
+ *x=*y=0;
}
-static void render_graphics(struct vga_internal *vga, void *fb)
-{
- PrintDebug("vga: render_graphics is unimplemented\n");
- // Multiuplane 16
- // Packed pixel mono
- // packed pixel 4 color
- // packed pixel 256 color
-
- find_graphics_cursor_pos(0,0,0);
-
-}
-
-static void render_text_cursor(struct vga_internal *vga, void *fb)
+static void find_shift_mode(struct vga_internal *vga, shift_mode_t *mode)
{
+ if (vga->vga_graphics_controller.vga_graphics_mode.c256) {
+ *mode=C256_SHIFT;
+ } else {
+ if (vga->vga_graphics_controller.vga_graphics_mode.shift_reg_mode) {
+ *mode=PACKED_SHIFT;
+ } else {
+ *mode=PLANAR_SHIFT;
+ }
+ }
}
-
-
static void dac_lookup_24bit_color(struct vga_internal *vga,
uint8_t entry,
uint8_t *red,
}
+
+/*
+ Colors work like this:
+
+ 4 bit modes: index is to the internal palette on the attribute controller
+ that supplies 6 bits, but we need 8 to index the dac
+ 2 more (the msbs) are supplied from the color select register
+ we can optionally overwrite bits 5 and 4 from the color
+ select register as well, depending on a selection bit
+ in the mode control register. The result of all this is
+ 8 bit index for the dac
+
+ 8 bit modes: the attribute controller passes the index straight through
+ to the DAC.
+
+
+ The DAC translates from the 8 bit index into 6 bits per color channel
+ (18 bit color). We mulitply by 4 to get 24 bit color.
+*/
+
+static void find_24bit_color(struct vga_internal *vga,
+ uint8_t val,
+ uint8_t *red,
+ uint8_t *green,
+ uint8_t *blue)
+{
+ uint8_t di; // ultimate dac index
+
+ if (vga->vga_attribute_controller.vga_attribute_mode_control.pixel_width) {
+ // 8 bit mode does right to the DAC
+ di=val;
+ } else {
+ struct vga_internal_palette_reg pr = vga->vga_attribute_controller.vga_internal_palette[val%16];
+ di = pr.palette_data;
+
+ // Fix bits 5-4 if needed
+ if (vga->vga_attribute_controller.vga_attribute_mode_control.p54_select) {
+ di &= ~0x30; // clear 5-4
+ di |= vga->vga_attribute_controller.vga_color_select.sc4 << 4;
+ di |= vga->vga_attribute_controller.vga_color_select.sc5 << 5;
+ }
+
+ // We must always produce bits 6 and 7
+ di &= ~0xc0; // clear 7-6
+ di |= vga->vga_attribute_controller.vga_color_select.sc6 << 6;
+ di |= vga->vga_attribute_controller.vga_color_select.sc7 << 7;
+ }
+
+ dac_lookup_24bit_color(vga,di,red,green,blue);
+}
+
+static void render_graphics(struct vga_internal *vga, void *fb)
+{
+
+ struct v3_frame_buffer_spec *spec = &(vga->target_spec);
+
+ uint32_t gw, gh; // graphics w/h
+ uint32_t fw, fh; // fb w/h
+ uint32_t rgw, rgh; // region we can actually show on the frame buffer
+
+
+ uint32_t fx, fy; // pixel position within the frame buffer
+
+ uint32_t offset; // offset into the maps
+ uint8_t m; // map
+ uint8_t p; // pixel in the current map byte (0..7)
+
+ uint8_t r,g,b; // looked up colors for entry
+
+ void *pixel; // current pixel in the fb
+ uint8_t *red; // and the channels in the pixel
+ uint8_t *green; //
+ uint8_t *blue; //
+
+ uint8_t db[4]; // 4 bytes read at a time
+ uint8_t pb[8]; // 8 pixels assembled at a time
+
+ shift_mode_t sm; // shift mode
+
+ uint32_t cur_x, cur_y;
+
+
+ find_graphics_res(vga,&gw,&gh);
+
+ find_shift_mode(vga,&sm);
+
+ find_graphics_cursor_pos(vga,&cur_x,&cur_y);
+
+ fw = spec->width;
+ fh = spec->height;
+
+
+ PrintDebug("vga: attempting graphics render (%s): graphics_res=(%u,%u), fb_res=(%u,%u), "
+ "fb=0x%p (16 color mode)\n",
+ sm == PLANAR_SHIFT ? "planar shift" :
+ sm == PACKED_SHIFT ? "packed shift" :
+ sm == C256_SHIFT ? "color256 shift" : "UNKNOWN",
+ gw,gh,fw,fh, fb);
+
+ // First we need to clip to what we can actually show
+ rgw = gw < fw ? gw : fw;
+ rgh = gh < fh ? gh : gw;
+
+ if (gw%8) {
+ PrintError("vga: warning: graphics width is not a multiple of 8\n");
+ }
+
+ offset=0; // do we always start at zero in the map?
+
+ // Now we scan across by row
+ for (fy=0;fy<gh;fy++) {
+ // by column
+ for (fx=0;fx<gw;
+ fx += (sm==C256_SHIFT ? 4 : 8) , offset++ ) {
+
+ // if any of these pixels are in the renger region
+ if (fy < rgh && fx < rgw) {
+ // assemble all 4 or 8 pixels
+
+ // fetch the data bytes
+ for (m=0;m<4;m++) {
+ db[m]=*((uint8_t*)(vga->map[m]+offset));
+ }
+
+ // assemble
+ switch (sm) {
+ case PLANAR_SHIFT:
+ for (p=0;p<8;p++) {
+ pb[p]=
+ ( db[0] >> 7) |
+ ( db[1] >> 6) |
+ ( db[2] >> 5) |
+ ( db[3] >> 4) ;
+
+ for (m=0;m<4;m++) {
+ db[m] <<= 1;
+ }
+ }
+ break;
+
+ case PACKED_SHIFT:
+ // first 4 pixels use planes 0 and 2
+ for (p=0;p<4;p++) {
+ pb[p] =
+ ( db[2] >> 4) |
+ ( db[0] >> 6) ;
+ db[2] <<= 2;
+ db[0] <<= 2;
+ }
+ break;
+
+ // next 4 pixels use planes 1 and 3
+ for (p=4;p<8;p++) {
+ pb[p] =
+ ( db[3] >> 4) |
+ ( db[1] >> 6) ;
+ db[3] <<= 2;
+ db[1] <<= 2;
+ }
+ break;
+
+ case C256_SHIFT:
+ // this one is either very bizarre or as simple as this
+ for (p=0;p<4;p++) {
+ pb[p] = db[p];
+ }
+ break;
+ }
+
+ // draw each pixel
+ for (p=0;p< (sm==C256_SHIFT ? 4 : 8);p++) {
+
+ // find its color
+ find_24bit_color(vga,db[p],&r,&g,&b);
+
+ // find its position in the framebuffer;
+ pixel = fb + (((fx + p) + (fy*spec->width)) * spec->bytes_per_pixel);
+ red = pixel + spec->red_offset;
+ green = pixel + spec->green_offset;
+ blue = pixel + spec->blue_offset;
+
+ // draw it
+ *red=r;
+ *green=g;
+ *blue=b;
+ }
+ }
+ }
+ }
+
+ PrintDebug("vga: render done\n");
+}
+
+
+static void render_text_cursor(struct vga_internal *vga, void *fb)
+{
+}
+
+
+
+
//
// A variant of this function could render to
// a text console interface as well
// foreground
if (!extended_fontset(vga)) {
- fg_entry = ((uint8_t)(a.foreground_intensity_or_font_select)) << 3;
+ fg_entry = a.foreground_intensity_or_font_select << 3;
} else {
fg_entry = 0;
}
fg_entry |= a.fore;
- dac_lookup_24bit_color(vga,fg_entry,&fgr,&fgg,&fgb);
+ find_24bit_color(vga,fg_entry,&fgr,&fgg,&fgb);
if (!blinking(vga)) {
- bg_entry = ((uint8_t)(a.blinking_or_bg_intensity)) << 3;
+ bg_entry = a.blinking_or_bg_intensity << 3;
} else {
bg_entry = 0;
}
bg_entry |= a.back;
- dac_lookup_24bit_color(vga,bg_entry,&bgr,&bgg,&bgb);
+ find_24bit_color(vga,bg_entry,&bgr,&bgg,&bgb);
// Draw the character
for (l=0; l<ch; l++, font++) {
fb = v3_graphics_console_get_frame_buffer_data_rw(vga->host_cons,&(vga->target_spec));
- // Draw some crap for testing for now
- if (0) { render_test(vga,fb);}
- // Draw the maps for debugging
- if (0) { render_maps(vga,fb);}
-
if (vga->vga_graphics_controller.vga_misc.graphics_mode) {
render_graphics(vga,fb);
} else {
render_text_cursor(vga,fb);
}
- render_maps(vga,fb);
+ if (0) { render_test(vga,fb); }
+ render_maps(vga,fb);
v3_graphics_console_release_frame_buffer_data_rw(vga->host_cons);
}
/* Write mode determine by Graphics Mode Register (Index 05h).writemode */
- // Probably need to add odd/even mode access here for text
-
- PrintDebug("vga: write is with odd/even = %u\n", vga->vga_sequencer.vga_mem_mode.odd_even);
-
switch (vga->vga_graphics_controller.vga_graphics_mode.write_mode) {
case 0: {
uint8_t bm = vga->vga_graphics_controller.vga_bit_mask;
uint8_t mm = find_map_write(vga,guest_addr+i);
- PrintDebug("vga: write i=%u, mm=0x%x, offset=0x%x\n",i,(unsigned int)mm,(unsigned int)offset);
+ //PrintDebug("vga: write i=%u, mm=0x%x, offset=0x%x\n",i,(unsigned int)mm,(unsigned int)offset);
for (mapnum=0;mapnum<4;mapnum++, sr>>=1, esr>>=1, bm>>=1, mm>>=1) {
vga_map map = vga->map[mapnum];