Should have been part of r42335.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42336 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Rene Gollent 2011-06-28 20:19:41 +00:00
parent 124cdd4f57
commit 43ad8a3327
3 changed files with 642 additions and 0 deletions

View File

@ -0,0 +1,145 @@
/*
Haiku ATI video driver adapted from the X.org ATI driver which has the
following copyright:
Copyright 2003 through 2004 by Marc Aurele La France, tsi@xfree86.org
Copyright 2011 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac
*/
#include "accelerant.h"
#include "mach64.h"
bool
Mach64_DisplayOverlay(const overlay_window* window,
const overlay_buffer* buffer)
{
// Return true if setup is successful.
SharedInfo& si = *gInfo.sharedInfo;
if (window == NULL || buffer == NULL)
return false;
uint32 videoFormat;
if (buffer->space == B_YCbCr422)
videoFormat = SCALE_IN_VYUY422;
else
return false; // color space not supported
int32 x1 = (window->h_start < 0) ? 0 : window->h_start;
int32 y1 = (window->v_start < 0) ? 0 : window->v_start;
int32 x2 = window->h_start + window->width - 1;
int32 y2 = window->v_start + window->height - 1;
if (x2 > si.displayMode.timing.h_display)
x2 = si.displayMode.timing.h_display;
if (y2 > si.displayMode.timing.v_display)
y2 = si.displayMode.timing.v_display;
// If window is moved beyond edge of screen, do not allow width < 4 or
// height < 4; otherwise there is a possibilty of divide by zero when
// computing the scale factors..
if (x2 < x1 + 4)
x2 = x1 + 4;
if (y2 < y1 + 4)
y2 = y1 + 4;
// Calculate overlay scale factors.
uint32 horzScale = (buffer->width << 12) / (x2 - x1 + 1);
uint32 vertScale = (buffer->height << 12) / (y2 - y1 + 1);
if (horzScale > 0xffff) // only 16 bits are used for scale factors
horzScale = 0xffff;
if (vertScale > 0xffff)
vertScale = 0xffff;
gInfo.WaitForFifo(2);
OUTREG(BUS_CNTL, INREG(BUS_CNTL) | BUS_EXT_REG_EN); // enable reg block 1
OUTREG(OVERLAY_SCALE_CNTL, SCALE_EN); // reset the video
if (si.chipType >= MACH64_264GTPRO) {
const uint32 brightness = 0;
const uint32 saturation = 12;
gInfo.WaitForFifo(6);
OUTREG(SCALER_COLOUR_CNTL, brightness | saturation << 8
| saturation << 16);
OUTREG(SCALER_H_COEFF0, 0x0002000);
OUTREG(SCALER_H_COEFF1, 0xd06200d);
OUTREG(SCALER_H_COEFF2, 0xd0a1c0d);
OUTREG(SCALER_H_COEFF3, 0xc0e1a0c);
OUTREG(SCALER_H_COEFF4, 0xc14140c);
}
uint32 keyColor = 0;
uint32 keyMask = 0;
switch (si.displayMode.bitsPerPixel) {
case 15:
keyMask = 0x7fff;
keyColor = (window->blue.value & window->blue.mask) << 0
| (window->green.value & window->green.mask) << 5
| (window->red.value & window->red.mask) << 10;
// 15 bit color has no alpha bits
break;
case 16:
keyMask = 0xffff;
keyColor = (window->blue.value & window->blue.mask) << 0
| (window->green.value & window->green.mask) << 5
| (window->red.value & window->red.mask) << 11;
// 16 bit color has no alpha bits
break;
default:
keyMask = 0xffffffff;
keyColor = (window->blue.value & window->blue.mask) << 0
| (window->green.value & window->green.mask) << 8
| (window->red.value & window->red.mask) << 16
| (window->alpha.value & window->alpha.mask) << 24;
break;
}
gInfo.WaitForFifo(3);
OUTREG(OVERLAY_GRAPHICS_KEY_MSK, keyMask);
OUTREG(OVERLAY_GRAPHICS_KEY_CLR, keyColor);
OUTREG(OVERLAY_KEY_CNTL, OVERLAY_MIX_FALSE | OVERLAY_MIX_EQUAL);
gInfo.WaitForFifo(8);
OUTREG(OVERLAY_Y_X_START, OVERLAY_LOCK_START | (x1 << 16) | y1);
OUTREG(OVERLAY_Y_X_END, (x2 << 16) | y2);
OUTREG(OVERLAY_SCALE_INC, (horzScale << 16) | vertScale);
OUTREG(SCALER_HEIGHT_WIDTH, (buffer->width << 16) | buffer->height);
OUTREG(VIDEO_FORMAT, videoFormat);
// Compute offset of overlay buffer in the video memory.
uint32 offset = uint32(buffer->buffer) - si.videoMemAddr;
if (si.chipType < MACH64_264VTB) {
OUTREG(BUF0_OFFSET, offset);
OUTREG(BUF0_PITCH, buffer->width);
} else {
OUTREG(SCALER_BUF0_OFFSET, offset);
OUTREG(SCALER_BUF0_PITCH, buffer->width);
}
OUTREG(OVERLAY_SCALE_CNTL, SCALE_PIX_EXPAND | OVERLAY_EN | SCALE_EN);
return true;
}
void
Mach64_StopOverlay(void)
{
OUTREG(OVERLAY_SCALE_CNTL, SCALE_EN); // reset the video
}

