#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;
}
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;
}
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;
}
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;
}
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;
}
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::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->Width();
uint16 height = (uint16)cursor->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);
}
}