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