* BeOS needs to define more colorspaces! It would be nice if BeOS would support the FourCC 'definitions'
* of colorspaces. These colorspaces are 32bit words, so it could be simply done (or is it already so?)
*/
#define MODULE_BIT 0x00000400
#include "acc_std.h"
* G200-G550 can all do YUV4:2:0 2-plane colorspace as well,
* G200 does not support RGB modes while > G200 do (but with limited scaling and without filtering),
* G200 does not support YUV4:2:0 3-plane mode while > G200 do.
* It would be nice to have the YUV4:2:0 2-plane mode implemented also later on, but the Be colorspace
* definitions (in GraphicsDefs.h, R5.0.3 and DANO5.1d0) do not include this one... */
static uint32 overlay_colorspaces [] = { (uint32)B_YCbCr422, (uint32)B_NO_COLOR_SPACE };
uint32 OVERLAY_COUNT(const display_mode *dm)
{
LOG(4,("Overlay: count called\n"));
if (dm == NULL)
{
LOG(4,("Overlay: No display mode specified!\n"));
}
return 1;
}
const uint32 *OVERLAY_SUPPORTED_SPACES(const display_mode *dm)
{
LOG(4,("Overlay: supported_spaces called.\n"));
if (dm == NULL)
{
LOG(4,("Overlay: No display mode specified!\n"));
return NULL;
}
if (dm->timing.flags & B_TIMING_INTERLACED)
{
return NULL;
}
return &overlay_colorspaces[0];
}
uint32 OVERLAY_SUPPORTED_FEATURES(uint32 a_color_space)
{
LOG(4,("Overlay: supported_features: color_space $%08x\n",a_color_space));
* Desktop colorspace */
switch (a_color_space)
{
default:
return
( B_OVERLAY_KEYING_USES_ALPHA |
B_OVERLAY_COLOR_KEY |
B_OVERLAY_HORIZONTAL_FILTERING |
B_OVERLAY_VERTICAL_FILTERING );
}
}
const overlay_buffer *ALLOCATE_OVERLAY_BUFFER(color_space cs, uint16 width, uint16 height)
{
int offset = 0;
uintptr_t adress, adress2, temp32;
uint32 oldsize = 0;
int cnt;
AQUIRE_BEN(si->overlay.lock)
LOG(4, ("Overlay: cardRAM_start = $%p\n", (uint8*)si->framebuffer));
LOG(4, ("Overlay: cardRAM_start_DMA = $%p\n", (uint8*)si->framebuffer_pci));
LOG(4, ("Overlay: cardRAM_size = %dMb\n", si->ps.memory_size));
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == NULL) break;
}
LOG(4, ("Overlay: Allocate_buffer offset = %d\n", offset));
if (offset < MAXBUFFERS)
{
switch (cs)
{
case B_YCbCr422:
* G200 can do with ~0x0003 while > G200 need ~x0007.
* Optimized settings for G200 could reduce CPU load a tiny little bit there... */
* case display_mode == B_RGB16: multiple = 32
* case display_mode == B_RGB32: multiple = 16 */
if (width == (width & ~0x0007))
{
si->overlay.myBuffer[offset].width = width;
}
else
{
si->overlay.myBuffer[offset].width = (width & ~0x0007) + 8;
}
si->overlay.myBuffer[offset].bytes_per_row = 2 * si->overlay.myBuffer[offset].width;
* G200 max. pitch is 4092 pixels, > G200 max pitch is 4088 pixels for this colorspace.
* Compatible check done, has no downside consequences here. */
if (si->overlay.myBuffer[offset].width > 4088)
{
LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n"));
RELEASE_BEN(si->overlay.lock)
return NULL;
}
break;
* G200 can do with ~0x0007 while > G200 need ~x001f.
* Optimized settings for G200 could reduce CPU load a tiny little bit there... */
{
si->overlay.myBuffer[offset].width = width;
}
else
{
si->overlay.myBuffer[offset].width = (width & ~0x001f) + 32;
}
*/
*/
* G200 max. pitch is 4088 pixels, > G200 max pitch is 4064 pixels for this colorspace.
* Compatible check done, has no real downside consequences here. */
{
LOG(4,("Overlay: Sorry, requested buffer pitch not supported, aborted\n");
*/
return NULL;
}
break;
*/
default:
LOG(4,("Overlay: Sorry, colorspace $%08x not supported, aborted\n",cs));
RELEASE_BEN(si->overlay.lock)
return NULL;
break;
}
if (si->ps.card_type < G450) {
if (si->overlay.myBuffer[offset].width > 1024) {
LOG(4,("Overlay: Sorry, requested buffer width not supported, aborted\n"));
RELEASE_BEN(si->overlay.lock)
return NULL;
}
if (height > 1024) {
LOG(4,("Overlay: Sorry, requested buffer height not supported, aborted\n"));
RELEASE_BEN(si->overlay.lock)
return NULL;
}
} else {
if (si->overlay.myBuffer[offset].width > 1920) {
LOG(4,("Overlay: Sorry, requested buffer width not supported, aborted\n"));
RELEASE_BEN(si->overlay.lock)
return NULL;
}
if (height > 1080) {
LOG(4,("Overlay: Sorry, requested buffer height not supported, aborted\n"));
RELEASE_BEN(si->overlay.lock)
return NULL;
}
}
si->overlay.myBufInfo[offset].slopspace = si->overlay.myBuffer[offset].width - width;
si->overlay.myBuffer[offset].space = cs;
si->overlay.myBuffer[offset].height = height;
* Beware that an app using overlay needs to track workspace switches and screenprefs
* changes. If such an action is detected, the app needs to reset it's pointers to the
* newly created overlay bitmaps, which will be assigned by BeOS automatically after such
* an event. (Also the app needs to respect the new overlay_constraints that will be applicable!)
*
* It is entirely possible that new bitmaps may *not* be re-setup at all, or less of them
* than previously setup by the app might be re-setup. This is due to cardRAM restraints then.
* This means that the app should also check for NULL pointers returned by the bitmaps,
* and if this happens, it needs to fallback to single buffered overlay or even fallback to
* bitmap output for the new situation. */
* A *positive* side-effect of assigning the first overlay buffer exactly at the end of the
* cardRAM is that apps that try to write beyond the buffer's space get a segfault immediately.
* This *greatly* simplifies tracking such errors!
* Of course such errors may lead to strange effects in the app or driver behaviour if they are
* not hunted down and removed.. */
* Driver setup is as follows:
* card base: - hardware cursor bitmap (if used),
* directly above - screen memory for both heads */
adress2 = (((uintptr_t)((uint8*)si->fbc.frame_buffer)) +
(si->fbc.bytes_per_row * si->dm.virtual_height));
LOG(4, ("Overlay: first free cardRAM virtual adress $%08x\n", adress2));
oldsize = si->overlay.myBufInfo[offset].size;
si->overlay.myBufInfo[offset].size
= si->overlay.myBuffer[offset].bytes_per_row * si->overlay.myBuffer[offset].height;
* For testing app behaviour regarding workspace switches or screen prefs changes to settings
* that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with
* a low amount of RAM. Or you can set in the file matrox.settings for example:
* memory 8 #8Mb RAM on card
* and reboot (this simulates 8Mb RAM on the card).
*
* If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to
* bitmap output or maybe single buffered overlay output if small bitmaps are used. */
adress = (((uintptr_t)((uint8*)si->framebuffer)) + (si->ps.memory_size * 1024 * 1024));
for (cnt = 0; cnt <= offset; cnt++)
{
adress -= si->overlay.myBufInfo[cnt].size;
}
* 8 byte pages cardRAM offset. Compatible settings used, has no real downside consequences here */
temp32 = (adress - ((uintptr_t)((vuint32 *)si->framebuffer)));
if (temp32 != (temp32 & 0xfffffff0))
{
si->overlay.myBufInfo[offset].size += (temp32 - (temp32 & 0xfffffff0));
adress -= (temp32 - (temp32 & 0xfffffff0));
}
LOG(4,("Overlay: new buffer needs virtual adress $%08x\n", adress));
* this is done to prevent a large buffer getting created in the space a small buffer
* occupied earlier, if not all buffers created were deleted.
* Note also that the app can delete the buffers in any order desired. */
* If you are going to delete a overlay buffer you created, you should delete them *all* and
* then re-create only the new ones needed. This way you are sure not to get unused memory-
* space in between your overlay buffers for instance, so cardRAM is used 'to the max'.
* If you don't, you might not get a buffer at all if you are trying to set up a larger one
* than before.
* (Indeed: not all buffers *have* to be of the same type and size...) */
for (cnt = offset; cnt < MAXBUFFERS; cnt++)
{
if (si->overlay.myBuffer[cnt].buffer != NULL)
{
if (si->overlay.myBufInfo[offset].size <= oldsize)
{
* if we get here again... */
adress -= (oldsize - si->overlay.myBufInfo[offset].size);
si->overlay.myBufInfo[offset].size = oldsize;
LOG(4,("Overlay: 'squeezing' in buffer:\n"
"Overlay: resetting it to virtual adress $%08x and size $%08x\n", adress,oldsize));
cnt = MAXBUFFERS;
}
else
{
LOG(4,("Overlay: Other buffer(s) exist after this one:\n"
"Overlay: not enough space to 'squeeze' this one in, aborted\n"));
si->overlay.myBufInfo[offset].size = oldsize;
RELEASE_BEN(si->overlay.lock)
return NULL;
}
}
}
* (preventing overlap of desktop RAMspace & overlay bitmap RAMspace here) */
if (adress < adress2)
{
LOG(4,("Overlay: Sorry, no more space for buffers: aborted\n"));
RELEASE_BEN(si->overlay.lock)
return NULL;
}
si->overlay.myBuffer[offset].buffer = (void *) adress;
* For testing app behaviour regarding workspace switches or screen prefs changes to settings
* that do not have enough cardRAM left for allocation of overlay bitmaps, you need a card with
* a low amount of RAM. Or you can set in the file matrox.settings for example:
* memory 8 #8Mb RAM on card
* and reboot (this simulates 8Mb RAM on the card).
*
* If you switch now to settings: 1600x1200x32bit (single head) the app needs to fallback to
* bitmap output or maybe single buffered overlay output if small bitmaps are used. */
adress = (((uintptr_t)((uint8*)si->framebuffer_pci)) + (si->ps.memory_size * 1024 * 1024));
for (cnt = 0; cnt <= offset; cnt++)
{
adress -= si->overlay.myBufInfo[cnt].size;
}
si->overlay.myBuffer[offset].buffer_dma = (void *) adress;
LOG(4, ("Overlay: New buffer: addr $%p, dma_addr $%p, color space $%08x\n",
(uint8*)si->overlay.myBuffer[offset].buffer,
(uint8*)si->overlay.myBuffer[offset].buffer_dma, cs));
LOG(4, ("Overlay: New buffer's size is $%08x\n", si->overlay.myBufInfo[offset].size));
RELEASE_BEN(si->overlay.lock)
return &si->overlay.myBuffer[offset];
} else {
LOG(4, ("Overlay: Sorry, no more space for buffers: aborted\n"));
RELEASE_BEN(si->overlay.lock)
return NULL;
}
}
status_t RELEASE_OVERLAY_BUFFER(const overlay_buffer *ob)
{
int offset = 0;
if (ob != NULL)
{
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
}
if (offset < MAXBUFFERS)
{
si->overlay.myBuffer[offset].buffer = NULL;
si->overlay.myBuffer[offset].buffer_dma = NULL;
LOG(4,("Overlay: Release_buffer offset = %d, buffer released\n",offset));
return B_OK;
}
else
{
LOG(4,("Overlay: Release_overlay_buffer: not ours, aborted!\n"));
return B_ERROR;
}
}
else
{
LOG(4,("Overlay: Release_overlay_buffer: no buffer specified, aborted!\n"));
return B_ERROR;
}
}
status_t GET_OVERLAY_CONSTRAINTS
(const display_mode *dm, const overlay_buffer *ob, overlay_constraints *oc)
{
int offset = 0;
LOG(4,("Overlay: Get_overlay_constraints called\n"));
if ((dm == NULL) || (ob == NULL) || (oc == NULL))
{
LOG(4,("Overlay: Get_overlay_constraints: Null pointer(s) detected!\n"));
return B_ERROR;
}
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
}
if (offset < MAXBUFFERS)
{
oc->view.h_alignment = 0;
oc->view.v_alignment = 0;
switch (ob->space)
{
case B_YCbCr422:
* Note: this has to be in sync with the slopspace setup during buffer allocation.. */
oc->view.width_alignment = 7;
break;
* Note: this has to be in sync with the slopspace setup during buffer allocation.. */
break;
*/
default:
oc->view.width_alignment = 31;
break;
}
oc->view.height_alignment = 0;
oc->view.width.min = 1;
oc->view.height.min = 2;
oc->view.width.max = ob->width;
oc->view.height.max = ob->height;
oc->window.h_alignment = 0;
oc->window.v_alignment = 0;
oc->window.width_alignment = 0;
oc->window.height_alignment = 0;
oc->window.width.min = 2;
if (dm->virtual_width > 2048)
{
oc->window.width.max = 2048;
}
else
{
oc->window.width.max = dm->virtual_width;
}
oc->window.height.min = 2;
if (dm->virtual_height > 2048)
{
oc->window.height.max = 2048;
}
else
{
oc->window.height.max = dm->virtual_height;
}
if (si->dm.timing.pixel_clock > BESMAXSPEED)
{
oc->h_scale.min = (1 * 2) / (32 - (1 / (float)16384));
oc->h_scale.max = (16384 * 2)/(float)(ob->width - si->overlay.myBufInfo[offset].slopspace);
}
else
{
oc->h_scale.min = 1 / (32 - (1 / (float)16384));
oc->h_scale.max = 16384/(float)(ob->width - si->overlay.myBufInfo[offset].slopspace);
}
oc->v_scale.min = 1 / (32 - (1 / (float)16384));
oc->v_scale.max = 16384/(float)ob->height;
return B_OK;
}
else
{
LOG(4,("Overlay: Get_overlay_constraints: buffer is not ours, aborted!\n"));
return B_ERROR;
}
}
overlay_token ALLOCATE_OVERLAY(void)
{
uint32 tmpToken;
LOG(4,("Overlay: Allocate_overlay called: "));
tmpToken = 0x12345678;
AQUIRE_BEN(si->overlay.lock)
if (si->overlay.myToken == NULL)
{
LOG(4,("succesfull\n"));
si->overlay.myToken = &tmpToken;
RELEASE_BEN(si->overlay.lock)
return si->overlay.myToken;
}
else
{
LOG(4,("failed: already in use!\n"));
RELEASE_BEN(si->overlay.lock)
return NULL;
}
}
status_t RELEASE_OVERLAY(overlay_token ot)
{
LOG(4,("Overlay: Release_overlay called: "));
if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
{
LOG(4,("failed, not in use!\n"));
return B_ERROR;
}
else
{
gx00_release_bes();
LOG(4,("succesfull\n"));
si->overlay.myToken = NULL;
return B_OK;
}
}
status_t CONFIGURE_OVERLAY
(overlay_token ot, const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov)
{
int offset = 0;
LOG(4,("Overlay: Configure_overlay called: "));
* When a Workspace switch, screen prefs change, or overlay app shutdown occurs, BeOS will
* release all overlay buffers. The buffer currently displayed at that moment, may need some
* 'hardware releasing' in the CONFIGURE_OVERLAY routine. This is why CONFIGURE_OVERLAY gets
* called one more time then, with a null pointer for overlay_window and overlay_view, while
* the currently displayed overlay_buffer is given.
* The G200-G550 do not need to do anything on such an occasion, so we simply return if we
* get called then. */
if ((ow == NULL) || (ov == NULL))
{
LOG(4,("output properties changed\n"));
return B_OK;
}
* If during overlay use the screen prefs are changed, or the workspace has changed, it
* may be that we were not able to re-allocate the requested overlay buffers (or only partly)
* due to lack of cardRAM. If the app does not respond properly to this, we might end up
* with a NULL pointer instead of a overlay_buffer to work with here.
* Of course, we need to abort then to prevent the system from 'going down'.
* The app will probably crash because it will want to write into this non-existant buffer
* at some point. */
if (ob == NULL)
{
LOG(4,("no overlay buffer specified\n"));
return B_ERROR;
}
if ((ot == NULL) || (si->overlay.myToken == NULL) || (ot != si->overlay.myToken))
{
LOG(4,("failed\n"));
return B_ERROR;
}
else
{
for (offset = 0; offset < MAXBUFFERS; offset++)
{
if (si->overlay.myBuffer[offset].buffer == ob->buffer) break;
}
if (offset < MAXBUFFERS)
{
LOG(4,("succesfull, switching to buffer %d\n", offset));
gx00_configure_bes(ob, ow, ov, offset);
return B_OK;
}
else
{
LOG(4,("buffer is not ours, aborted!\n"));
return B_ERROR;
}
}
}