View File

@ -0,0 +1,319 @@
/*
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; // avoid compiler warning for unused arg
return 1;
}
const uint32*
OverlaySupportedSpaces(const display_mode* mode)
{
(void)mode; // avoid compiler warning for unused arg
static const uint32 kSupportedSpaces[] = {B_YCbCr422, 0};
return kSupportedSpaces;
}
uint32
OverlaySupportedFeatures(uint32 colorSpace)
{
(void)colorSpace; // avoid compiler warning for unused arg
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 Mach 64 chip, check hardware limits.
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();
// Note: When allocating buffers, buffer allocation starts at the end of
// video memory, and works backward to the end of the video frame buffer.
// The allocated buffers are recorded in a linked list of OverlayBuffer
// objects which are ordered by the buffer address with the first object
// in the list having the highest buffer address.
if (colorSpace != B_YCbCr422) {
si.overlayLock.Release();
TRACE("AllocateOverlayBuffer() unsupported color space 0x%x\n",
colorSpace);
return NULL;
}
uint32 bytesPerPixel = 2; // B_YCbCr422 uses 2 bytes per pixel
// Calculate required buffer size as a multiple of 1K.
uint32 buffSize = (width * bytesPerPixel * height + 0x3ff) & ~0x3ff;
OverlayBuffer* ovBuff = si.overlayBuffer;
OverlayBuffer* prevOvBuff = NULL;
// If no buffers have been allocated, prevBuffAddr calculated here will be
// the address where the buffer area will start. Leave a gap of about 4K
// between where the overlay buffers will start and the cursor image;
// thus, if the overlay buffer overflows it will be less apt to affect the
// cursor.
uint32 prevBuffAddr = (si.videoMemAddr + si.cursorOffset - 0xfff) & ~0xfff;
while (ovBuff != NULL) {
// Test if there is sufficient space between the end of the current
// buffer and the start of the previous buffer to allocate the new
// buffer.
uint32 currentBuffEndAddr = (addr_t)ovBuff->buffer + ovBuff->size;
if ((prevBuffAddr - currentBuffEndAddr) >= buffSize)
break; // sufficient space for the new buffer
prevBuffAddr = (uint32)ovBuff->buffer;
prevOvBuff = ovBuff;
ovBuff = ovBuff->nextBuffer;
}
OverlayBuffer* nextOvBuff = ovBuff;
if (ovBuff == NULL) {
// No space between any current buffers of the required size was found;
// thus space must be allocated between the last buffer and the end of
// the video frame buffer. Compute where current video frame buffer
// ends so that it can be determined if there is sufficient space for
// the new buffer to be created.
uint32 fbEndAddr = si.videoMemAddr + si.frameBufferOffset
+ (si.displayMode.virtual_width
* ((si.displayMode.bitsPerPixel + 7) / 8) // bytes per pixel
* 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; // insufficient space for buffer
}
nextOvBuff = NULL;
}
ovBuff = (OverlayBuffer*)malloc(sizeof(OverlayBuffer));
if (ovBuff == NULL) {
si.overlayLock.Release();
return NULL; // memory not available for OverlayBuffer struct
}
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;
// Find the buffer to be released.
OverlayBuffer* ovBuff = si.overlayBuffer;
OverlayBuffer* prevOvBuff = NULL;
while (ovBuff != NULL) {
if (ovBuff->buffer == buffer->buffer) {
// Buffer to be released has been found. Remove the OverlayBuffer
// object from the chain of overlay buffers.
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; // buffer to be released not found in chain of buffers
}
status_t
GetOverlayConstraints(const display_mode* mode, const overlay_buffer* buffer,
overlay_constraints* constraints)
{
if ((mode == NULL) || (buffer == NULL) || (constraints == NULL))
return B_ERROR;
// Position (values are in pixels)
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;
//Size
constraints->view.width.min = 4;
constraints->view.height.min = 4;
constraints->view.width.max = buffer->width;
constraints->view.height.max = buffer->height;
// Scaler output restrictions
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;
// There is only a single overlay channel; thus, check if it is already
// allocated.
if (atomic_or(&si.overlayAllocated, 1) != 0) {
TRACE("AllocateOverlay() overlay channel already in use\n");
return NULL;
}
return (overlay_token)++si.overlayToken;
}
status_t
ReleaseOverlay(overlay_token overlayToken)
{
SharedInfo& si = *gInfo.sharedInfo;
if (overlayToken != (overlay_token)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); // mark overlay as unallocated
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) {
if (MACH64_FAMILY(si.chipType))
Mach64_StopOverlay();
else
Rage128_StopOverlay();
return B_OK;
}
// Program the overlay hardware.
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;
}

View File

@ -0,0 +1,178 @@
/*
Haiku ATI video driver adapted from the X.org ATI driver which has the
following copyright:
Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario,
Precision Insight, Inc., Cedar Park, Texas, and
VA Linux Systems Inc., Fremont, California.
Copyright 2011 Haiku, Inc. All rights reserved.
Distributed under the terms of the MIT license.
Authors:
Gerald Zajac
*/
#include "accelerant.h"
#include "rage128.h"
static uint32 sCurrentKeyColor = 0;
static uint32 sCurrentKeyMask = 0;
bool
Rage128_DisplayOverlay(const overlay_window* window,
const overlay_buffer* buffer)
{
// Return true if setup is successful.
SharedInfo& si = *gInfo.sharedInfo;
if (window == NULL || buffer == NULL)
return false;
if (buffer->space != B_YCbCr422)
return false; // color space not supported
uint32 keyColor = 0;
uint32 keyMask = 0;
switch (si.displayMode.bitsPerPixel) {
case 15:
keyMask = 0x7fff;
keyColor = (window->blue.value & window->blue.mask) << 0
| (window->green.value & window->green.mask) << 5
| (window->red.value & window->red.mask) << 10;
// 15 bit color has no alpha bits
break;
case 16:
keyMask = 0xffff;
keyColor = (window->blue.value & window->blue.mask) << 0
| (window->green.value & window->green.mask) << 5
| (window->red.value & window->red.mask) << 11;
// 16 bit color has no alpha bits
break;
default:
keyMask = 0xffffffff;
keyColor = (window->blue.value & window->blue.mask) << 0
| (window->green.value & window->green.mask) << 8
| (window->red.value & window->red.mask) << 16
| (window->alpha.value & window->alpha.mask) << 24;
break;
}
// If the key color or key mask has changed since the overlay was
// previously initialized, initialize it again. This is to avoid
// initializing the overlay video everytime the overlay buffer is
// switched which causes artifacts in the overlay display.
if (keyColor != sCurrentKeyColor || keyMask != sCurrentKeyMask)
{
TRACE("Rage128_DisplayOverlay() initializing overlay video\n");
// Initialize the overlay video by first resetting the video.
OUTREG(R128_OV0_SCALE_CNTL, 0);
OUTREG(R128_OV0_EXCLUSIVE_HORZ, 0);
OUTREG(R128_OV0_AUTO_FLIP_CNTL, 0);
OUTREG(R128_OV0_FILTER_CNTL, 0x0000000f);
const uint32 brightness = 0;
const uint32 saturation = 16;
OUTREG(R128_OV0_COLOUR_CNTL, brightness | saturation << 8
| saturation << 16);
OUTREG(R128_OV0_GRAPHICS_KEY_MSK, keyMask);
OUTREG(R128_OV0_GRAPHICS_KEY_CLR, keyColor);
OUTREG(R128_OV0_KEY_CNTL, R128_GRAPHIC_KEY_FN_NE);
OUTREG(R128_OV0_TEST, 0);
sCurrentKeyColor = keyColor;
sCurrentKeyMask = keyMask;
}
uint32 ecpDiv;
if (si.displayMode.timing.pixel_clock < 125000)
ecpDiv = 0;
else if (si.displayMode.timing.pixel_clock < 250000)
ecpDiv = 1;
else
ecpDiv = 2;
SetPLLReg(R128_VCLK_ECP_CNTL, ecpDiv << 8, R128_ECP_DIV_MASK);
int32 vertInc = (buffer->height << 20) / window->height;
int32 horzInc = (buffer->width << (12 + ecpDiv)) / window->width;
int32 stepBy = 1;
while (horzInc >= (2 << 12)) {
stepBy++;
horzInc >>= 1;
}
int32 x1 = window->h_start;
int32 y1 = window->v_start;
int32 x2 = window->h_start + window->width;
int32 y2 = window->v_start + window->height;
int32 left = x1;
int32 tmp = (left & 0x0003ffff) + 0x00028000 + (horzInc << 3);
int32 p1_h_accum_init = ((tmp << 4) & 0x000f8000) |
((tmp << 12) & 0xf0000000);
tmp = ((left >> 1) & 0x0001ffff) + 0x00028000 + (horzInc << 2);
int32 p23_h_accum_init = ((tmp << 4) & 0x000f8000) |
((tmp << 12) & 0x70000000);
tmp = (y1 & 0x0000ffff) + 0x00018000;
int32 p1_v_accum_init = ((tmp << 4) & 0x03ff8000) | 0x00000001;
// Compute offset of overlay buffer in the video memory.
uint32 offset = uint32(buffer->buffer) - si.videoMemAddr;
OUTREG(R128_OV0_REG_LOAD_CNTL, 1);
while (!(INREG(R128_OV0_REG_LOAD_CNTL) & (1 << 3)))
;
OUTREG(R128_OV0_H_INC, horzInc | ((horzInc >> 1) << 16));
OUTREG(R128_OV0_STEP_BY, stepBy | (stepBy << 8));
OUTREG(R128_OV0_Y_X_START, x1 | y1 << 16);
OUTREG(R128_OV0_Y_X_END, x2 | y2 << 16);
OUTREG(R128_OV0_V_INC, vertInc);
OUTREG(R128_OV0_P1_BLANK_LINES_AT_TOP,
0x00000fff | ((buffer->height - 1) << 16));
OUTREG(R128_OV0_VID_BUF_PITCH0_VALUE, buffer->bytes_per_row);
int32 width = window->width;
left = 0;
OUTREG(R128_OV0_P1_X_START_END, (width - 1) | (left << 16));
width >>= 1;
OUTREG(R128_OV0_P2_X_START_END, (width - 1) | (left << 16));
OUTREG(R128_OV0_P3_X_START_END, (width - 1) | (left << 16));
OUTREG(R128_OV0_VID_BUF0_BASE_ADRS, offset);
OUTREG(R128_OV0_P1_V_ACCUM_INIT, p1_v_accum_init);
OUTREG(R128_OV0_P23_V_ACCUM_INIT, 0);
OUTREG(R128_OV0_P1_H_ACCUM_INIT, p1_h_accum_init);
OUTREG(R128_OV0_P23_H_ACCUM_INIT, p23_h_accum_init);
OUTREG(R128_OV0_SCALE_CNTL, 0x41FF8B03);
OUTREG(R128_OV0_REG_LOAD_CNTL, 0);
return true;
}
void
Rage128_StopOverlay(void)
{
OUTREG(R128_OV0_SCALE_CNTL, 0); // reset the video
// Reset the key color and mask so that when the overlay is started again
// it will be initialized.
sCurrentKeyColor = 0;
sCurrentKeyMask = 0;
}