xref: /haiku/src/add-ons/accelerants/nvidia/Overlay.c (revision 91c0454716f24a7454b20f7a54cfe32e288e3710)
1 /* Written by Rudolf Cornelissen 05/2002-5/2009 */
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_KEYING_USES_ALPHA 	 |
65 				  B_OVERLAY_COLOR_KEY 			 |
66 				  B_OVERLAY_HORIZONTAL_FILTERING |
67 				  B_OVERLAY_VERTICAL_FILTERING );
68 	}
69 }
70 
71 
72 const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width,
73 	uint16 height)
74 {
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 */
79 
80 	/* acquire the shared benaphore */
81 	AQUIRE_BEN(si->overlay.lock)
82 
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))));
86 
87 	/* find first empty slot (room for another buffer?) */
88 	for (offset = 0; offset < MAXBUFFERS; offset++)
89 	{
90 		if (si->overlay.myBuffer[offset].buffer == NULL) break;
91 	}
92 
93 	LOG(4, ("Overlay: Allocate_buffer offset = %d\n", offset));
94 
95 	if (offset < MAXBUFFERS)
96 	/* setup new scaler input buffer */
97 	{
98 		switch (cs)
99 		{
100 			case B_YCbCr422:
101 					if (si->ps.card_arch < NV10A)
102 					{
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);
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 		/* 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..) */
141 
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"));
145 
146 				/* release the shared benaphore */
147 				RELEASE_BEN(si->overlay.lock)
148 				return NULL;
149 			}
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"));
153 
154 				/* release the shared benaphore */
155 				RELEASE_BEN(si->overlay.lock)
156 				return NULL;
157 			}
158 			break;
159 		default:
160 			/* HDTV 1920x1080p is confirmed OK on NV11 and higher cards */
161 
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"));
165 
166 				/* release the shared benaphore */
167 				RELEASE_BEN(si->overlay.lock)
168 				return NULL;
169 			}
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"));
173 
174 				/* release the shared benaphore */
175 				RELEASE_BEN(si->overlay.lock)
176 				return NULL;
177 			}
178 			break;
179 		}
180 
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;
183 
184 		si->overlay.myBuffer[offset].space = cs;
185 		si->overlay.myBuffer[offset].height = height;
186 
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!)
193 		 *
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. */
199 
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.. */
206 
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));
214 
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;
219 
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).
227 		 *
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. */
230 
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;
238 
239 		for (cnt = 0; cnt <= offset; cnt++)
240 		{
241 			adress -= si->overlay.myBufInfo[cnt].size;
242 		}
243 
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 */
246 
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))
252 		{
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));
257 		}
258 		LOG(4, ("Overlay: new buffer needs virtual adress $%08x\n", adress));
259 
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. */
264 
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...) */
272 
273 		for (cnt = offset; cnt < MAXBUFFERS; cnt++)
274 		{
275 			if (si->overlay.myBuffer[cnt].buffer != NULL)
276 			{
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)
279 				{
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"));
292 
293 					/* Reset to the old size to prevent the space from 'growing' if we get here again... */
294 					si->overlay.myBufInfo[offset].size = oldsize;
295 
296 					/* release the shared benaphore */
297 					RELEASE_BEN(si->overlay.lock)
298 
299 					return NULL;
300 				}
301 			}
302 		}
303 
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 */
308 		{
309 			LOG(4, ("Overlay: Sorry, no more space for buffers: aborted\n"));
310 
311 			/* release the shared benaphore */
312 			RELEASE_BEN(si->overlay.lock)
313 
314 			return NULL;
315 		}
316 		/* continue buffer setup */
317 		si->overlay.myBuffer[offset].buffer = (void *) adress;
318 
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;
327 
328 		for (cnt = 0; cnt <= offset; cnt++)
329 		{
330 			adress -= si->overlay.myBufInfo[cnt].size;
331 		}
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;
334 
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));
339 
340 		/* release the shared benaphore */
341 		RELEASE_BEN(si->overlay.lock)
342 
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"));
347 
348 		/* release the shared benaphore */
349 		RELEASE_BEN(si->overlay.lock)
350 
351 		return NULL;
352 	}
353 }
354 
355 
356 status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob)
357 /* Note that the user can delete the buffers in any order desired! */
358 {
359 	int offset = 0;
360 
361 	if (ob != NULL)
362 	{
363 		/* find the buffer */
364 		for (offset = 0; offset < MAXBUFFERS; offset++)
365 		{
366 			if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
367 		}
368 
369 		if (offset < MAXBUFFERS)
370 		/* delete current buffer */
371 		{
372 			si->overlay.myBuffer[offset].buffer = NULL;
373 			si->overlay.myBuffer[offset].buffer_dma = NULL;
374 
375 			LOG(4,("Overlay: Release_buffer offset = %d, buffer released\n",offset));
376 
377 			return B_OK;
378 		}
379 		else
380 		{
381 			/* this is no buffer of ours! */
382 			LOG(4,("Overlay: Release_overlay_buffer: not ours, aborted!\n"));
383 
384 			return B_ERROR;
385 		}
386 	}
387 	else
388 	/* no buffer specified! */
389 	{
390 		LOG(4,("Overlay: Release_overlay_buffer: no buffer specified, aborted!\n"));
391 
392 		return B_ERROR;
393 	}
394 }
395 
396 status_t GET_OVERLAY_CONSTRAINTS
397 	(const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc)
398 {
399 	int offset = 0;
400 
401 	LOG(4,("Overlay: Get_overlay_constraints called\n"));
402 
403 	/* check for NULL pointers */
404 	if ((dm == NULL) || (ob == NULL) || (oc == NULL))
405 	{
406 		LOG(4,("Overlay: Get_overlay_constraints: Null pointer(s) detected!\n"));
407 		return B_ERROR;
408 	}
409 
410 	/* find the buffer */
411 	for (offset = 0; offset < MAXBUFFERS; offset++)
412 	{
413 		if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
414 	}
415 
416 	if (offset < MAXBUFFERS)
417 	{
418 		/* scaler input (values are in pixels) */
419 		oc->view.h_alignment = 0;
420 		oc->view.v_alignment = 0;
421 
422 		switch (ob->space)
423 		{
424 			case B_YCbCr422:
425 					if (si->ps.card_arch < NV10A)
426 					{
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;
430 					}
431 					else
432 					{
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;
436 					}
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;
442 		}
443 
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;
449 
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)
459 		{
460 			oc->window.width.max = 2046;
461 		}
462 		else
463 		{
464 			oc->window.width.max = dm->virtual_width;
465 		}
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)
470 		{
471 			oc->window.height.max = 2046;
472 		}
473 		else
474 		{
475 			oc->window.height.max = dm->virtual_height;
476 		}
477 
478 		/* GeForce scaling restrictions */
479 		switch (si->ps.card_arch)
480 		{
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;
499 		}
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;
503 
504 		return B_OK;
505 	}
506 	else
507 	{
508 		/* this is no buffer of ours! */
509 		LOG(4,("Overlay: Get_overlay_constraints: buffer is not ours, aborted!\n"));
510 
511 		return B_ERROR;
512 	}
513 }
514 
515 overlay_token ALLOCATE_OVERLAY(void)
516 {
517 	uint32 tmpToken;
518 	LOG(4,("Overlay: Allocate_overlay called: "));
519 
520 	/* come up with a token */
521 	tmpToken = 0x12345678;
522 
523 	/* acquire the shared benaphore */
524 	AQUIRE_BEN(si->overlay.lock)
525 
526 	/* overlay unit already in use? */
527 	if (si->overlay.myToken == NULL)
528 	/* overlay unit is available */
529 	{
530 		LOG(4,("succesfull\n"));
531 
532 		si->overlay.myToken = &tmpToken;
533 
534 		/* release the shared benaphore */
535 		RELEASE_BEN(si->overlay.lock)
536 
537 		return si->overlay.myToken;
538 	}
539 	else
540 	/* sorry, overlay unit is occupied */
541 	{
542 		LOG(4,("failed: already in use!\n"));
543 
544 		/* release the shared benaphore */
545 		RELEASE_BEN(si->overlay.lock)
546 
547 		return NULL;
548 	}
549 }
550 
551 status_t RELEASE_OVERLAY(overlay_token ot)
552 {
553 	LOG(4,("Overlay: Release_overlay called: "));
554 
555 	/* is this call for real? */
556 	if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
557 	/* nope, abort */
558 	{
559 		LOG(4,("failed, not in use!\n"));
560 
561 		return B_ERROR;
562 	}
563 	else
564 	/* call is for real */
565 	{
566 
567 		nv_release_bes();
568 
569 		LOG(4,("succesfull\n"));
570 
571 		si->overlay.myToken = NULL;
572 		return B_OK;
573 	}
574 }
575 
576 status_t CONFIGURE_OVERLAY
577 	(overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov)
578 {
579 	int offset = 0; /* used for buffer index */
580 
581 	LOG(4,("Overlay: Configure_overlay called: "));
582 
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))
592 	{
593 		LOG(4,("output properties changed\n"));
594 
595 		return B_OK;
596 	}
597 
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)
607 	{
608 		LOG(4,("no overlay buffer specified\n"));
609 
610 		return B_ERROR;
611 	}
612 
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 */
616 	{
617 		LOG(4,("failed\n"));
618 
619 		return B_ERROR;
620 	}
621 	else
622 	/* call is for real */
623 	{
624 		/* find the buffer's offset */
625 		for (offset = 0; offset < MAXBUFFERS; offset++)
626 		{
627 			if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
628 		}
629 
630 		if (offset < MAXBUFFERS)
631 		{
632 			LOG(4,("succesfull, switching to buffer %d\n", offset));
633 
634 			/* program overlay hardware */
635 			nv_configure_bes(ob, ow, ov, offset);
636 
637 			return B_OK;
638 		}
639 		else
640 		{
641 			/* this is no buffer of ours! */
642 			LOG(4,("buffer is not ours, aborted!\n"));
643 
644 			return B_ERROR;
645 		}
646 	}
647 }
648