tcp: Add APICall trace entry and move TRACEs into locked parts.
[haiku.git] / src / add-ons / accelerants / matrox / Overlay.c
blob6c06295b1bf1a117e0c0334e0a431fc3a4a83e98
1 /* Written by Rudolf Cornelissen 05-2002/11-2009 */
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 */
8 #define MODULE_BIT 0x00000400
10 #include "acc_std.h"
12 /* define the supported overlay input colorspaces */
13 /* Note:
14 * G200-G550 can all do YUV4:2:0 2-plane colorspace as well,
15 * G200 does not support RGB modes while > G200 do (but with limited scaling and without filtering),
16 * G200 does not support YUV4:2:0 3-plane mode while > G200 do.
17 * It would be nice to have the YUV4:2:0 2-plane mode implemented also later on, but the Be colorspace
18 * definitions (in GraphicsDefs.h, R5.0.3 and DANO5.1d0) do not include this one... */
19 static uint32 overlay_colorspaces [] = { (uint32)B_YCbCr422, (uint32)B_NO_COLOR_SPACE };
21 uint32 OVERLAY_COUNT(const display_mode *dm)
22 // This method is never used AFAIK though it *is* exported on R5.0.3 and DANO.
23 // Does someone know howto invoke it?
25 LOG(4,("Overlay: count called\n"));
27 /* check for NULL pointer */
28 if (dm == NULL)
30 LOG(4,("Overlay: No display mode specified!\n"));
32 /* apparantly overlay count should report the number of 'overlay units' on the card */
33 return 1;
36 const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm)
37 // This method is never used AFAIK though it *is* exported on R5.0.3 and DANO.
38 // Does someone know howto invoke it?
40 LOG(4,("Overlay: supported_spaces called.\n"));
42 /* check for NULL pointer */
43 if (dm == NULL)
45 LOG(4,("Overlay: No display mode specified!\n"));
46 return NULL;
49 /* interlaced VGA is not supported by G200-G550 BES */
50 if (dm->timing.flags & B_TIMING_INTERLACED)
52 return NULL;
54 /* return a B_NO_COLOR_SPACE terminated list */
55 return &overlay_colorspaces[0];
58 uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space)
59 // This method is never used AFAIK. On R5.0.3 and DANO it is not even exported!
61 LOG(4,("Overlay: supported_features: color_space $%08x\n",a_color_space));
63 /* check what features (like the keying method) are supported on the current
64 * Desktop colorspace */
65 //fixme? Or are we talking about the overlay input bitmap's colorspace?
66 switch (a_color_space)
68 default:
69 /* fixme: for now 'direct 32bit' desktop colorspace assumed */
70 return
71 ( B_OVERLAY_KEYING_USES_ALPHA |
72 B_OVERLAY_COLOR_KEY |
73 B_OVERLAY_HORIZONTAL_FILTERING |
74 B_OVERLAY_VERTICAL_FILTERING );
79 const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height)
81 int offset = 0; /* used to determine next buffer to create */
82 uintptr_t adress, adress2, temp32; /* used to calculate buffer adresses */
83 uint32 oldsize = 0; /* used to 'squeeze' new buffers between already existing ones */
84 int cnt; /* loopcounter */
86 /* acquire the shared benaphore */
87 AQUIRE_BEN(si->overlay.lock)
89 LOG(4, ("Overlay: cardRAM_start = $%p\n", (uint8*)si->framebuffer));
90 LOG(4, ("Overlay: cardRAM_start_DMA = $%p\n", (uint8*)si->framebuffer_pci));
91 LOG(4, ("Overlay: cardRAM_size = %dMb\n", si->ps.memory_size));
93 /* find first empty slot (room for another buffer?) */
94 for (offset = 0; offset < MAXBUFFERS; offset++)
96 if (si->overlay.myBuffer[offset].buffer == NULL) break;
99 LOG(4, ("Overlay: Allocate_buffer offset = %d\n", offset));
101 if (offset < MAXBUFFERS)
102 /* setup new scaler input buffer */
104 switch (cs)
106 case B_YCbCr422:
107 /* check if slopspace is needed: compatible settings choosen for now:
108 * G200 can do with ~0x0003 while > G200 need ~x0007.
109 * Optimized settings for G200 could reduce CPU load a tiny little bit there... */
110 /* fixme: update needed for DVDmax support to adhere to CRTC2 constraints:
111 * case display_mode == B_RGB16: multiple = 32
112 * case display_mode == B_RGB32: multiple = 16 */
113 if (width == (width & ~0x0007))
115 si->overlay.myBuffer[offset].width = width;
117 else
119 si->overlay.myBuffer[offset].width = (width & ~0x0007) + 8;
121 si->overlay.myBuffer[offset].bytes_per_row = 2 * si->overlay.myBuffer[offset].width;
123 /* check if the requested horizontal pitch is supported:
124 * G200 max. pitch is 4092 pixels, > G200 max pitch is 4088 pixels for this colorspace.
125 * Compatible check done, has no downside consequences here. */
126 if (si->overlay.myBuffer[offset].width > 4088)
128 LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n"));
130 /* release the shared benaphore */
131 RELEASE_BEN(si->overlay.lock)
133 return NULL;
135 break;
137 // case 0xffff://fixme: which one(s)?
138 //fixme: 4:2:0 2-plane supported format, should be selected only if detected
139 /* check if slopspace is needed: compatible settings choosen for now:
140 * G200 can do with ~0x0007 while > G200 need ~x001f.
141 * Optimized settings for G200 could reduce CPU load a tiny little bit there... */
142 /* if (width == (width & ~0x001f))
144 si->overlay.myBuffer[offset].width = width;
146 else
148 si->overlay.myBuffer[offset].width = (width & ~0x001f) + 32;
150 */ /* assuming Y-plane only bytes_per_row are requested here */
151 /* si->overlay.myBuffer[offset].bytes_per_row = si->overlay.myBuffer[offset].width;
153 /* check if the requested horizontal pitch is supported:
154 * G200 max. pitch is 4088 pixels, > G200 max pitch is 4064 pixels for this colorspace.
155 * Compatible check done, has no real downside consequences here. */
156 /* if (si->overlay.myBuffer[offset].width > 4064)
158 LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n");
160 /* release the shared benaphore */
161 /* RELEASE_BEN(si->overlay.lock)
163 return NULL;
165 break;
167 default:
168 /* unsupported colorspace! */
169 LOG(4,("Overlay: Sorry, colorspace $%08x not supported, aborted\n",cs));
171 /* release the shared benaphore */
172 RELEASE_BEN(si->overlay.lock)
174 return NULL;
175 break;
178 /* check if the requested buffer width is supported */
179 if (si->ps.card_type < G450) {
180 if (si->overlay.myBuffer[offset].width > 1024) {
181 LOG(4,("Overlay: Sorry, requested buffer width not supported, aborted\n"));
183 /* release the shared benaphore */
184 RELEASE_BEN(si->overlay.lock)
186 return NULL;
189 /* check if the requested buffer height is supported */
190 if (height > 1024) {
191 LOG(4,("Overlay: Sorry, requested buffer height not supported, aborted\n"));
193 /* release the shared benaphore */
194 RELEASE_BEN(si->overlay.lock)
196 return NULL;
198 } else {
199 if (si->overlay.myBuffer[offset].width > 1920) {
200 LOG(4,("Overlay: Sorry, requested buffer width not supported, aborted\n"));
202 /* release the shared benaphore */
203 RELEASE_BEN(si->overlay.lock)
205 return NULL;
208 /* check if the requested buffer height is supported */
209 if (height > 1080) {
210 LOG(4,("Overlay: Sorry, requested buffer height not supported, aborted\n"));
212 /* release the shared benaphore */
213 RELEASE_BEN(si->overlay.lock)
215 return NULL;
219 /* store slopspace (in pixels) for each bitmap for use by 'overlay unit' (BES) */
220 si->overlay.myBufInfo[offset].slopspace = si->overlay.myBuffer[offset].width - width;
222 si->overlay.myBuffer[offset].space = cs;
223 si->overlay.myBuffer[offset].height = height;
225 /* we define the overlay buffers to reside 'in the back' of the cards RAM */
226 /* NOTE to app programmers:
227 * Beware that an app using overlay needs to track workspace switches and screenprefs
228 * changes. If such an action is detected, the app needs to reset it's pointers to the
229 * newly created overlay bitmaps, which will be assigned by BeOS automatically after such
230 * an event. (Also the app needs to respect the new overlay_constraints that will be applicable!)
232 * It is entirely possible that new bitmaps may *not* be re-setup at all, or less of them
233 * than previously setup by the app might be re-setup. This is due to cardRAM restraints then.
234 * This means that the app should also check for NULL pointers returned by the bitmaps,
235 * and if this happens, it needs to fallback to single buffered overlay or even fallback to
236 * bitmap output for the new situation. */
238 /* Another NOTE for app programmers:
239 * A *positive* side-effect of assigning the first overlay buffer exactly at the end of the
240 * cardRAM is that apps that try to write beyond the buffer's space get a segfault immediately.
241 * This *greatly* simplifies tracking such errors!
242 * Of course such errors may lead to strange effects in the app or driver behaviour if they are
243 * not hunted down and removed.. */
245 /* calculate first free RAM adress in card:
246 * Driver setup is as follows:
247 * card base: - hardware cursor bitmap (if used),
248 * directly above - screen memory for both heads */
249 adress2 = (((uintptr_t)((uint8*)si->fbc.frame_buffer)) + /* cursor already included here */
250 (si->fbc.bytes_per_row * si->dm.virtual_height)); /* size in bytes of screen(s) */
251 LOG(4, ("Overlay: first free cardRAM virtual adress $%08x\n", adress2));
253 /* calculate 'preliminary' buffer size including slopspace */
254 oldsize = si->overlay.myBufInfo[offset].size;
255 si->overlay.myBufInfo[offset].size
256 = si->overlay.myBuffer[offset].bytes_per_row * si->overlay.myBuffer[offset].height;
258 /* calculate virtual memory adress that would be needed for a new bitmap */
259 /* NOTE to app programmers:
260 * For testing app behaviour regarding workspace switches or screen prefs changes to settings
261 * that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with
262 * a low amount of RAM. Or you can set in the file matrox.settings for example:
263 * memory 8 #8Mb RAM on card
264 * and reboot (this simulates 8Mb RAM on the card).
266 * If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to
267 * bitmap output or maybe single buffered overlay output if small bitmaps are used. */
269 adress = (((uintptr_t)((uint8*)si->framebuffer)) + (si->ps.memory_size * 1024 * 1024));
270 for (cnt = 0; cnt <= offset; cnt++)
272 adress -= si->overlay.myBufInfo[cnt].size;
275 /* the > G200 scalers require buffers to be aligned to 16 byte pages cardRAM offset, G200 can do with
276 * 8 byte pages cardRAM offset. Compatible settings used, has no real downside consequences here */
278 /* Check if we need to modify the buffers starting adress and thus the size */
279 /* calculate 'would be' cardRAM offset */
280 temp32 = (adress - ((uintptr_t)((vuint32 *)si->framebuffer)));
281 /* check if it is aligned */
282 if (temp32 != (temp32 & 0xfffffff0))
284 /* update the (already calculated) buffersize to get it aligned */
285 si->overlay.myBufInfo[offset].size += (temp32 - (temp32 & 0xfffffff0));
286 /* update the (already calculated) adress to get it aligned */
287 adress -= (temp32 - (temp32 & 0xfffffff0));
289 LOG(4,("Overlay: new buffer needs virtual adress $%08x\n", adress));
291 /* First check now if buffer to be defined is 'last one' in memory (speaking backwards):
292 * this is done to prevent a large buffer getting created in the space a small buffer
293 * occupied earlier, if not all buffers created were deleted.
294 * Note also that the app can delete the buffers in any order desired. */
296 /* NOTE to app programmers:
297 * If you are going to delete a overlay buffer you created, you should delete them *all* and
298 * then re-create only the new ones needed. This way you are sure not to get unused memory-
299 * space in between your overlay buffers for instance, so cardRAM is used 'to the max'.
300 * If you don't, you might not get a buffer at all if you are trying to set up a larger one
301 * than before.
302 * (Indeed: not all buffers *have* to be of the same type and size...) */
304 for (cnt = offset; cnt < MAXBUFFERS; cnt++)
306 if (si->overlay.myBuffer[cnt].buffer != NULL)
308 /* Check if the new buffer would fit into the space the single old one used here */
309 if (si->overlay.myBufInfo[offset].size <= oldsize)
311 /* It does, so we reset to the old size and adresses to prevent the space from shrinking
312 * if we get here again... */
313 adress -= (oldsize - si->overlay.myBufInfo[offset].size);
314 si->overlay.myBufInfo[offset].size = oldsize;
315 LOG(4,("Overlay: 'squeezing' in buffer:\n"
316 "Overlay: resetting it to virtual adress $%08x and size $%08x\n", adress,oldsize));
317 /* force exiting the FOR loop */
318 cnt = MAXBUFFERS;
320 else
322 /* nogo, sorry */
323 LOG(4,("Overlay: Other buffer(s) exist after this one:\n"
324 "Overlay: not enough space to 'squeeze' this one in, aborted\n"));
326 /* Reset to the old size to prevent the space from 'growing' if we get here again... */
327 si->overlay.myBufInfo[offset].size = oldsize;
329 /* release the shared benaphore */
330 RELEASE_BEN(si->overlay.lock)
332 return NULL;
337 /* check if we have enough space to setup this new bitmap
338 * (preventing overlap of desktop RAMspace & overlay bitmap RAMspace here) */
339 if (adress < adress2)
340 /* nope, sorry */
342 LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n"));
344 /* release the shared benaphore */
345 RELEASE_BEN(si->overlay.lock)
347 return NULL;
349 /* continue buffer setup */
350 si->overlay.myBuffer[offset].buffer = (void *) adress;
352 /* calculate physical memory adress (for dma use) */
353 /* NOTE to app programmers:
354 * For testing app behaviour regarding workspace switches or screen prefs changes to settings
355 * that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with
356 * a low amount of RAM. Or you can set in the file matrox.settings for example:
357 * memory 8 #8Mb RAM on card
358 * and reboot (this simulates 8Mb RAM on the card).
360 * If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to
361 * bitmap output or maybe single buffered overlay output if small bitmaps are used. */
363 adress = (((uintptr_t)((uint8*)si->framebuffer_pci)) + (si->ps.memory_size * 1024 * 1024));
364 for (cnt = 0; cnt <= offset; cnt++)
366 adress -= si->overlay.myBufInfo[cnt].size;
368 /* this adress is already aligned to the scaler's requirements (via the already modified sizes) */
369 si->overlay.myBuffer[offset].buffer_dma = (void *) adress;
371 LOG(4, ("Overlay: New buffer: addr $%p, dma_addr $%p, color space $%08x\n",
372 (uint8*)si->overlay.myBuffer[offset].buffer,
373 (uint8*)si->overlay.myBuffer[offset].buffer_dma, cs));
374 LOG(4, ("Overlay: New buffer's size is $%08x\n", si->overlay.myBufInfo[offset].size));
376 /* release the shared benaphore */
377 RELEASE_BEN(si->overlay.lock)
379 return &si->overlay.myBuffer[offset];
380 } else {
381 /* sorry, no more room for buffers */
382 LOG(4, ("Overlay: Sorry, no more space for buffers: aborted\n"));
384 /* release the shared benaphore */
385 RELEASE_BEN(si->overlay.lock)
387 return NULL;
392 status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob)
393 /* Note that the user can delete the buffers in any order desired! */
395 int offset = 0;
397 if (ob != NULL)
399 /* find the buffer */
400 for (offset = 0; offset < MAXBUFFERS; offset++)
402 if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
405 if (offset < MAXBUFFERS)
406 /* delete current buffer */
408 si->overlay.myBuffer[offset].buffer = NULL;
409 si->overlay.myBuffer[offset].buffer_dma = NULL;
411 LOG(4,("Overlay: Release_buffer offset = %d, buffer released\n",offset));
413 return B_OK;
415 else
417 /* this is no buffer of ours! */
418 LOG(4,("Overlay: Release_overlay_buffer: not ours, aborted!\n"));
420 return B_ERROR;
423 else
424 /* no buffer specified! */
426 LOG(4,("Overlay: Release_overlay_buffer: no buffer specified, aborted!\n"));
428 return B_ERROR;
432 status_t GET_OVERLAY_CONSTRAINTS
433 (const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc)
435 int offset = 0;
437 LOG(4,("Overlay: Get_overlay_constraints called\n"));
439 /* check for NULL pointers */
440 if ((dm == NULL) || (ob == NULL) || (oc == NULL))
442 LOG(4,("Overlay: Get_overlay_constraints: Null pointer(s) detected!\n"));
443 return B_ERROR;
446 /* find the buffer */
447 for (offset = 0; offset < MAXBUFFERS; offset++)
449 if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
452 if (offset < MAXBUFFERS)
454 /* scaler input (values are in pixels) */
455 oc->view.h_alignment = 0;
456 oc->view.v_alignment = 0;
458 switch (ob->space)
460 case B_YCbCr422:
461 /* G200 can work with 3, > G200 need 7. Compatible setting returned for now.
462 * Note: this has to be in sync with the slopspace setup during buffer allocation.. */
463 oc->view.width_alignment = 7;
464 break;
466 // case 0xffff://fixme: which one(s)? (4:2:0 supported formats. Not yet used...)
467 /* G200 can work with 7, > G200 need 31. Compatible setting returned for now.
468 * Note: this has to be in sync with the slopspace setup during buffer allocation.. */
469 /* oc->view.width_alignment = 31;
470 break;
472 default:
473 /* we should not be here, but set the worst-case value just to be safe anyway */
474 oc->view.width_alignment = 31;
475 break;
478 oc->view.height_alignment = 0;
479 oc->view.width.min = 1;
480 oc->view.height.min = 2; /* two fields */
481 oc->view.width.max = ob->width;
482 oc->view.height.max = ob->height;
484 /* scaler output restrictions */
485 oc->window.h_alignment = 0;
486 oc->window.v_alignment = 0;
487 oc->window.width_alignment = 0;
488 oc->window.height_alignment = 0;
489 oc->window.width.min = 2;
490 /* G200-G550 can output upto and including 2048 pixels in width */
491 if (dm->virtual_width > 2048)
493 oc->window.width.max = 2048;
495 else
497 oc->window.width.max = dm->virtual_width;
499 oc->window.height.min = 2;
500 /* G200-G550 can output upto and including 2048 pixels in height */
501 if (dm->virtual_height > 2048)
503 oc->window.height.max = 2048;
505 else
507 oc->window.height.max = dm->virtual_height;
510 /* G200-G550 scaling restrictions */
511 /* Adjust horizontal restrictions if pixelclock is above BES max. speed! */
512 /* Note: If RGB32 is implemented no scaling is supported! */
513 if (si->dm.timing.pixel_clock > BESMAXSPEED)
515 oc->h_scale.min = (1 * 2) / (32 - (1 / (float)16384));
516 oc->h_scale.max = (16384 * 2)/(float)(ob->width - si->overlay.myBufInfo[offset].slopspace);
518 else
520 oc->h_scale.min = 1 / (32 - (1 / (float)16384));
521 oc->h_scale.max = 16384/(float)(ob->width - si->overlay.myBufInfo[offset].slopspace);
523 oc->v_scale.min = 1 / (32 - (1 / (float)16384));
524 oc->v_scale.max = 16384/(float)ob->height;
526 return B_OK;
528 else
530 /* this is no buffer of ours! */
531 LOG(4,("Overlay: Get_overlay_constraints: buffer is not ours, aborted!\n"));
533 return B_ERROR;
537 overlay_token ALLOCATE_OVERLAY(void)
539 uint32 tmpToken;
540 LOG(4,("Overlay: Allocate_overlay called: "));
542 /* come up with a token */
543 tmpToken = 0x12345678;
545 /* acquire the shared benaphore */
546 AQUIRE_BEN(si->overlay.lock)
548 /* overlay unit already in use? */
549 if (si->overlay.myToken == NULL)
550 /* overlay unit is available */
552 LOG(4,("succesfull\n"));
554 si->overlay.myToken = &tmpToken;
556 /* release the shared benaphore */
557 RELEASE_BEN(si->overlay.lock)
559 return si->overlay.myToken;
561 else
562 /* sorry, overlay unit is occupied */
564 LOG(4,("failed: already in use!\n"));
566 /* release the shared benaphore */
567 RELEASE_BEN(si->overlay.lock)
569 return NULL;
573 status_t RELEASE_OVERLAY(overlay_token ot)
575 LOG(4,("Overlay: Release_overlay called: "));
577 /* is this call for real? */
578 if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
579 /* nope, abort */
581 LOG(4,("failed, not in use!\n"));
583 return B_ERROR;
585 else
586 /* call is for real */
589 gx00_release_bes();
591 LOG(4,("succesfull\n"));
593 si->overlay.myToken = NULL;
594 return B_OK;
598 status_t CONFIGURE_OVERLAY
599 (overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov)
601 int offset = 0; /* used for buffer index */
603 LOG(4,("Overlay: Configure_overlay called: "));
605 /* Note:
606 * When a Workspace switch, screen prefs change, or overlay app shutdown occurs, BeOS will
607 * release all overlay buffers. The buffer currently displayed at that moment, may need some
608 * 'hardware releasing' in the CONFIGURE_OVERLAY routine. This is why CONFIGURE_OVERLAY gets
609 * called one more time then, with a null pointer for overlay_window and overlay_view, while
610 * the currently displayed overlay_buffer is given.
611 * The G200-G550 do not need to do anything on such an occasion, so we simply return if we
612 * get called then. */
613 if ((ow == NULL) || (ov == NULL))
615 LOG(4,("output properties changed\n"));
617 return B_OK;
620 /* Note:
621 * If during overlay use the screen prefs are changed, or the workspace has changed, it
622 * may be that we were not able to re-allocate the requested overlay buffers (or only partly)
623 * due to lack of cardRAM. If the app does not respond properly to this, we might end up
624 * with a NULL pointer instead of a overlay_buffer to work with here.
625 * Of course, we need to abort then to prevent the system from 'going down'.
626 * The app will probably crash because it will want to write into this non-existant buffer
627 * at some point. */
628 if (ob == NULL)
630 LOG(4,("no overlay buffer specified\n"));
632 return B_ERROR;
635 /* is this call done by the app that owns us? */
636 if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
637 /* nope, abort */
639 LOG(4,("failed\n"));
641 return B_ERROR;
643 else
644 /* call is for real */
646 /* find the buffer's offset */
647 for (offset = 0; offset < MAXBUFFERS; offset++)
649 if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
652 if (offset < MAXBUFFERS)
654 LOG(4,("succesfull, switching to buffer %d\n", offset));
656 gx00_configure_bes(ob, ow, ov, offset);
658 return B_OK;
660 else
662 /* this is no buffer of ours! */
663 LOG(4,("buffer is not ours, aborted!\n"));
665 return B_ERROR;