Copyright 2011 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac
*/
#include "accelerant.h"
#include "rage128.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_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);
if (MACH64_FAMILY(si.chipType)) {
if (height > 2048 || width > 768
|| (width > 384 && si.chipType < MACH64_264VTB)
|| (width > 720 && (si.chipType < MACH64_264GTPRO
|| si.chipType > MACH64_264LTPRO)))
return NULL;
}
si.overlayLock.Acquire();
if (colorSpace != B_YCbCr422) {
si.overlayLock.Release();
TRACE("AllocateOverlayBuffer() unsupported color space 0x%x\n",
colorSpace);
return NULL;
}
uint32 bytesPerPixel = 2;
uint32 buffSize = (width * bytesPerPixel * height + 0x3ff) & ~0x3ff;
OverlayBuffer* ovBuff = si.overlayBuffer;
OverlayBuffer* prevOvBuff = NULL;
addr_t prevBuffAddr = (si.videoMemAddr + si.cursorOffset - 0xfff) & ~0xfff;
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.bitsPerPixel + 7) / 8)
* 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;
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);
return B_OK;
}
prevOvBuff = ovBuff;
ovBuff = ovBuff->nextBuffer;
}
TRACE("ReleaseOverlayBuffer() buffer to release at 0x%lx not found\n",
buffer->buffer);
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;
if (buffer->space == B_YCbCr422)
constraints->view.width_alignment = 7;
else {
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;
if (atomic_or(&si.overlayAllocated, 1) != 0) {
TRACE("AllocateOverlay() overlay channel already in use\n");
return NULL;
}
return (overlay_token)(addr_t)++si.overlayToken;
}
status_t
ReleaseOverlay(overlay_token overlayToken)
{
SharedInfo& si = *gInfo.sharedInfo;
if (overlayToken != (overlay_token)(addr_t)si.overlayToken) {
TRACE("ReleaseOverlay() error - no overlay previously allocated\n");
return B_BAD_VALUE;
}
if (MACH64_FAMILY(si.chipType))
Mach64_StopOverlay();
else
Rage128_StopOverlay();
atomic_and(&si.overlayAllocated, 0);
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)(addr_t)si.overlayToken)
return B_BAD_VALUE;
if (buffer == NULL)
return B_BAD_VALUE;
if (window == NULL || view == NULL) {
if (MACH64_FAMILY(si.chipType))
Mach64_StopOverlay();
else
Rage128_StopOverlay();
return B_OK;
}
if (MACH64_FAMILY(si.chipType)) {
if (!Mach64_DisplayOverlay(window, buffer)) {
TRACE("ConfigureOverlay(), call to Mach64_DisplayOverlay() "
"returned error\n");
return B_ERROR;
}
} else {
if (!Rage128_DisplayOverlay(window, buffer)) {
TRACE("ConfigureOverlay(), call to Rage128_DisplayOverlay() "
"returned error\n");
return B_ERROR;
}
}
return B_OK;
}