vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / neomagic / Overlay.c
blob98a59194931e6a4a4257078e262df3641a1fb39c
1 /* Written by Rudolf Cornelissen 05-2002/4-2006 */
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 static uint32 overlay_colorspaces [] = { (uint32)B_YCbCr422, (uint32)B_NO_COLOR_SPACE };
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?
19 LOG(4,("Overlay: count called\n"));
21 /* check for NULL pointer */
22 if (dm == NULL)
24 LOG(4,("Overlay: No display mode specified!\n"));
26 /* apparantly overlay count should report the number of 'overlay units' on the card */
27 return 1;
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?
34 LOG(4,("Overlay: supported_spaces called.\n"));
36 /* check for NULL pointer */
37 if (dm == NULL)
39 LOG(4,("Overlay: No display mode specified!\n"));
40 return NULL;
43 /* assuming interlaced VGA is not supported */
44 if (dm->timing.flags & B_TIMING_INTERLACED)
46 return NULL;
48 /* return a B_NO_COLOR_SPACE terminated list */
49 return &overlay_colorspaces[0];
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!
55 LOG(4,("Overlay: supported_features: color_space $%08x\n",a_color_space));
57 /* check what features are supported for the current overlaybitmap colorspace */
58 switch (a_color_space)
60 default:
61 return
62 ( B_OVERLAY_COLOR_KEY |
63 B_OVERLAY_HORIZONTAL_FILTERING |
64 B_OVERLAY_VERTICAL_FILTERING );
68 const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height)
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 */
75 /* acquire the shared benaphore */
76 AQUIRE_BEN(si->overlay.lock)
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));
82 /* find first empty slot (room for another buffer?) */
83 for (offset = 0; offset < MAXBUFFERS; offset++)
85 if (si->overlay.myBuffer[offset].buffer == NULL) break;
88 LOG(4,("Overlay: Allocate_buffer offset = %d\n",offset));
90 if (offset < MAXBUFFERS)
91 /* setup new scaler input buffer */
93 switch (cs)
95 case B_YCbCr422:
96 /* check if slopspace is needed: NeoMagic cards can do with ~x0007 */
97 if (width == (width & ~0x0007))
99 si->overlay.myBuffer[offset].width = width;
101 else
103 si->overlay.myBuffer[offset].width = (width & ~0x0007) + 8;
105 si->overlay.myBuffer[offset].bytes_per_row = 2 * si->overlay.myBuffer[offset].width;
107 /* check if the requested horizontal pitch is supported */
108 //fixme?...
109 if (si->overlay.myBuffer[offset].width > 2048)
111 LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n"));
113 /* release the shared benaphore */
114 RELEASE_BEN(si->overlay.lock)
116 return NULL;
118 break;
119 default:
120 /* unsupported colorspace! */
121 LOG(4,("Overlay: Sorry, colorspace $%08x not supported, aborted\n",cs));
123 /* release the shared benaphore */
124 RELEASE_BEN(si->overlay.lock)
126 return NULL;
127 break;
130 /* check if the requested buffer width is supported */
131 if (si->overlay.myBuffer[offset].width > 1024)
133 LOG(4,("Overlay: Sorry, requested buffer width not supported, aborted\n"));
135 /* release the shared benaphore */
136 RELEASE_BEN(si->overlay.lock)
138 return NULL;
140 /* check if the requested buffer height is supported */
141 if (height > 1024)
143 LOG(4,("Overlay: Sorry, requested buffer height not supported, aborted\n"));
145 /* release the shared benaphore */
146 RELEASE_BEN(si->overlay.lock)
148 return NULL;
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;
154 si->overlay.myBuffer[offset].space = cs;
155 si->overlay.myBuffer[offset].height = height;
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!)
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. */
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.. */
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));
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;
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++)
198 adress -= si->overlay.myBufInfo[cnt].size;
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 */
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))
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));
215 LOG(4,("Overlay: new buffer needs virtual adress $%08x\n", adress));
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. */
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...) */
230 for (cnt = offset; cnt < MAXBUFFERS; cnt++)
232 if (si->overlay.myBuffer[cnt].buffer != NULL)
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)
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;
246 else
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"));
252 /* Reset to the old size to prevent the space from 'growing' if we get here again... */
253 si->overlay.myBufInfo[offset].size = oldsize;
255 /* release the shared benaphore */
256 RELEASE_BEN(si->overlay.lock)
258 return NULL;
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 */
268 LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n"));
270 /* release the shared benaphore */
271 RELEASE_BEN(si->overlay.lock)
273 return NULL;
275 /* continue buffer setup */
276 si->overlay.myBuffer[offset].buffer = (void *) adress;
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++)
284 adress -= si->overlay.myBufInfo[cnt].size;
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;
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));
294 /* release the shared benaphore */
295 RELEASE_BEN(si->overlay.lock)
297 return &si->overlay.myBuffer[offset];
299 else
300 /* sorry, no more room for buffers */
302 LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n"));
304 /* release the shared benaphore */
305 RELEASE_BEN(si->overlay.lock)
307 return NULL;
311 status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob)
312 /* Note that the user can delete the buffers in any order desired! */
314 int offset = 0;
316 if (ob != NULL)
318 /* find the buffer */
319 for (offset = 0; offset < MAXBUFFERS; offset++)
321 if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
324 if (offset < MAXBUFFERS)
325 /* delete current buffer */
327 si->overlay.myBuffer[offset].buffer = NULL;
328 si->overlay.myBuffer[offset].buffer_dma = NULL;
330 LOG(4,("Overlay: Release_buffer offset = %d, buffer released\n",offset));
332 return B_OK;
334 else
336 /* this is no buffer of ours! */
337 LOG(4,("Overlay: Release_overlay_buffer: not ours, aborted!\n"));
339 return B_ERROR;
342 else
343 /* no buffer specified! */
345 LOG(4,("Overlay: Release_overlay_buffer: no buffer specified, aborted!\n"));
347 return B_ERROR;
351 status_t GET_OVERLAY_CONSTRAINTS
352 (const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc)
354 int offset = 0;
356 LOG(4,("Overlay: Get_overlay_constraints called\n"));
358 /* check for NULL pointers */
359 if ((dm == NULL) || (ob == NULL) || (oc == NULL))
361 LOG(4,("Overlay: Get_overlay_constraints: Null pointer(s) detected!\n"));
362 return B_ERROR;
365 /* find the buffer */
366 for (offset = 0; offset < MAXBUFFERS; offset++)
368 if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
371 if (offset < MAXBUFFERS)
373 /* scaler input (values are in pixels) */
374 oc->view.h_alignment = 0;
375 oc->view.v_alignment = 0;
377 switch (ob->space)
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;
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;
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)
407 oc->window.width.max = 2048;
409 else
411 oc->window.width.max = dm->virtual_width;
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)
418 oc->window.height.max = 2048;
420 else
422 oc->window.height.max = dm->virtual_height;
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;
432 return B_OK;
434 else
436 /* this is no buffer of ours! */
437 LOG(4,("Overlay: Get_overlay_constraints: buffer is not ours, aborted!\n"));
439 return B_ERROR;
443 overlay_token ALLOCATE_OVERLAY(void)
445 uint32 tmpToken;
446 LOG(4,("Overlay: Allocate_overlay called: "));
448 /* come up with a token */
449 tmpToken = 0x12345678;
451 /* acquire the shared benaphore */
452 AQUIRE_BEN(si->overlay.lock)
454 /* overlay unit already in use? */
455 if (si->overlay.myToken == NULL)
456 /* overlay unit is available */
458 LOG(4,("succesfull\n"));
460 si->overlay.myToken = &tmpToken;
462 /* release the shared benaphore */
463 RELEASE_BEN(si->overlay.lock)
465 return si->overlay.myToken;
467 else
468 /* sorry, overlay unit is occupied */
470 LOG(4,("failed: already in use!\n"));
472 /* release the shared benaphore */
473 RELEASE_BEN(si->overlay.lock)
475 return NULL;
479 status_t RELEASE_OVERLAY(overlay_token ot)
481 LOG(4,("Overlay: Release_overlay called: "));
483 /* is this call for real? */
484 if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
485 /* nope, abort */
487 LOG(4,("failed, not in use!\n"));
489 return B_ERROR;
491 else
492 /* call is for real */
495 nm_release_bes();
497 LOG(4,("succesfull\n"));
499 si->overlay.myToken = NULL;
500 return B_OK;
504 status_t CONFIGURE_OVERLAY
505 (overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov)
507 int offset = 0; /* used for buffer index */
509 LOG(4,("Overlay: Configure_overlay called: "));
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))
521 LOG(4,("output properties changed\n"));
523 return B_OK;
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)
536 LOG(4,("no overlay buffer specified\n"));
538 return B_ERROR;
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 */
545 LOG(4,("failed\n"));
547 return B_ERROR;
549 else
550 /* call is for real */
552 /* find the buffer's offset */
553 for (offset = 0; offset < MAXBUFFERS; offset++)
555 if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
558 if (offset < MAXBUFFERS)
560 LOG(4,("succesfull, switching to buffer %d\n", offset));
562 nm_configure_bes(ob, ow, ov, offset);
564 return B_OK;
566 else
568 /* this is no buffer of ours! */
569 LOG(4,("buffer is not ours, aborted!\n"));
571 return B_ERROR;