From b2c9e18270670bd93366ef512cb5c190af111a94 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Tue, 29 Mar 2005 16:31:46 +0000 Subject: [PATCH] Accelerant based implementations of HWInterface and RenderingBuffer. Untested. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12123 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/Jamfile | 2 + src/servers/app/drawing/AccelerantBuffer.cpp | 127 +++ src/servers/app/drawing/AccelerantBuffer.h | 61 ++ .../app/drawing/AccelerantHWInterface.cpp | 966 ++++++++++++++++++ .../app/drawing/AccelerantHWInterface.h | 113 ++ src/servers/app/drawing/DisplayDriverImpl.cpp | 2 +- 6 files changed, 1270 insertions(+), 1 deletion(-) create mode 100644 src/servers/app/drawing/AccelerantBuffer.cpp create mode 100644 src/servers/app/drawing/AccelerantBuffer.h create mode 100644 src/servers/app/drawing/AccelerantHWInterface.cpp create mode 100644 src/servers/app/drawing/AccelerantHWInterface.h diff --git a/src/servers/app/Jamfile b/src/servers/app/Jamfile index e293b1b8a3..9e83170a78 100644 --- a/src/servers/app/Jamfile +++ b/src/servers/app/Jamfile @@ -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 ; } diff --git a/src/servers/app/drawing/AccelerantBuffer.cpp b/src/servers/app/drawing/AccelerantBuffer.cpp new file mode 100644 index 0000000000..2a8cb36cfe --- /dev/null +++ b/src/servers/app/drawing/AccelerantBuffer.cpp @@ -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 +// 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; +} diff --git a/src/servers/app/drawing/AccelerantBuffer.h b/src/servers/app/drawing/AccelerantBuffer.h new file mode 100644 index 0000000000..d378e1e5bc --- /dev/null +++ b/src/servers/app/drawing/AccelerantBuffer.h @@ -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 +// Description: A RenderingBuffer implementation that accesses graphics +// memory directly. +// +//------------------------------------------------------------------------------ + +#ifndef ACCELERANT_BUFFER_H +#define ACCELERANT_BUFFER_H + +#include +#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 diff --git a/src/servers/app/drawing/AccelerantHWInterface.cpp b/src/servers/app/drawing/AccelerantHWInterface.cpp new file mode 100644 index 0000000000..393b8ea540 --- /dev/null +++ b/src/servers/app/drawing/AccelerantHWInterface.cpp @@ -0,0 +1,966 @@ +//------------------------------------------------------------------------------ +// +// Copyright 2002-2005, Haiku, Inc. +// Distributed under the terms of the MIT License. +// +// +// File Name: AccelerantHWInterface.cpp +// Authors: Michael Lotz +// DarkWyrm +// Stephan Aßmus +// Description: Accelerant based HWInterface implementation +// +//------------------------------------------------------------------------------ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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 +# 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_yLock(); + 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(); +} +*/ diff --git a/src/servers/app/drawing/AccelerantHWInterface.h b/src/servers/app/drawing/AccelerantHWInterface.h new file mode 100644 index 0000000000..e13870a0f3 --- /dev/null +++ b/src/servers/app/drawing/AccelerantHWInterface.h @@ -0,0 +1,113 @@ +//------------------------------------------------------------------------------ +// +// Copyright 2005, Haiku, Inc. +// Distributed under the terms of the MIT License. +// +// +// File Name: AccelerantHWInterface.h +// Author: Michael Lotz +// Stephan Aßmus +// Description: Accelerant based HWInterface implementation +// +//------------------------------------------------------------------------------ + +#ifndef ACCELERANT_HW_INTERFACE_H +#define ACCELERANT_HW_INTERFACE_H + +#include "HWInterface.h" +#include + +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 diff --git a/src/servers/app/drawing/DisplayDriverImpl.cpp b/src/servers/app/drawing/DisplayDriverImpl.cpp index d8f7a7588e..c747c981fe 100644 --- a/src/servers/app/drawing/DisplayDriverImpl.cpp +++ b/src/servers/app/drawing/DisplayDriverImpl.cpp @@ -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;