From 0c6f77951ed2366737266cae1bf0c2f98842e6f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 19 Dec 2006 22:57:56 +0000 Subject: [PATCH] * 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 --- headers/private/graphics/vesa/vesa_info.h | 18 ++++ src/add-ons/accelerants/vesa/mode.cpp | 7 +- .../kernel/drivers/graphics/vesa/Jamfile | 1 + .../kernel/drivers/graphics/vesa/device.cpp | 33 +++++-- .../kernel/drivers/graphics/vesa/driver.cpp | 17 +++- .../kernel/drivers/graphics/vesa/driver.h | 5 +- .../kernel/drivers/graphics/vesa/vga.cpp | 87 +++++++++++++++++++ .../kernel/drivers/graphics/vesa/vga.h | 16 ++++ .../app/drawing/AccelerantHWInterface.cpp | 43 ++++++++- .../app/drawing/AccelerantHWInterface.h | 1 + src/servers/app/drawing/HWInterface.cpp | 72 ++++++++------- src/servers/app/drawing/HWInterface.h | 1 + 12 files changed, 255 insertions(+), 46 deletions(-) create mode 100644 src/add-ons/kernel/drivers/graphics/vesa/vga.cpp create mode 100644 src/add-ons/kernel/drivers/graphics/vesa/vga.h diff --git a/headers/private/graphics/vesa/vesa_info.h b/headers/private/graphics/vesa/vesa_info.h index cf86cd1e9b..f67c7368e5 100644 --- a/headers/private/graphics/vesa/vesa_info.h +++ b/headers/private/graphics/vesa/vesa_info.h @@ -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; }; //---------------------------------------------------------- diff --git a/src/add-ons/accelerants/vesa/mode.cpp b/src/add-ons/accelerants/vesa/mode.cpp index 90d83541bd..1a5dbb4714 100644 --- a/src/add-ons/accelerants/vesa/mode.cpp +++ b/src/add-ons/accelerants/vesa/mode.cpp @@ -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)); } diff --git a/src/add-ons/kernel/drivers/graphics/vesa/Jamfile b/src/add-ons/kernel/drivers/graphics/vesa/Jamfile index 785ae69a42..4703adb230 100644 --- a/src/add-ons/kernel/drivers/graphics/vesa/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/vesa/Jamfile @@ -6,5 +6,6 @@ KernelAddon vesa : device.cpp driver.cpp vesa.cpp + vga.cpp ; diff --git a/src/add-ons/kernel/drivers/graphics/vesa/device.cpp b/src/add-ons/kernel/drivers/graphics/vesa/device.cpp index 22de417a86..dd9653ab3c 100644 --- a/src/add-ons/kernel/drivers/graphics/vesa/device.cpp +++ b/src/add-ons/kernel/drivers/graphics/vesa/device.cpp @@ -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 #include #include @@ -15,11 +21,6 @@ #include #include -#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)); } diff --git a/src/add-ons/kernel/drivers/graphics/vesa/driver.cpp b/src/add-ons/kernel/drivers/graphics/vesa/driver.cpp index c6ffdc32ad..8d911bbcfd 100644 --- a/src/add-ons/kernel/drivers/graphics/vesa/driver.cpp +++ b/src/add-ons/kernel/drivers/graphics/vesa/driver.cpp @@ -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 diff --git a/src/add-ons/kernel/drivers/graphics/vesa/driver.h b/src/add-ons/kernel/drivers/graphics/vesa/driver.h index 586117ed0f..45d17c1ebf 100644 --- a/src/add-ons/kernel/drivers/graphics/vesa/driver.h +++ b/src/add-ons/kernel/drivers/graphics/vesa/driver.h @@ -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 -#include +#include #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 */ diff --git a/src/add-ons/kernel/drivers/graphics/vesa/vga.cpp b/src/add-ons/kernel/drivers/graphics/vesa/vga.cpp new file mode 100644 index 0000000000..ec1c4e76ce --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/vesa/vga.cpp @@ -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 + +#include + + +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; +} + diff --git a/src/add-ons/kernel/drivers/graphics/vesa/vga.h b/src/add-ons/kernel/drivers/graphics/vesa/vga.h new file mode 100644 index 0000000000..573c99f86b --- /dev/null +++ b/src/add-ons/kernel/drivers/graphics/vesa/vga.h @@ -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 + + +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 */ diff --git a/src/servers/app/drawing/AccelerantHWInterface.cpp b/src/servers/app/drawing/AccelerantHWInterface.cpp index eec1be2251..f071b82db7 100644 --- a/src/servers/app/drawing/AccelerantHWInterface.cpp +++ b/src/servers/app/drawing/AccelerantHWInterface.cpp @@ -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); + } +} diff --git a/src/servers/app/drawing/AccelerantHWInterface.h b/src/servers/app/drawing/AccelerantHWInterface.h index 3849a4c94c..ef2c72de24 100644 --- a/src/servers/app/drawing/AccelerantHWInterface.h +++ b/src/servers/app/drawing/AccelerantHWInterface.h @@ -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; diff --git a/src/servers/app/drawing/HWInterface.cpp b/src/servers/app/drawing/HWInterface.cpp index 259792d3da..ffdcfe3bd7 100644 --- a/src/servers/app/drawing/HWInterface.cpp +++ b/src/servers/app/drawing/HWInterface.cpp @@ -16,6 +16,8 @@ #include "SystemPalette.h" #include "UpdateQueue.h" +#include + #include #include @@ -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 diff --git a/src/servers/app/drawing/HWInterface.h b/src/servers/app/drawing/HWInterface.h index 6a9c5d16a4..2f9bc43350 100644 --- a/src/servers/app/drawing/HWInterface.h +++ b/src/servers/app/drawing/HWInterface.h @@ -220,6 +220,7 @@ class HWInterface : protected MultiLocker { bool fCursorObscured; BPoint fCursorLocation; bool fDoubleBuffered; + int fVGADevice; private: UpdateQueue* fUpdateExecutor;