* Copyright 2001-2016 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus, superstippi@gmx.de
* DarkWyrm, bpmagic@columbus.rr.com
* Axel Dörfler, axeld@pinc-software.de
* Michael Lotz, mmlr@mlotz.ch
* John Scipione, jscipione@gmail.com
*/
#include "AccelerantHWInterface.h"
#include <new>
#include <dirent.h>
#include <edid.h>
#include <driver_settings.h>
#include <graphic_driver.h>
#include <image.h>
#include <safemode_defs.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/ioctl.h>
#include <syscalls.h>
#include <syslog.h>
#include <unistd.h>
#include <Accelerant.h>
#include <Cursor.h>
#include <Directory.h>
#include <FindDirectory.h>
#include <Path.h>
#include <PathFinder.h>
#include <String.h>
#include <StringList.h>
#include "AccelerantBuffer.h"
#include "MallocBuffer.h"
#include "Overlay.h"
#include "RGBColor.h"
#include "ServerConfig.h"
#include "ServerCursor.h"
#include "ServerProtocol.h"
#include "SystemPalette.h"
using std::nothrow;
#ifdef DEBUG_DRIVER_MODULE
# include <stdio.h>
# define ATRACE(x) printf x
#else
# define ATRACE(x) ;
#endif
const int32 kDefaultParamsCount = 64;
bool
operator==(const display_mode& a, const display_mode& b)
{
return memcmp(&a, &b, sizeof(display_mode)) == 0;
}
bool
use_fail_safe_video_mode()
{
char buffer[B_FILE_NAME_LENGTH];
size_t size = sizeof(buffer);
status_t status = _kern_get_safemode_option(
B_SAFEMODE_FAIL_SAFE_VIDEO_MODE, buffer, &size);
if (status == B_OK) {
if (!strncasecmp(buffer, "true", size)
|| !strncasecmp(buffer, "yes", size)
|| !strncasecmp(buffer, "on", size)
|| !strncasecmp(buffer, "enabled", size)) {
return true;
}
}
return false;
}
AccelerantHWInterface::AccelerantHWInterface()
:
HWInterface(),
fCardFD(-1),
fAccelerantImage(-1),
fAccelerantHook(NULL),
fEngineToken(NULL),
fSyncToken(),
fAccGetModeCount(NULL),
fAccGetModeList(NULL),
fAccGetFrameBufferConfig(NULL),
fAccSetDisplayMode(NULL),
fAccGetDisplayMode(NULL),
fAccGetPixelClockLimits(NULL),
fAccGetTimingConstraints(NULL),
fAccProposeDisplayMode(NULL),
fAccSetCursorShape(NULL),
fAccSetCursorBitmap(NULL),
fAccMoveCursor(NULL),
fAccShowCursor(NULL),
fAccDPMSCapabilities(NULL),
fAccDPMSMode(NULL),
fAccSetDPMSMode(NULL),
fAccSetBrightness(NULL),
fAccGetBrightness(NULL),
fAccOverlayCount(NULL),
fAccOverlaySupportedSpaces(NULL),
fAccOverlaySupportedFeatures(NULL),
fAccAllocateOverlayBuffer(NULL),
fAccReleaseOverlayBuffer(NULL),
fAccGetOverlayConstraints(NULL),
fAccAllocateOverlay(NULL),
fAccReleaseOverlay(NULL),
fAccConfigureOverlay(NULL),
fModeCount(0),
fModeList(NULL),
fBackBuffer(NULL),
fFrontBuffer(new (nothrow) AccelerantBuffer()),
fInitialModeSwitch(true),
fRetraceSemaphore(-1),
fRectParams(new (nothrow) fill_rect_params[kDefaultParamsCount]),
fRectParamsCount(kDefaultParamsCount),
fBlitParams(new (nothrow) blit_params[kDefaultParamsCount]),
fBlitParamsCount(kDefaultParamsCount)
{
fDisplayMode.virtual_width = 0;
fDisplayMode.virtual_height = 0;
fDisplayMode.space = B_RGB32;
memset(&fSyncToken, 0, sizeof(sync_token));
}
AccelerantHWInterface::~AccelerantHWInterface()
{
delete[] fRectParams;
delete[] fBlitParams;
delete[] fModeList;
}
\return B_OK on success or an appropriate error message on failure.
*/
status_t
AccelerantHWInterface::Initialize()
{
status_t ret = HWInterface::Initialize();
if (!fRectParams || !fBlitParams)
return B_NO_MEMORY;
if (ret >= B_OK) {
for (int32 i = 0; fCardFD != B_ENTRY_NOT_FOUND; i++) {
fCardFD = _OpenGraphicsDevice(i);
if (fCardFD < 0) {
ATRACE(("Failed to open graphics device\n"));
continue;
}
if (_OpenAccelerant(fCardFD) == B_OK)
break;
close(fCardFD);
}
return fCardFD >= 0 ? B_OK : fCardFD;
}
return ret;
}
\return Whether a device path matching the \a deviceNumber is found.
*/
bool
AccelerantHWInterface::_RecursiveScan(const char* directory, int deviceNumber, int &count,
char *_path)
{
ATRACE(("_RecursiveScan directory: %s\n", directory));
BEntry entry;
BDirectory dir(directory);
while (dir.GetNextEntry(&entry) == B_OK) {
BPath path;
entry.GetPath(&path);
if (!strcmp(path.Path(), "/dev/graphics/vesa")
|| !strcmp(path.Path(), "/dev/graphics/framebuffer")) {
continue;
}
if (entry.IsDirectory()) {
if (_RecursiveScan(path.Path(), deviceNumber, count, _path))
return true;
} else {
if (count == deviceNumber) {
strlcpy(_path, path.Path(), PATH_MAX);
return true;
}
count++;
}
}
return false;
}
The \a deviceNumber is relative to the number of graphics devices that can
be opened. One represents the first card that can be opened (not necessarily
the first one listed in the directory).
Graphics drivers must be able to be opened more than once, so we really get
the first working entry.
\param deviceNumber Number identifying which graphics card to open
(1 for first card).
\return The file descriptor of the opened graphics device.
*/
int
AccelerantHWInterface::_OpenGraphicsDevice(int deviceNumber)
{
int device = -1;
int count = 0;
if (!use_fail_safe_video_mode()) {
char path[PATH_MAX];
if (_RecursiveScan("/dev/graphics/", deviceNumber, count, path))
device = open(path, B_READ_WRITE);
}
if (device == -1 && count < deviceNumber) {
device = open("/dev/graphics/vesa", B_READ_WRITE);
if (device > 0) {
fVGADevice = device;
} else {
device = open("/dev/graphics/framebuffer", B_READ_WRITE);
}
if (device < 0)
return B_ENTRY_NOT_FOUND;
}
return device;
}
status_t
AccelerantHWInterface::_OpenAccelerant(int device)
{
char signature[1024];
if (ioctl(device, B_GET_ACCELERANT_SIGNATURE,
&signature, sizeof(signature)) != B_OK) {
return B_ERROR;
}
ATRACE(("accelerant signature is: %s\n", signature));
fAccelerantImage = -1;
BString leafPath("/accelerants/");
leafPath << signature;
BStringList addOnPaths;
BPathFinder::FindPaths(B_FIND_PATH_ADD_ONS_DIRECTORY, leafPath.String(),
addOnPaths);
int32 count = addOnPaths.CountStrings();
for (int32 i = 0; i < count; i++) {
const char* path = addOnPaths.StringAt(i).String();
struct stat accelerantStat;
if (stat(path, &accelerantStat) != 0)
continue;
ATRACE(("accelerant path is: %s\n", path));
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(device) != B_OK) {
ATRACE(("InitAccelerant unsuccessful\n"));
unload_add_on(fAccelerantImage);
fAccelerantImage = -1;
return B_ERROR;
}
break;
}
}
if (fAccelerantImage < B_OK)
return B_ERROR;
if (_SetupDefaultHooks() != B_OK) {
syslog(LOG_ERR, "Accelerant %s does not export the required hooks.\n",
signature);
uninit_accelerant uninitAccelerant = (uninit_accelerant)
fAccelerantHook(B_UNINIT_ACCELERANT, NULL);
if (uninitAccelerant != NULL)
uninitAccelerant();
unload_add_on(fAccelerantImage);
return B_ERROR;
}
return B_OK;
}
status_t
AccelerantHWInterface::_SetupDefaultHooks()
{
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);
fAccGetDisplayMode
= (get_display_mode)fAccelerantHook(B_GET_DISPLAY_MODE, NULL);
fAccGetPixelClockLimits = (get_pixel_clock_limits)fAccelerantHook(
B_GET_PIXEL_CLOCK_LIMITS, NULL);
if (!fAccGetFrameBufferConfig || !fAccGetModeCount || !fAccGetModeList
|| !fAccSetDisplayMode || !fAccGetDisplayMode || !fAccGetPixelClockLimits) {
return B_ERROR;
}
fAccGetTimingConstraints = (get_timing_constraints)fAccelerantHook(
B_GET_TIMING_CONSTRAINTS, NULL);
fAccProposeDisplayMode = (propose_display_mode)fAccelerantHook(
B_PROPOSE_DISPLAY_MODE, NULL);
fAccGetPreferredDisplayMode = (get_preferred_display_mode)fAccelerantHook(
B_GET_PREFERRED_DISPLAY_MODE, NULL);
fAccGetMonitorInfo
= (get_monitor_info)fAccelerantHook(B_GET_MONITOR_INFO, NULL);
fAccGetEDIDInfo = (get_edid_info)fAccelerantHook(B_GET_EDID_INFO, NULL);
fAccSetCursorShape
= (set_cursor_shape)fAccelerantHook(B_SET_CURSOR_SHAPE, NULL);
fAccSetCursorBitmap
= (set_cursor_bitmap)fAccelerantHook(B_SET_CURSOR_BITMAP, NULL);
fAccMoveCursor = (move_cursor)fAccelerantHook(B_MOVE_CURSOR, NULL);
fAccShowCursor = (show_cursor)fAccelerantHook(B_SHOW_CURSOR, NULL);
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);
fAccGetBrightness = (get_brightness)fAccelerantHook(B_GET_BRIGHTNESS, NULL);
fAccSetBrightness = (set_brightness)fAccelerantHook(B_SET_BRIGHTNESS, NULL);
return B_OK;
}
void
AccelerantHWInterface::_UpdateHooksAfterModeChange()
{
fAccOverlayCount = (overlay_count)fAccelerantHook(B_OVERLAY_COUNT, NULL);
fAccOverlaySupportedSpaces = (overlay_supported_spaces)fAccelerantHook(
B_OVERLAY_SUPPORTED_SPACES, NULL);
fAccOverlaySupportedFeatures = (overlay_supported_features)fAccelerantHook(
B_OVERLAY_SUPPORTED_FEATURES, NULL);
fAccAllocateOverlayBuffer = (allocate_overlay_buffer)fAccelerantHook(
B_ALLOCATE_OVERLAY_BUFFER, NULL);
fAccReleaseOverlayBuffer = (release_overlay_buffer)fAccelerantHook(
B_RELEASE_OVERLAY_BUFFER, NULL);
fAccGetOverlayConstraints = (get_overlay_constraints)fAccelerantHook(
B_GET_OVERLAY_CONSTRAINTS, NULL);
fAccAllocateOverlay
= (allocate_overlay)fAccelerantHook(B_ALLOCATE_OVERLAY, NULL);
fAccReleaseOverlay
= (release_overlay)fAccelerantHook(B_RELEASE_OVERLAY, NULL);
fAccConfigureOverlay
= (configure_overlay)fAccelerantHook(B_CONFIGURE_OVERLAY, NULL);
}
status_t
AccelerantHWInterface::Shutdown()
{
if (fAccelerantHook != NULL) {
uninit_accelerant uninitAccelerant
= (uninit_accelerant)fAccelerantHook(B_UNINIT_ACCELERANT, NULL);
if (uninitAccelerant != NULL)
uninitAccelerant();
fAccelerantHook = NULL;
}
if (fAccelerantImage >= 0) {
unload_add_on(fAccelerantImage);
fAccelerantImage = -1;
}
if (fCardFD >= 0) {
close(fCardFD);
fCardFD = -1;
}
return B_OK;
}
As long as the mode list is not empty, this method will always succeed.
*/
status_t
AccelerantHWInterface::_FindBestMode(const display_mode& compareMode,
float compareAspectRatio, display_mode& modeFound, int32 *_diff) const
{
int32 bestDiff = 0;
int32 bestIndex = -1;
for (int32 i = 0; i < fModeCount; i++) {
display_mode& mode = fModeList[i];
float aspectRatio = 0;
if (compareAspectRatio != 0 && mode.timing.v_display != 0)
aspectRatio = mode.timing.h_display / mode.timing.v_display;
int32 diff
= 1000 * abs(mode.timing.h_display - compareMode.timing.h_display)
+ 1000 * abs(mode.timing.v_display - compareMode.timing.v_display)
+ abs(mode.timing.h_total * mode.timing.v_total
- compareMode.timing.h_total * compareMode.timing.v_total)
/ 100
+ abs((int)(mode.timing.pixel_clock - compareMode.timing.pixel_clock))
/ 100
+ (int32)(500 * fabs(aspectRatio - compareAspectRatio))
+ 100 * abs((int)(mode.space - compareMode.space));
if (bestIndex == -1 || diff < bestDiff) {
bestDiff = diff;
bestIndex = i;
}
}
if (bestIndex < 0)
return B_ERROR;
modeFound = fModeList[bestIndex];
if (_diff != 0)
*_diff = bestDiff;
return B_OK;
}
should really not fail.
Basically we try to set all modes as found in the mode list the driver
returned, but we start with the one that best fits the originally
desired mode.
The mode list must have been retrieved already.
*/
status_t
AccelerantHWInterface::_SetFallbackMode(display_mode& newMode) const
{
if (_FindBestMode(newMode, 0, newMode) == B_OK
&& fAccSetDisplayMode(&newMode) == B_OK) {
return B_OK;
}
for (int32 i = 0; i < fModeCount; i++) {
newMode = fModeList[i];
if (fAccSetDisplayMode(&newMode) == B_OK)
return B_OK;
}
return B_ERROR;
}
status_t
AccelerantHWInterface::SetMode(const display_mode& mode)
{
AutoWriteLocker _(this);
if (fModeCount > 0 && fFrontBuffer.IsSet() && fDisplayMode == mode) {
return B_OK;
}
if (!_IsValidMode(mode))
return B_BAD_VALUE;
if (!fFrontBuffer.IsSet())
return B_NO_INIT;
display_mode newMode = mode;
status_t status = B_ERROR;
if (!use_fail_safe_video_mode() || !fInitialModeSwitch)
status = fAccSetDisplayMode(&newMode);
if (status != B_OK) {
ATRACE(("setting display mode failed\n"));
if (!fInitialModeSwitch)
return status;
if (fModeList == NULL) {
status = _UpdateModeList();
if (status != B_OK)
return status;
}
status = use_fail_safe_video_mode()
? B_ERROR : _SetFallbackMode(newMode);
if (status != B_OK) {
if (fAccGetDisplayMode(&newMode) != B_OK)
return B_ERROR;
if (!_IsValidMode(newMode))
return B_BAD_DATA;
status = B_OK;
}
}
fDisplayMode = newMode;
fInitialModeSwitch = false;
fFrontBuffer->SetDisplayMode(fDisplayMode);
if (_UpdateFrameBufferConfig() != B_OK) {
return B_ERROR;
}
#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
uint32 depth = (fFrameBufferConfig.bytes_per_row
/ fFrontBuffer->Width()) << 3;
if (fDisplayMode.space == B_RGB15)
depth = 15;
_kern_frame_buffer_update((addr_t)fFrameBufferConfig.frame_buffer,
fFrontBuffer->Width(), fFrontBuffer->Height(),
depth, fFrameBufferConfig.bytes_per_row);
#endif
_UpdateHooksAfterModeChange();
if (!fBackBuffer.IsSet()
|| fBackBuffer->Width() != fFrontBuffer->Width()
|| fBackBuffer->Height() != fFrontBuffer->Height()
|| (fFrontBuffer->ColorSpace() == B_RGB32 && fBackBuffer.IsSet())) {
fBackBuffer.Unset();
fBackBuffer.SetTo(new(nothrow) MallocBuffer(
fFrontBuffer->Width(), fFrontBuffer->Height()));
status = fBackBuffer.IsSet()
? fBackBuffer->InitCheck() : B_NO_MEMORY;
if (status < B_OK) {
fBackBuffer.Unset();
return status;
}
memset(fBackBuffer->Bits(), 255, fBackBuffer->BitsLength());
}
if (fDisplayMode.space == B_CMAP8)
_SetSystemPalette();
else if (fDisplayMode.space == B_GRAY8)
_SetGrayscalePalette();
_NotifyFrameBufferChanged();
return status;
}
void
AccelerantHWInterface::GetMode(display_mode* mode)
{
if (mode && LockParallelAccess()) {
*mode = fDisplayMode;
UnlockParallelAccess();
}
}
status_t
AccelerantHWInterface::_UpdateModeList()
{
fModeCount = fAccGetModeCount();
if (fModeCount <= 0)
return B_ERROR;
delete[] fModeList;
fModeList = new(nothrow) 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;
}
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);
}
status_t
AccelerantHWInterface::GetFrameBufferConfig(frame_buffer_config& config)
{
config = fFrameBufferConfig;
return B_OK;
}
status_t
AccelerantHWInterface::GetModeList(display_mode** _modes, uint32* _count)
{
AutoReadLocker _(this);
if (_count == NULL || _modes == NULL)
return B_BAD_VALUE;
status_t status = B_OK;
if (fModeList == NULL)
status = _UpdateModeList();
if (status >= B_OK) {
*_modes = new(nothrow) display_mode[fModeCount];
if (*_modes) {
*_count = fModeCount;
memcpy(*_modes, fModeList, sizeof(display_mode) * fModeCount);
} else {
*_count = 0;
status = B_NO_MEMORY;
}
}
return status;
}
status_t
AccelerantHWInterface::GetPixelClockLimits(display_mode *mode, uint32* _low,
uint32* _high)
{
if (mode == NULL || _low == NULL || _high == NULL)
return B_BAD_VALUE;
AutoReadLocker _(this);
return fAccGetPixelClockLimits(mode, _low, _high);
}
status_t
AccelerantHWInterface::GetTimingConstraints(
display_timing_constraints* constraints)
{
if (constraints == NULL)
return B_BAD_VALUE;
AutoReadLocker _(this);
if (fAccGetTimingConstraints)
return fAccGetTimingConstraints(constraints);
return B_UNSUPPORTED;
}
status_t
AccelerantHWInterface::ProposeMode(display_mode* candidate,
const display_mode* _low, const display_mode* _high)
{
if (candidate == NULL || _low == NULL || _high == NULL)
return B_BAD_VALUE;
AutoReadLocker _(this);
if (fAccProposeDisplayMode == NULL)
return B_UNSUPPORTED;
display_mode high, low;
high = *_high;
low = *_low;
return fAccProposeDisplayMode(candidate, &low, &high);
}
status_t
AccelerantHWInterface::GetPreferredMode(display_mode* preferredMode)
{
status_t status = B_NOT_SUPPORTED;
if (fAccGetPreferredDisplayMode != NULL) {
status = fAccGetPreferredDisplayMode(preferredMode);
if (status == B_OK)
return B_OK;
}
if (fAccGetEDIDInfo != NULL) {
edid1_info info;
uint32 version;
status = fAccGetEDIDInfo(&info, sizeof(info), &version);
if (status < B_OK)
return status;
if (version != EDID_VERSION_1)
return B_NOT_SUPPORTED;
if (fModeList == NULL) {
status = _UpdateModeList();
if (status != B_OK)
return status;
}
status = B_NOT_SUPPORTED;
display_mode bestMode;
int32 bestDiff = INT_MAX;
for (uint32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
if (info.detailed_monitor[i].monitor_desc_type
!= EDID1_IS_DETAILED_TIMING)
continue;
const edid1_detailed_timing& timing
= info.detailed_monitor[i].data.detailed_timing;
if (timing.h_active < 640 || timing.v_active < 350)
continue;
float aspectRatio = 0.0f;
if (timing.h_size > 0 && timing.v_size > 0)
aspectRatio = 1.0f * timing.h_size / timing.v_size;
display_mode modeFound;
display_mode mode;
mode.timing.pixel_clock = timing.pixel_clock * 10;
mode.timing.h_display = timing.h_active;
mode.timing.h_sync_start = timing.h_active + timing.h_sync_off;
mode.timing.h_sync_end = mode.timing.h_sync_start
+ timing.h_sync_width;
mode.timing.h_total = timing.h_active + timing.h_blank;
mode.timing.v_display = timing.v_active;
mode.timing.v_sync_start = timing.v_active + timing.v_sync_off;
mode.timing.v_sync_end = mode.timing.v_sync_start
+ timing.v_sync_width;
mode.timing.v_total = timing.v_active + timing.v_blank;
mode.space = B_RGB32;
mode.virtual_width = mode.timing.h_display;
mode.virtual_height = mode.timing.v_display;
int32 diff;
if (_FindBestMode(mode, aspectRatio, modeFound, &diff) == B_OK) {
status = B_OK;
if (diff < bestDiff) {
bestMode = modeFound;
bestDiff = diff;
}
}
}
if (status == B_OK)
*preferredMode = bestMode;
}
return status;
}
status_t
AccelerantHWInterface::GetMonitorInfo(monitor_info* info)
{
status_t status = B_NOT_SUPPORTED;
if (fAccGetMonitorInfo != NULL) {
status = fAccGetMonitorInfo(info);
if (status == B_OK)
return B_OK;
}
if (fAccGetEDIDInfo == NULL)
return status;
edid1_info edid;
uint32 version;
status = fAccGetEDIDInfo(&edid, sizeof(edid), &version);
if (status < B_OK)
return status;
if (version != EDID_VERSION_1)
return B_NOT_SUPPORTED;
memset(info, 0, sizeof(monitor_info));
strlcpy(info->vendor, edid.vendor.manufacturer, sizeof(info->vendor));
if (edid.vendor.serial != 0) {
snprintf(info->serial_number, sizeof(info->serial_number), "%" B_PRIu32,
edid.vendor.serial);
}
info->product_id = edid.vendor.prod_id;
info->produced.week = edid.vendor.week;
info->produced.year = edid.vendor.year;
info->width = edid.display.h_size;
info->height = edid.display.v_size;
for (uint32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i) {
edid1_detailed_monitor *monitor = &edid.detailed_monitor[i];
switch (monitor->monitor_desc_type) {
case EDID1_SERIAL_NUMBER:
strlcpy(info->serial_number, monitor->data.serial_number,
sizeof(info->serial_number));
break;
case EDID1_MONITOR_NAME:
strlcpy(info->name, monitor->data.monitor_name,
sizeof(info->name));
break;
case EDID1_MONITOR_RANGES:
{
edid1_monitor_range& range = monitor->data.monitor_range;
info->min_horizontal_frequency = range.min_h;
info->max_horizontal_frequency = range.max_h;
info->min_vertical_frequency = range.min_v;
info->max_vertical_frequency = range.max_v;
info->max_pixel_clock = range.max_clock * 10000;
break;
}
case EDID1_IS_DETAILED_TIMING:
{
edid1_detailed_timing& timing = monitor->data.detailed_timing;
info->width = timing.h_size / 10.0;
info->height = timing.v_size / 10.0;
}
default:
break;
}
}
return B_OK;
}
sem_id
AccelerantHWInterface::RetraceSemaphore()
{
AutoWriteLocker _(this);
if (fRetraceSemaphore != -1)
return fRetraceSemaphore;
accelerant_retrace_semaphore AccelerantRetraceSemaphore =
(accelerant_retrace_semaphore)fAccelerantHook(
B_ACCELERANT_RETRACE_SEMAPHORE, NULL);
if (!AccelerantRetraceSemaphore)
fRetraceSemaphore = B_UNSUPPORTED;
else
fRetraceSemaphore = AccelerantRetraceSemaphore();
return fRetraceSemaphore;
}
status_t
AccelerantHWInterface::WaitForRetrace(bigtime_t timeout)
{
sem_id sem = RetraceSemaphore();
if (sem < 0)
return sem;
return acquire_sem_etc(sem, 1, B_RELATIVE_TIMEOUT, timeout);
}
status_t
AccelerantHWInterface::SetDPMSMode(uint32 state)
{
AutoWriteLocker _(this);
if (!fAccSetDPMSMode)
return B_UNSUPPORTED;
return fAccSetDPMSMode(state);
}
uint32
AccelerantHWInterface::DPMSMode()
{
AutoReadLocker _(this);
if (!fAccDPMSMode)
return B_UNSUPPORTED;
return fAccDPMSMode();
}
uint32
AccelerantHWInterface::DPMSCapabilities()
{
AutoReadLocker _(this);
if (!fAccDPMSCapabilities)
return B_UNSUPPORTED;
return fAccDPMSCapabilities();
}
status_t
AccelerantHWInterface::SetBrightness(float brightness)
{
AutoReadLocker _(this);
if (!fAccSetBrightness)
return B_UNSUPPORTED;
return fAccSetBrightness(brightness);
}
status_t
AccelerantHWInterface::GetBrightness(float* brightness)
{
AutoReadLocker _(this);
if (!fAccGetBrightness)
return B_UNSUPPORTED;
return fAccGetBrightness(brightness);
}
status_t
AccelerantHWInterface::GetAccelerantPath(BString& string)
{
image_info info;
status_t status = get_image_info(fAccelerantImage, &info);
if (status == B_OK)
string = info.name;
return status;
}
status_t
AccelerantHWInterface::GetDriverPath(BString& string)
{
char path[B_PATH_NAME_LENGTH];
get_accelerant_clone_info getCloneInfo;
getCloneInfo = (get_accelerant_clone_info)fAccelerantHook(
B_GET_ACCELERANT_CLONE_INFO, NULL);
if (getCloneInfo == NULL)
return B_NOT_SUPPORTED;
getCloneInfo((void*)path);
string.SetTo(path);
return B_OK;
}
overlay_token
AccelerantHWInterface::AcquireOverlayChannel()
{
if (fAccAllocateOverlay == NULL
|| fAccReleaseOverlay == NULL)
return NULL;
return fAccAllocateOverlay();
}
void
AccelerantHWInterface::ReleaseOverlayChannel(overlay_token token)
{
if (token == NULL)
return;
fAccReleaseOverlay(token);
}
status_t
AccelerantHWInterface::GetOverlayRestrictions(const Overlay* overlay,
overlay_restrictions* restrictions)
{
if (overlay == NULL || restrictions == NULL)
return B_BAD_VALUE;
if (fAccGetOverlayConstraints == NULL)
return B_NOT_SUPPORTED;
overlay_constraints constraints;
status_t status = fAccGetOverlayConstraints(&fDisplayMode,
overlay->OverlayBuffer(), &constraints);
if (status < B_OK)
return status;
memset(restrictions, 0, sizeof(overlay_restrictions));
memcpy(&restrictions->source, &constraints.view, sizeof(overlay_limits));
memcpy(&restrictions->destination, &constraints.window,
sizeof(overlay_limits));
restrictions->min_width_scale = constraints.h_scale.min;
restrictions->max_width_scale = constraints.h_scale.max;
restrictions->min_height_scale = constraints.v_scale.min;
restrictions->max_height_scale = constraints.v_scale.max;
return B_OK;
}
bool
AccelerantHWInterface::CheckOverlayRestrictions(int32 width, int32 height,
color_space colorSpace)
{
if (fAccOverlaySupportedSpaces == NULL
|| fAccGetOverlayConstraints == NULL
|| fAccAllocateOverlayBuffer == NULL
|| fAccReleaseOverlayBuffer == NULL)
return false;
if (width < 0 || width > 65535 || height < 0 || height > 65535)
return false;
const uint32* spaces = fAccOverlaySupportedSpaces(&fDisplayMode);
if (spaces == NULL)
return false;
for (int32 i = 0; spaces[i] != 0; i++) {
if (spaces[i] == (uint32)colorSpace)
return true;
}
return false;
}
const overlay_buffer*
AccelerantHWInterface::AllocateOverlayBuffer(int32 width, int32 height,
color_space space)
{
if (fAccAllocateOverlayBuffer == NULL)
return NULL;
return fAccAllocateOverlayBuffer(space, width, height);
}
void
AccelerantHWInterface::FreeOverlayBuffer(const overlay_buffer* buffer)
{
if (buffer == NULL || fAccReleaseOverlayBuffer == NULL)
return;
fAccReleaseOverlayBuffer(buffer);
}
void
AccelerantHWInterface::ConfigureOverlay(Overlay* overlay)
{
overlay->SetColorSpace(fDisplayMode.space);
fAccConfigureOverlay(overlay->OverlayToken(), overlay->OverlayBuffer(),
overlay->OverlayWindow(), overlay->OverlayView());
}
void
AccelerantHWInterface::HideOverlay(Overlay* overlay)
{
fAccConfigureOverlay(overlay->OverlayToken(), overlay->OverlayBuffer(),
NULL, NULL);
}
void
AccelerantHWInterface::SetCursor(ServerCursor* cursor)
{
if (cursor == NULL || LockExclusiveAccess() == false)
return;
bool cursorSet = false;
if (fAccSetCursorBitmap != NULL) {
uint16 xHotSpot = (uint16)cursor->GetHotSpot().x;
uint16 yHotSpot = (uint16)cursor->GetHotSpot().y;
uint16 width = (uint16)cursor->Bounds().Width();
uint16 height = (uint16)cursor->Bounds().Height();
cursorSet = fAccSetCursorBitmap(width, height, xHotSpot,
yHotSpot, cursor->ColorSpace(), (uint16)cursor->BytesPerRow(),
cursor->Bits()) == B_OK;
} else if (cursor->CursorData() != NULL && fAccSetCursorShape != NULL) {
uint8 size = cursor->CursorData()[0];
uint8 xHotSpot = cursor->CursorData()[3];
uint8 yHotSpot = cursor->CursorData()[2];
const uint8* xorMask = cursor->CursorData() + 4;
uint8 andMask[32];
const uint8* transMask = cursor->CursorData() + 36;
for (int32 i = 0; i < 32; i++)
andMask[i] = ~transMask[i];
cursorSet = fAccSetCursorShape(size, size, xHotSpot,
yHotSpot, andMask, xorMask) == B_OK;
}
if (cursorSet && !fHardwareCursorEnabled) {
if (fCursorVisible && fFloatingOverlaysLock.Lock()) {
IntRect r = _CursorFrame();
fCursorVisible = false;
_RestoreCursorArea();
Invalidate(r);
fCursorVisible = true;
fFloatingOverlaysLock.Unlock();
}
if (fAccMoveCursor != NULL)
fAccMoveCursor((uint16)fCursorLocation.x,
(uint16)fCursorLocation.y);
}
if (fAccShowCursor != NULL)
fAccShowCursor(cursorSet);
UnlockExclusiveAccess();
fHardwareCursorEnabled = cursorSet;
HWInterface::SetCursor(cursor);
}
void
AccelerantHWInterface::SetCursorVisible(bool visible)
{
HWInterface::SetCursorVisible(visible);
if (fHardwareCursorEnabled && LockExclusiveAccess()) {
if (fAccShowCursor != NULL)
fAccShowCursor(visible);
else
fHardwareCursorEnabled = false;
UnlockExclusiveAccess();
}
}
void
AccelerantHWInterface::MoveCursorTo(float x, float y)
{
HWInterface::MoveCursorTo(x, y);
if (fHardwareCursorEnabled && LockExclusiveAccess()) {
if (fAccMoveCursor != NULL)
fAccMoveCursor((uint16)x, (uint16)y);
else {
fHardwareCursorEnabled = false;
if (fAccShowCursor != NULL)
fAccShowCursor(false);
}
UnlockExclusiveAccess();
}
}
RenderingBuffer*
AccelerantHWInterface::FrontBuffer() const
{
return fFrontBuffer.Get();
}
RenderingBuffer*
AccelerantHWInterface::BackBuffer() const
{
return fBackBuffer.Get();
}
bool
AccelerantHWInterface::IsDoubleBuffered() const
{
return fBackBuffer.IsSet();
}
void
AccelerantHWInterface::_CopyBackToFront( BRegion& region)
{
return HWInterface::_CopyBackToFront(region);
}
void
AccelerantHWInterface::_DrawCursor(IntRect area) const
{
if (!fHardwareCursorEnabled)
HWInterface::_DrawCursor(area);
}
void
AccelerantHWInterface::_RegionToRectParams( BRegion* region,
uint32* count) const
{
*count = region->CountRects();
if (fRectParamsCount < *count) {
fRectParamsCount = (*count / kDefaultParamsCount + 1)
* kDefaultParamsCount;
fill_rect_params* params
= new (nothrow) fill_rect_params[fRectParamsCount];
if (params) {
delete[] fRectParams;
fRectParams = params;
} else {
*count = fRectParamsCount;
}
}
for (uint32 i = 0; i < *count; i++) {
clipping_rect r = region->RectAtInt(i);
fRectParams[i].left = (uint16)r.left;
fRectParams[i].top = (uint16)r.top;
fRectParams[i].right = (uint16)r.right;
fRectParams[i].bottom = (uint16)r.bottom;
}
}
uint32
AccelerantHWInterface::_NativeColor(const rgb_color& color) const
{
switch (fDisplayMode.space) {
case B_CMAP8:
case B_GRAY8:
return RGBColor(color).GetColor8();
case B_RGB15_BIG:
case B_RGBA15_BIG:
case B_RGB15_LITTLE:
case B_RGBA15_LITTLE:
return RGBColor(color).GetColor15();
case B_RGB16_BIG:
case B_RGB16_LITTLE:
return RGBColor(color).GetColor16();
case B_RGB32_BIG:
case B_RGBA32_BIG:
case B_RGB32_LITTLE:
case B_RGBA32_LITTLE: {
return (uint32)((color.alpha << 24) | (color.red << 16)
| (color.green << 8) | color.blue);
}
}
return 0;
}
void
AccelerantHWInterface::_SetSystemPalette()
{
set_indexed_colors setIndexedColors = (set_indexed_colors)fAccelerantHook(
B_SET_INDEXED_COLORS, NULL);
if (setIndexedColors == NULL)
return;
const rgb_color* palette = SystemPalette();
uint8 colors[3 * 256];
uint32 j = 0;
for (int32 i = 0; i < 256; i++) {
colors[j++] = palette[i].red;
colors[j++] = palette[i].green;
colors[j++] = palette[i].blue;
}
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];
uint32 j = 0;
if (fFrontBuffer->Width() > fFrontBuffer->BytesPerRow()) {
for (int32 i = 0; i < 256; i++) {
colors[j++] = (i & 0xf) * 17;
colors[j++] = (i & 0xf) * 17;
colors[j++] = (i & 0xf) * 17;
}
setIndexedColors(256, 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);
}
}