1 /* 2 * Copyright 2001-2013, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Adi Oanca <adioanca@myrealbox.com> 7 * Axel Dörfler, axeld@pinc-software.de 8 * Stephan Aßmus, <superstippi@gmx.de> 9 */ 10 11 12 #include "Screen.h" 13 14 #include "BitmapManager.h" 15 #include "DrawingEngine.h" 16 #include "HWInterface.h" 17 18 #include <Accelerant.h> 19 #include <Point.h> 20 #include <GraphicsDefs.h> 21 22 #include <stdlib.h> 23 #include <stdio.h> 24 25 26 static float 27 get_mode_frequency(const display_mode& mode) 28 { 29 // Taken from Screen preferences 30 float timing = float(mode.timing.h_total * mode.timing.v_total); 31 if (timing == 0.0f) 32 return 0.0f; 33 34 return rint(10 * float(mode.timing.pixel_clock * 1000) 35 / timing) / 10.0; 36 } 37 38 39 // #pragma mark - 40 41 42 Screen::Screen(::HWInterface *interface, int32 id) 43 : 44 fID(id), 45 fDriver(interface ? interface->CreateDrawingEngine() : NULL), 46 fHWInterface(interface) 47 { 48 } 49 50 51 Screen::Screen() 52 : 53 fID(-1), 54 fDriver(NULL), 55 fHWInterface(NULL) 56 { 57 } 58 59 60 Screen::~Screen() 61 { 62 Shutdown(); 63 delete fDriver; 64 delete fHWInterface; 65 } 66 67 68 /*! Finds the mode in the mode list that is closest to the mode specified. 69 As long as the mode list is not empty, this method will always succeed. 70 */ 71 status_t 72 Screen::Initialize() 73 { 74 if (fHWInterface) { 75 // init the graphics hardware 76 return fHWInterface->Initialize(); 77 } 78 79 return B_NO_INIT; 80 } 81 82 83 void 84 Screen::Shutdown() 85 { 86 if (fHWInterface) 87 fHWInterface->Shutdown(); 88 } 89 90 91 status_t 92 Screen::SetMode(const display_mode& mode) 93 { 94 display_mode current; 95 GetMode(current); 96 if (!memcmp(&mode, ¤t, sizeof(display_mode))) 97 return B_OK; 98 99 gBitmapManager->SuspendOverlays(); 100 101 status_t status = fHWInterface->SetMode(mode); 102 // any attached DrawingEngines will be notified 103 104 gBitmapManager->ResumeOverlays(); 105 106 return status; 107 } 108 109 110 status_t 111 Screen::SetMode(uint16 width, uint16 height, uint32 colorSpace, 112 const display_timing& timing) 113 { 114 display_mode mode; 115 mode.timing = timing; 116 mode.space = colorSpace; 117 mode.virtual_width = width; 118 mode.virtual_height = height; 119 mode.h_display_start = 0; 120 mode.v_display_start = 0; 121 mode.flags = 0; 122 123 return SetMode(mode); 124 } 125 126 127 status_t 128 Screen::SetBestMode(uint16 width, uint16 height, uint32 colorSpace, 129 float frequency, bool strict) 130 { 131 // search for a matching mode 132 display_mode* modes = NULL; 133 uint32 count; 134 status_t status = fHWInterface->GetModeList(&modes, &count); 135 if (status < B_OK) 136 return status; 137 if (count <= 0) 138 return B_ERROR; 139 140 int32 index = _FindBestMode(modes, count, width, height, colorSpace, 141 frequency); 142 if (index < 0) { 143 debug_printf("app_server: Finding best mode for %ux%u (%" B_PRIu32 144 ", %g Hz%s) failed\n", width, height, colorSpace, frequency, 145 strict ? ", strict" : ""); 146 147 if (strict) { 148 delete[] modes; 149 return B_ERROR; 150 } else { 151 index = 0; 152 // Just use the first mode in the list 153 debug_printf("app_server: Use %ux%u (%" B_PRIu32 ") instead.\n", 154 modes[0].timing.h_total, modes[0].timing.v_total, modes[0].space); 155 } 156 } 157 158 display_mode mode = modes[index]; 159 delete[] modes; 160 161 float modeFrequency = get_mode_frequency(mode); 162 display_mode originalMode = mode; 163 bool adjusted = false; 164 165 if (modeFrequency != frequency) { 166 // adjust timing to fit the requested frequency if needed 167 // (taken from Screen preferences application) 168 mode.timing.pixel_clock = ((uint32)mode.timing.h_total 169 * mode.timing.v_total / 10 * int32(frequency * 10)) / 1000; 170 adjusted = true; 171 } 172 status = SetMode(mode); 173 if (status != B_OK && adjusted) { 174 // try again with the unchanged mode 175 status = SetMode(originalMode); 176 } 177 178 return status; 179 } 180 181 182 status_t 183 Screen::SetPreferredMode() 184 { 185 display_mode mode; 186 status_t status = fHWInterface->GetPreferredMode(&mode); 187 if (status != B_OK) 188 return status; 189 190 return SetMode(mode); 191 } 192 193 194 void 195 Screen::GetMode(display_mode& mode) const 196 { 197 fHWInterface->GetMode(&mode); 198 } 199 200 201 void 202 Screen::GetMode(uint16 &width, uint16 &height, uint32 &colorspace, 203 float &frequency) const 204 { 205 display_mode mode; 206 fHWInterface->GetMode(&mode); 207 208 width = mode.virtual_width; 209 height = mode.virtual_height; 210 colorspace = mode.space; 211 frequency = get_mode_frequency(mode); 212 } 213 214 215 status_t 216 Screen::GetMonitorInfo(monitor_info& info) const 217 { 218 return fHWInterface->GetMonitorInfo(&info); 219 } 220 221 222 void 223 Screen::SetFrame(const BRect& rect) 224 { 225 // TODO: multi-monitor support... 226 } 227 228 229 BRect 230 Screen::Frame() const 231 { 232 display_mode mode; 233 fHWInterface->GetMode(&mode); 234 235 return BRect(0, 0, mode.virtual_width - 1, mode.virtual_height - 1); 236 } 237 238 239 color_space 240 Screen::ColorSpace() const 241 { 242 display_mode mode; 243 fHWInterface->GetMode(&mode); 244 245 return (color_space)mode.space; 246 } 247 248 249 /*! \brief Returns the mode that matches the given criteria best. 250 The "width" argument is the only hard argument, the rest will be adapted 251 as needed. 252 */ 253 int32 254 Screen::_FindBestMode(const display_mode* modes, uint32 count, 255 uint16 width, uint16 height, uint32 colorSpace, float frequency) const 256 { 257 int32 bestDiff = 0; 258 int32 bestIndex = -1; 259 for (uint32 i = 0; i < count; i++) { 260 const display_mode& mode = modes[i]; 261 if (mode.virtual_width != width) 262 continue; 263 264 // compute some random equality score 265 // TODO: check if these scores make sense 266 int32 diff = 1000 * abs(mode.timing.v_display - height) 267 + int32(fabs(get_mode_frequency(mode) - frequency) * 10) 268 + 100 * abs(mode.space - colorSpace); 269 270 if (bestIndex == -1 || diff < bestDiff) { 271 bestDiff = diff; 272 bestIndex = i; 273 } 274 } 275 276 return bestIndex; 277 } 278