1 /* Written by Rudolf Cornelissen 05/2002-4/2006 */ 2 3 /* Note on 'missing features' in BeOS 5.0.3 and DANO: 4 * BeOS needs to define more colorspaces! It would be nice if BeOS would support the FourCC 'definitions' 5 * of colorspaces. These colorspaces are 32bit words, so it could be simply done (or is it already so?) 6 */ 7 8 #define MODULE_BIT 0x00000400 9 10 #include "acc_std.h" 11 12 /* define the supported overlay input colorspaces */ 13 /* It would be nice to have the YUV4:2:0 2-plane mode implemented also later on, but the Be colorspace 14 * definitions (in GraphicsDefs.h, R5.0.3 and DANO5.1d0) do not include this one... */ 15 static uint32 overlay_colorspaces [] = { (uint32)B_YCbCr422, (uint32)B_NO_COLOR_SPACE }; 16 17 uint32 OVERLAY_COUNT(const display_mode *dm) 18 // This method is never used AFAIK though it *is* exported on R5.0.3 and DANO. 19 // Does someone know howto invoke it? 20 { 21 LOG(4,("Overlay: count called\n")); 22 23 /* check for NULL pointer */ 24 if (dm == NULL) 25 { 26 LOG(4,("Overlay: No display mode specified!\n")); 27 } 28 /* apparantly overlay count should report the number of 'overlay units' on the card */ 29 return 1; 30 } 31 32 const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm) 33 // This method is never used AFAIK though it *is* exported on R5.0.3 and DANO. 34 // Does someone know howto invoke it? 35 { 36 LOG(4,("Overlay: supported_spaces called.\n")); 37 38 /* check for NULL pointer */ 39 if (dm == NULL) 40 { 41 LOG(4,("Overlay: No display mode specified!\n")); 42 return NULL; 43 } 44 45 /* assuming interlaced VGA is not supported */ 46 if (dm->timing.flags & B_TIMING_INTERLACED) 47 { 48 return NULL; 49 } 50 /* return a B_NO_COLOR_SPACE terminated list */ 51 return &overlay_colorspaces[0]; 52 } 53 54 uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space) 55 // This method is never used AFAIK. On R5.0.3 and DANO it is not even exported! 56 { 57 LOG(4,("Overlay: supported_features: color_space $%08x\n",a_color_space)); 58 59 /* check what features are supported for the current overlaybitmap colorspace */ 60 switch (a_color_space) 61 { 62 default: 63 return 64 ( B_OVERLAY_COLOR_KEY | 65 B_OVERLAY_HORIZONTAL_FILTERING | 66 B_OVERLAY_VERTICAL_FILTERING ); 67 } 68 } 69 70 const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height) 71 { 72 int offset = 0; /* used to determine next buffer to create */ 73 uintptr_t adress, adress2, temp32; /* used to calculate buffer adresses */ 74 uint32 oldsize = 0; /* used to 'squeeze' new buffers between already existing ones */ 75 int cnt; /* loopcounter */ 76 77 /* acquire the shared benaphore */ 78 AQUIRE_BEN(si->overlay.lock) 79 80 LOG(4,("Overlay: cardRAM_start = $%p\n", (uint8*)si->framebuffer)); 81 LOG(4,("Overlay: cardRAM_start_DMA = $%p\n", (uint8*)si->framebuffer_pci)); 82 LOG(4,("Overlay: cardRAM_size = %3.3fMb\n",(si->ps.memory_size / (1024.0 * 1024.0)))); 83 84 /* find first empty slot (room for another buffer?) */ 85 for (offset = 0; offset < MAXBUFFERS; offset++) 86 { 87 if (si->overlay.myBuffer[offset].buffer == NULL) break; 88 } 89 90 LOG(4,("Overlay: Allocate_buffer offset = %d\n",offset)); 91 92 if (offset < MAXBUFFERS) 93 /* setup new scaler input buffer */ 94 { 95 switch (cs) 96 { 97 case B_YCbCr422: 98 /* check if slopspace is needed: VIA CLE266 needs ~0x0007. */ 99 si->overlay.myBuffer[offset].width = ((width + 0x0007) & ~0x0007); 100 si->overlay.myBuffer[offset].bytes_per_row = 2 * si->overlay.myBuffer[offset].width; 101 102 /* check if the requested horizontal pitch is supported: */ 103 //fixme: tune for VIA... (overruled below, this should probably be a bytes_per_row check) 104 if (si->overlay.myBuffer[offset].width > 4088) 105 { 106 LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n")); 107 108 /* release the shared benaphore */ 109 RELEASE_BEN(si->overlay.lock) 110 111 return NULL; 112 } 113 break; 114 default: 115 /* unsupported colorspace! */ 116 LOG(4,("Overlay: Sorry, colorspace $%08x not supported, aborted\n",cs)); 117 118 /* release the shared benaphore */ 119 RELEASE_BEN(si->overlay.lock) 120 121 return NULL; 122 break; 123 } 124 125 /* check if the requested buffer width is supported */ 126 if (si->overlay.myBuffer[offset].width > 1024) 127 { 128 LOG(4,("Overlay: Sorry, requested buffer width not supported, aborted\n")); 129 130 /* release the shared benaphore */ 131 RELEASE_BEN(si->overlay.lock) 132 133 return NULL; 134 } 135 /* check if the requested buffer height is supported */ 136 if (height > 1024) 137 { 138 LOG(4,("Overlay: Sorry, requested buffer height not supported, aborted\n")); 139 140 /* release the shared benaphore */ 141 RELEASE_BEN(si->overlay.lock) 142 143 return NULL; 144 } 145 146 /* store slopspace (in pixels) for each bitmap for use by 'overlay unit' (BES) */ 147 si->overlay.myBufInfo[offset].slopspace = si->overlay.myBuffer[offset].width - width; 148 149 si->overlay.myBuffer[offset].space = cs; 150 si->overlay.myBuffer[offset].height = height; 151 152 /* we define the overlay buffers to reside 'in the back' of the cards RAM */ 153 /* NOTE to app programmers: 154 * Beware that an app using overlay needs to track workspace switches and screenprefs 155 * changes. If such an action is detected, the app needs to reset it's pointers to the 156 * newly created overlay bitmaps, which will be assigned by BeOS automatically after such 157 * an event. (Also the app needs to respect the new overlay_constraints that will be applicable!) 158 * 159 * It is entirely possible that new bitmaps may *not* be re-setup at all, or less of them 160 * than previously setup by the app might be re-setup. This is due to cardRAM restraints then. 161 * This means that the app should also check for NULL pointers returned by the bitmaps, 162 * and if this happens, it needs to fallback to single buffered overlay or even fallback to 163 * bitmap output for the new situation. */ 164 165 /* Another NOTE for app programmers: 166 * A *positive* side-effect of assigning the first overlay buffer exactly at the end of the 167 * cardRAM is that apps that try to write beyond the buffer's space get a segfault immediately. 168 * This *greatly* simplifies tracking such errors! 169 * Of course such errors may lead to strange effects in the app or driver behaviour if they are 170 * not hunted down and removed.. */ 171 172 /* calculate first free RAM adress in card: 173 * Driver setup is as follows: 174 * card base: - hardware cursor bitmap (if used), 175 * directly above - screen memory for both heads */ 176 adress2 = (((uintptr_t)((uint8*)si->fbc.frame_buffer)) + /* cursor already included here */ 177 (si->fbc.bytes_per_row * si->dm.virtual_height)); /* size in bytes of screen(s) */ 178 LOG(4,("Overlay: first free cardRAM virtual adress $%08x\n", adress2)); 179 180 /* calculate 'preliminary' buffer size including slopspace */ 181 oldsize = si->overlay.myBufInfo[offset].size; 182 si->overlay.myBufInfo[offset].size = 183 si->overlay.myBuffer[offset].bytes_per_row * si->overlay.myBuffer[offset].height; 184 185 /* calculate virtual memory adress that would be needed for a new bitmap */ 186 /* NOTE to app programmers: 187 * For testing app behaviour regarding workspace switches or screen prefs changes to settings 188 * that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with 189 * a low amount of RAM. Or you can set in the file skel.settings for example: 190 * memory 8 #8Mb RAM on card 191 * and reboot (this simulates 8Mb RAM on the card). 192 * 193 * If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to 194 * bitmap output or maybe single buffered overlay output if small bitmaps are used. */ 195 196 adress = (((uintptr_t)((uint8*)si->framebuffer)) + si->ps.memory_size); 197 for (cnt = 0; cnt <= offset; cnt++) 198 { 199 adress -= si->overlay.myBufInfo[cnt].size; 200 } 201 202 /* the > G200 scalers require buffers to be aligned to 16 byte pages cardRAM offset, G200 can do with 203 * 8 byte pages cardRAM offset. Compatible settings used, has no real downside consequences here */ 204 205 /* Check if we need to modify the buffers starting adress and thus the size */ 206 /* calculate 'would be' cardRAM offset */ 207 temp32 = (adress - ((uintptr_t)((vuint32 *)si->framebuffer))); 208 /* check if it is aligned */ 209 if (temp32 != (temp32 & 0xfffffff0)) 210 { 211 /* update the (already calculated) buffersize to get it aligned */ 212 si->overlay.myBufInfo[offset].size += (temp32 - (temp32 & 0xfffffff0)); 213 /* update the (already calculated) adress to get it aligned */ 214 adress -= (temp32 - (temp32 & 0xfffffff0)); 215 } 216 LOG(4,("Overlay: new buffer needs virtual adress $%08x\n", adress)); 217 218 /* First check now if buffer to be defined is 'last one' in memory (speaking backwards): 219 * this is done to prevent a large buffer getting created in the space a small buffer 220 * occupied earlier, if not all buffers created were deleted. 221 * Note also that the app can delete the buffers in any order desired. */ 222 223 /* NOTE to app programmers: 224 * If you are going to delete a overlay buffer you created, you should delete them *all* and 225 * then re-create only the new ones needed. This way you are sure not to get unused memory- 226 * space in between your overlay buffers for instance, so cardRAM is used 'to the max'. 227 * If you don't, you might not get a buffer at all if you are trying to set up a larger one 228 * than before. 229 * (Indeed: not all buffers *have* to be of the same type and size...) */ 230 231 for (cnt = offset; cnt < MAXBUFFERS; cnt++) 232 { 233 if (si->overlay.myBuffer[cnt].buffer != NULL) 234 { 235 /* Check if the new buffer would fit into the space the single old one used here */ 236 if (si->overlay.myBufInfo[offset].size <= oldsize) 237 { 238 /* It does, so we reset to the old size and adresses to prevent the space from shrinking 239 * if we get here again... */ 240 adress -= (oldsize - si->overlay.myBufInfo[offset].size); 241 si->overlay.myBufInfo[offset].size = oldsize; 242 LOG(4,("Overlay: 'squeezing' in buffer:\n" 243 "Overlay: resetting it to virtual adress $%08x and size $%08x\n", adress,oldsize)); 244 /* force exiting the FOR loop */ 245 cnt = MAXBUFFERS; 246 } 247 else 248 { 249 /* nogo, sorry */ 250 LOG(4,("Overlay: Other buffer(s) exist after this one:\n" 251 "Overlay: not enough space to 'squeeze' this one in, aborted\n")); 252 253 /* Reset to the old size to prevent the space from 'growing' if we get here again... */ 254 si->overlay.myBufInfo[offset].size = oldsize; 255 256 /* release the shared benaphore */ 257 RELEASE_BEN(si->overlay.lock) 258 259 return NULL; 260 } 261 } 262 } 263 264 /* check if we have enough space to setup this new bitmap 265 * (preventing overlap of desktop RAMspace & overlay bitmap RAMspace here) */ 266 if (adress < adress2) 267 /* nope, sorry */ 268 { 269 LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n")); 270 271 /* release the shared benaphore */ 272 RELEASE_BEN(si->overlay.lock) 273 274 return NULL; 275 } 276 /* continue buffer setup */ 277 si->overlay.myBuffer[offset].buffer = (void *) adress; 278 279 /* calculate physical memory adress (for dma use) */ 280 adress = (((uintptr_t)((uint8*)si->framebuffer_pci)) + si->ps.memory_size); 281 for (cnt = 0; cnt <= offset; cnt++) 282 { 283 adress -= si->overlay.myBufInfo[cnt].size; 284 } 285 /* this adress is already aligned to the scaler's requirements (via the already modified sizes) */ 286 si->overlay.myBuffer[offset].buffer_dma = (void *) adress; 287 288 LOG(4,("Overlay: New buffer: addr $%p, dma_addr $%p, color space $%p\n", 289 (uint8*)si->overlay.myBuffer[offset].buffer, 290 (uint8*)si->overlay.myBuffer[offset].buffer_dma, cs)); 291 LOG(4,("Overlay: New buffer's size is $%08x\n", si->overlay.myBufInfo[offset].size)); 292 293 /* release the shared benaphore */ 294 RELEASE_BEN(si->overlay.lock) 295 296 return &si->overlay.myBuffer[offset]; 297 } 298 else 299 /* sorry, no more room for buffers */ 300 { 301 LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n")); 302 303 /* release the shared benaphore */ 304 RELEASE_BEN(si->overlay.lock) 305 306 return NULL; 307 } 308 } 309 310 status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob) 311 /* Note that the user can delete the buffers in any order desired! */ 312 { 313 int offset = 0; 314 315 if (ob != NULL) 316 { 317 /* find the buffer */ 318 for (offset = 0; offset < MAXBUFFERS; offset++) 319 { 320 if (si->overlay.myBuffer[offset].buffer == ob->buffer) break; 321 } 322 323 if (offset < MAXBUFFERS) 324 /* delete current buffer */ 325 { 326 si->overlay.myBuffer[offset].buffer = NULL; 327 si->overlay.myBuffer[offset].buffer_dma = NULL; 328 329 LOG(4,("Overlay: Release_buffer offset = %d, buffer released\n",offset)); 330 331 return B_OK; 332 } 333 else 334 { 335 /* this is no buffer of ours! */ 336 LOG(4,("Overlay: Release_overlay_buffer: not ours, aborted!\n")); 337 338 return B_ERROR; 339 } 340 } 341 else 342 /* no buffer specified! */ 343 { 344 LOG(4,("Overlay: Release_overlay_buffer: no buffer specified, aborted!\n")); 345 346 return B_ERROR; 347 } 348 } 349 350 status_t GET_OVERLAY_CONSTRAINTS 351 (const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc) 352 { 353 int offset = 0; 354 355 LOG(4,("Overlay: Get_overlay_constraints called\n")); 356 357 /* check for NULL pointers */ 358 if ((dm == NULL) || (ob == NULL) || (oc == NULL)) 359 { 360 LOG(4,("Overlay: Get_overlay_constraints: Null pointer(s) detected!\n")); 361 return B_ERROR; 362 } 363 364 /* find the buffer */ 365 for (offset = 0; offset < MAXBUFFERS; offset++) 366 { 367 if (si->overlay.myBuffer[offset].buffer == ob->buffer) break; 368 } 369 370 if (offset < MAXBUFFERS) 371 { 372 /* scaler input (values are in pixels) */ 373 oc->view.h_alignment = 0; 374 oc->view.v_alignment = 0; 375 376 switch (ob->space) 377 { 378 case B_YCbCr422: 379 /* Note: this has to be in sync with the slopspace setup during buffer allocation.. */ 380 oc->view.width_alignment = 7; 381 break; 382 default: 383 /* we should not be here, but set the worst-case value just to be safe anyway */ 384 oc->view.width_alignment = 7; 385 break; 386 } 387 388 oc->view.height_alignment = 0; 389 oc->view.width.min = 1; 390 oc->view.height.min = 2; /* two fields */ 391 oc->view.width.max = ob->width; 392 oc->view.height.max = ob->height; 393 394 /* scaler output restrictions */ 395 oc->window.h_alignment = 0; 396 oc->window.v_alignment = 0; 397 oc->window.width_alignment = 0; 398 oc->window.height_alignment = 0; 399 oc->window.width.min = 2; 400 /* GeForce cards can output upto and including 2046 pixels in width */ 401 //fixme: how about TNT? 402 if (dm->virtual_width > 2046) 403 { 404 oc->window.width.max = 2046; 405 } 406 else 407 { 408 oc->window.width.max = dm->virtual_width; 409 } 410 oc->window.height.min = 2; 411 /* GeForce cards can output upto and including 2046 pixels in height */ 412 //fixme: how about TNT? 413 if (dm->virtual_height > 2046) 414 { 415 oc->window.height.max = 2046; 416 } 417 else 418 { 419 oc->window.height.max = dm->virtual_height; 420 } 421 422 /* VIA scaling restrictions */ 423 /* VIA has a 'tricked' 1/16 minimum */ 424 oc->h_scale.min = 0.0625; 425 oc->v_scale.min = 0.0625; 426 /* all cards have a upscaling limit of 8.0 (see official nVidia specsheets) */ 427 //checkout.. (fixme) 428 oc->h_scale.max = 8.0; 429 oc->v_scale.max = 8.0; 430 431 return B_OK; 432 } 433 else 434 { 435 /* this is no buffer of ours! */ 436 LOG(4,("Overlay: Get_overlay_constraints: buffer is not ours, aborted!\n")); 437 438 return B_ERROR; 439 } 440 } 441 442 overlay_token ALLOCATE_OVERLAY(void) 443 { 444 uint32 tmpToken; 445 LOG(4,("Overlay: Allocate_overlay called: ")); 446 447 /* come up with a token */ 448 tmpToken = 0x12345678; 449 450 /* acquire the shared benaphore */ 451 AQUIRE_BEN(si->overlay.lock) 452 453 /* overlay unit already in use? */ 454 if (si->overlay.myToken == NULL) 455 /* overlay unit is available */ 456 { 457 LOG(4,("succesfull\n")); 458 459 si->overlay.myToken = &tmpToken; 460 461 /* release the shared benaphore */ 462 RELEASE_BEN(si->overlay.lock) 463 464 return si->overlay.myToken; 465 } 466 else 467 /* sorry, overlay unit is occupied */ 468 { 469 LOG(4,("failed: already in use!\n")); 470 471 /* release the shared benaphore */ 472 RELEASE_BEN(si->overlay.lock) 473 474 return NULL; 475 } 476 } 477 478 status_t RELEASE_OVERLAY(overlay_token ot) 479 { 480 LOG(4,("Overlay: Release_overlay called: ")); 481 482 /* is this call for real? */ 483 if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken)) 484 /* nope, abort */ 485 { 486 LOG(4,("failed, not in use!\n")); 487 488 return B_ERROR; 489 } 490 else 491 /* call is for real */ 492 { 493 494 eng_release_bes(); 495 496 LOG(4,("succesfull\n")); 497 498 si->overlay.myToken = NULL; 499 return B_OK; 500 } 501 } 502 503 status_t CONFIGURE_OVERLAY 504 (overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov) 505 { 506 int offset = 0; /* used for buffer index */ 507 508 LOG(4,("Overlay: Configure_overlay called: ")); 509 510 /* Note: 511 * When a Workspace switch, screen prefs change, or overlay app shutdown occurs, BeOS will 512 * release all overlay buffers. The buffer currently displayed at that moment, may need some 513 * 'hardware releasing' in the CONFIGURE_OVERLAY routine. This is why CONFIGURE_OVERLAY gets 514 * called one more time then, with a null pointer for overlay_window and overlay_view, while 515 * the currently displayed overlay_buffer is given. 516 * The G200-G550 do not need to do anything on such an occasion, so we simply return if we 517 * get called then. */ 518 if ((ow == NULL) || (ov == NULL)) 519 { 520 LOG(4,("output properties changed\n")); 521 522 return B_OK; 523 } 524 525 /* Note: 526 * If during overlay use the screen prefs are changed, or the workspace has changed, it 527 * may be that we were not able to re-allocate the requested overlay buffers (or only partly) 528 * due to lack of cardRAM. If the app does not respond properly to this, we might end up 529 * with a NULL pointer instead of a overlay_buffer to work with here. 530 * Of course, we need to abort then to prevent the system from 'going down'. 531 * The app will probably crash because it will want to write into this non-existant buffer 532 * at some point. */ 533 if (ob == NULL) 534 { 535 LOG(4,("no overlay buffer specified\n")); 536 537 return B_ERROR; 538 } 539 540 /* is this call done by the app that owns us? */ 541 if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken)) 542 /* nope, abort */ 543 { 544 LOG(4,("failed\n")); 545 546 return B_ERROR; 547 } 548 else 549 /* call is for real */ 550 { 551 /* find the buffer's offset */ 552 for (offset = 0; offset < MAXBUFFERS; offset++) 553 { 554 if (si->overlay.myBuffer[offset].buffer == ob->buffer) break; 555 } 556 557 if (offset < MAXBUFFERS) 558 { 559 LOG(4,("succesfull, switching to buffer %d\n", offset)); 560 561 /* program overlay hardware */ 562 eng_configure_bes(ob, ow, ov, offset); 563 564 return B_OK; 565 } 566 else 567 { 568 /* this is no buffer of ours! */ 569 LOG(4,("buffer is not ours, aborted!\n")); 570 571 return B_ERROR; 572 } 573 } 574 } 575