1938efc0a9
it can also no longer create a default mode. * This SetBestMode() function now follows a similar logic than the boot loader, that is, only the width must not deviate, all other values are chosen as close to the original as possible. * VirtualScreen::AddScreen() now follows the same logic as the boot loader in case no configuration was found, and the current screen has no preferred mode (for example via EDID). That is, it will first try 1024x768, and then 800x600. * This means there is no mode change anymore when switching from the boot loader to the app_server in Qemu and VMware. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25782 a95241bf-73f2-0310-859d-f6bbb57e9c96
260 lines
4.9 KiB
C++
260 lines
4.9 KiB
C++
/*
|
|
* Copyright (c) 2001-2008, Haiku, Inc.
|
|
* Distributed under the terms of the MIT license.
|
|
*
|
|
* Authors:
|
|
* Adi Oanca <adioanca@myrealbox.com>
|
|
* Axel Dörfler, axeld@pinc-software.de
|
|
* Stephan Aßmus, <superstippi@gmx.de>
|
|
*/
|
|
|
|
|
|
#include "Screen.h"
|
|
|
|
#include "BitmapManager.h"
|
|
#include "DrawingEngine.h"
|
|
#include "HWInterface.h"
|
|
|
|
#include <Accelerant.h>
|
|
#include <Point.h>
|
|
#include <GraphicsDefs.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
|
|
static float
|
|
get_mode_frequency(const display_mode& mode)
|
|
{
|
|
// Taken from Screen preferences
|
|
float timing = float(mode.timing.h_total * mode.timing.v_total);
|
|
if (timing == 0.0f)
|
|
return 0.0f;
|
|
|
|
return rint(10 * float(mode.timing.pixel_clock * 1000)
|
|
/ timing) / 10.0;
|
|
}
|
|
|
|
|
|
// #pragma mark -
|
|
|
|
|
|
Screen::Screen(::HWInterface *interface, int32 id)
|
|
: fID(id),
|
|
fDriver(interface ? new DrawingEngine(interface) : NULL),
|
|
fHWInterface(interface),
|
|
fIsDefault(true)
|
|
{
|
|
}
|
|
|
|
|
|
Screen::Screen()
|
|
: fID(-1),
|
|
fDriver(NULL),
|
|
fHWInterface(NULL),
|
|
fIsDefault(true)
|
|
{
|
|
}
|
|
|
|
|
|
Screen::~Screen()
|
|
{
|
|
Shutdown();
|
|
delete fDriver;
|
|
delete fHWInterface;
|
|
}
|
|
|
|
/*! Finds the mode in the mode list that is closest to the mode specified.
|
|
As long as the mode list is not empty, this method will always succeed.
|
|
*/
|
|
|
|
status_t
|
|
Screen::Initialize()
|
|
{
|
|
if (fHWInterface) {
|
|
// init the graphics hardware
|
|
return fHWInterface->Initialize();
|
|
}
|
|
|
|
return B_NO_INIT;
|
|
}
|
|
|
|
|
|
void
|
|
Screen::Shutdown()
|
|
{
|
|
if (fHWInterface)
|
|
fHWInterface->Shutdown();
|
|
}
|
|
|
|
|
|
status_t
|
|
Screen::SetMode(const display_mode& mode, bool makeDefault)
|
|
{
|
|
gBitmapManager->SuspendOverlays();
|
|
|
|
status_t status = fHWInterface->SetMode(mode);
|
|
// any attached DrawingEngines will be notified
|
|
|
|
gBitmapManager->ResumeOverlays();
|
|
|
|
if (status >= B_OK)
|
|
fIsDefault = makeDefault;
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
status_t
|
|
Screen::SetMode(uint16 width, uint16 height, uint32 colorSpace,
|
|
const display_timing& timing, bool makeDefault)
|
|
{
|
|
display_mode mode;
|
|
mode.timing = timing;
|
|
mode.space = colorSpace;
|
|
mode.virtual_width = width;
|
|
mode.virtual_height = height;
|
|
mode.h_display_start = 0;
|
|
mode.v_display_start = 0;
|
|
mode.flags = 0;
|
|
|
|
return SetMode(mode, makeDefault);
|
|
}
|
|
|
|
|
|
status_t
|
|
Screen::SetBestMode(uint16 width, uint16 height, uint32 colorSpace,
|
|
float frequency)
|
|
{
|
|
// search for a matching mode
|
|
display_mode* modes = NULL;
|
|
uint32 count;
|
|
status_t status = fHWInterface->GetModeList(&modes, &count);
|
|
if (status < B_OK)
|
|
return status;
|
|
if (count <= 0)
|
|
return B_ERROR;
|
|
|
|
int32 index = _FindBestMode(modes, count, width, height, colorSpace,
|
|
frequency);
|
|
if (index < 0) {
|
|
debug_printf("Finding best mode failed");
|
|
delete[] modes;
|
|
return B_ERROR;
|
|
}
|
|
|
|
display_mode mode = modes[index];
|
|
delete[] modes;
|
|
|
|
float modeFrequency = get_mode_frequency(mode);
|
|
display_mode originalMode = mode;
|
|
bool adjusted = false;
|
|
|
|
if (modeFrequency != frequency) {
|
|
// adjust timing to fit the requested frequency if needed
|
|
// (taken from Screen preferences application)
|
|
mode.timing.pixel_clock = ((uint32)mode.timing.h_total
|
|
* mode.timing.v_total / 10 * int32(frequency * 10)) / 1000;
|
|
adjusted = true;
|
|
}
|
|
|
|
status = SetMode(mode, false);
|
|
if (status < B_OK && adjusted) {
|
|
// try again with the unchanged mode
|
|
status = SetMode(originalMode, false);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
status_t
|
|
Screen::SetPreferredMode()
|
|
{
|
|
display_mode mode;
|
|
status_t status = fHWInterface->GetPreferredMode(&mode);
|
|
if (status < B_OK)
|
|
return status;
|
|
|
|
return SetMode(mode, false);
|
|
}
|
|
|
|
|
|
void
|
|
Screen::GetMode(display_mode* mode) const
|
|
{
|
|
fHWInterface->GetMode(mode);
|
|
}
|
|
|
|
|
|
void
|
|
Screen::GetMode(uint16 &width, uint16 &height, uint32 &colorspace,
|
|
float &frequency) const
|
|
{
|
|
display_mode mode;
|
|
fHWInterface->GetMode(&mode);
|
|
|
|
width = mode.virtual_width;
|
|
height = mode.virtual_height;
|
|
colorspace = mode.space;
|
|
frequency = get_mode_frequency(mode);
|
|
}
|
|
|
|
|
|
status_t
|
|
Screen::GetMonitorInfo(monitor_info& info) const
|
|
{
|
|
return fHWInterface->GetMonitorInfo(&info);
|
|
}
|
|
|
|
|
|
BRect
|
|
Screen::Frame() const
|
|
{
|
|
display_mode mode;
|
|
fHWInterface->GetMode(&mode);
|
|
|
|
return BRect(0, 0, mode.virtual_width - 1, mode.virtual_height - 1);
|
|
}
|
|
|
|
|
|
color_space
|
|
Screen::ColorSpace() const
|
|
{
|
|
display_mode mode;
|
|
fHWInterface->GetMode(&mode);
|
|
|
|
return (color_space)mode.space;
|
|
}
|
|
|
|
|
|
/*! \brief Returns the mode that matches the given criteria best.
|
|
The "width" argument is the only hard argument, the rest will be adapted
|
|
as needed.
|
|
*/
|
|
int32
|
|
Screen::_FindBestMode(const display_mode* modes, uint32 count,
|
|
uint16 width, uint16 height, uint32 colorSpace, float frequency) const
|
|
{
|
|
int32 bestDiff = 0;
|
|
int32 bestIndex = -1;
|
|
for (uint32 i = 0; i < count; i++) {
|
|
const display_mode& mode = modes[i];
|
|
if (mode.virtual_width != width)
|
|
continue;
|
|
|
|
// compute some random equality score
|
|
// TODO: check if these scores make sense
|
|
int32 diff = 1000 * abs(mode.timing.v_display - height)
|
|
+ int32(fabs(get_mode_frequency(mode) - frequency) * 10)
|
|
+ 100 * abs(mode.space - colorSpace);
|
|
|
|
if (bestIndex == -1 || diff < bestDiff) {
|
|
bestDiff = diff;
|
|
bestIndex = i;
|
|
}
|
|
}
|
|
|
|
return bestIndex;
|
|
}
|