* Copyright 2010 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT license.
*
* Authors:
* Gerald Zajac
*/
#include "accelerant.h"
#include "3dfx.h"
#include <stdlib.h>
uint32
OverlayCount(const display_mode *mode)
{
(void)mode;
return 1;
}
const uint32*
OverlaySupportedSpaces(const display_mode* mode)
{
(void)mode;
static const uint32 kSupportedSpaces[] = {B_RGB16, B_YCbCr422, 0};
return kSupportedSpaces;
}
uint32
OverlaySupportedFeatures(uint32 colorSpace)
{
(void)colorSpace;
return B_OVERLAY_COLOR_KEY
| B_OVERLAY_HORIZONTAL_FILTERING
| B_OVERLAY_VERTICAL_FILTERING;
}
const overlay_buffer*
AllocateOverlayBuffer(color_space colorSpace, uint16 width, uint16 height)
{
SharedInfo& si = *gInfo.sharedInfo;
TRACE("AllocateOverlayBuffer() width %u, height %u, colorSpace 0x%lx\n",
width, height, colorSpace);
si.overlayLock.Acquire();
uint32 bytesPerPixel;
switch (colorSpace) {
case B_YCbCr422:
case B_RGB16:
bytesPerPixel = 2;
break;
default:
si.overlayLock.Release();
TRACE("AllocateOverlayBuffer() unsupported color space 0x%x\n",
colorSpace);
return NULL;
}
uint32 buffSize = (width * bytesPerPixel * height + 0x3ff) & ~0x3ff;
if (si.chipType == VOODOO_5)
buffSize += 16 * 1024;
OverlayBuffer* ovBuff = si.overlayBuffer;
OverlayBuffer* prevOvBuff = NULL;
addr_t prevBuffAddr = si.videoMemAddr + si.frameBufferOffset
+ si.maxFrameBufferSize;
while (ovBuff != NULL) {
addr_t currentBuffEndAddr = (addr_t)ovBuff->buffer + ovBuff->size;
if ((prevBuffAddr - currentBuffEndAddr) >= buffSize)
break;
prevBuffAddr = (addr_t)ovBuff->buffer;
prevOvBuff = ovBuff;
ovBuff = ovBuff->nextBuffer;
}
OverlayBuffer* nextOvBuff = ovBuff;
if (ovBuff == NULL) {
addr_t fbEndAddr = si.videoMemAddr + si.frameBufferOffset
+ (si.displayMode.virtual_width * si.displayMode.bytesPerPixel
* si.displayMode.virtual_height);
if (buffSize > prevBuffAddr - fbEndAddr) {
si.overlayLock.Release();
TRACE("AllocateOverlayBuffer() insuffcient space for %ld (0x%lx) "
"byte buffer\n", buffSize, buffSize);
return NULL;
}
nextOvBuff = NULL;
}
ovBuff = (OverlayBuffer*)malloc(sizeof(OverlayBuffer));
if (ovBuff == NULL) {
si.overlayLock.Release();
return NULL;
}
ovBuff->nextBuffer = nextOvBuff;
ovBuff->size = buffSize;
ovBuff->space = colorSpace;
ovBuff->width = width;
ovBuff->height = height;
ovBuff->bytes_per_row = width * bytesPerPixel;
ovBuff->buffer = (void*)(prevBuffAddr - buffSize);
ovBuff->buffer_dma = (void*)(si.videoMemPCI
+ ((addr_t)ovBuff->buffer - si.videoMemAddr));
if (prevOvBuff == NULL)
si.overlayBuffer = ovBuff;
else
prevOvBuff->nextBuffer = ovBuff;
si.overlayLock.Release();
TRACE("AllocateOverlayBuffer() allocated %ld (0x%lx) byte buffer at 0x%lx\n",
buffSize, buffSize, ovBuff->buffer);
return ovBuff;
}
status_t
ReleaseOverlayBuffer(const overlay_buffer* buffer)
{
SharedInfo& si = *gInfo.sharedInfo;
TRACE("ReleaseOverlayBuffer() called\n");
if (buffer == NULL)
return B_BAD_VALUE;
OverlayBuffer* ovBuff = si.overlayBuffer;
OverlayBuffer* prevOvBuff = NULL;
while (ovBuff != NULL) {
if (ovBuff->buffer == buffer->buffer) {
if (prevOvBuff == NULL)
si.overlayBuffer = ovBuff->nextBuffer;
else
prevOvBuff->nextBuffer = ovBuff->nextBuffer;
free(ovBuff);
TRACE("ReleaseOverlayBuffer() return OK\n");
return B_OK;
}
prevOvBuff = ovBuff;
ovBuff = ovBuff->nextBuffer;
}
return B_ERROR;
}
status_t
GetOverlayConstraints(const display_mode* mode, const overlay_buffer* buffer,
overlay_constraints* constraints)
{
if ((mode == NULL) || (buffer == NULL) || (constraints == NULL))
return B_ERROR;
constraints->view.h_alignment = 0;
constraints->view.v_alignment = 0;
switch (buffer->space) {
case B_YCbCr422:
case B_RGB16:
constraints->view.width_alignment = 7;
break;
default:
TRACE("GetOverlayConstraints() color space 0x%x out of range\n",
buffer->space);
return B_BAD_VALUE;
}
constraints->view.height_alignment = 0;
constraints->view.width.min = 4;
constraints->view.height.min = 4;
constraints->view.width.max = buffer->width;
constraints->view.height.max = buffer->height;
constraints->window.h_alignment = 0;
constraints->window.v_alignment = 0;
constraints->window.width_alignment = 0;
constraints->window.height_alignment = 0;
constraints->window.width.min = 2;
constraints->window.width.max = mode->virtual_width;
constraints->window.height.min = 2;
constraints->window.height.max = mode->virtual_height;
constraints->h_scale.min = 1.0;
constraints->h_scale.max = 8.0;
constraints->v_scale.min = 1.0;
constraints->v_scale.max = 8.0;
return B_OK;
}
overlay_token
AllocateOverlay(void)
{
SharedInfo& si = *gInfo.sharedInfo;
TRACE("AllocateOverlay() called\n");
if (atomic_or(&si.overlayAllocated, 1) != 0) {
TRACE("AllocateOverlay() overlay channel already in use\n");
return NULL;
}
TRACE("AllocateOverlay() Overlay allocated, overlayToken: %d\n",
si.overlayToken);
return (overlay_token)++si.overlayToken;
}
status_t
ReleaseOverlay(overlay_token overlayToken)
{
SharedInfo& si = *gInfo.sharedInfo;
TRACE("ReleaseOverlay() called\n");
if (overlayToken != (overlay_token)si.overlayToken)
return B_BAD_VALUE;
TDFX_StopOverlay();
atomic_and(&si.overlayAllocated, 0);
TRACE("ReleaseOverlay() return OK\n");
return B_OK;
}
status_t
ConfigureOverlay (overlay_token overlayToken, const overlay_buffer* buffer,
const overlay_window* window, const overlay_view* view)
{
SharedInfo& si = *gInfo.sharedInfo;
if (overlayToken != (overlay_token)si.overlayToken)
return B_BAD_VALUE;
if (buffer == NULL)
return B_BAD_VALUE;
if (window == NULL || view == NULL) {
TDFX_StopOverlay();
TRACE("ConfigureOverlay() hide only\n");
return B_OK;
}
if (!TDFX_DisplayOverlay(window, buffer, view)) {
TRACE("ConfigureOverlay(), call to TDFX_DisplayOverlay() returned error\n");
return B_ERROR;
}
return B_OK;
}