Accelerant based implementations of HWInterface and RenderingBuffer. Untested.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12123 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2005-03-29 16:31:46 +00:00
parent 0985210969
commit b2c9e18270
6 changed files with 1270 additions and 1 deletions

View File

@ -32,10 +32,12 @@ if ( $(TARGET_PLATFORM) = haiku ) {
#ScreenDriver.cpp
# Painter based DisplayDriver Classes
BitmapBuffer.cpp
AccelerantBuffer.cpp
DisplayDriverPainter.cpp
HWInterface.cpp
UpdateQueue.cpp
ViewHWInterface.cpp
AccelerantHWInterface.cpp
;
}

View File

@ -0,0 +1,127 @@
//------------------------------------------------------------------------------
// Copyright (c) 2005, Haiku, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: AccelerantBuffer.cpp
// Author: Michael Lotz <mmlr@mlotz.ch>
// Description: A RenderingBuffer implementation that accesses graphics
// memory directly.
//
//------------------------------------------------------------------------------
#include "AccelerantBuffer.h"
// constructors
AccelerantBuffer::AccelerantBuffer()
: fDisplayModeSet(false),
fFrameBufferConfigSet(false)
{
}
AccelerantBuffer::AccelerantBuffer( const display_mode &mode,
const frame_buffer_config &config)
: fDisplayModeSet(false),
fFrameBufferConfigSet(false)
{
SetDisplayMode(mode);
SetFrameBufferConfig(config);
}
// destructor
AccelerantBuffer::~AccelerantBuffer()
{
}
// InitCheck
status_t
AccelerantBuffer::InitCheck() const
{
if (fDisplayModeSet && fFrameBufferConfigSet)
return B_OK;
return B_NO_INIT;
}
// ColorSpace
color_space
AccelerantBuffer::ColorSpace() const
{
if (InitCheck() == B_OK)
return (color_space)fDisplayMode.space;
return B_NO_COLOR_SPACE;
}
// Bits
void *
AccelerantBuffer::Bits() const
{
if (InitCheck() != B_OK)
return NULL;
if (fFrameBufferConfig.frame_buffer_dma)
return fFrameBufferConfig.frame_buffer_dma;
return fFrameBufferConfig.frame_buffer;
}
// BytesPerRow
uint32
AccelerantBuffer::BytesPerRow() const
{
if (InitCheck() == B_OK)
return fFrameBufferConfig.bytes_per_row;
return 0;
}
// Width
uint32
AccelerantBuffer::Width() const
{
if (InitCheck() == B_OK)
return fDisplayMode.virtual_width;
return 0;
}
// Height
uint32
AccelerantBuffer::Height() const
{
if (InitCheck() == B_OK)
return fDisplayMode.virtual_height;
return 0;
}
void
AccelerantBuffer::SetDisplayMode(const display_mode &mode)
{
fDisplayMode = mode;
fDisplayModeSet = true;
}
void
AccelerantBuffer::SetFrameBufferConfig(const frame_buffer_config &config)
{
fFrameBufferConfig = config;
fFrameBufferConfigSet = true;
}

View File

@ -0,0 +1,61 @@
//------------------------------------------------------------------------------
// Copyright (c) 2005, Haiku, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: AccelerantBuffer.h
// Author: Michael Lotz <mmlr@mlotz.ch>
// Description: A RenderingBuffer implementation that accesses graphics
// memory directly.
//
//------------------------------------------------------------------------------
#ifndef ACCELERANT_BUFFER_H
#define ACCELERANT_BUFFER_H
#include <Accelerant.h>
#include "RenderingBuffer.h"
class AccelerantBuffer : public RenderingBuffer {
public:
AccelerantBuffer();
AccelerantBuffer(const display_mode &mode,
const frame_buffer_config &config);
virtual ~AccelerantBuffer();
virtual status_t InitCheck() const;
virtual color_space ColorSpace() const;
virtual void *Bits() const;
virtual uint32 BytesPerRow() const;
virtual uint32 Width() const;
virtual uint32 Height() const;
void SetDisplayMode(const display_mode &mode);
void SetFrameBufferConfig(const frame_buffer_config &config);
private:
display_mode fDisplayMode;
frame_buffer_config fFrameBufferConfig;
bool fDisplayModeSet;
bool fFrameBufferConfigSet;
};
#endif // ACCELERANT_BUFFER_H

View File

