* Moved VGA planar mode blitting into the VESA kernel driver.

* In grayscale mode, the AccelerantHWInterface now sets the palette correctly.
* HWInterface now has a fVGADevice set by AccelerantHWInterface which will be used
  to talk to the VESA driver.
* Completed planar blitting for all 4 planes; we now have a perfect 16 color
  grayscale mode when you choose "Standard VGA mode" in the boot loader with
  an unsupported graphics card (such as in Qemu).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19567 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-12-19 22:57:56 +00:00
parent 30b0fe7561
commit 0c6f77951e
12 changed files with 255 additions and 46 deletions

View File

@ -47,6 +47,24 @@ struct vesa_info {
enum {
VESA_GET_PRIVATE_DATA = B_DEVICE_OP_CODES_END + 1,
VESA_GET_DEVICE_NAME,
VGA_SET_INDEXED_COLORS,
VGA_PLANAR_BLIT,
};
struct vga_set_indexed_colors_args {
uint8 first;
uint16 count;
uint8 *colors;
};
struct vga_planar_blit_args {
uint8 *source;
int32 source_bytes_per_row;
int32 left;
int32 top;
int32 right;
int32 bottom;
};
//----------------------------------------------------------

View File

@ -231,8 +231,13 @@ vesa_get_timing_constraints(display_timing_constraints *dtc)
void
vesa_set_indexed_colors(uint count, uint8 first, uint8 *color_data, uint32 flags)
vesa_set_indexed_colors(uint count, uint8 first, uint8 *colors, uint32 flags)
{
TRACE(("vesa_set_indexed_colors()\n"));
vga_set_indexed_colors_args args;
args.first = first;
args.count = count;
args.colors = colors;
ioctl(gInfo->device, VGA_SET_INDEXED_COLORS, &args, sizeof(args));
}

View File

@ -6,5 +6,6 @@ KernelAddon vesa :
device.cpp
driver.cpp
vesa.cpp
vga.cpp
;

View File

@ -1,9 +1,15 @@
/*
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2005-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "device.h"
#include "driver.h"
#include "utility.h"
#include "vesa_info.h"
#include "vga.h"
#include <OS.h>
#include <KernelExport.h>
#include <Drivers.h>
@ -15,11 +21,6 @@
#include <stdlib.h>
#include <string.h>
#include "driver.h"
#include "device.h"
#include "vesa_info.h"
#include "utility.h"
//#define TRACE_DEVICE
#ifdef TRACE_DEVICE
@ -141,6 +142,26 @@ device_ioctl(void *cookie, uint32 msg, void *buffer, size_t bufferLength)
return B_BAD_ADDRESS;
return B_OK;
case VGA_SET_INDEXED_COLORS:
{
vga_set_indexed_colors_args args;
if (user_memcpy(&args, buffer, sizeof(args)) < B_OK)
return B_BAD_ADDRESS;
return vga_set_indexed_colors(args.first, args.colors, args.count);
}
case VGA_PLANAR_BLIT:
{
vga_planar_blit_args args;
if (user_memcpy(&args, buffer, sizeof(args)) < B_OK)
return B_BAD_ADDRESS;
return vga_planar_blit(info->shared_info, args.source,
args.source_bytes_per_row, args.left, args.top,
args.right, args.bottom);
}
default:
TRACE((DEVICE_NAME ": ioctl() unknown message %ld (length = %lu)\n", msg, bufferLength));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2005-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
@ -32,6 +32,7 @@ int32 api_version = B_CUR_DRIVER_API_VERSION;
char *gDeviceNames[MAX_CARDS + 1];
vesa_info *gDeviceInfo[MAX_CARDS];
isa_module_info *gISA;
lock gLock;
@ -88,10 +89,21 @@ init_driver(void)
else
return B_NO_MEMORY;
status_t status = get_module(B_ISA_MODULE_NAME, (module_info **)&gISA);
if (status < B_OK)
goto err1;
gDeviceNames[0] = strdup("graphics/vesa");
gDeviceNames[1] = NULL;
return init_lock(&gLock, "vesa lock");
status = init_lock(&gLock, "vesa lock");
if (status == B_OK)
return B_OK;
put_module(B_ISA_MODULE_NAME);
err1:
free(gDeviceInfo[0]);
return status;
}
@ -100,6 +112,7 @@ uninit_driver(void)
{
TRACE((DEVICE_NAME ": uninit_driver()\n"));
put_module(B_ISA_MODULE_NAME);
uninit_lock(&gLock);
// free device related structures

View File

@ -1,5 +1,5 @@
/*
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2005-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef DRIVER_H
@ -7,7 +7,7 @@
#include <KernelExport.h>
#include <PCI.h>
#include <ISA.h>
#include "vesa_info.h"
#include "lock.h"
@ -15,6 +15,7 @@
extern char *gDeviceNames[];
extern vesa_info *gDeviceInfo[];
extern isa_module_info *gISA;
extern lock gLock;
#endif /* DRIVER_H */

View File

@ -0,0 +1,87 @@
/*
* Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "vga.h"
#include "driver.h"
#include <vga.h>
#include <KernelExport.h>
status_t
vga_set_indexed_colors(uint8 first, uint8 *colors, uint16 count)
{
gISA->write_io_8(VGA_COLOR_WRITE_MODE, first);
// write VGA palette
for (int32 i = first; i < count; i++) {
uint8 color[3];
if (user_memcpy(color, &colors[i * 3], 3) < B_OK)
return B_BAD_ADDRESS;
// VGA (usually) has only 6 bits per gun
gISA->write_io_8(VGA_COLOR_DATA, color[0] >> 2);
gISA->write_io_8(VGA_COLOR_DATA, color[1] >> 2);
gISA->write_io_8(VGA_COLOR_DATA, color[2] >> 2);
}
return B_OK;
}
status_t
vga_planar_blit(vesa_shared_info *info, uint8 *src, int32 srcBPR,
int32 left, int32 top, int32 right, int32 bottom)
{
int32 dstBPR = info->bytes_per_row;
uint8 *dst = info->frame_buffer + top * dstBPR + left / 8;
// TODO: this is awfully slow...
// TODO: assumes BGR order
for (int32 y = top; y <= bottom; y++) {
for (int32 plane = 0; plane < 4; plane++) {
// select the plane we intend to write to and read from
gISA->write_io_16(VGA_SEQUENCER_INDEX, (1 << (plane + 8)) | 0x02);
gISA->write_io_16(VGA_GRAPHICS_INDEX, (plane << 8) | 0x04);
uint8* srcHandle = src;
uint8* dstHandle = dst;
uint8 current8 = dstHandle[0];
// we store 8 pixels before writing them back
int32 x = left;
for (; x <= right; x++) {
uint8 rgba[4];
if (user_memcpy(rgba, srcHandle, 4) < B_OK)
return B_BAD_ADDRESS;
uint8 pixel = (308 * rgba[2] + 600 * rgba[1]
+ 116 * rgba[0]) / 16384;
srcHandle += 4;
if (pixel & (1 << plane))
current8 |= 0x80 >> (x & 7);
else
current8 &= ~(0x80 >> (x & 7));
if ((x & 7) == 7) {
// last pixel in 8 pixel group
dstHandle[0] = current8;
dstHandle++;
current8 = dstHandle[0];
}
}
if (x & 7) {
// last pixel has not been written yet
dstHandle[0] = current8;
}
}
dst += dstBPR;
src += srcBPR;
}
return B_OK;
}

View File

@ -0,0 +1,16 @@
/*
* Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _VGA_H
#define _VGA_H
#include <vesa_info.h>
status_t vga_set_indexed_colors(uint8 first, uint8 *colors, uint16 count);
status_t vga_planar_blit(vesa_shared_info *info, uint8 *src, int32 srcBPR,
int32 left, int32 top, int32 right, int32 bottom);
#endif /* _VGA_H */

View File

@ -153,14 +153,14 @@ AccelerantHWInterface::Initialize()
ATRACE(("Failed to open graphics device\n"));
continue;
}
if (_OpenAccelerant(fCardFD) == B_OK)
break;
close(fCardFD);
// _OpenAccelerant() failed, try to open next graphics card
}
return fCardFD >= 0 ? B_OK : fCardFD;
}
return ret;
@ -214,6 +214,8 @@ AccelerantHWInterface::_OpenGraphicsDevice(int deviceNumber)
if (deviceNumber == 1) {
sprintf(path, "/dev/graphics/vesa");
device = open(path, B_READ_WRITE);
fVGADevice = device;
// store the device, so that we can access the planar blitter
} else {
close(device);
device = B_ENTRY_NOT_FOUND;
@ -528,6 +530,8 @@ AccelerantHWInterface::SetMode(const display_mode& mode)
if (fDisplayMode.space == B_CMAP8)
_SetSystemPalette();
else if (fDisplayMode.space == B_GRAY8)
_SetGrayscalePalette();
// update acceleration hooks
fAccFillRect = (fill_rectangle)fAccelerantHook(B_FILL_RECTANGLE, (void *)&fDisplayMode);
@ -1155,3 +1159,36 @@ AccelerantHWInterface::_SetSystemPalette()
setIndexedColors(256, 0, colors, 0);
}
void
AccelerantHWInterface::_SetGrayscalePalette()
{
set_indexed_colors setIndexedColors = (set_indexed_colors)fAccelerantHook(
B_SET_INDEXED_COLORS, NULL);
if (setIndexedColors == NULL)
return;
uint8 colors[3 * 256];
// the color table is an array with 3 bytes per color
uint32 j = 0;
if (fFrontBuffer->Width() > fFrontBuffer->BytesPerRow()) {
// VGA 16 color grayscale planar mode
for (int32 i = 0; i < 16; i++) {
colors[j++] = i * 17;
colors[j++] = i * 17;
colors[j++] = i * 17;
}
setIndexedColors(16, 0, colors, 0);
} else {
for (int32 i = 0; i < 256; i++) {
colors[j++] = i;
colors[j++] = i;
colors[j++] = i;
}
setIndexedColors(256, 0, colors, 0);
}
}

