BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / accelerants / nvidia / Overlay.c
blob35cafa89c5b827d1aa3a52bedb19ab77a9c57ece
1 /* Written by Rudolf Cornelissen 05/2002-5/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 /* 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 };
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?
21 LOG(4,("Overlay: count called\n"));
23 /* check for NULL pointer */
24 if (dm == NULL)
26 LOG(4,("Overlay: No display mode specified!\n"));
28 /* apparantly overlay count should report the number of 'overlay units' on the card */
29 return 1;
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?
36 LOG(4,("Overlay: supported_spaces called.\n"));
38 /* check for NULL pointer */
39 if (dm == NULL)
41 LOG(4,("Overlay: No display mode specified!\n"));
42 return NULL;
45 /* assuming interlaced VGA is not supported */
46 if (dm->timing.flags & B_TIMING_INTERLACED)
48 return NULL;
50 /* return a B_NO_COLOR_SPACE terminated list */
51 return &overlay_colorspaces[0];
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!
57 LOG(4,("Overlay: supported_features: color_space $%08x\n",a_color_space));
59 /* check what features are supported for the current overlaybitmap colorspace */
60 switch (a_color_space)
62 default:
63 return
64 ( B_OVERLAY_KEYING_USES_ALPHA |
65 B_OVERLAY_COLOR_KEY |
66 B_OVERLAY_HORIZONTAL_FILTERING |
67 B_OVERLAY_VERTICAL_FILTERING );
72 const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width,
73 uint16 height)
75 int offset = 0; /* used to determine next buffer to create */
76 uintptr_t adress, adress2, temp32; /* used to calculate buffer adresses */
77 uint32 oldsize = 0; /* used to 'squeeze' new buffers between already existing ones */
78 int cnt; /* loopcounter */
80 /* acquire the shared benaphore */
81 AQUIRE_BEN(si->overlay.lock)
83 LOG(4, ("Overlay: cardRAM_start = $%p\n", (uint8*)si->framebuffer));
84 LOG(4, ("Overlay: cardRAM_start_DMA = $%p\n", (uint8*)si->framebuffer_pci));
85 LOG(4, ("Overlay: cardRAM_size = %3.3fMb\n", (si->ps.memory_size / (1024.0 * 1024.0))));
87 /* find first empty slot (room for another buffer?) */
88 for (offset = 0; offset < MAXBUFFERS; offset++)
90 if (si->overlay.myBuffer[offset].buffer == NULL) break;
93 LOG(4, ("Overlay: Allocate_buffer offset = %d\n", offset));
95 if (offset < MAXBUFFERS)
96 /* setup new scaler input buffer */
98 switch (cs)
100 case B_YCbCr422:
101 if (si->ps.card_arch < NV10A)
103 /* check if slopspace is needed: RIVA128 and TNT need ~0x000f. */
104 si->overlay.myBuffer[offset].width = ((width + 0x000f) & ~0x000f);
105 } else {
106 /* check if slopspace is needed: GeForce need ~0x001f. */
107 /* fixme:
108 * update needed for GF DVDmax support to adhere to CRTC2 constraints?? */
109 si->overlay.myBuffer[offset].width = ((width + 0x001f) & ~0x001f);
111 si->overlay.myBuffer[offset].bytes_per_row = 2 * si->overlay.myBuffer[offset].width;
113 /* check if the requested horizontal pitch is supported: */
114 //fixme: tune for GF and TNT...
115 if (si->overlay.myBuffer[offset].width > 4088)
117 LOG(4, ("Overlay: Sorry, requested buffer pitch not supported, aborted\n"));
119 /* release the shared benaphore */
120 RELEASE_BEN(si->overlay.lock)
122 return NULL;
124 break;
125 default:
126 /* unsupported colorspace! */
127 LOG(4, ("Overlay: Sorry, colorspace $%08x not supported, aborted\n",cs));
129 /* release the shared benaphore */
130 RELEASE_BEN(si->overlay.lock)
132 return NULL;
133 break;
136 /* checkout input picture size */
137 switch (si->ps.card_arch) {
138 case NV04A:
139 /* all DVD's are OK, but HDTV 1280x720p is not: it displays ghost images
140 * (still find exact limit..) */
142 /* check if the requested buffer width is supported */
143 if (si->overlay.myBuffer[offset].width > 1024) {
144 LOG(4, ("Overlay: Sorry, requested buffer width not supported, aborted\n"));
146 /* release the shared benaphore */
147 RELEASE_BEN(si->overlay.lock)
148 return NULL;
150 /* check if the requested buffer height is supported */
151 if (height > 1024) {
152 LOG(4, ("Overlay: Sorry, requested buffer height not supported, aborted\n"));
154 /* release the shared benaphore */
155 RELEASE_BEN(si->overlay.lock)
156 return NULL;
158 break;
159 default:
160 /* HDTV 1920x1080p is confirmed OK on NV11 and higher cards */
162 /* check if the requested buffer width is supported */
163 if (si->overlay.myBuffer[offset].width > 1920) {
164 LOG(4, ("Overlay: Sorry, requested buffer width not supported, aborted\n"));
166 /* release the shared benaphore */
167 RELEASE_BEN(si->overlay.lock)
168 return NULL;
170 /* check if the requested buffer height is supported */
171 if (height > 1080) {
172 LOG(4, ("Overlay: Sorry, requested buffer height not supported, aborted\n"));
174 /* release the shared benaphore */
175 RELEASE_BEN(si->overlay.lock)
176 return NULL;
178 break;
181 /* store slopspace (in pixels) for each bitmap for use by 'overlay unit' (BES) */
182 si->overlay.myBufInfo[offset].slopspace = si->overlay.myBuffer[offset].width - width;
184 si->overlay.myBuffer[offset].space = cs;
185 si->overlay.myBuffer[offset].height = height;
187 /* we define the overlay buffers to reside 'in the back' of the cards RAM */
188 /* NOTE to app programmers:
189 * Beware that an app using overlay needs to track workspace switches and screenprefs
190 * changes. If such an action is detected, the app needs to reset it's pointers to the
191 * newly created overlay bitmaps, which will be assigned by BeOS automatically after such
192 * an event. (Also the app needs to respect the new overlay_constraints that will be applicable!)
194 * It is entirely possible that new bitmaps may *not* be re-setup at all, or less of them
195 * than previously setup by the app might be re-setup. This is due to cardRAM restraints then.
196 * This means that the app should also check for NULL pointers returned by the bitmaps,
197 * and if this happens, it needs to fallback to single buffered overlay or even fallback to
198 * bitmap output for the new situation. */
200 /* Another NOTE for app programmers:
201 * A *positive* side-effect of assigning the first overlay buffer exactly at the end of the
202 * cardRAM is that apps that try to write beyond the buffer's space get a segfault immediately.
203 * This *greatly* simplifies tracking such errors!
204 * Of course such errors may lead to strange effects in the app or driver behaviour if they are
205 * not hunted down and removed.. */
207 /* calculate first free RAM adress in card:
208 * Driver setup is as follows:
209 * card base: - hardware cursor bitmap (if used),
210 * directly above - screen memory for both heads */
211 adress2 = (((uintptr_t)((uint8*)si->fbc.frame_buffer)) + /* cursor already included here */
212 (si->fbc.bytes_per_row * si->dm.virtual_height)); /* size in bytes of screen(s) */
213 LOG(4, ("Overlay: first free cardRAM virtual adress $%08x\n", adress2));
215 /* calculate 'preliminary' buffer size including slopspace */
216 oldsize = si->overlay.myBufInfo[offset].size;
217 si->overlay.myBufInfo[offset].size
218 = si->overlay.myBuffer[offset].bytes_per_row * si->overlay.myBuffer[offset].height;
220 /* calculate virtual memory adress that would be needed for a new bitmap */
221 /* NOTE to app programmers:
222 * For testing app behaviour regarding workspace switches or screen prefs changes to settings
223 * that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with
224 * a low amount of RAM. Or you can set in the file nv.settings for example:
225 * memory 8 #8Mb RAM on card
226 * and reboot (this simulates 8Mb RAM on the card).
228 * If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to
229 * bitmap output or maybe single buffered overlay output if small bitmaps are used. */
231 adress = (((uintptr_t)((uint8*)si->framebuffer)) + si->ps.memory_size);
232 /* Keep some extra distance as a workaround for certain bugs (see
233 * DriverInterface.h for an explanation). */
234 if (si->ps.card_arch < NV40A)
235 adress -= PRE_NV40_OFFSET;
236 else
237 adress -= NV40_PLUS_OFFSET;
239 for (cnt = 0; cnt <= offset; cnt++)
241 adress -= si->overlay.myBufInfo[cnt].size;
244 /* the > G200 scalers require buffers to be aligned to 16 byte pages cardRAM offset, G200 can do with
245 * 8 byte pages cardRAM offset. Compatible settings used, has no real downside consequences here */
247 /* Check if we need to modify the buffers starting adress and thus the size */
248 /* calculate 'would be' cardRAM offset */
249 temp32 = (adress - ((uintptr_t)((vuint32 *)si->framebuffer)));
250 /* check if it is aligned */
251 if (temp32 != (temp32 & 0xfffffff0))
253 /* update the (already calculated) buffersize to get it aligned */
254 si->overlay.myBufInfo[offset].size += (temp32 - (temp32 & 0xfffffff0));
255 /* update the (already calculated) adress to get it aligned */
256 adress -= (temp32 - (temp32 & 0xfffffff0));
258 LOG(4, ("Overlay: new buffer needs virtual adress $%08x\n", adress));
260 /* First check now if buffer to be defined is 'last one' in memory (speaking backwards):
261 * this is done to prevent a large buffer getting created in the space a small buffer
262 * occupied earlier, if not all buffers created were deleted.
263 * Note also that the app can delete the buffers in any order desired. */
265 /* NOTE to app programmers:
266 * If you are going to delete a overlay buffer you created, you should delete them *all* and
267 * then re-create only the new ones needed. This way you are sure not to get unused memory-
268 * space in between your overlay buffers for instance, so cardRAM is used 'to the max'.
269 * If you don't, you might not get a buffer at all if you are trying to set up a larger one
270 * than before.
271 * (Indeed: not all buffers *have* to be of the same type and size...) */
273 for (cnt = offset; cnt < MAXBUFFERS; cnt++)
275 if (si->overlay.myBuffer[cnt].buffer != NULL)
277 /* Check if the new buffer would fit into the space the single old one used here */
278 if (si->overlay.myBufInfo[offset].size <= oldsize)
280 /* It does, so we reset to the old size and adresses to prevent the space from shrinking
281 * if we get here again... */
282 adress -= (oldsize - si->overlay.myBufInfo[offset].size);
283 si->overlay.myBufInfo[offset].size = oldsize;
284 LOG(4,("Overlay: 'squeezing' in buffer:\n"
285 "Overlay: resetting it to virtual adress $%08x and size $%08x\n", adress,oldsize));
286 /* force exiting the FOR loop */
287 cnt = MAXBUFFERS;
288 } else {
289 /* nogo, sorry */
290 LOG(4, ("Overlay: Other buffer(s) exist after this one:\n"
291 "Overlay: not enough space to 'squeeze' this one in, aborted\n"));
293 /* Reset to the old size to prevent the space from 'growing' if we get here again... */
294 si->overlay.myBufInfo[offset].size = oldsize;
296 /* release the shared benaphore */
297 RELEASE_BEN(si->overlay.lock)
299 return NULL;
304 /* check if we have enough space to setup this new bitmap
305 * (preventing overlap of desktop RAMspace & overlay bitmap RAMspace here) */
306 if (adress < adress2)
307 /* nope, sorry */
309 LOG(4, ("Overlay: Sorry, no more space for buffers: aborted\n"));
311 /* release the shared benaphore */
312 RELEASE_BEN(si->overlay.lock)
314 return NULL;
316 /* continue buffer setup */
317 si->overlay.myBuffer[offset].buffer = (void *) adress;
319 /* calculate physical memory adress (for dma use) */
320 adress = (((uintptr_t)((uint8*)si->framebuffer_pci)) + si->ps.memory_size);
321 /* Keep some extra distance as a workaround for certain bugs (see
322 * DriverInterface.h for an explanation). */
323 if (si->ps.card_arch < NV40A)
324 adress -= PRE_NV40_OFFSET;
325 else
326 adress -= NV40_PLUS_OFFSET;
328 for (cnt = 0; cnt <= offset; cnt++)
330 adress -= si->overlay.myBufInfo[cnt].size;
332 /* this adress is already aligned to the scaler's requirements (via the already modified sizes) */
333 si->overlay.myBuffer[offset].buffer_dma = (void *) adress;
335 LOG(4, ("Overlay: New buffer: addr $%p, dma_addr $%p, color space $%08x\n",
336 (uint8*)si->overlay.myBuffer[offset].buffer,
337 (uint8*)si->overlay.myBuffer[offset].buffer_dma, cs));
338 LOG(4, ("Overlay: New buffer's size is $%08x\n", si->overlay.myBufInfo[offset].size));
340 /* release the shared benaphore */
341 RELEASE_BEN(si->overlay.lock)
343 return &si->overlay.myBuffer[offset];
344 } else {
345 /* sorry, no more room for buffers */
346 LOG(4, ("Overlay: Sorry, no more space for buffers: aborted\n"));
348 /* release the shared benaphore */
349 RELEASE_BEN(si->overlay.lock)
351 return NULL;
356 status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob)
357 /* Note that the user can delete the buffers in any order desired! */
359 int offset = 0;
361 if (ob != NULL)
363 /* find the buffer */
364 for (offset = 0; offset < MAXBUFFERS; offset++)
366 if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
369 if (offset < MAXBUFFERS)
370 /* delete current buffer */
372 si->overlay.myBuffer[offset].buffer = NULL;
373 si->overlay.myBuffer[offset].buffer_dma = NULL;
375 LOG(4,("Overlay: Release_buffer offset = %d, buffer released\n",offset));
377 return B_OK;
379 else
381 /* this is no buffer of ours! */
382 LOG(4,("Overlay: Release_overlay_buffer: not ours, aborted!\n"));
384 return B_ERROR;
387 else
388 /* no buffer specified! */
390 LOG(4,("Overlay: Release_overlay_buffer: no buffer specified, aborted!\n"));
392 return B_ERROR;
396 status_t GET_OVERLAY_CONSTRAINTS
397 (const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc)
399 int offset = 0;
401 LOG(4,("Overlay: Get_overlay_constraints called\n"));
403 /* check for NULL pointers */
404 if ((dm == NULL) || (ob == NULL) || (oc == NULL))
406 LOG(4,("Overlay: Get_overlay_constraints: Null pointer(s) detected!\n"));
407 return B_ERROR;
410 /* find the buffer */
411 for (offset = 0; offset < MAXBUFFERS; offset++)
413 if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
416 if (offset < MAXBUFFERS)
418 /* scaler input (values are in pixels) */
419 oc->view.h_alignment = 0;
420 oc->view.v_alignment = 0;
422 switch (ob->space)
424 case B_YCbCr422:
425 if (si->ps.card_arch < NV10A)
427 /* RIVA128 and TNT need 15.
428 * Note: this has to be in sync with the slopspace setup during buffer allocation.. */
429 oc->view.width_alignment = 15;
431 else
433 /* GeForce need 31.
434 * Note: this has to be in sync with the slopspace setup during buffer allocation.. */
435 oc->view.width_alignment = 31;
437 break;
438 default:
439 /* we should not be here, but set the worst-case value just to be safe anyway */
440 oc->view.width_alignment = 31;
441 break;
444 oc->view.height_alignment = 0;
445 oc->view.width.min = 1;
446 oc->view.height.min = 2; /* two fields */
447 oc->view.width.max = ob->width;
448 oc->view.height.max = ob->height;
450 /* scaler output restrictions */
451 oc->window.h_alignment = 0;
452 oc->window.v_alignment = 0;
453 oc->window.width_alignment = 0;
454 oc->window.height_alignment = 0;
455 oc->window.width.min = 2;
456 /* GeForce cards can output upto and including 2046 pixels in width */
457 //fixme: how about TNT?
458 if (dm->virtual_width > 2046)
460 oc->window.width.max = 2046;
462 else
464 oc->window.width.max = dm->virtual_width;
466 oc->window.height.min = 2;
467 /* GeForce cards can output upto and including 2046 pixels in height */
468 //fixme: how about TNT?
469 if (dm->virtual_height > 2046)
471 oc->window.height.max = 2046;
473 else
475 oc->window.height.max = dm->virtual_height;
478 /* GeForce scaling restrictions */
479 switch (si->ps.card_arch)
481 case NV04A:
482 /* Riva128-TNT2 series have an old BES engine... */
483 oc->h_scale.min = 1.0;
484 oc->v_scale.min = 1.0;
485 break;
486 case NV30A:
487 case NV40A:
488 /* GeForceFX series and up have a new BES engine... */
489 oc->h_scale.min = 0.5;
490 oc->v_scale.min = 0.5;
491 /* NV31 (confirmed GeForceFX 5600) has NV20A scaling limits!
492 * So let it fall through... */
493 if (si->ps.card_type != NV31) break;
494 default:
495 /* the rest in between... */
496 oc->h_scale.min = 0.125;
497 oc->v_scale.min = 0.125;
498 break;
500 /* all cards have a upscaling limit of 8.0 (see official nVidia specsheets) */
501 oc->h_scale.max = 8.0;
502 oc->v_scale.max = 8.0;
504 return B_OK;
506 else
508 /* this is no buffer of ours! */
509 LOG(4,("Overlay: Get_overlay_constraints: buffer is not ours, aborted!\n"));
511 return B_ERROR;
515 overlay_token ALLOCATE_OVERLAY(void)
517 uint32 tmpToken;
518 LOG(4,("Overlay: Allocate_overlay called: "));
520 /* come up with a token */
521 tmpToken = 0x12345678;
523 /* acquire the shared benaphore */
524 AQUIRE_BEN(si->overlay.lock)
526 /* overlay unit already in use? */
527 if (si->overlay.myToken == NULL)
528 /* overlay unit is available */
530 LOG(4,("succesfull\n"));
532 si->overlay.myToken = &tmpToken;
534 /* release the shared benaphore */
535 RELEASE_BEN(si->overlay.lock)
537 return si->overlay.myToken;
539 else
540 /* sorry, overlay unit is occupied */
542 LOG(4,("failed: already in use!\n"));
544 /* release the shared benaphore */
545 RELEASE_BEN(si->overlay.lock)
547 return NULL;
551 status_t RELEASE_OVERLAY(overlay_token ot)
553 LOG(4,("Overlay: Release_overlay called: "));
555 /* is this call for real? */
556 if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
557 /* nope, abort */
559 LOG(4,("failed, not in use!\n"));
561 return B_ERROR;
563 else
564 /* call is for real */
567 nv_release_bes();
569 LOG(4,("succesfull\n"));
571 si->overlay.myToken = NULL;
572 return B_OK;
576 status_t CONFIGURE_OVERLAY
577 (overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov)
579 int offset = 0; /* used for buffer index */
581 LOG(4,("Overlay: Configure_overlay called: "));
583 /* Note:
584 * When a Workspace switch, screen prefs change, or overlay app shutdown occurs, BeOS will
585 * release all overlay buffers. The buffer currently displayed at that moment, may need some
586 * 'hardware releasing' in the CONFIGURE_OVERLAY routine. This is why CONFIGURE_OVERLAY gets
587 * called one more time then, with a null pointer for overlay_window and overlay_view, while
588 * the currently displayed overlay_buffer is given.
589 * The G200-G550 do not need to do anything on such an occasion, so we simply return if we
590 * get called then. */
591 if ((ow == NULL) || (ov == NULL))
593 LOG(4,("output properties changed\n"));
595 return B_OK;
598 /* Note:
599 * If during overlay use the screen prefs are changed, or the workspace has changed, it
600 * may be that we were not able to re-allocate the requested overlay buffers (or only partly)
601 * due to lack of cardRAM. If the app does not respond properly to this, we might end up
602 * with a NULL pointer instead of a overlay_buffer to work with here.
603 * Of course, we need to abort then to prevent the system from 'going down'.
604 * The app will probably crash because it will want to write into this non-existant buffer
605 * at some point. */
606 if (ob == NULL)
608 LOG(4,("no overlay buffer specified\n"));
610 return B_ERROR;
613 /* is this call done by the app that owns us? */
614 if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
615 /* nope, abort */
617 LOG(4,("failed\n"));
619 return B_ERROR;
621 else
622 /* call is for real */
624 /* find the buffer's offset */
625 for (offset = 0; offset < MAXBUFFERS; offset++)
627 if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
630 if (offset < MAXBUFFERS)
632 LOG(4,("succesfull, switching to buffer %d\n", offset));
634 /* program overlay hardware */
635 nv_configure_bes(ob, ow, ov, offset);
637 return B_OK;
639 else
641 /* this is no buffer of ours! */
642 LOG(4,("buffer is not ours, aborted!\n"));
644 return B_ERROR;