@ -0,0 +1,966 @@
//------------------------------------------------------------------------------
//
// Copyright 2002-2005, Haiku, Inc.
// Distributed under the terms of the MIT License.
//
//
// File Name: AccelerantHWInterface.cpp
// Authors: Michael Lotz <mmlr@mlotz.ch>
// DarkWyrm <bpmagic@columbus.rr.com>
// Stephan Aßmus <superstippi@gmx.de>
// Description: Accelerant based HWInterface implementation
//
//------------------------------------------------------------------------------
#include <stdio.h>
#include <Bitmap.h>
#include <Cursor.h>
#include <Locker.h>
#include <Message.h>
#include <MessageRunner.h>
#include <Region.h>
#include <Accelerant.h>
#include <graphic_driver.h>
#include <FindDirectory.h>
#include <image.h>
#include <dirent.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "PortLink.h"
#include "ServerConfig.h"
#include "ServerCursor.h"
#include "ServerProtocol.h"
#include "UpdateQueue.h"
#include "AccelerantHWInterface.h"
#include "AccelerantBuffer.h"
#include "BitmapBuffer.h"
#ifdef DEBUG_DRIVER_MODULE
# include <stdio.h>
# define ATRACE(x) printf x
#else
# define ATRACE(x) ;
#endif
const unsigned char kEmptyCursor[] = { 16, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
enum {
MSG_UPDATE = 'updt',
};
// constructor
AccelerantHWInterface::AccelerantHWInterface()
: HWInterface(),
fCardFD(-1),
fAccelerantImage(-1),
fAccelerantHook(NULL),
fEngineToken(NULL),
// required hooks
fAccAcquireEngine(NULL),
fAccReleaseEngine(NULL),
fAccGetModeCount(NULL),
fAccGetModeList(NULL),
fAccGetFrameBufferConfig(NULL),
fAccSetDisplayMode(NULL),
fAccGetPixelClockLimits(NULL),
// optional accelerant hooks
fAccGetTimingConstraints(NULL),
fAccProposeDisplayMode(NULL),
fAccFillRect(NULL),
fAccInvertRect(NULL),
fAccScreenBlit(NULL),
fAccSetCursorShape(NULL),
fAccMoveCursor(NULL),
fAccShowCursor(NULL),
// dpms hooks
fAccDPMSCapabilities(NULL),
fAccDPMSMode(NULL),
fAccSetDPMSMode(NULL),
fModeCount(0),
fModeList(NULL),
fBackBuffer(NULL),
fFrontBuffer(NULL),
fUpdateExecutor(new UpdateQueue(this))
{
fDisplayMode.virtual_width = 640;
fDisplayMode.virtual_height = 480;
fDisplayMode.space = B_RGB32;
fFrontBuffer = new AccelerantBuffer();
// TODO: isn't this supposed to be called form outside?
Initialize();
}
// destructor
AccelerantHWInterface::~AccelerantHWInterface()
{
delete fBackBuffer;
delete fFrontBuffer;
delete fModeList;
}
// Initialize
status_t
AccelerantHWInterface::Initialize()
{
char path[PATH_MAX];
fCardFD = OpenGraphicsDevice(1);
if (fCardFD < 0) {
ATRACE(("Failed to open graphics device\n"));
return B_ERROR;
}
char signature[1024];
if (ioctl(fCardFD, B_GET_ACCELERANT_SIGNATURE, &signature, sizeof(signature)) != B_OK) {
close(fCardFD);
return B_ERROR;
}
ATRACE(("accelerant signature is: %s\n", signature));
struct stat accelerant_stat;
const static directory_which dirs[] = {
B_USER_ADDONS_DIRECTORY,
B_COMMON_ADDONS_DIRECTORY,
B_BEOS_ADDONS_DIRECTORY
};
fAccelerantImage = -1;
for (int32 i = 0; i < 3; i++) {
if (find_directory(dirs[i], -1, false, path, PATH_MAX) != B_OK)
continue;
strcat(path, "/accelerants/");
strcat(path, signature);
if (stat(path, &accelerant_stat) != 0)
continue;
fAccelerantImage = load_add_on(path);
if (fAccelerantImage >= 0) {
if (get_image_symbol(fAccelerantImage, B_ACCELERANT_ENTRY_POINT,
B_SYMBOL_TYPE_ANY, (void**)(&fAccelerantHook)) != B_OK ) {
ATRACE(("unable to get B_ACCELERANT_ENTRY_POINT\n"));
unload_add_on(fAccelerantImage);
fAccelerantImage = -1;
return B_ERROR;
}
init_accelerant InitAccelerant;
InitAccelerant = (init_accelerant)fAccelerantHook(B_INIT_ACCELERANT, NULL);
if (!InitAccelerant || InitAccelerant(fCardFD) != B_OK) {
// TODO: continue / go on to the next graphics card?
ATRACE(("InitAccelerant unsuccessful\n"));
unload_add_on(fAccelerantImage);
fAccelerantImage = -1;
return B_ERROR;
}
break;
}
}
if (fAccelerantImage < 0)
return B_ERROR;
if (SetupDefaultHooks() != B_OK) {
ATRACE(("cannot setup default hooks\n"));
return B_ERROR;
}
return B_OK;
}
/*!
\brief Opens a graphics device for read-write access
\param deviceNumber Number identifying which graphics card to open (1 for first card)
\return The file descriptor for the opened graphics device
The deviceNumber is relative to the number of graphics devices that can be successfully
opened. One represents the first card that can be successfully opened (not necessarily
the first one listed in the directory).
*/
int
AccelerantHWInterface::OpenGraphicsDevice(int deviceNumber)
{
DIR *directory = opendir("/dev/graphics");
if (!directory)
return -1;
int count = 0;
struct dirent *entry;
int current_card_fd = -1;
char path[PATH_MAX];
while ((count < deviceNumber) && ((entry = readdir(directory)) != NULL)) {
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") ||
!strcmp(entry->d_name, "stub"))
continue;
if (current_card_fd >= 0) {
close(current_card_fd);
current_card_fd = -1;
}
sprintf(path, "/dev/graphics/%s", entry->d_name);
current_card_fd = open(path, B_READ_WRITE);
if (current_card_fd >= 0)
count++;
}
// open stub if we were not able to get a "real" card
if (count < deviceNumber) {
if (deviceNumber == 1) {
sprintf(path, "/dev/graphics/stub");
current_card_fd = open(path, B_READ_WRITE);
} else {
close(current_card_fd);
current_card_fd = -1;
}
}
return current_card_fd;
}
status_t
AccelerantHWInterface::SetupDefaultHooks()
{
// required
fAccAcquireEngine = (acquire_engine)fAccelerantHook(B_ACQUIRE_ENGINE, NULL);
fAccReleaseEngine = (release_engine)fAccelerantHook(B_RELEASE_ENGINE, NULL);
fAccGetModeCount = (accelerant_mode_count)fAccelerantHook(B_ACCELERANT_MODE_COUNT, NULL);
fAccGetModeList = (get_mode_list)fAccelerantHook(B_GET_MODE_LIST, NULL);
fAccGetFrameBufferConfig = (get_frame_buffer_config)fAccelerantHook(B_GET_FRAME_BUFFER_CONFIG, NULL);
fAccSetDisplayMode = (set_display_mode)fAccelerantHook(B_SET_DISPLAY_MODE, NULL);
fAccGetPixelClockLimits = (get_pixel_clock_limits)fAccelerantHook(B_GET_PIXEL_CLOCK_LIMITS, NULL);
if (!fAccAcquireEngine || !fAccReleaseEngine || !fAccGetFrameBufferConfig
|| !fAccGetModeCount || !fAccGetModeList || !fAccSetDisplayMode
|| !fAccGetPixelClockLimits)
return B_ERROR;
// optional
fAccGetTimingConstraints = (get_timing_constraints)fAccelerantHook(B_GET_TIMING_CONSTRAINTS, NULL);
fAccProposeDisplayMode = (propose_display_mode)fAccelerantHook(B_PROPOSE_DISPLAY_MODE, NULL);
fAccFillRect = (fill_rectangle)fAccelerantHook(B_FILL_RECTANGLE, NULL);
fAccInvertRect = (invert_rectangle)fAccelerantHook(B_INVERT_RECTANGLE, NULL);
fAccScreenBlit = (screen_to_screen_blit)fAccelerantHook(B_SCREEN_TO_SCREEN_BLIT, NULL);
fAccSetCursorShape = (set_cursor_shape)fAccelerantHook(B_SET_CURSOR_SHAPE, NULL);
fAccMoveCursor = (move_cursor)fAccelerantHook(B_MOVE_CURSOR, NULL);
fAccShowCursor = (show_cursor)fAccelerantHook(B_SHOW_CURSOR, NULL);
// dpms
fAccDPMSCapabilities = (dpms_capabilities)fAccelerantHook(B_DPMS_CAPABILITIES, NULL);
fAccDPMSMode = (dpms_mode)fAccelerantHook(B_DPMS_MODE, NULL);
fAccSetDPMSMode = (set_dpms_mode)fAccelerantHook(B_SET_DPMS_MODE, NULL);
return B_OK;
}
// Shutdown
status_t
AccelerantHWInterface::Shutdown()
{
if (fAccelerantHook) {
uninit_accelerant UninitAccelerant = (uninit_accelerant)fAccelerantHook(B_UNINIT_ACCELERANT, NULL);
if (UninitAccelerant)
UninitAccelerant();
}
if (fAccelerantImage >= 0)
unload_add_on(fAccelerantImage);
if (fCardFD >= 0)
close(fCardFD);
return B_OK;
}
// SetMode
status_t
AccelerantHWInterface::SetMode(const display_mode &mode)
{
// prevent from doing the unnecessary
if (fModeCount > 0 && fBackBuffer && fFrontBuffer
&& fDisplayMode.virtual_width == mode.virtual_width
&& fDisplayMode.virtual_height == mode.virtual_height
&& fDisplayMode.space == mode.space) {
return B_OK;
}
// TODO: check if the mode is valid even (ie complies to the modes we said we would support)
// or else ret = B_BAD_VALUE
if (fModeCount <= 0 || !fModeList) {
if (UpdateModeList() != B_OK || fModeCount <= 0) {
ATRACE(("unable to update mode list\n"));
return B_ERROR;
}
}
for (int32 i = 0; i < fModeCount; i++) {
if (fModeList[i].virtual_width == mode.virtual_width
&& fModeList[i].virtual_height == mode.virtual_height
&& fModeList[i].space == mode.space) {
fDisplayMode = fModeList[i];
break;
}
}
if (fAccSetDisplayMode(&fDisplayMode) != B_OK) {
ATRACE(("setting display mode failed\n"));
return B_ERROR;
}
// update frontbuffer
fFrontBuffer->SetDisplayMode(fDisplayMode);
if (UpdateFrameBufferConfig() != B_OK)
return B_ERROR;
// update backbuffer if neccessary
if (!fBackBuffer || fBackBuffer->Width() != fDisplayMode.virtual_width
|| fBackBuffer->Height() != fDisplayMode.virtual_height) {
// NOTE: backbuffer is always B_RGBA32, this simplifies the
// drawing backend implementation tremendously for the time
// being. The color space conversion is handled in CopyBackToFront()
BRect bounds(0, 0, fDisplayMode.virtual_width, fDisplayMode.virtual_height);
BBitmap *backBitmap = new BBitmap(bounds, 0, B_RGBA32);
delete fBackBuffer;
fBackBuffer = new BitmapBuffer(backBitmap);
if (fBackBuffer->InitCheck() != B_OK) {
delete fBackBuffer;
fBackBuffer = NULL;
return B_ERROR;
}
// clear out backbuffer, alpha is 255 this way
// TODO: maybe this should handle different color spaces in different
// ways
memset(backBitmap->Bits(), 255, backBitmap->BitsLength());
}
return B_OK;
}
void
AccelerantHWInterface::GetMode(display_mode *mode)
{
*mode = fDisplayMode;
}
status_t
AccelerantHWInterface::UpdateModeList()
{
fModeCount = fAccGetModeCount();
if (fModeCount <= 0)
return B_ERROR;
fModeList = new display_mode[fModeCount];;
if (!fModeList)
return B_NO_MEMORY;
if (fAccGetModeList(fModeList) != B_OK) {
ATRACE(("unable to get mode list\n"));
return B_ERROR;
}
return B_OK;
}
status_t
AccelerantHWInterface::UpdateFrameBufferConfig()
{
if (fAccGetFrameBufferConfig(&fFrameBufferConfig) != B_OK) {
ATRACE(("unable to get frame buffer config\n"));
return B_ERROR;
}
fFrontBuffer->SetFrameBufferConfig(fFrameBufferConfig);
return B_OK;
}
// GetDeviceInfo
status_t
AccelerantHWInterface::GetDeviceInfo(accelerant_device_info *info)
{
get_accelerant_device_info GetAccelerantDeviceInfo = (get_accelerant_device_info)fAccelerantHook(B_GET_ACCELERANT_DEVICE_INFO, NULL);
if (!GetAccelerantDeviceInfo) {
ATRACE(("No B_GET_ACCELERANT_DEVICE_INFO hook found\n"));
return B_UNSUPPORTED;
}
return GetAccelerantDeviceInfo(info);
}
// GetModeList
status_t
AccelerantHWInterface::GetModeList(display_mode **modes, uint32 *count)
{
if (!count || !modes)
return B_BAD_VALUE;
*modes = new display_mode[fModeCount];
*count = fModeCount;
memcpy(*modes, fModeList, sizeof(display_mode) * fModeCount);
return B_OK;
}
status_t
AccelerantHWInterface::GetPixelClockLimits(display_mode *mode, uint32 *low, uint32 *high)
{
if (!mode || !low || !high)
return B_BAD_VALUE;
return fAccGetPixelClockLimits(mode, low, high);
}
status_t
AccelerantHWInterface::GetTimingConstraints(display_timing_constraints *dtc)
{
if (!dtc)
return B_BAD_VALUE;
if (fAccGetTimingConstraints)
return fAccGetTimingConstraints(dtc);
return B_UNSUPPORTED;
}
status_t
AccelerantHWInterface::ProposeMode(display_mode *candidate, const display_mode *low, const display_mode *high)
{
if (!candidate || !low || !high)
return B_BAD_VALUE;
if (!fAccProposeDisplayMode)
return B_UNSUPPORTED;
// avoid const issues
display_mode this_high, this_low;
this_high = *high;
this_low = *low;
return fAccProposeDisplayMode(candidate, &this_low, &this_high);
}
// SetDPMSMode
status_t
AccelerantHWInterface::SetDPMSMode(const uint32 &state)
{
if (!fAccSetDPMSMode)
return B_UNSUPPORTED;
return fAccSetDPMSMode(state);
}
// DPMSMode
uint32
AccelerantHWInterface::DPMSMode() const
{
if (!fAccDPMSMode)
return B_UNSUPPORTED;
return fAccDPMSMode();
}
// DPMSCapabilities
uint32
AccelerantHWInterface::DPMSCapabilities() const
{
if (!fAccDPMSCapabilities)
return B_UNSUPPORTED;
return fAccDPMSCapabilities();
}
// WaitForRetrace
status_t
AccelerantHWInterface::WaitForRetrace(bigtime_t timeout = B_INFINITE_TIMEOUT)
{
accelerant_retrace_semaphore AccelerantRetraceSemaphore = (accelerant_retrace_semaphore)fAccelerantHook(B_ACCELERANT_RETRACE_SEMAPHORE, NULL);
if (!AccelerantRetraceSemaphore)
return B_UNSUPPORTED;
sem_id sem = AccelerantRetraceSemaphore();
if (sem < 0)
return B_ERROR;
return acquire_sem_etc(sem, 1, B_RELATIVE_TIMEOUT, timeout);
}
// FrontBuffer
RenderingBuffer *
AccelerantHWInterface::FrontBuffer() const
{
return fFrontBuffer;
}
// BackBuffer
RenderingBuffer *
AccelerantHWInterface::BackBuffer() const
{
return fBackBuffer;
}
// Invalidate
status_t
AccelerantHWInterface::Invalidate(const BRect& frame)
{
return CopyBackToFront(frame);;
// TODO: get this working, the locking in the DisplayDriverPainter needs
// to be based on locking this object, which essentially means the access
// to the back buffer is locked, or more precise the access to the invalid
// region scheduled to be copied to the front buffer
//fUpdateExecutor->AddRect(frame);
//return B_OK;
}
// CopyBackToFront
status_t
AccelerantHWInterface::CopyBackToFront(const BRect &frame)
{
if (!fBackBuffer || !fFrontBuffer)
return B_NO_INIT;
// we need to mess with the area, but it is const
BRect area(frame);
if (area.IsValid() && area.Intersects(fBackBuffer->Bitmap()->Bounds())) {
const BBitmap *from = fBackBuffer->Bitmap();
// make sure we don't copy out of bounds
area = from->Bounds() & area;
uint32 src_bytes = fBackBuffer->BytesPerRow();
uint8 *src_bits = (uint8 *)fBackBuffer->Bits();
// convert to integer coordinates
int32 x = (int32)floorf(area.left);
int32 y = (int32)floorf(area.top);
int32 right = (int32)ceilf(area.right);
int32 bottom = (int32)ceilf(area.bottom);
// offset to left top pixel in source buffer (always B_RGBA32)
src_bits += y * src_bytes + x * 4;
_CopyToFront(src_bits, src_bytes, x, y, right, bottom);
//_DrawCursor(area);
// update the region on screen
//Invalidate(area);
}
return B_OK;
}
// _DrawCursor
void
AccelerantHWInterface::_DrawCursor(BRect area) const
{
BRect cf = _CursorFrame();
if (cf.IsValid() && area.Intersects(cf)) {
// clip to common area
area = area & cf;
int32 left = (int32)floorf(area.left);
int32 top = (int32)floorf(area.top);
int32 right = (int32)ceilf(area.right);
int32 bottom = (int32)ceilf(area.bottom);
int32 width = right - left + 1;
int32 height = bottom - top + 1;
// make a bitmap from the backbuffer
// that has the cursor blended on top of it
// blending buffer
uint8* buffer = new uint8[width * height * 4];
// offset into back buffer
uint8* src = (uint8*)fBackBuffer->Bits();
uint32 srcBPR = fBackBuffer->BytesPerRow();
src += top * srcBPR + left * 4;
// offset into cursor bitmap
uint8* crs = (uint8*)fCursor->Bits();
uint32 crsBPR = fCursor->BytesPerRow();
// since area is clipped to cf,
// the diff between top and cf.top is always positive,
// same for diff between left and cf.left
crs += (top - (int32)floorf(cf.top)) * crsBPR
+ (left - (int32)floorf(cf.left)) * 4;
uint8* dst = buffer;
// blending
for (int32 y = top; y <= bottom; y++) {
uint8* s = src;
uint8* c = crs;
uint8* d = dst;
for (int32 x = left; x <= right; x++) {
// assume backbuffer alpha = 255
// TODO: it appears alpha in cursor us upside down
uint8 a = 255 - c[3];
d[0] = (((s[0] - c[0]) * a) + (c[0] << 8)) >> 8;
d[1] = (((s[1] - c[1]) * a) + (c[1] << 8)) >> 8;
d[2] = (((s[2] - c[2]) * a) + (c[2] << 8)) >> 8;
d[3] = 255;
s += 4;
c += 4;
d += 4;
}
crs += crsBPR;
src += srcBPR;
dst += width * 4;
}
// copy result to front buffer
_CopyToFront(buffer, width * 4, left, top, right, bottom);
delete[] buffer;
}
}
// _CopyToFront
//
// * source is assumed to be already at the right offset
// * source is assumed to be in B_RGBA32 format
// * location in front buffer is calculated
// * conversion from B_RGBA32 to format of front buffer is taken care of
void
AccelerantHWInterface::_CopyToFront(uint8* src, uint32 srcBPR,
int32 x, int32 y,
int32 right, int32 bottom) const
{
uint8* dst = (uint8*)fFrontBuffer->Bits();
uint32 dstBPR = fFrontBuffer->BytesPerRow();
// transfer, handle colorspace conversion
switch (fFrontBuffer->ColorSpace()) {
case B_RGB32:
case B_RGBA32: {
int32 bytes = (right - x + 1) * 4;
if (bytes > 0) {
// offset to left top pixel in dest buffer
dst += y * dstBPR + x * 4;
// copy
for (; y <= bottom; y++) {
memcpy(dst, src, bytes);
dst += dstBPR;
src += srcBPR;
}
}
break;
}
// NOTE: on R5, B_RGB24 bitmaps are not supported by DrawBitmap()
case B_RGB24: {
// offset to left top pixel in dest buffer
dst += y * dstBPR + x * 3;
int32 left = x;
// copy
for (; y <= bottom; y++) {
uint8* srcHandle = src;
uint8* dstHandle = dst;
x = left;
for (; x <= right; x++) {
dstHandle[0] = srcHandle[0];
dstHandle[1] = srcHandle[1];
dstHandle[2] = srcHandle[2];
dstHandle += 3;
srcHandle += 4;
}
dst += dstBPR;
src += srcBPR;
}
break;
}
case B_RGB16: {
// offset to left top pixel in dest buffer
dst += y * dstBPR + x * 2;
int32 left = x;
// copy
// TODO: assumes BGR order, does this work on big endian as well?
for (; y <= bottom; y++) {
uint8* srcHandle = src;
uint16* dstHandle = (uint16*)dst;
x = left;
for (; x <= right; x++) {
*dstHandle = (uint16)(((srcHandle[2] & 0xf8) << 8) |
((srcHandle[1] & 0xfc) << 3) |
(srcHandle[0] >> 3));
dstHandle ++;
srcHandle += 4;
}
dst += dstBPR;
src += srcBPR;
}
break;
}
case B_RGB15: {
// offset to left top pixel in dest buffer
dst += y * dstBPR + x * 2;
int32 left = x;
// copy
// TODO: assumes BGR order, does this work on big endian as well?
for (; y <= bottom; y++) {
uint8* srcHandle = src;
uint16* dstHandle = (uint16*)dst;
x = left;
for (; x <= right; x++) {
*dstHandle = (uint16)(((srcHandle[2] & 0xf8) << 7) |
((srcHandle[1] & 0xf8) << 2) |
(srcHandle[0] >> 3));
dstHandle ++;
srcHandle += 4;
}
dst += dstBPR;
src += srcBPR;
}
break;
}
case B_CMAP8: {
// offset to left top pixel in dest buffer
dst += y * dstBPR + x;
int32 left = x;
// copy
// TODO: using BScreen will not be an option in the
// final implementation, will it? The BBitmap implementation
// has a class that handles this, something so useful
// should be moved to a more public place.
// TODO: assumes BGR order again
/*BScreen screen;
for (; y <= bottom; y++) {
uint8* srcHandle = src;
uint8* dstHandle = dst;
x = left;
for (; x <= right; x++) {
*dstHandle = screen.IndexForColor(srcHandle[2],
srcHandle[1],
srcHandle[0]);
dstHandle ++;
srcHandle += 4;
}
dst += dstBPR;
src += srcBPR;
}*/
break;
}
case B_GRAY8: {
// offset to left top pixel in dest buffer
dst += y * dstBPR + x;
int32 left = x;
// copy
// TODO: assumes BGR order, does this work on big endian as well?
for (; y <= bottom; y++) {
uint8* srcHandle = src;
uint8* dstHandle = dst;
x = left;
for (; x <= right; x++) {
*dstHandle = (308 * srcHandle[2] + 600 * srcHandle[1] + 116 * srcHandle[0]) / 1024;
dstHandle ++;
srcHandle += 4;
}
dst += dstBPR;
src += srcBPR;
}
break;
}
default:
fprintf(stderr, "AccelerantHWInterface::CopyBackToFront() - unsupported front buffer format!\n");
break;
}
}
/*void AccelerantHWInterface::CopyBitmap(ServerBitmap *bitmap, const BRect &source, const BRect &dest, const DrawData *d)
{
if(!is_initialized || !bitmap || !d)
{
printf("CopyBitmap returned - not init or NULL bitmap\n");
return;
}
// DON't set draw data here! your existing clipping region will be deleted
// SetDrawData(d);
// Oh, wow, is this going to be slow. Then again, AccelerantHWInterface was never meant to be very fast. It could
// be made significantly faster by directly copying from the source to the destination, but that would
// require implementing a lot of code. Eventually, this should be replaced, but for now, using
// DrawBitmap will at least work with a minimum of effort.
BBitmap *mediator=new BBitmap(bitmap->Bounds(),bitmap->ColorSpace());
memcpy(mediator->Bits(),bitmap->Bits(),bitmap->BitsLength());
screenwin->Lock();
framebuffer->Lock();
drawview->DrawBitmap(mediator,source,dest);
drawview->Sync();
screenwin->view->Invalidate(dest);
framebuffer->Unlock();
screenwin->Unlock();
delete mediator;
}
void AccelerantHWInterface::CopyToBitmap(ServerBitmap *destbmp, const BRect &sourcerect)
{
if(!is_initialized || !destbmp)
{
printf("CopyToBitmap returned - not init or NULL bitmap\n");
return;
}
if(((uint32)destbmp->ColorSpace() & 0x000F) != (fDisplayMode.space & 0x000F))
{
printf("CopyToBitmap returned - unequal buffer pixel depth\n");
return;
}
BRect destrect(destbmp->Bounds()), source(sourcerect);
uint8 colorspace_size=destbmp->BitsPerPixel()/8;
// First, clip source rect to destination
if(source.Width() > destrect.Width())
source.right=source.left+destrect.Width();
if(source.Height() > destrect.Height())
source.bottom=source.top+destrect.Height();
// Second, check rectangle bounds against their own bitmaps
BRect work_rect(destbmp->Bounds());
if( !(work_rect.Contains(destrect)) )
{
// something in selection must be clipped
if(destrect.left < 0)
destrect.left = 0;
if(destrect.right > work_rect.right)
destrect.right = work_rect.right;
if(destrect.top < 0)
destrect.top = 0;
if(destrect.bottom > work_rect.bottom)
destrect.bottom = work_rect.bottom;
}
work_rect.Set(0,0,fDisplayMode.virtual_width-1,fDisplayMode.virtual_height-1);
if(!work_rect.Contains(sourcerect))
return;
if( !(work_rect.Contains(source)) )
{
// something in selection must be clipped
if(source.left < 0)
source.left = 0;
if(source.right > work_rect.right)
source.right = work_rect.right;
if(source.top < 0)
source.top = 0;
if(source.bottom > work_rect.bottom)
source.bottom = work_rect.bottom;
}
// Set pointers to the actual data
uint8 *dest_bits = (uint8*) destbmp->Bits();
uint8 *src_bits = (uint8*) framebuffer->Bits();
// Get row widths for offset looping
uint32 dest_width = uint32 (destbmp->BytesPerRow());
uint32 src_width = uint32 (framebuffer->BytesPerRow());
// Offset bitmap pointers to proper spot in each bitmap
src_bits += uint32 ( (source.top * src_width) + (source.left * colorspace_size) );
dest_bits += uint32 ( (destrect.top * dest_width) + (destrect.left * colorspace_size) );
uint32 line_length = uint32 ((destrect.right - destrect.left+1)*colorspace_size);
uint32 lines = uint32 (source.bottom-source.top+1);
for (uint32 pos_y=0; pos_y<lines; pos_y++)
{
memcpy(dest_bits,src_bits,line_length);
// Increment offsets
src_bits += src_width;
dest_bits += dest_width;
}
}
void AccelerantHWInterface::ConstrainClippingRegion(BRegion *reg)
{
if(!is_initialized)
{
printf("ConstrainClippingRegion returned - not init\n");
return;
}
screenwin->Lock();
framebuffer->Lock();
// screenwin->view->ConstrainClippingRegion(reg);
drawview->ConstrainClippingRegion(reg);
framebuffer->Unlock();
screenwin->Unlock();
}
bool AccelerantHWInterface::AcquireBuffer(FBBitmap *bmp)
{
if(!bmp || !is_initialized)
return false;
screenwin->Lock();
framebuffer->Lock();
bmp->SetBytesPerRow(framebuffer->BytesPerRow());
bmp->SetSpace(framebuffer->ColorSpace());
bmp->SetSize(framebuffer->Bounds().IntegerWidth(), framebuffer->Bounds().IntegerHeight());
bmp->SetBuffer(framebuffer->Bits());
bmp->SetBitsPerPixel(framebuffer->ColorSpace(),framebuffer->BytesPerRow());
return true;
}
void AccelerantHWInterface::ReleaseBuffer()
{
if(!is_initialized)
return;
framebuffer->Unlock();
screenwin->Unlock();
}
void AccelerantHWInterface::Invalidate(const BRect &r)
{
if(!is_initialized)
return;
screenwin->Lock();
screenwin->view->Draw(r);
screenwin->Unlock();
}
*/

