MacGLide/MacGLide/OpenGLide/grguLfb.cpp

620 lines
19 KiB
C++

//**************************************************************
//* OpenGLide - Glide to OpenGL Wrapper
//* http://openglide.sourceforge.net
//*
//* Linear Frame Buffer Functions
//*
//* OpenGLide is OpenSource under LGPL license
//* Originaly made by Fabio Barros
//* Modified by Paul for Glidos (http://www.glidos.net)
//* Mac version and additional features by Jens-Olaf Hemprich
//**************************************************************
#include "Glide.h"
#include "GlideApplication.h"
#include "FormatConversion.h"
#include "GLExtensions.h"
#include "GLRender.h"
#include "GLUtil.h"
//*************************************************
FX_ENTRY FxBool FX_CALL
grLfbLock( GrLock_t dwType,
GrBuffer_t dwBuffer,
GrLfbWriteMode_t dwWriteMode,
GrOriginLocation_t dwOrigin,
FxBool bPixelPipeline,
GrLfbInfo_t *lfbInfo )
{
#if defined(OGL_CRITICAL) || defined(OGL_FRAMEBUFFER)
GlideMsg("grLfbLock( %d, %d, %d, %d, %d, 0x%x )\n",
dwType, dwBuffer, dwWriteMode, dwOrigin, bPixelPipeline, lfbInfo);
#endif
#ifdef OGL_NOTDONE
if (dwWriteMode != GR_LFBWRITEMODE_565
&& dwWriteMode != GR_LFBWRITEMODE_1555
&& dwWriteMode != GR_LFBWRITEMODE_888
&& dwWriteMode != GR_LFBWRITEMODE_ANY)
{
GlideMsg("grLfbLock() - dwWriteMode %d not supported\n", dwWriteMode);
}
#endif
glReportErrors("grLfbLock");
dwWriteMode = (dwWriteMode == GR_LFBWRITEMODE_ANY) ? GR_LFBWRITEMODE_565 : dwWriteMode;
lfbInfo->strideInBytes = Glide.WindowWidth * (dwWriteMode >= GR_LFBWRITEMODE_888 ? 4 : 2);
lfbInfo->writeMode = dwWriteMode;
lfbInfo->origin = dwOrigin;
if ( dwType & GR_LFB_WRITE_ONLY )
{
lfbInfo->lfbPtr = Glide.FrameBuffer.Address;
s_Framebuffer.OnBufferLockStartWrite(dwType, dwBuffer, dwWriteMode, dwOrigin, bPixelPipeline);
}
else if (OpenGL.WinOpen == false && Glide.ReadBuffer.Address)
{
BufferStruct* targetbuffer = &Glide.ReadBuffer;
lfbInfo->lfbPtr = targetbuffer->Address;
lfbInfo->origin = GR_ORIGIN_UPPER_LEFT;
}
else
{
// finish rendering
RenderDrawTriangles();
glFinish();
glReportError();
// Alloc readbuffer
if (Glide.ReadBuffer.Address == NULL)
{
// @todo: 32bit read buffers are cureently not supported (any mac game using this format for reads?)
Glide.ReadBuffer.Address = (FxU16*) AllocFrameBuffer(Glide.WindowTotalPixels,
//dwWriteMode >= GR_LFBWRITEMODE_888 ? sizeof(FxU32) : sizeof(FxU16)
sizeof(FxU16)
);
#ifdef OPENGL_DEBUG
GlideMsg("Allocated Readbuffer(%dx%d) at 0x%x\n",
Glide.WindowWidth, Glide.WindowHeight, Glide.ReadBuffer.Address);
#endif
}
// select main memory buffers
BufferStruct* targetbuffer = &Glide.ReadBuffer;
const BufferStruct* sourcebuffer = &Glide.TempBuffer;
if (s_Framebuffer.GetRenderBufferChangedForRead())
{
// select buffer size
const unsigned long bufferwidth = OpenGL.WindowWidth;
const unsigned long bufferheight = OpenGL.WindowHeight;
glReadBuffer(dwBuffer == GR_BUFFER_BACKBUFFER ? GL_BACK : GL_FRONT);
glReportError();
const bool scale = bufferwidth != Glide.WindowWidth || bufferheight != Glide.WindowHeight;
GLint glWriteMode;
switch (dwWriteMode)
{
case GR_LFBWRITEMODE_1555: glWriteMode = GL_UNSIGNED_SHORT_1_5_5_5_REV; break;
case GR_LFBWRITEMODE_565: glWriteMode = GL_UNSIGNED_SHORT_5_6_5; break;
//case GR_LFBWRITEMODE_888: glWriteMode = GL_UNSIGNED_BYTE_8_8_8_8; break;
default: glWriteMode = GL_UNSIGNED_SHORT_5_6_5; break;
}
// The read buffer is sized for Glide pixels. As a result we cannot be used it when the read buffer has to be resized
void* destination = (!scale && dwOrigin == GR_ORIGIN_LOWER_LEFT) ? targetbuffer->Address : sourcebuffer->Address;
#ifdef OPENGL_DEBUG
GlideMsg("Calling glReadPixels(%d, %d, 0x%x)\n", bufferwidth, bufferheight, destination);
#endif
glReadPixels(0, 0, bufferwidth, bufferheight,
(dwWriteMode == GR_LFBWRITEMODE_565) ? GL_RGB : GL_RGBA,
glWriteMode, destination);
glReportError();
#ifdef OPENGL_DEBUG
if (scale)
GlideMsg("Scaling to (%d, %d) from 0x%x to 0x%x\n",
Glide.WindowWidth, Glide.WindowHeight, sourcebuffer->Address, targetbuffer->Address);
#endif
if (dwOrigin == GR_ORIGIN_UPPER_LEFT)
{
// When the OpenGL resolution differs from the Glide resolution,
// the content of the read buffer must be scaled
if (scale)
{
// size/copy from OpenGL-sized buffer to Glide-sized buffer?
const FxU16* src;
FxU16* dst = targetbuffer->Address;
const int xratio = (bufferwidth << 16) / (Glide.WindowWidth);
const int yratio = (bufferheight << 16) / (Glide.WindowHeight);
int u;
int v = 0;
int x;
int y;
for(y = 0; y < Glide.WindowHeight; y++)
{
src = sourcebuffer->Address + (bufferheight -1 - (v >> 16)) * bufferwidth;
u = 0;
for(x = 0;x < Glide.WindowWidth; x++)
{
*dst++ = src[u >> 16];
u += xratio;
}
v += yratio;
}
}
else
{
#ifdef OPENGL_DEBUG
GlideMsg("Copying/Vertical mirroring pixels to destination buffer from 0x%x to 0x%x\n",
sourcebuffer->Address, targetbuffer->Address);
#endif
// Swap pixels during copy from temp to read buffer
for ( int j = 0; j < Glide.WindowHeight; j++ )
{
memcpy(targetbuffer->Address + (j * Glide.WindowWidth),
sourcebuffer->Address + ((bufferheight - 1 - j) * bufferwidth),
2 * Glide.WindowWidth);
}
}
}
else if (scale) // GR_ORIGIN_LOWER_LEFT
{
// size/copy from OpenGL-sized buffer to Glide-sized buffer?
if (scale)
{
// Copy and scale
const FxU16* src;
FxU16* dst = targetbuffer->Address;
const int xratio = (bufferwidth << 16) / Glide.WindowWidth;
const int yratio = (bufferheight << 16) / Glide.WindowHeight;
int u;
int v = 0;
int x;
int y;
for(y = 0; y < Glide.WindowHeight; y++)
{
src = sourcebuffer->Address + (v >> 16) * bufferwidth;
u = 0;
for(x = 0;x < Glide.WindowWidth; x++)
{
*dst++ = src[u >> 16];
u += xratio;
}
v += yratio;
}
}
else
{
#ifdef OPENGL_DEBUG
GlideMsg("Copying/Vertical mirroring not necessary - pixels already in the right orientation\n");
#endif
}
}
// Update with current framebuffer pixels not yet written to vram
// (Obmitting causes incomplete screenshots in Falcon 4.0)
s_Framebuffer.CopyFrameBuffer(targetbuffer->Address);
s_Framebuffer.ResetRenderBufferChangedForRead();
}
// Update buffer struct
targetbuffer->Lock = true;
targetbuffer->Type = dwType;
targetbuffer->Buffer = dwBuffer;
targetbuffer->WriteMode = dwWriteMode;
targetbuffer->PixelPipeline = bPixelPipeline;
lfbInfo->lfbPtr = targetbuffer->Address;
}
return FXTRUE;
}
//*************************************************
FX_ENTRY FxBool FX_CALL
grLfbUnlock( GrLock_t dwType, GrBuffer_t dwBuffer )
{
#if defined(OGL_CRITICAL) || defined(OGL_FRAMEBUFFER)
GlideMsg("grLfbUnlock( %d, %d )\n", dwType, dwBuffer );
#endif
if ( dwType & GR_LFB_WRITE_ONLY )
{
if ( ! Glide.FrameBuffer.Lock )
{
return FXFALSE;
}
s_Framebuffer.OnBufferUnlockEndWrite(dwBuffer);
Glide.FrameBuffer.Lock = false;
return FXTRUE;
}
else
{
if (Glide.ReadBuffer.Lock)
{
// We're not interested in keeping track of unlocks since this breaks
// Framebuffer updates when moving the cursor in Carmageddon movie mode
// (because grLfbReadRegion() is called)
// @todo: -> Doesn't solve the issue
Glide.ReadBuffer.Lock = false;
return FXTRUE;
}
else
{
return FXFALSE;
}
}
}
//*************************************************
FX_ENTRY FxBool FX_CALL
grLfbReadRegion( GrBuffer_t src_buffer,
FxU32 src_x, FxU32 src_y,
FxU32 src_width, FxU32 src_height,
FxU32 dst_stride, void *dst_data )
{
#if defined(OGL_DONE) || defined(OGL_FRAMEBUFFER)
GlideMsg("grLfbReadRegion( %d, %d, %d, %d, %d, %d, 0x%x )\n",
src_buffer, src_x, src_y, src_width, src_height, dst_stride, dst_data);
#endif
if (s_GlideApplication.GetType() == GlideApplication::Carmageddon)
{
RenderDrawTriangles();
s_Framebuffer.OnLfbReadRegion();
// To render the cursor in Movie-mode correctly, the region
// must be filled with the framebuffer's chromakey color.
// But Carmageddon seems to write a column filled with the
// endian-swapped chromakey value into the framebuffer.
// Workaround:
// Using an endian-symetric chromakey value (outch)
// Also one more pixel than expected must be set in order to
// avoid a black dot in the lower right corner of the cursor.
// All of this could be avoided with PedanticFrameBufferEmulation.
const unsigned jump_dst = ((dst_stride >> 1) - src_width);
unsigned long jump = jump_dst;
const unsigned long pixels = src_width * src_height + 1;
FxU16* d = reinterpret_cast<FxU16*>(dst_data);
FxU16 chromakey = s_Framebuffer.GetChromaKeyValue();
swapshort(&chromakey);
for(unsigned int i = 0; i < pixels; i+=1)
{
d[i] = chromakey;
jump--;
if (jump == 0)
{
jump = jump_dst;
i += jump;
}
}
return FXTRUE;
}
// Copied from the linux sst1 driver src
FxBool rv = FXTRUE;
GrLfbInfo_t info;
//#if (GLIDE_PLATFORM & GLIDE_HW_SST1)
// gc->lfbSliOk = 1;
info.size = sizeof( info );
if ( grLfbLock( GR_LFB_READ_ONLY,
src_buffer,
GR_LFBWRITEMODE_ANY,
GR_ORIGIN_UPPER_LEFT,
FXFALSE,
&info ) ) {
FxU32 *srcData; /* Tracking Source Pointer */
FxU32 *dstData; /* Tracking Destination Pointer */
FxU32 *end; /* Demarks End of each Scanline */
FxU32 srcJump; /* bytes to next scanline */
FxU32 dstJump; /* bytes to next scanline */
FxU32 length; /* bytes to copy in scanline */
FxU32 scanline; /* scanline number */
int aligned; /* word aligned? */
FxU32 odd; /* is src_y odd? ( for sli ) */
dstData = ( FxU32 * ) dst_data;
srcData = ( FxU32 * ) ( ((char*)info.lfbPtr)+
(src_y*info.strideInBytes) +
(src_x<<1) );
scanline = src_height;
length = src_width * 2;
dstJump = dst_stride - length;
srcJump = info.strideInBytes - length;
aligned = !((int)srcData&0x2);
odd = (src_y+src_height) & 0x1;
if ( aligned ) {
while( scanline-- ) {
end = (FxU32*)((char*)srcData + length - 2);
/*
if(gc->scanline_interleaved == FXTRUE) {
if((scanline+odd) & 0x1)
sst1InitSliPciOwner(gc->base_ptr, SST_SLI_MASTER_OWNPCI);
else
sst1InitSliPciOwner(gc->base_ptr, SST_SLI_SLAVE_OWNPCI);
}
*/
while( srcData < end )
*dstData++ = *srcData++;
if ( ((int)length) & 0x2 ) {
(*(FxU16*)dstData) = (*(FxU16*)srcData);
dstData = (FxU32*)(((FxU16*)dstData) + 1 );
srcData = (FxU32*)(((FxU16*)srcData) + 1 );
}
dstData = (FxU32*)(((char*)dstData)+dstJump);
srcData = (FxU32*)(((char*)srcData)+srcJump);
}
} else {
while( scanline-- ) {
end = (FxU32*)((char*)srcData + length - 2);
/*
if(gc->scanline_interleaved == FXTRUE) {
if((scanline+odd) & 0x1)
sst1InitSliPciOwner(gc->base_ptr, SST_SLI_MASTER_OWNPCI);
else
sst1InitSliPciOwner(gc->base_ptr, SST_SLI_SLAVE_OWNPCI);
}
*/
(*(FxU16*)dstData) = (*(FxU16*)srcData);
dstData = (FxU32*)(((FxU16*)dstData) + 1 );
srcData = (FxU32*)(((FxU16*)srcData) + 1 );
while( srcData < end )
*dstData++ = *srcData++;
if ( !(((int)length) & 0x2) ) {
(*(FxU16*)dstData) = (*(FxU16*)srcData);
dstData = (FxU32*)(((FxU16*)dstData) + 1 );
srcData = (FxU32*)(((FxU16*)srcData) + 1 );
}
dstData = (FxU32*)(((char*)dstData)+dstJump);
srcData = (FxU32*)(((char*)srcData)+srcJump);
}
}
grLfbUnlock( GR_LFB_READ_ONLY, src_buffer );
/*
if ( gc->scanline_interleaved )
sst1InitSliPciOwner( gc->base_ptr, SST_SLI_MASTER_OWNPCI );
*/
} else {
rv = FXFALSE;
}
return rv;
}
//*************************************************
FX_ENTRY FxBool FX_CALL
grLfbWriteRegion( GrBuffer_t dst_buffer,
FxU32 dst_x, FxU32 dst_y,
GrLfbSrcFmt_t src_format,
FxU32 src_width, FxU32 src_height,
FxI32 src_stride, void *src_data )
{
#if defined(OGL_DONE) || defined(OGL_FRAMEBUFFER)
GlideMsg("grLfbWriteRegion( %d, %d, %d, %d, %d, %d, %d, 0x%x )\n",
dst_buffer, dst_x, dst_y, src_format, src_width, src_height, src_stride, src_data);
#endif
// Copied from the linux sst1 driver src
FxBool rv = FXTRUE;
GrLfbInfo_t info;
GrLfbWriteMode_t writeMode;
/*
GR_BEGIN_NOFIFOCHECK("grLfbWriteRegion",82);
GDBG_INFO_MORE((gc->myLevel,
"(0x%x,%d,%d,%d,%d,%d,%d,0x%x)\n",
dst_buffer, dst_x, dst_y,
src_format, src_width, src_height,
src_stride, src_data ));
*/
// #if ( GLIDE_PLATFORM & GLIDE_HW_SST1 )
if ( src_format == GR_LFB_SRC_FMT_RLE16 )
writeMode = GR_LFBWRITEMODE_565;
else
writeMode = src_format;
info.size = sizeof( info );
if ( grLfbLock( GR_LFB_WRITE_ONLY | GR_LFB_NOIDLE,
dst_buffer,
writeMode,
GR_ORIGIN_UPPER_LEFT,
FXFALSE,
&info ) ) {
FxU32 *srcData; /* Tracking Source Pointer */
FxU32 *dstData; /* Tracking Destination Pointer */
FxU32 *end; /* Demarks End of each Scanline */
FxI32 srcJump; /* bytes to next scanline */
FxU32 dstJump; /* bytes to next scanline */
FxU32 length; /* bytes to copy in scanline */
FxU32 scanline; /* scanline number */
int aligned; /* word aligned? */
srcData = ( FxU32 * ) src_data;
dstData = ( FxU32 * ) ( ((char*)info.lfbPtr)+
(dst_y*info.strideInBytes) );
scanline = src_height;
switch( src_format ) {
/* 16-bit aligned */
case GR_LFB_SRC_FMT_565:
case GR_LFB_SRC_FMT_555:
case GR_LFB_SRC_FMT_1555:
case GR_LFB_SRC_FMT_ZA16:
dstData = (FxU32*)(((FxU16*)dstData) + dst_x);
length = src_width * 2;
aligned = !((int)dstData&0x2);
srcJump = src_stride - length;
dstJump = info.strideInBytes - length;
if ( aligned )
{
while( scanline-- )
{
// GR_SET_EXPECTED_SIZE(length);
end = (FxU32*)((char*)srcData + length - 2);
while( srcData < end )
{
// GR_SET( dstData[0], srcData[0] );
#ifdef OPENGLIDE_HOST_MAC
swaplong(dstData, srcData);
#else
*dstData = *srcData;
#endif
dstData++;
srcData++;
}
if ( ((int)length) & 0x2 )
{
/*
GR_SET16( (*(FxU16*)&(dstData[0])),
(*(FxU16*)&(srcData[0])) );
*/
(*(FxU16*)&(dstData[0])) = (*(FxU16*)&(srcData[0]));
dstData = (FxU32*)(((FxU16*)dstData) + 1 );
srcData = (FxU32*)(((FxU16*)srcData) + 1 );
}
dstData = (FxU32*)(((char*)dstData)+dstJump);
srcData = (FxU32*)(((char*)srcData)+srcJump);
// GR_CHECK_SIZE_SLOPPY();
}
}
else
{
while( scanline-- ) {
// GR_SET_EXPECTED_SIZE(length);
end = (FxU32*)((char*)srcData + length - 2);
/*
GR_SET16( (*(FxU16*)&(dstData[0])),
(*(FxU16*)&(srcData[0])) );
*/
#ifdef OPENGLIDE_HOST_MAC
swapshort(dstData, srcData);
#else
(*(FxU16*)&(dstData[0])) = (*(FxU16*)&(srcData[0]));
#endif
dstData = (FxU32*)(((FxU16*)dstData) + 1 );
srcData = (FxU32*)(((FxU16*)srcData) + 1 );
while( srcData < end ) {
// GR_SET( dstData[0], srcData[0] );
#ifdef OPENGLIDE_HOST_MAC
swaplong(dstData, srcData);
#else
*dstData = *srcData;
#endif
dstData++;
srcData++;
}
if ( !(length & 0x2) )
{
/*
GR_SET16( (*(FxU16*)&(dstData[0])),
(*(FxU16*)&(srcData[0])) );
*/
#ifdef OPENGLIDE_HOST_MAC
swapshort(dstData, srcData);
#else
(*(FxU16*)&(dstData[0])) = (*(FxU16*)&(srcData[0]));
#endif
dstData = (FxU32*)(((FxU16*)dstData) + 1 );
srcData = (FxU32*)(((FxU16*)srcData) + 1 );
}
dstData = (FxU32*)(((char*)dstData)+dstJump);
srcData = (FxU32*)(((char*)srcData)+srcJump);
// GR_CHECK_SIZE_SLOPPY();
}
}
break;
/* 32-bit aligned */
case GR_LFB_SRC_FMT_888:
case GR_LFB_SRC_FMT_8888:
case GR_LFB_SRC_FMT_565_DEPTH:
case GR_LFB_SRC_FMT_555_DEPTH:
case GR_LFB_SRC_FMT_1555_DEPTH:
dstData = ((FxU32*)dstData) + dst_x;
length = src_width * 4;
srcJump = src_stride - length;
dstJump = info.strideInBytes - length;
while( scanline-- ) {
// GR_SET_EXPECTED_SIZE(length);
end = (FxU32*)((char*)srcData + length);
while( srcData < end ) {
// GR_SET( dstData[0], srcData[0] );
#ifdef OPENGLIDE_HOST_MAC
swaplong(dstData, srcData);
#else
*dstData = *srcData;
#endif
dstData++;
srcData++;
}
dstData = (FxU32*)(((char*)dstData)+dstJump);
srcData = (FxU32*)(((char*)srcData)+srcJump);
// GR_CHECK_SIZE_SLOPPY();
}
break;
case GR_LFB_SRC_FMT_RLE16:
/* needs to be implemented */
rv = FXFALSE;
break;
}
grLfbUnlock( GR_LFB_WRITE_ONLY, dst_buffer );
} else {
rv = FXFALSE;
}
return rv;
}
FX_ENTRY void FX_CALL
grLfbConstantAlpha( GrAlpha_t alpha )
{
#ifdef /* OGL_CRITICAL*/ OGL_DONE
GlideMsg("grLfbConstantAlpha( %lu )\n", alpha );
#endif
s_Framebuffer.SetAlpha(alpha);
}
FX_ENTRY void FX_CALL
grLfbConstantDepth( FxU16 depth )
{
#ifdef /* OGL_CRITICAL*/ OGL_DONE
GlideMsg("grLfbConstantDepth( %u )\n", depth );
#endif
if (OpenGL.DepthBufferType == 1) // == GR_DEPTHBUFFER_ZBUFFER)
{
// map depth to range (0.0, 1.0)
s_Framebuffer.SetDepth(depth * D1OVER65535);
}
else
{
// depth is a float value
#ifdef /* OGL_CRITICAL*/ OGL_DONE
GlideMsg("grLfbConstantDepth( %u ) wbuffer not done\n", depth );
#endif
s_Framebuffer.SetDepth(depth * D1OVER65535);
}
}
FX_ENTRY void FX_CALL
grLfbWriteColorSwizzle( FxBool swizzleBytes, FxBool swapFxU16s )
{
#ifdef /* OGL_CRITICAL*/ OGL_NOTDONE
GlideMsg("grLfbWriteColorSwizzle( %d, %d )\n",
swizzleBytes, swapFxU16s );
#endif
}
FX_ENTRY void FX_CALL
grLfbWriteColorFormat( GrColorFormat_t colorFormat )
{
#ifdef /* OGL_CRITICAL */ OGL_NOTDONE
GlideMsg("grLfbWriteColorFormat( %u )\n", colorFormat );
#endif
}