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