View File

@ -0,0 +1,113 @@
//------------------------------------------------------------------------------
//
// Copyright 2005, Haiku, Inc.
// Distributed under the terms of the MIT License.
//
//
// File Name: AccelerantHWInterface.h
// Author: Michael Lotz <mmlr@mlotz.ch>
// Stephan Aßmus <superstippi@gmx.de>
// Description: Accelerant based HWInterface implementation
//
//------------------------------------------------------------------------------
#ifndef ACCELERANT_HW_INTERFACE_H
#define ACCELERANT_HW_INTERFACE_H
#include "HWInterface.h"
#include <image.h>
class BitmapBuffer;
class AccelerantBuffer;
class UpdateQueue;
class AccelerantHWInterface : public HWInterface {
public:
AccelerantHWInterface();
virtual ~AccelerantHWInterface();
virtual status_t Initialize();
virtual status_t Shutdown();
virtual status_t SetMode(const display_mode &mode);
virtual void GetMode(display_mode *mode);
virtual status_t GetDeviceInfo(accelerant_device_info *info);
virtual status_t GetModeList(display_mode **mode_list,
uint32 *count);
virtual status_t GetPixelClockLimits(display_mode *mode,
uint32 *low,
uint32 *high);
virtual status_t GetTimingConstraints(display_timing_constraints *dtc);
virtual status_t ProposeMode(display_mode *candidate,
const display_mode *low,
const display_mode *high);
virtual status_t WaitForRetrace(bigtime_t timeout = B_INFINITE_TIMEOUT);
virtual status_t SetDPMSMode(const uint32 &state);
virtual uint32 DPMSMode() const;
virtual uint32 DPMSCapabilities() const;
// frame buffer access
virtual RenderingBuffer *FrontBuffer() const;
virtual RenderingBuffer *BackBuffer() const;
virtual status_t Invalidate(const BRect& frame);
virtual status_t CopyBackToFront(const BRect& area);
private:
int OpenGraphicsDevice(int deviceNumber);
status_t SetupDefaultHooks();
status_t UpdateModeList();
status_t UpdateFrameBufferConfig();
void _DrawCursor(BRect area) const;
void _CopyToFront(uint8* src, uint32 srcBPR,
int32 x, int32 y,
int32 right, int32 bottom) const;
int fCardFD;
image_id fAccelerantImage;
GetAccelerantHook fAccelerantHook;
engine_token *fEngineToken;
// required hooks - guaranteed to be valid
acquire_engine fAccAcquireEngine;
release_engine fAccReleaseEngine;
accelerant_mode_count fAccGetModeCount;
get_mode_list fAccGetModeList;
get_frame_buffer_config fAccGetFrameBufferConfig;
set_display_mode fAccSetDisplayMode;
get_pixel_clock_limits fAccGetPixelClockLimits;
// optional accelerant hooks
get_timing_constraints fAccGetTimingConstraints;
propose_display_mode fAccProposeDisplayMode;
fill_rectangle fAccFillRect;
invert_rectangle fAccInvertRect;
screen_to_screen_blit fAccScreenBlit;
set_cursor_shape fAccSetCursorShape;
move_cursor fAccMoveCursor;
show_cursor fAccShowCursor;
// dpms hooks
dpms_capabilities fAccDPMSCapabilities;
dpms_mode fAccDPMSMode;
set_dpms_mode fAccSetDPMSMode;
frame_buffer_config fFrameBufferConfig;
int fModeCount;
display_mode *fModeList;
BitmapBuffer *fBackBuffer;
AccelerantBuffer *fFrontBuffer;
display_mode fDisplayMode;
UpdateQueue *fUpdateExecutor;
};
#endif // ACCELERANT_HW_INTERFACE_H

View File

@ -2766,7 +2766,7 @@ DisplayDriverImpl::BlitGray2RGB32(FT_Bitmap *src, const BPoint &pt, const DrawDa
int32 destinc = framebuffer.BytesPerRow();
int32 srcwidth = src->width;
int32 srcheight = src->rows;
int32 incval=0;
int32 incval = 0;
// pointers to the top left corner of the area to be copied in each bitmap
uint8 *srcbuffer = (uint8 *)src->buffer;