Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


VGA graphics rendering, attribute palette handling, corrected attribute processing
Peter Dinda [Fri, 15 Apr 2011 01:07:59 +0000 (20:07 -0500)]
This commit includes:

   - Implementation of graphics mode rendering
   - Corrected color handling for graphics and text modes (16 color)
       (2 stage color lookup via attribute palette THEN DAC palette)
   - Work around for probable gcc bug to correctly
     process attributes in text mode (this fixes occasional flashing display)

palacios/src/devices/vga.c
palacios/src/devices/vga_regs.h

index 834f780..de6bc66 100644 (file)
@@ -272,7 +272,7 @@ struct vga_dac_regs {
     
 
 struct vga_internal {
-    struct vm_device *dev;  
+    struct vm_device *dev; 
     
     bool passthrough;
     bool skip_next_passthrough_out; // for word access 
@@ -320,6 +320,8 @@ struct vga_internal {
 };
 
 
+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)
 {
@@ -462,30 +464,26 @@ static void find_graphics_res(struct vga_internal *vga, uint32_t *width, uint32_
 }
 
 
-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,
@@ -503,6 +501,207 @@ static void dac_lookup_24bit_color(struct vga_internal *vga,
 
 }
 
+
+/*
+  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
@@ -593,22 +792,22 @@ static void render_text(struct vga_internal *vga, void *fb)
                // 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++) {
@@ -757,11 +956,6 @@ static int render(struct vga_internal *vga)
 
        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 {
@@ -769,8 +963,9 @@ static int render(struct vga_internal *vga)
            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);
     }
@@ -887,10 +1082,6 @@ static int vga_write(struct guest_info * core,
 
     /* 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: {
@@ -925,7 +1116,7 @@ static int vga_write(struct guest_info * core,
                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];
index c9858db..08b65f2 100644 (file)
@@ -632,8 +632,7 @@ page 2-88).
            // 1 = odd/even addressing as in CGMA
            uint8_t shift_reg_mode:1;
            // 1 = shift regs get odd bits from odd maps and even/even
-           uint8_t c256:1;         
-           // 1 = 256 color mode
+           uint8_t c256:1;                 // 1 = 256 color mode
            // 0 = shift_reg_mode controls shift regs
            uint8_t reserved2:1; 
        } __attribute__((packed));
@@ -713,7 +712,7 @@ struct vga_attribute_controller_address_reg {
        uint8_t val;
        struct {
            uint8_t index:5;    // actual address
-           uint8_t internal_palette_address_srouce:1; 
+           uint8_t internal_palette_address_source:1; 
            // 0 => use the internal color palette (load the regs)
            // 1 => use the external color palette
            uint8_t reserved:2; 
@@ -866,27 +865,13 @@ struct vga_attribute_byte {
     union {
        uint8_t val;
        struct {
-           union {
-               uint8_t fore:3;
-               struct { 
-                   uint8_t fore_red:1;
-                   uint8_t fore_green:1;
-                   uint8_t fore_blue:1;
-               } __attribute__((packed));
-           } __attribute__((packed));
+           uint8_t fore:3;   //foreground color
            uint8_t foreground_intensity_or_font_select:1; // depends on char map select reg
            // character map selection is effected
            // when memory_mode.extended meomory=1
            // and the two character map enteries on character_map_select are 
            // different
-           union {
-               uint8_t back:3;
-               struct { 
-                   uint8_t back_red:1;
-                   uint8_t back_green:1;
-                   uint8_t back_blue:1;
-               } __attribute__((packed));
-           } __attribute__((packed));
+           uint8_t back:3;   //background color
            uint8_t blinking_or_bg_intensity:1; 
            // attribute mode control.enableblink = 1 => blink
            // =0 => intensity (16 colors of bg)