View File

@ -104,6 +104,7 @@ private:
uint32 _NativeColor(const RGBColor& color) const;
status_t _SetFallbackMode(display_mode& mode) const;
void _SetSystemPalette();
void _SetGrayscalePalette();
int fCardFD;
image_id fAccelerantImage;

View File

@ -16,6 +16,8 @@
#include "SystemPalette.h"
#include "UpdateQueue.h"
#include <vesa/vesa_info.h>
#include <stdio.h>
#include <string.h>
@ -39,6 +41,7 @@ HWInterface::HWInterface(bool doubleBuffered)
fCursorObscured(false),
fCursorLocation(0, 0),
fDoubleBuffered(doubleBuffered),
fVGADevice(-1),
// fUpdateExecutor(new UpdateQueue(this))
fUpdateExecutor(NULL),
fListeners(20)
@ -669,49 +672,54 @@ HWInterface::_CopyToFront(uint8* src, uint32 srcBPR,
case B_GRAY8:
if (frontBuffer->Width() > dstBPR) {
// VGA 16 color grayscale planar mode
if (fVGADevice > 0) {
vga_planar_blit_args args;
args.source = src;
args.source_bytes_per_row = srcBPR;
args.left = x;
args.top = y;
args.right = right;
args.bottom = bottom;
if (ioctl(fVGADevice, VGA_PLANAR_BLIT, &args, sizeof(args)) == 0)
break;
}
// Since we cannot set the plane, we do monochrome output
dst += y * dstBPR + x / 8;
uint8* dstBase = dst;
uint8* srcBase = src;
int32 left = x;
// TODO: this is awfully slow...
// TODO: assumes BGR order
for (int32 plane = 0; plane < 1; plane++) {
// TODO: we need to select the plane here!
src = srcBase;
dst = dstBase;
for (; y <= bottom; y++) {
uint8* srcHandle = src;
uint8* dstHandle = dst;
uint8 current8 = dstHandle[0];
// we store 8 pixels before writing them back
for (; y <= bottom; y++) {
uint8* srcHandle = src;
uint8* dstHandle = dst;
uint8 current8 = dstHandle[0];
// we store 8 pixels before writing them back
for (x = left; x <= right; x++) {
uint8 pixel = (308 * srcHandle[2] + 600 * srcHandle[1]
+ 116 * srcHandle[0]) / 1024;
srcHandle += 4;
for (x = left; x <= right; x++) {
uint8 pixel = (308 * srcHandle[2] + 600 * srcHandle[1]
+ 116 * srcHandle[0]) / 1024;
srcHandle += 4;
if (pixel > 128)
current8 |= 0x80 >> (x & 7);
else
current8 &= ~(0x80 >> (x & 7));
if (pixel > 128)
current8 |= 0x80 >> (x & 7);
else
current8 &= ~(0x80 >> (x & 7));
if ((x & 7) == 7) {
// last pixel in 8 pixel group
dstHandle[0] = current8;
dstHandle++;
current8 = dstHandle[0];
}
}
if (x & 7) {
// last pixel has not been written yet
if ((x & 7) == 7) {
// last pixel in 8 pixel group
dstHandle[0] = current8;
dstHandle++;
current8 = dstHandle[0];
}
dst += dstBPR;
src += srcBPR;
}
if (x & 7) {
// last pixel has not been written yet
dstHandle[0] = current8;
}
dst += dstBPR;
src += srcBPR;
}
} else {
// offset to left top pixel in dest buffer

View File

@ -220,6 +220,7 @@ class HWInterface : protected MultiLocker {
bool fCursorObscured;
BPoint fCursorLocation;
bool fDoubleBuffered;
int fVGADevice;
private:
UpdateQueue* fUpdateExecutor;